Skip to content

Commit

Permalink
feat: support struct array
Browse files Browse the repository at this point in the history
  • Loading branch information
zhangyuang committed Dec 23, 2024
1 parent c96b001 commit 5c38db9
Show file tree
Hide file tree
Showing 8 changed files with 128 additions and 104 deletions.
6 changes: 0 additions & 6 deletions cpp/sum.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -242,12 +242,6 @@ extern "C" MyClass *createMyClassFromC(const char *name, int age)

extern "C" void printMyClass(MyClass *instance) { instance->print(); }

// typedef struct
// {
// short x, y, dir;
// unsigned char kind;
// } MINUTIA;

typedef struct
{
short x;
Expand Down
47 changes: 31 additions & 16 deletions src/datatype/pointer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -353,19 +353,23 @@ pub unsafe fn free_rs_pointer_memory(
RefDataType::FloatArray => free_dynamic_float_array(ptr, array_len),
RefDataType::StringArray => free_dynamic_string_array(ptr, array_len),
RefDataType::StructArray => {
let (size, align) = calculate_struct_size(&struct_item_type.as_ref().unwrap());
if size > 0 {
let layout = Layout::from_size_align(size, align).unwrap();
let mut start_ptr = ptr;
(0..array_len).for_each(|_| {
free_struct_memory(
*(start_ptr as *mut *mut c_void),
struct_item_type.as_ref().unwrap(),
PointerType::RsPointer,
);
start_ptr = start_ptr.offset(size as isize);
});
dealloc(*(ptr as *mut *mut u8), layout);
let is_stack_struct =
get_ffi_tag(struct_item_type.as_ref().unwrap()) == FFITypeTag::StackStruct;
if !is_stack_struct {
let (size, align) = calculate_struct_size(&struct_item_type.as_ref().unwrap());
if size > 0 {
let layout = Layout::from_size_align(size, align).unwrap();
let mut start_ptr = ptr;
(0..array_len).for_each(|_| {
free_struct_memory(
*(start_ptr as *mut *mut c_void),
struct_item_type.as_ref().unwrap(),
PointerType::RsPointer,
);
start_ptr = start_ptr.offset(size as isize);
});
dealloc(*(ptr as *mut *mut u8), layout);
}
}
}
}
Expand All @@ -375,11 +379,16 @@ pub unsafe fn free_rs_pointer_memory(
free_closure(ptr)
}
} else {
let is_stack_struct = get_ffi_tag(&obj) == FFITypeTag::StackStruct;
let (size, align) = calculate_struct_size(&obj);
if size > 0 {
let layout = Layout::from_size_align(size, align).unwrap();
free_struct_memory(*(ptr as *mut *mut c_void), obj, PointerType::RsPointer);
dealloc(*(ptr as *mut *mut u8), layout);
if !is_stack_struct {
free_struct_memory(*(ptr as *mut *mut c_void), obj, PointerType::RsPointer);
dealloc(*(ptr as *mut *mut u8), layout);
} else {
free_struct_memory(ptr, obj, PointerType::RsPointer);
}
}
}
}
Expand Down Expand Up @@ -441,7 +450,13 @@ pub unsafe fn free_c_pointer_memory(
}
} else {
// struct
free_struct_memory(*(ptr as *mut *mut c_void), obj, PointerType::CPointer);
let is_stack_struct = get_ffi_tag(&obj) == FFITypeTag::StackStruct;
println!("xxx");
if !is_stack_struct {
free_struct_memory(*(ptr as *mut *mut c_void), obj, PointerType::CPointer);
} else {
free_struct_memory(ptr, obj, PointerType::CPointer);
}
free(*(ptr as *mut *mut c_void))
}
}
Expand Down
1 change: 0 additions & 1 deletion src/datatype/restore_struct.rs
Original file line number Diff line number Diff line change
Expand Up @@ -241,7 +241,6 @@ pub unsafe fn create_rs_struct_from_pointer(
let (size, align) = get_size_align::<*const c_void>();
(size, align)
};

let arr = (0..*array_len)
.map(|_| {
let padding = (align - (offset % align)) % align;
Expand Down
55 changes: 2 additions & 53 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,7 @@ mod utils;
use datatype::pointer::{free_c_pointer_memory, free_rs_pointer_memory};
use define::*;
use dlopen::symbor::{Library, Symbol};
use libffi_sys::{
ffi_abi_FFI_DEFAULT_ABI, ffi_call, ffi_cif, ffi_prep_cif, ffi_type, ffi_type_double,
ffi_type_enum_STRUCT, ffi_type_float, ffi_type_pointer, ffi_type_sint16, ffi_type_sint32,
ffi_type_sint64, ffi_type_uint64, ffi_type_uint8, ffi_type_void,
};
use libffi_sys::{ffi_abi_FFI_DEFAULT_ABI, ffi_call, ffi_cif, ffi_prep_cif};
use napi::{Env, JsExternal, JsUnknown, Result};
use std::collections::HashMap;
use std::ffi::c_void;
Expand All @@ -20,6 +16,7 @@ use utils::dataprocess::{
get_arg_types_values, get_ffi_tag, get_js_external_wrap_data, get_js_unknown_from_pointer,
get_value_pointer, type_define_to_rs_args,
};
use utils::pointer::get_ffi_type;

static mut LIBRARY_MAP: Option<
HashMap<
Expand Down Expand Up @@ -224,54 +221,6 @@ unsafe fn load(env: Env, params: FFIParams) -> napi::Result<JsUnknown> {
let ret_type_rs = type_define_to_rs_args(&env, ret_type)?;
let mut ffi_type_cleanup = FFITypeCleanup::new();

unsafe fn get_ffi_type(
ret_type_rs: &RsArgsValue,
ffi_type_cleanup: &mut FFITypeCleanup,
) -> *mut ffi_type {
match ret_type_rs {
RsArgsValue::I32(number) => {
let ret_data_type = (*number).try_into().unwrap();
match ret_data_type {
BasicDataType::U8 => &mut ffi_type_uint8 as *mut ffi_type,
BasicDataType::I32 => &mut ffi_type_sint32 as *mut ffi_type,
BasicDataType::I16 => &mut ffi_type_sint16 as *mut ffi_type,
BasicDataType::I64 | BasicDataType::BigInt => &mut ffi_type_sint64 as *mut ffi_type,
BasicDataType::U64 => &mut ffi_type_uint64 as *mut ffi_type,
BasicDataType::String | BasicDataType::WString => &mut ffi_type_pointer as *mut ffi_type,
BasicDataType::Void => &mut ffi_type_void as *mut ffi_type,
BasicDataType::Float => &mut ffi_type_float as *mut ffi_type,
BasicDataType::Double => &mut ffi_type_double as *mut ffi_type,
BasicDataType::Boolean => &mut ffi_type_uint8 as *mut ffi_type,
BasicDataType::External => &mut ffi_type_pointer as *mut ffi_type,
}
}
RsArgsValue::Object(struct_type) => {
if get_ffi_tag(struct_type) == FFITypeTag::StackStruct {
let mut elements: Vec<*mut ffi_type> = struct_type
.iter()
.filter(|(field_name, _)| field_name != &FFI_TAG_FIELD)
.map(|(_, field_type)| get_ffi_type(field_type, ffi_type_cleanup))
.collect();
elements.push(std::ptr::null_mut());
let struct_type_box = ffi_type {
size: 0,
alignment: 0,
type_: ffi_type_enum_STRUCT as u16,
elements: elements.as_mut_ptr(),
};
let elements_ptr = Box::into_raw(Box::new(elements));
let struct_type_ptr = Box::into_raw(Box::new(struct_type_box));
ffi_type_cleanup.elements_box = Some(elements_ptr);
ffi_type_cleanup.struct_type_box = Some(struct_type_ptr);
struct_type_ptr
} else {
&mut ffi_type_pointer as *mut ffi_type
}
}
_ => &mut ffi_type_void as *mut ffi_type,
}
}

let r_type = get_ffi_type(&ret_type_rs, &mut ffi_type_cleanup);
ffi_type_cleanup.r_type = Some(r_type);
ffi_type_cleanup.arg_types = arg_types;
Expand Down
25 changes: 18 additions & 7 deletions src/utils/dataprocess.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
use super::get_array_desc;
use super::js_value::create_js_value_unchecked;
use super::object_utils::calculate_struct_size;
use super::pointer::get_ffi_type;
use crate::datatype::array::ToRsArray;
use crate::datatype::buffer::get_safe_buffer;
use crate::datatype::create_struct::generate_c_struct;
Expand Down Expand Up @@ -252,6 +253,17 @@ pub unsafe fn get_arg_types_values(
RsArgsValue::Function(params_type_object_rs.clone(), params_val_function),
)
} else {
// struct
let is_stack_struct = get_ffi_tag(&params_type_object_rs) == FFITypeTag::StackStruct;
let mut ffi_type_cleanup = FFITypeCleanup::new();
let arg_type = if is_stack_struct {
get_ffi_type(
&RsArgsValue::Object(params_type_object_rs.clone()),
&mut ffi_type_cleanup,
)
} else {
&mut ffi_type_pointer as *mut ffi_type
};
let params_value_object = create_js_value_unchecked::<JsObject>(value)?;
let index_map = get_params_value_rs_struct(params_type_object_rs, &params_value_object);
(arg_type, RsArgsValue::Object(index_map.unwrap()))
Expand Down Expand Up @@ -415,13 +427,12 @@ pub unsafe fn get_value_pointer(
if let RsArgsValue::Object(arg_type_rs) = arg_type {
let is_stack_struct = get_ffi_tag(arg_type_rs) == FFITypeTag::StackStruct;
Ok(
generate_c_struct(&env, &arg_type_rs, val, None)?
// if is_stack_struct {
// generate_c_struct(&env, &arg_type_rs, val, None)?
// } else {
// Box::into_raw(Box::new(generate_c_struct(&env, &arg_type_rs, val, None)?))
// as *mut c_void
// }
if is_stack_struct {
generate_c_struct(&env, &arg_type_rs, val, None)?
} else {
Box::into_raw(Box::new(generate_c_struct(&env, &arg_type_rs, val, None)?))
as *mut c_void
}
)
} else {
Err(FFIError::Panic(format!("uncorrect params type {:?}", arg_type)).into())
Expand Down
2 changes: 1 addition & 1 deletion src/utils/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ pub mod array;
pub mod dataprocess;
pub mod js_value;
pub mod object_utils;

pub mod pointer;
pub use array::*;
pub use dataprocess::*;
pub use object_utils::*;
56 changes: 56 additions & 0 deletions src/utils/pointer.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
use super::dataprocess::get_ffi_tag;
use super::object_utils::calculate_struct_size;
use crate::define::*;
use libffi_sys::{
ffi_type, ffi_type_double, ffi_type_enum_STRUCT, ffi_type_float, ffi_type_pointer,
ffi_type_sint16, ffi_type_sint32, ffi_type_sint64, ffi_type_uint64, ffi_type_uint8,
ffi_type_void,
};
pub unsafe fn get_ffi_type(
ret_type_rs: &RsArgsValue,
ffi_type_cleanup: &mut FFITypeCleanup,
) -> *mut ffi_type {
match ret_type_rs {
RsArgsValue::I32(number) => {
let ret_data_type = (*number).try_into().unwrap();
match ret_data_type {
BasicDataType::U8 => &mut ffi_type_uint8 as *mut ffi_type,
BasicDataType::I32 => &mut ffi_type_sint32 as *mut ffi_type,
BasicDataType::I16 => &mut ffi_type_sint16 as *mut ffi_type,
BasicDataType::I64 | BasicDataType::BigInt => &mut ffi_type_sint64 as *mut ffi_type,
BasicDataType::U64 => &mut ffi_type_uint64 as *mut ffi_type,
BasicDataType::String | BasicDataType::WString => &mut ffi_type_pointer as *mut ffi_type,
BasicDataType::Void => &mut ffi_type_void as *mut ffi_type,
BasicDataType::Float => &mut ffi_type_float as *mut ffi_type,
BasicDataType::Double => &mut ffi_type_double as *mut ffi_type,
BasicDataType::Boolean => &mut ffi_type_uint8 as *mut ffi_type,
BasicDataType::External => &mut ffi_type_pointer as *mut ffi_type,
}
}
RsArgsValue::Object(struct_type) => {
if get_ffi_tag(struct_type) == FFITypeTag::StackStruct {
let mut elements: Vec<*mut ffi_type> = struct_type
.iter()
.filter(|(field_name, _)| field_name != &FFI_TAG_FIELD)
.map(|(_, field_type)| get_ffi_type(field_type, ffi_type_cleanup))
.collect();
elements.push(std::ptr::null_mut());
let (size, align) = calculate_struct_size(struct_type);
let struct_type_box = ffi_type {
size,
alignment: align as u16,
type_: ffi_type_enum_STRUCT as u16,
elements: elements.as_mut_ptr(),
};
let elements_ptr = Box::into_raw(Box::new(elements));
let struct_type_ptr = Box::into_raw(Box::new(struct_type_box));
ffi_type_cleanup.elements_box = Some(elements_ptr);
ffi_type_cleanup.struct_type_box = Some(struct_type_ptr);
struct_type_ptr
} else {
&mut ffi_type_pointer as *mut ffi_type
}
}
_ => &mut ffi_type_void as *mut ffi_type,
}
}
40 changes: 20 additions & 20 deletions tests/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -402,26 +402,26 @@ const testDefine = () => {
equal(res.sum([1, 2]), 3)
}
const unitTest = () => {
// testNumber()
// logGreen('test number succeed')
// testString()
// logGreen('test string succeed')
// testDefine()
// logGreen('test define succeed')
// testArray()
// logGreen('test array succeed')
// testVoid()
// logGreen('test void succeed')
// testBool()
// logGreen('test bool succeed')
// testMainProgram()
// logGreen('test main program succeed')
// testFunction()
// testCpp()
// logGreen('test cpp succeed')
// testPointer()
// logGreen('test createPointer succeed')
// testRunInNewThread()
testNumber()
logGreen('test number succeed')
testString()
logGreen('test string succeed')
testDefine()
logGreen('test define succeed')
testArray()
logGreen('test array succeed')
testVoid()
logGreen('test void succeed')
testBool()
logGreen('test bool succeed')
testMainProgram()
logGreen('test main program succeed')
testFunction()
testCpp()
logGreen('test cpp succeed')
testPointer()
logGreen('test createPointer succeed')
testRunInNewThread()
testObject()
logGreen('test object succeed')
};
Expand Down

0 comments on commit 5c38db9

Please sign in to comment.