From 48d9749af9cc942815fcbe303311bd2423614b1e Mon Sep 17 00:00:00 2001 From: zhangyuang Date: Fri, 20 Oct 2023 12:49:20 +0800 Subject: [PATCH] feat: support struct field type doubleArray --- cpp/sum.cpp | 9 ++++++--- scripts/type.js | 50 +++++++++++++++++++++++++--------------------- src/lib.rs | 53 ++++++++++++++++++++++++++++++++++++++++--------- src/utils.rs | 44 ++++++++++++++++++++++++++++++++++++++++ test.ts | 17 ++++++++++++---- 5 files changed, 134 insertions(+), 39 deletions(-) diff --git a/cpp/sum.cpp b/cpp/sum.cpp index 93ad0bb..ba1d35c 100644 --- a/cpp/sum.cpp +++ b/cpp/sum.cpp @@ -52,7 +52,8 @@ typedef struct Person { const char *name; int age; double doubleProps; - char **stringArrProps; + char **stringArray; + double *doubleArray; // Parent parent; } Person; @@ -60,8 +61,10 @@ extern "C" const Person *getStruct(const Person *person) { printf("Name: %s\n", person->name); printf("Age: %d\n", person->age); printf("doubleProps: %f \n", person->doubleProps); - printf("stringArrProps: %s\n", person->stringArrProps[0]); - printf("stringArrProps: %s\n", person->stringArrProps[1]); + 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("Parent Age: %d\n", person->parent.age); // printf("Parent Name: %s\n", person->parent.name); return person; diff --git a/scripts/type.js b/scripts/type.js index fc837c2..e5368e5 100644 --- a/scripts/type.js +++ b/scripts/type.js @@ -32,35 +32,39 @@ const { resolve } = require('path'); retType: DataType.Void }): undefined - type DataTypeToType = { - [K in keyof T]: T[K] extends DataType.String ? string : - T[K] extends DataType.I32 ? number : - T[K] extends DataType.Double ? number : - T[K] extends DataType.I32Array ? number[] : - T[K] extends DataType.StringArray ? string[] : - T[K] extends DataType.DoubleArray ? number[] : - T[K] extends DataType.Boolean ? boolean : - T[K] extends DataType.Void ? undefined : - never; - }; - export function load>(params: FfiParams & { retType: T }): DataTypeToType + type DataTypeToType = + T extends DataType.String ? string : + T extends DataType.I32 ? number : + T extends DataType.Double ? number : + T extends DataType.I32Array ? number[] : + T extends DataType.StringArray ? string[] : + T extends DataType.DoubleArray ? number[] : + T extends DataType.Boolean ? boolean : + T extends DataType.Void ? undefined : + never + + export type ArrayConstructorOptions = { type: DataType length: number + ffiTypeTag?: string } - export function arrayConstructor(options: ArrayConstructorOptions): ArrayConstructorOptions & { - ffiTypeTag: T - } - type ffiTypeTag = 'double' | 'string' | 'i32'; + export function arrayConstructor(options: ArrayConstructorOptions): ArrayConstructorOptions - type FfiReturnType = T extends 'double' ? number : - T extends 'i32' ? number : - string; + export function load(params: FfiParams & { + retType: ArrayConstructorOptions + }): DataTypeToType - export function load(params: FfiParams & { retType: { ffiTypeTag: T } }): Array> - export type DataFieldType = DataType | Record| ArrayConstructorOptions & { - ffiTypeTag: ffiTypeTag - } + export type DataFieldType = DataType | Record | ArrayConstructorOptions + + export function load>(params: FfiParams & { + retType: { + type: T + length: number + ffiTypeTag?: string + } + }): DataTypeToType + export type DataFieldType = DataType | Record | ArrayConstructorOptions ${typeContent} `) })() diff --git a/src/lib.rs b/src/lib.rs index 4881b6b..484b2c2 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -6,8 +6,9 @@ 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, - get_js_function_call_value, js_array_to_string_array, js_nunmber_to_i32, js_string_to_string, - js_unknown_to_data_type, ArrayPointerType, ArrayType, + get_js_function_call_value, js_array_to_double_array, js_array_to_string_array, + js_nunmber_to_i32, js_string_to_string, js_unknown_to_data_type, rs_array_to_js_array, + ArrayPointerType, ArrayType, }; use indexmap::IndexMap; @@ -188,6 +189,12 @@ fn load( let arg_val = js_array_to_string_array(js_array); RsArgsValue::StringArray(arg_val) } + DataType::DoubleArray => { + let js_array: JsObject = + params_value_object.get_named_property(&field).unwrap(); + let arg_val = js_array_to_double_array(js_array); + RsArgsValue::DoubleArray(arg_val) + } // DataType::Object => { // let val: JsObject = js_object.get_named_property(&field).unwrap(); // let index_map = jsobject_to_rs_struct(val); @@ -347,6 +354,13 @@ fn load( as *mut c_void; field_ptr = align_ptr(field_ptr, align); } + RsArgsValue::DoubleArray(arr) => { + (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); + } RsArgsValue::Object(val) => { let (size, _) = calculate_layout(&val); write_data(val, field_ptr, align); @@ -553,7 +567,7 @@ fn load( _ => panic!("some error"), } } - _ => unreachable!(), + _ => panic!("some error"), } } else { let (ret_fields_size, align) = @@ -633,18 +647,39 @@ fn load( create_array_from_pointer(ArrayPointerType::String(*type_field_ptr), array_len); match arr { ArrayType::String(arr) => { - let mut js_array = env.create_array_with_length(arr.len()).unwrap(); - arr.into_iter().enumerate().for_each(|(index, str)| { - js_array - .set_element(index as u32, env.create_string(&str).unwrap()) - .unwrap(); - }); + let js_array = rs_array_to_js_array(env, ArrayType::String(arr)); js_object .set_property(env.create_string(&field).unwrap(), js_array) .unwrap(); } _ => panic!("some error"), } + 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); + } + DataType::DoubleArray => { + let array_constructor: JsObject = ret_object.get_named_property(&field).unwrap(); + let array_len: usize = js_nunmber_to_i32( + array_constructor + .get_named_property::("length") + .unwrap(), + ) as usize; + let type_field_ptr = field_ptr as *mut *mut c_double; + let arr = + create_array_from_pointer(ArrayPointerType::Double(*type_field_ptr), array_len); + match arr { + ArrayType::Double(arr) => { + let js_array = rs_array_to_js_array(env, ArrayType::Double(arr)); + js_object + .set_property(env.create_string(&field).unwrap(), js_array) + .unwrap(); + } + _ => panic!("some error"), + } + 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); } _ => panic!( diff --git a/src/utils.rs b/src/utils.rs index b11432d..620d1cf 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -57,6 +57,17 @@ pub fn js_array_to_string_array(js_array: JsObject) -> Vec { .collect::>() } +pub fn js_array_to_double_array(js_array: JsObject) -> Vec { + vec![0; js_array.get_array_length().unwrap() as usize] + .iter() + .enumerate() + .map(|(index, _)| { + let js_element: JsNumber = js_array.get_element(index as u32).unwrap(); + return js_element.try_into().unwrap(); + }) + .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; @@ -94,6 +105,11 @@ pub fn calculate_layout(map: &IndexMap) -> (usize, usize) { let size = size + std::mem::size_of::<*const *const c_char>(); (size, align) } + RsArgsValue::DoubleArray(_) => { + let align = align.max(std::mem::align_of::<*const c_double>()); + let size = size + std::mem::size_of::<*const c_double>(); + (size, align) + } _ => panic!("calculate_layout"), }); (size, align) @@ -114,6 +130,10 @@ pub fn get_data_type_size_align(data_type: DataType) -> (usize, usize) { std::mem::size_of::<*const *const c_char>(), std::mem::align_of::<*const *const c_char>(), ), + DataType::DoubleArray => ( + std::mem::size_of::<*const c_double>(), + std::mem::align_of::<*const c_double>(), + ), _ => { panic!("{:?} Not available as a field type at this time", data_type) } @@ -197,3 +217,27 @@ pub fn js_unknown_to_data_type(val: JsUnknown) -> DataType { _ => panic!("some error"), } } + +pub fn rs_array_to_js_array(env: Env, val: ArrayType) -> JsObject { + match val { + ArrayType::String(arr) => { + let mut js_array = env.create_array_with_length(arr.len()).unwrap(); + arr.into_iter().enumerate().for_each(|(index, str)| { + js_array + .set_element(index as u32, env.create_string(&str).unwrap()) + .unwrap(); + }); + js_array + } + ArrayType::Double(arr) => { + let mut js_array = env.create_array_with_length(arr.len()).unwrap(); + arr.into_iter().enumerate().for_each(|(index, item)| { + js_array + .set_element(index as u32, env.create_double(item).unwrap()) + .unwrap(); + }); + js_array + } + _ => panic!("some error"), + } +} diff --git a/test.ts b/test.ts index 5eb7735..32938e2 100644 --- a/test.ts +++ b/test.ts @@ -55,7 +55,13 @@ const unitTest = () => { paramsType: [DataType.I32Array, DataType.I32], paramsValue: [bigArr, bigArr.length], })) - + // let foo = load({ + // library: 'libsum', + // funcName: 'createArrayi32', + // retType: arrayConstructor({ type: DataType.I32Array, length: bigArr.length }), + // paramsType: [DataType.I32Array, DataType.I32], + // paramsValue: [bigArr, bigArr.length], + // }) let bigDoubleArr = new Array(5).fill(1.1) deepStrictEqual(bigDoubleArr, load({ library: 'libsum', @@ -85,7 +91,8 @@ const unitTest = () => { name: 'tom', age: 23, doubleProps: 1.1, - stringArrProps: ["foo", "bar"] + stringArray: ["foo", "bar"], + doubleArray: [1.1, 2.2, 3.3] } const personObj = load({ library: 'libsum', @@ -94,13 +101,15 @@ const unitTest = () => { name: DataType.String, age: DataType.I32, doubleProps: DataType.Double, - stringArrProps: arrayConstructor({ type: DataType.StringArray, length: person.stringArrProps.length }) + stringArray: arrayConstructor({ type: DataType.StringArray, length: person.stringArray.length }), + doubleArray: arrayConstructor({ type: DataType.DoubleArray, length: person.doubleArray.length }) }, paramsType: [{ name: DataType.String, age: DataType.I32, doubleProps: DataType.Double, - stringArrProps: DataType.StringArray + stringArray: DataType.StringArray, + doubleArray: DataType.DoubleArray, }], paramsValue: [person] })