Skip to content

Commit

Permalink
feat: support struct field type doubleArray
Browse files Browse the repository at this point in the history
  • Loading branch information
zhangyuang committed Oct 20, 2023
1 parent 31d9beb commit 48d9749
Show file tree
Hide file tree
Showing 5 changed files with 134 additions and 39 deletions.
9 changes: 6 additions & 3 deletions cpp/sum.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -52,16 +52,19 @@ typedef struct Person {
const char *name;
int age;
double doubleProps;
char **stringArrProps;
char **stringArray;
double *doubleArray;
// Parent parent;
} Person;

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;
Expand Down
50 changes: 27 additions & 23 deletions scripts/type.js
Original file line number Diff line number Diff line change
Expand Up @@ -32,35 +32,39 @@ const { resolve } = require('path');
retType: DataType.Void
}): undefined
type DataTypeToType<T> = {
[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<T extends Record<string, DataType>>(params: FfiParams & { retType: T }): DataTypeToType<T>
type DataTypeToType<T extends DataType> =
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<T extends ffiTypeTag>(options: ArrayConstructorOptions): ArrayConstructorOptions & {
ffiTypeTag: T
}
type ffiTypeTag = 'double' | 'string' | 'i32';
export function arrayConstructor(options: ArrayConstructorOptions): ArrayConstructorOptions
type FfiReturnType<T extends ffiTypeTag> = T extends 'double' ? number :
T extends 'i32' ? number :
string;
export function load<T extends DataType>(params: FfiParams & {
retType: ArrayConstructorOptions
}): DataTypeToType<T>
export function load<T extends ffiTypeTag>(params: FfiParams & { retType: { ffiTypeTag: T } }): Array<FfiReturnType<T>>
export type DataFieldType = DataType | Record<string, DataType>| ArrayConstructorOptions & {
ffiTypeTag: ffiTypeTag
}
export type DataFieldType = DataType | Record<string, DataType> | ArrayConstructorOptions
export function load<T extends Record<string, DataType>>(params: FfiParams & {
retType: {
type: T
length: number
ffiTypeTag?: string
}
}): DataTypeToType<T>
export type DataFieldType = DataType | Record<string, DataType> | ArrayConstructorOptions
${typeContent}
`)
})()
53 changes: 44 additions & 9 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -553,7 +567,7 @@ fn load(
_ => panic!("some error"),
}
}
_ => unreachable!(),
_ => panic!("some error"),
}
} else {
let (ret_fields_size, align) =
Expand Down Expand Up @@ -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::<JsNumber>("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!(
Expand Down
44 changes: 44 additions & 0 deletions src/utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,17 @@ pub fn js_array_to_string_array(js_array: JsObject) -> Vec<String> {
.collect::<Vec<String>>()
}

pub fn js_array_to_double_array(js_array: JsObject) -> Vec<f64> {
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::<Vec<f64>>()
}

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;
Expand Down Expand Up @@ -94,6 +105,11 @@ pub fn calculate_layout(map: &IndexMap<String, RsArgsValue>) -> (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)
Expand All @@ -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)
}
Expand Down Expand Up @@ -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"),
}
}
17 changes: 13 additions & 4 deletions test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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',
Expand Down Expand Up @@ -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',
Expand All @@ -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]
})
Expand Down

0 comments on commit 48d9749

Please sign in to comment.