diff --git a/cpp/sum.cpp b/cpp/sum.cpp index f594d6b..5c1480c 100644 --- a/cpp/sum.cpp +++ b/cpp/sum.cpp @@ -49,24 +49,30 @@ typedef struct Parent { } Parent; typedef struct Person { - const char *name; int age; double doubleProps; + const char *name; char **stringArray; double *doubleArray; int *i32Array; + int testnum; + bool boolTrue; + bool boolFalse; // Parent parent; } Person; extern "C" const Person *getStruct(const Person *person) { - printf("Name: %s\n", person->name); + // printf("Name: %s\n", person->name); printf("Age: %d\n", person->age); - printf("doubleProps: %f \n", person->doubleProps); + printf("doubleProps: %f\n", person->doubleProps); printf("stringArray: %s\n", person->stringArray[0]); - printf("stringArray: %s\n", person->stringArray[1]); - printf("doubleArray: %f\n", person->doubleArray[0]); - printf("doubleArray: %f\n", person->doubleArray[1]); - printf("i32Array: %d\n", person->i32Array[0]); + printf("testnum: %d\n", person->testnum); + // printf("stringArray: %s\n", person->stringArray[1]); + // printf("doubleArray: %f\n", person->doubleArray[0]); + // printf("doubleArray: %f\n", person->doubleArray[1]); + // printf("i32Array: %d\n", person->i32Array[0]); + // printf("bool: %d\n", person->boolTrue); + // printf("bool: %d\n", person->boolFalse); // printf("Parent Age: %d\n", person->parent.age); // printf("Parent Name: %s\n", person->parent.name); return person; diff --git a/memory.js b/memory.js index 7d38bb0..f923a2c 100644 --- a/memory.js +++ b/memory.js @@ -1,5 +1,6 @@ const Koa = require('koa'); const app = new Koa(); +process.env.MEMORY = 1 const { unitTest } = require('./test') app.use(async ctx => { diff --git a/scripts/types.d.ts b/scripts/types.d.ts index 60f1b7a..6d15c69 100644 --- a/scripts/types.d.ts +++ b/scripts/types.d.ts @@ -17,10 +17,10 @@ type DataFieldTypeToType> = T extends ArrayConstructorOptions ? DataTypeToType : never; - export function load>>(params: Omit, 'retType'> & { - retType?: U - }): { [K in keyof U]: DataFieldTypeToType } - +export function load>>(params: Omit, 'retType'> & { + retType?: U +}): { [K in keyof U]: DataFieldTypeToType } + export function load(params: Omit, 'retType'> & { retType: T }): DataTypeToType diff --git a/src/lib.rs b/src/lib.rs index fd41bc3..44e8881 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -5,7 +5,7 @@ mod utils; use define::{number_to_data_type, DataType, FFIParams, OpenParams, RsArgsValue}; use napi::bindgen_prelude::*; use utils::{ - align_ptr, calculate_layout, create_array_from_pointer, get_data_type_size_align, + calculate_layout, create_array_from_pointer, get_data_type_size_align, get_js_function_call_value, js_array_to_number_array, js_array_to_string_array, js_nunmber_to_i32, js_string_to_string, js_unknown_to_data_type, rs_array_to_js_array, ArrayType, }; @@ -18,7 +18,7 @@ use libffi_sys::{ ffi_type_pointer, ffi_type_sint32, ffi_type_uint8, ffi_type_void, }; use libloading::{Library, Symbol}; -use napi::{Env, JsFunction, JsNumber, JsObject, JsString, JsUnknown}; +use napi::{Env, JsBoolean, JsFunction, JsNumber, JsObject, JsString, JsUnknown}; use std::alloc::{alloc, Layout}; use std::collections::HashMap; use std::ffi::c_void; @@ -142,7 +142,7 @@ fn load( } DataType::Boolean => { let arg_type = &mut ffi_type_uint8 as *mut ffi_type; - let arg_val: bool = value.coerce_to_bool().unwrap().try_into().unwrap(); + let arg_val: bool = value.coerce_to_bool().unwrap().get_value().unwrap(); (arg_type, RsArgsValue::Boolean(arg_val)) } DataType::Void => { @@ -177,6 +177,11 @@ fn load( let val: i32 = val.try_into().unwrap(); RsArgsValue::I32(val) } + DataType::Boolean => { + let val: JsBoolean = params_value_object.get_named_property(&field).unwrap(); + let val: bool = val.get_value().unwrap(); + RsArgsValue::Boolean(val) + } DataType::Double => { let val: JsNumber = params_value_object.get_named_property(&field).unwrap(); let val: f64 = val.try_into().unwrap(); @@ -308,41 +313,51 @@ fn load( RsArgsValue::Object(val) => { let (size, align) = calculate_layout(&val); let layout = if size > 0 && align > 0 { - Layout::from_size_align(size, align).unwrap() + Layout::from_size_align(size, 4).unwrap() } else { Layout::new::() }; let ptr = alloc(layout) as *mut c_void; let field_ptr = ptr; - unsafe fn write_data( - map: IndexMap, - mut field_ptr: *mut c_void, - align: usize, - ) { + unsafe fn write_data(map: IndexMap, mut field_ptr: *mut c_void) { + let mut offset = 0; for (_, field_val) in map { match field_val { RsArgsValue::I32(number) => { + let align = std::mem::align_of::(); + let padding = (align - (offset % align)) % align; + field_ptr = field_ptr.offset(padding as isize); (field_ptr as *mut c_int).write(number); - field_ptr = - field_ptr.offset(std::mem::size_of::() as isize) as *mut c_void; - field_ptr = align_ptr(field_ptr, align); + offset = std::mem::size_of::(); } RsArgsValue::Double(double_number) => { + let align = std::mem::align_of::(); + let padding = (align - (offset % align)) % align; + field_ptr = field_ptr.offset(padding as isize); (field_ptr as *mut c_double).write(double_number); - field_ptr = - field_ptr.offset(std::mem::size_of::() as isize) as *mut c_void; - field_ptr = align_ptr(field_ptr, align); + offset = std::mem::size_of::(); + } + RsArgsValue::Boolean(val) => { + let align = std::mem::align_of::(); + let padding = (align - (offset % align)) % align; + field_ptr = field_ptr.offset(padding as isize); + (field_ptr as *mut bool).write(val); + offset = std::mem::size_of::(); } RsArgsValue::String(str) => { + let align = std::mem::align_of::<*const c_char>(); + let padding = (align - (offset % align)) % align; + field_ptr = field_ptr.offset(padding as isize); let c_string = CString::new(str).unwrap(); (field_ptr as *mut *const c_char).write(c_string.as_ptr()); std::mem::forget(c_string); - field_ptr = - field_ptr.offset(std::mem::size_of::<*const c_char>() as isize) as *mut c_void; - field_ptr = align_ptr(field_ptr, align); + offset = std::mem::size_of::<*const c_char>(); } RsArgsValue::StringArray(str_arr) => { + let align = std::mem::align_of::<*const *const c_char>(); + let padding = (align - (offset % align)) % align; + field_ptr = field_ptr.offset(padding as isize); let c_char_vec: Vec<*const c_char> = str_arr .into_iter() .map(|str| { @@ -352,39 +367,42 @@ fn load( return ptr; }) .collect(); - (field_ptr as *mut *const *const c_char).write(c_char_vec.as_ptr()); std::mem::forget(c_char_vec); - field_ptr = field_ptr.offset(std::mem::size_of::<*const *const c_char>() as isize) - as *mut c_void; - field_ptr = align_ptr(field_ptr, align); + offset = std::mem::size_of::<*const *const c_char>(); } RsArgsValue::DoubleArray(arr) => { + let align = std::mem::align_of::<*const c_double>(); + let padding = (align - (offset % align)) % align; + field_ptr = field_ptr.offset(padding as isize); (field_ptr as *mut *const c_double).write(arr.as_ptr()); std::mem::forget(arr); - field_ptr = field_ptr.offset(std::mem::size_of::<*const c_double>() as isize) - as *mut c_void; - field_ptr = align_ptr(field_ptr, align); + offset = std::mem::size_of::<*const c_double>(); } RsArgsValue::I32Array(arr) => { + let align = std::mem::align_of::<*const c_int>(); + let padding = (align - (offset % align)) % align; + field_ptr = field_ptr.offset(padding as isize); (field_ptr as *mut *const c_int).write(arr.as_ptr()); std::mem::forget(arr); - field_ptr = - field_ptr.offset(std::mem::size_of::<*const c_int>() as isize) as *mut c_void; - field_ptr = align_ptr(field_ptr, align); + offset = std::mem::size_of::<*const c_int>(); } RsArgsValue::Object(val) => { let (size, _) = calculate_layout(&val); - write_data(val, field_ptr, align); - field_ptr = field_ptr.offset(size as isize) as *mut c_void; - field_ptr = align_ptr(field_ptr, align); + let align = std::mem::align_of::(); // Assuming the alignment of the object is the same as usize + let padding = (align - (offset % align)) % align; + field_ptr = field_ptr.offset(padding as isize); + write_data(val, field_ptr); + offset = size; } _ => panic!("write_data"), } + field_ptr = field_ptr.offset(offset as isize); } } - write_data(val, field_ptr, align); - return Box::into_raw(Box::new(ptr)) as *mut c_void; + write_data(val, field_ptr); + let p = Box::into_raw(Box::new(ptr)) as *mut c_void; + return p; } }) .collect(); @@ -483,17 +501,15 @@ fn load( Either9::D(result) } DataType::Boolean => { - let mut result: u8 = 255; + let mut result: bool = false; ffi_call( &mut cif, Some(*func), - &mut result as *mut u8 as *mut c_void, + &mut result as *mut bool as *mut c_void, arg_values_c_void.as_mut_ptr(), ); - if result != 0 && result != 1 { - panic!("The returned type is not a boolean") - } - Either9::H(if result == 0 { false } else { true }) + + Either9::H(result) } _ => { panic!( @@ -573,17 +589,16 @@ fn load( _ => panic!("some error"), } } else { - let (ret_fields_size, align) = + let ret_fields_size = JsObject::keys(&ret_object) .unwrap() .into_iter() - .fold((0, 0), |pre, current| { - let (size, mut align) = pre; + .fold(0, |pre, current| { + let size = pre; let val: JsUnknown = ret_object.get_named_property(¤t).unwrap(); let data_type = js_unknown_to_data_type(val); - let (field_size, field_align) = get_data_type_size_align(data_type); - align = align.max(field_align); - (size + field_size, align) + let (field_size, _) = get_data_type_size_align(data_type); + size + field_size }); let mut result: *mut c_void = malloc(ret_fields_size); ffi_call( @@ -594,6 +609,7 @@ fn load( ); let mut js_object = env.create_object().unwrap(); let mut field_ptr = result; + let mut offset = 0; JsObject::keys(&ret_object) .unwrap() .into_iter() @@ -612,18 +628,22 @@ fn load( }; match data_type { DataType::I32 => { - let type_field_ptr = field_ptr as *mut i32; + let align = std::mem::align_of::(); + let padding = (align - (offset % align)) % align; + field_ptr = field_ptr.offset(padding as isize); + let type_field_ptr = field_ptr as *mut c_int; js_object .set_property( env.create_string(&field).unwrap(), env.create_int32(*type_field_ptr).unwrap(), ) .unwrap(); - field_ptr = - field_ptr.offset(std::mem::size_of::() as isize) as *mut c_void; - field_ptr = align_ptr(field_ptr, align); + offset = std::mem::size_of::(); } DataType::Double => { + let align = std::mem::align_of::(); + let padding = (align - (offset % align)) % align; + field_ptr = field_ptr.offset(padding as isize); let type_field_ptr = field_ptr as *mut c_double; js_object .set_property( @@ -631,11 +651,25 @@ fn load( env.create_double(*type_field_ptr).unwrap(), ) .unwrap(); - field_ptr = - field_ptr.offset(std::mem::size_of::() as isize) as *mut c_void; - field_ptr = align_ptr(field_ptr, align); + offset = std::mem::size_of::(); + } + DataType::Boolean => { + let align = std::mem::align_of::(); + let padding = (align - (offset % align)) % align; + field_ptr = field_ptr.offset(padding as isize); + let type_field_ptr = field_ptr as *mut bool; + js_object + .set_property( + env.create_string(&field).unwrap(), + env.get_boolean(*type_field_ptr).unwrap(), + ) + .unwrap(); + offset = std::mem::size_of::(); } DataType::String => { + let align = std::mem::align_of::<*const c_char>(); + let padding = (align - (offset % align)) % align; + field_ptr = field_ptr.offset(padding as isize); let type_field_ptr = field_ptr as *mut *mut c_char; let js_string = CString::from_raw(*type_field_ptr).into_string().unwrap(); js_object @@ -644,42 +678,43 @@ fn load( env.create_string(&js_string).unwrap(), ) .unwrap(); - field_ptr = - field_ptr.offset(std::mem::size_of::<*const c_char>() as isize) as *mut c_void; - field_ptr = align_ptr(field_ptr, align); + offset = std::mem::size_of::<*const c_char>(); } DataType::StringArray => { + let align = std::mem::align_of::<*const *const c_char>(); + let padding = (align - (offset % align)) % align; + field_ptr = field_ptr.offset(padding as isize); let type_field_ptr = field_ptr as *mut *mut *mut c_char; let arr = create_array_from_pointer(*type_field_ptr, array_len); let js_array = rs_array_to_js_array(env, ArrayType::String(arr)); js_object .set_property(env.create_string(&field).unwrap(), js_array) .unwrap(); - field_ptr = field_ptr.offset(std::mem::size_of::<*const *const c_char>() as isize) - as *mut c_void; - field_ptr = align_ptr(field_ptr, align); + offset = std::mem::size_of::<*const *const c_char>(); } DataType::DoubleArray => { + let align = std::mem::align_of::<*const c_double>(); + let padding = (align - (offset % align)) % align; + field_ptr = field_ptr.offset(padding as isize); let type_field_ptr = field_ptr as *mut *mut c_double; let arr = create_array_from_pointer(*type_field_ptr, array_len); let js_array = rs_array_to_js_array(env, ArrayType::Double(arr)); js_object .set_property(env.create_string(&field).unwrap(), js_array) .unwrap(); - field_ptr = field_ptr.offset(std::mem::size_of::<*const c_double>() as isize) - as *mut c_void; - field_ptr = align_ptr(field_ptr, align); + offset = std::mem::size_of::<*const c_double>(); } DataType::I32Array => { + let align = std::mem::align_of::<*const c_int>(); + let padding = (align - (offset % align)) % align; + field_ptr = field_ptr.offset(padding as isize); let type_field_ptr = field_ptr as *mut *mut c_int; let arr = create_array_from_pointer(*type_field_ptr, array_len); let js_array = rs_array_to_js_array(env, ArrayType::I32(arr)); js_object .set_property(env.create_string(&field).unwrap(), js_array) .unwrap(); - field_ptr = - field_ptr.offset(std::mem::size_of::<*const c_int>() as isize) as *mut c_void; - field_ptr = align_ptr(field_ptr, align); + offset = std::mem::size_of::<*const c_int>(); } _ => panic!( @@ -687,6 +722,7 @@ fn load( data_type ), } + field_ptr = field_ptr.offset(offset as isize) as *mut c_void; }); Either9::I(js_object) } diff --git a/src/utils.rs b/src/utils.rs index 6fff021..4b11477 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -72,12 +72,6 @@ where .collect::>() } -pub fn align_ptr(ptr: *mut c_void, align: usize) -> *mut c_void { - let align_minus_one = align - 1; - let ptr_int = ptr as usize; - let aligned = (ptr_int + align_minus_one) & !align_minus_one; - aligned as *mut c_void -} macro_rules! calculate_layout_for { ($variant:ident, $type:ty) => { fn $variant(size: usize, align: usize) -> (usize, usize) { @@ -90,6 +84,7 @@ macro_rules! calculate_layout_for { calculate_layout_for!(calculate_i32, c_int); calculate_layout_for!(calculate_double, c_double); +calculate_layout_for!(calculate_boolean, bool); calculate_layout_for!(calculate_string, *const c_char); calculate_layout_for!(calculate_string_array, *const *const c_char); calculate_layout_for!(calculate_double_array, *const c_double); @@ -102,6 +97,7 @@ pub fn calculate_layout(map: &IndexMap) -> (usize, usize) { RsArgsValue::I32(_) => calculate_i32(size, align), RsArgsValue::Double(_) => calculate_double(size, align), RsArgsValue::String(_) => calculate_string(size, align), + RsArgsValue::Boolean(_) => calculate_boolean(size, align), RsArgsValue::Object(val) => { let (obj_size, obj_align) = calculate_layout(val); let align = align.max(obj_align); @@ -118,7 +114,8 @@ pub fn calculate_layout(map: &IndexMap) -> (usize, usize) { pub fn get_data_type_size_align(data_type: DataType) -> (usize, usize) { return match data_type { - DataType::I32 => (std::mem::size_of::(), std::mem::align_of::()), + DataType::I32 => (std::mem::size_of::(), std::mem::align_of::()), + DataType::Boolean => (std::mem::size_of::(), std::mem::align_of::()), DataType::String => ( std::mem::size_of::<*const c_char>(), std::mem::align_of::<*const c_char>(), diff --git a/test.ts b/test.ts index 8a58b54..7f2625d 100644 --- a/test.ts +++ b/test.ts @@ -82,34 +82,44 @@ const unitTest = () => { paramsValue: [bool_val], })) const person = { - name: 'tom', age: 23, doubleProps: 1.1, + name: 'tom', stringArray: ["foo", "bar"], doubleArray: [1.1, 2.2, 3.3], - i32Array: [1, 2, 3, 4] + i32Array: [1, 2, 3, 4], + testnum: 32, + boolTrue: true, + boolFalse: false } const personObj = load({ library: 'libsum', funcName: 'getStruct', retType: { - name: DataType.String, age: DataType.I32, doubleProps: DataType.Double, + name: DataType.String, stringArray: arrayConstructor({ type: DataType.StringArray, length: person.stringArray.length }), doubleArray: arrayConstructor({ type: DataType.DoubleArray, length: person.doubleArray.length }), i32Array: arrayConstructor({ type: DataType.I32Array, length: person.i32Array.length }), + testnum: DataType.I32, + boolTrue: DataType.Boolean, + boolFalse: DataType.Boolean, }, paramsType: [{ - name: DataType.String, age: DataType.I32, doubleProps: DataType.Double, + name: DataType.String, stringArray: DataType.StringArray, doubleArray: DataType.DoubleArray, i32Array: DataType.I32Array, + testnum: DataType.I32, + boolTrue: DataType.Boolean, + boolFalse: DataType.Boolean, }], paramsValue: [person] }) + console.log(personObj) deepStrictEqual(person, personObj) // deepStrictEqual(person.stringArrProps, personObj.stringArrProps) // const func = () => { @@ -129,6 +139,9 @@ const unitTest = () => { } unitTest() -close('libsum') + +if (!process.env.MEMORY) { + close('libsum') +} exports.unitTest = unitTest