feat(assets): implement exported AAssetManager C-ABI functions and handle table
This commit is contained in:
parent
1969f7aae9
commit
4850bade6b
3 changed files with 252 additions and 0 deletions
225
crates/molotov-core/src/assets/c_api.rs
Normal file
225
crates/molotov-core/src/assets/c_api.rs
Normal file
|
|
@ -0,0 +1,225 @@
|
|||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
#![allow(non_snake_case)]
|
||||
use super::asset::AssetFile;
|
||||
use super::dir::AssetDir;
|
||||
use super::manager::AssetManager;
|
||||
use std::collections::HashMap;
|
||||
use std::ffi::{c_void, CStr};
|
||||
use std::sync::atomic::{AtomicUsize, Ordering};
|
||||
use std::sync::{Arc, Mutex, RwLock};
|
||||
|
||||
static NEXT_ASSET_ID: AtomicUsize = AtomicUsize::new(3001);
|
||||
|
||||
lazy_static::lazy_static! {
|
||||
static ref ASSET_TABLE: RwLock<HashMap<usize, Mutex<AssetFile>>> = RwLock::new(HashMap::new());
|
||||
static ref DIR_TABLE: RwLock<HashMap<usize, Mutex<AssetDir>>> = RwLock::new(HashMap::new());
|
||||
pub static ref GLOBAL_ASSET_MANAGER: Arc<RwLock<AssetManager>> = Arc::new(RwLock::new(AssetManager::new()));
|
||||
}
|
||||
|
||||
pub fn register_test_asset(path: &str, data: Vec<u8>) -> *mut () {
|
||||
if let Ok(mut mgr) = GLOBAL_ASSET_MANAGER.write() {
|
||||
mgr.add_asset(path, data);
|
||||
}
|
||||
1001 as *mut ()
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn AAssetManager_open(
|
||||
_mgr: *mut (),
|
||||
filename: *const libc::c_char,
|
||||
_mode: i32,
|
||||
) -> *mut () {
|
||||
if filename.is_null() {
|
||||
return std::ptr::null_mut();
|
||||
}
|
||||
let name_str = match CStr::from_ptr(filename).to_str() {
|
||||
Ok(s) => s,
|
||||
Err(_) => return std::ptr::null_mut(),
|
||||
};
|
||||
|
||||
let mgr = match GLOBAL_ASSET_MANAGER.read() {
|
||||
Ok(m) => m,
|
||||
Err(_) => return std::ptr::null_mut(),
|
||||
};
|
||||
|
||||
if let Some(file) = mgr.open(name_str) {
|
||||
let id = NEXT_ASSET_ID.fetch_add(1, Ordering::Relaxed);
|
||||
if let Ok(mut table) = ASSET_TABLE.write() {
|
||||
table.insert(id, Mutex::new(file));
|
||||
id as *mut ()
|
||||
} else {
|
||||
std::ptr::null_mut()
|
||||
}
|
||||
} else {
|
||||
std::ptr::null_mut()
|
||||
}
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn AAssetManager_openDir(_mgr: *mut (), dirName: *const libc::c_char) -> *mut () {
|
||||
let name_str = if !dirName.is_null() {
|
||||
CStr::from_ptr(dirName).to_str().unwrap_or("")
|
||||
} else {
|
||||
""
|
||||
};
|
||||
|
||||
let mgr = match GLOBAL_ASSET_MANAGER.read() {
|
||||
Ok(m) => m,
|
||||
Err(_) => return std::ptr::null_mut(),
|
||||
};
|
||||
|
||||
let dir = mgr.open_dir(name_str);
|
||||
let id = NEXT_ASSET_ID.fetch_add(1, Ordering::Relaxed);
|
||||
if let Ok(mut table) = DIR_TABLE.write() {
|
||||
table.insert(id, Mutex::new(dir));
|
||||
id as *mut ()
|
||||
} else {
|
||||
std::ptr::null_mut()
|
||||
}
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn AAsset_read(asset: *mut (), buf: *mut c_void, count: usize) -> i32 {
|
||||
if asset.is_null() || buf.is_null() || count == 0 {
|
||||
return 0;
|
||||
}
|
||||
let id = asset as usize;
|
||||
if let Ok(table) = ASSET_TABLE.read() {
|
||||
if let Some(mutex) = table.get(&id) {
|
||||
if let Ok(mut file) = mutex.lock() {
|
||||
let slice = std::slice::from_raw_parts_mut(buf as *mut u8, count);
|
||||
return file.read(slice) as i32;
|
||||
}
|
||||
}
|
||||
}
|
||||
0
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn AAsset_seek(asset: *mut (), offset: i64, whence: i32) -> i64 {
|
||||
if asset.is_null() {
|
||||
return -1;
|
||||
}
|
||||
let id = asset as usize;
|
||||
if let Ok(table) = ASSET_TABLE.read() {
|
||||
if let Some(mutex) = table.get(&id) {
|
||||
if let Ok(mut file) = mutex.lock() {
|
||||
return file.seek(offset, whence);
|
||||
}
|
||||
}
|
||||
}
|
||||
-1
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn AAsset_seek64(asset: *mut (), offset: i64, whence: i32) -> i64 {
|
||||
AAsset_seek(asset, offset, whence)
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn AAsset_getLength(asset: *mut ()) -> i64 {
|
||||
if asset.is_null() {
|
||||
return 0;
|
||||
}
|
||||
let id = asset as usize;
|
||||
if let Ok(table) = ASSET_TABLE.read() {
|
||||
if let Some(mutex) = table.get(&id) {
|
||||
if let Ok(file) = mutex.lock() {
|
||||
return file.length();
|
||||
}
|
||||
}
|
||||
}
|
||||
0
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn AAsset_getLength64(asset: *mut ()) -> i64 {
|
||||
AAsset_getLength(asset)
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn AAsset_getRemainingLength(asset: *mut ()) -> i64 {
|
||||
if asset.is_null() {
|
||||
return 0;
|
||||
}
|
||||
let id = asset as usize;
|
||||
if let Ok(table) = ASSET_TABLE.read() {
|
||||
if let Some(mutex) = table.get(&id) {
|
||||
if let Ok(file) = mutex.lock() {
|
||||
return file.remaining_length();
|
||||
}
|
||||
}
|
||||
}
|
||||
0
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn AAsset_getRemainingLength64(asset: *mut ()) -> i64 {
|
||||
AAsset_getRemainingLength(asset)
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn AAsset_getBuffer(asset: *mut ()) -> *const c_void {
|
||||
if asset.is_null() {
|
||||
return std::ptr::null();
|
||||
}
|
||||
let id = asset as usize;
|
||||
if let Ok(table) = ASSET_TABLE.read() {
|
||||
if let Some(mutex) = table.get(&id) {
|
||||
if let Ok(file) = mutex.lock() {
|
||||
return file.get_buffer();
|
||||
}
|
||||
}
|
||||
}
|
||||
std::ptr::null()
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn AAsset_close(asset: *mut ()) {
|
||||
if !asset.is_null() {
|
||||
let id = asset as usize;
|
||||
if let Ok(mut table) = ASSET_TABLE.write() {
|
||||
table.remove(&id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn AAssetDir_getNextFileName(assetDir: *mut ()) -> *const libc::c_char {
|
||||
if assetDir.is_null() {
|
||||
return std::ptr::null();
|
||||
}
|
||||
let id = assetDir as usize;
|
||||
if let Ok(table) = DIR_TABLE.read() {
|
||||
if let Some(mutex) = table.get(&id) {
|
||||
if let Ok(mut dir) = mutex.lock() {
|
||||
return dir.get_next_filename();
|
||||
}
|
||||
}
|
||||
}
|
||||
std::ptr::null()
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn AAssetDir_rewind(assetDir: *mut ()) {
|
||||
if !assetDir.is_null() {
|
||||
let id = assetDir as usize;
|
||||
if let Ok(table) = DIR_TABLE.read() {
|
||||
if let Some(mutex) = table.get(&id) {
|
||||
if let Ok(mut dir) = mutex.lock() {
|
||||
dir.rewind();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn AAssetDir_close(assetDir: *mut ()) {
|
||||
if !assetDir.is_null() {
|
||||
let id = assetDir as usize;
|
||||
if let Ok(mut table) = DIR_TABLE.write() {
|
||||
table.remove(&id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,5 +1,6 @@
|
|||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
pub mod asset;
|
||||
pub mod c_api;
|
||||
pub mod dir;
|
||||
pub mod manager;
|
||||
pub mod types;
|
||||
|
|
|
|||
26
crates/molotov-core/tests/aasset_c_api_test.rs
Normal file
26
crates/molotov-core/tests/aasset_c_api_test.rs
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
use molotov_core::assets::c_api::*;
|
||||
use std::ffi::CString;
|
||||
|
||||
#[test]
|
||||
fn test_aasset_c_api_lifecycle() {
|
||||
let mgr_handle = register_test_asset("sounds/click.ogg", b"TEST_CLICK_AUDIO".to_vec());
|
||||
|
||||
unsafe {
|
||||
let filename = CString::new("sounds/click.ogg").unwrap();
|
||||
let asset = AAssetManager_open(mgr_handle, filename.as_ptr(), 3);
|
||||
assert!(!asset.is_null());
|
||||
|
||||
assert_eq!(AAsset_getLength(asset), 16);
|
||||
assert_eq!(AAsset_getRemainingLength(asset), 16);
|
||||
|
||||
let mut buf = [0u8; 16];
|
||||
let read_bytes = AAsset_read(asset, buf.as_mut_ptr() as *mut _, 16);
|
||||
assert_eq!(read_bytes, 16);
|
||||
assert_eq!(&buf, b"TEST_CLICK_AUDIO");
|
||||
|
||||
AAsset_close(asset);
|
||||
// Double-close must not panic or abort
|
||||
AAsset_close(asset);
|
||||
}
|
||||
}
|
||||
Reference in a new issue