Skip to content

Commit

Permalink
fix: struct offset position
Browse files Browse the repository at this point in the history
  • Loading branch information
zhangyuang committed Oct 21, 2023
1 parent e83bcbe commit 0dc4483
Show file tree
Hide file tree
Showing 6 changed files with 140 additions and 87 deletions.
20 changes: 13 additions & 7 deletions cpp/sum.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
1 change: 1 addition & 0 deletions memory.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
const Koa = require('koa');
const app = new Koa();
process.env.MEMORY = 1
const { unitTest } = require('./test')

app.use(async ctx => {
Expand Down
8 changes: 4 additions & 4 deletions scripts/types.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,10 @@ type DataFieldTypeToType<T extends DataFieldType<DataType>> =
T extends ArrayConstructorOptions<infer U> ? DataTypeToType<U> :
never;

export function load<T extends DataType, U extends Record<string, DataFieldType<T>>>(params: Omit<FfiParams<T>, 'retType'> & {
retType?: U
}): { [K in keyof U]: DataFieldTypeToType<U[K]> }
export function load<T extends DataType, U extends Record<string, DataFieldType<T>>>(params: Omit<FfiParams<T>, 'retType'> & {
retType?: U
}): { [K in keyof U]: DataFieldTypeToType<U[K]> }

export function load<T extends DataType>(params: Omit<FfiParams<T>, 'retType'> & {
retType: T
}): DataTypeToType<T>
Expand Down
164 changes: 100 additions & 64 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
};
Expand All @@ -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;
Expand Down Expand Up @@ -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 => {
Expand Down Expand Up @@ -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();
Expand Down Expand Up @@ -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::<i32>()
};

let ptr = alloc(layout) as *mut c_void;
let field_ptr = ptr;
unsafe fn write_data(
map: IndexMap<String, RsArgsValue>,
mut field_ptr: *mut c_void,
align: usize,
) {
unsafe fn write_data(map: IndexMap<String, RsArgsValue>, 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::<c_int>();
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::<c_int>() as isize) as *mut c_void;
field_ptr = align_ptr(field_ptr, align);
offset = std::mem::size_of::<c_int>();
}
RsArgsValue::Double(double_number) => {
let align = std::mem::align_of::<c_double>();
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::<c_double>() as isize) as *mut c_void;
field_ptr = align_ptr(field_ptr, align);
offset = std::mem::size_of::<c_double>();
}
RsArgsValue::Boolean(val) => {
let align = std::mem::align_of::<bool>();
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::<bool>();
}
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| {
Expand All @@ -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::<usize>(); // 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();
Expand Down Expand Up @@ -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!(
Expand Down Expand Up @@ -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(&current).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(
Expand All @@ -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()
Expand All @@ -612,30 +628,48 @@ fn load(
};
match data_type {
DataType::I32 => {
let type_field_ptr = field_ptr as *mut i32;
let align = std::mem::align_of::<c_int>();
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::<c_int>() as isize) as *mut c_void;
field_ptr = align_ptr(field_ptr, align);
offset = std::mem::size_of::<c_int>();
}
DataType::Double => {
let align = std::mem::align_of::<c_double>();
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(
env.create_string(&field).unwrap(),
env.create_double(*type_field_ptr).unwrap(),
)
.unwrap();
field_ptr =
field_ptr.offset(std::mem::size_of::<c_int>() as isize) as *mut c_void;
field_ptr = align_ptr(field_ptr, align);
offset = std::mem::size_of::<c_double>();
}
DataType::Boolean => {
let align = std::mem::align_of::<bool>();
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::<bool>();
}
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
Expand All @@ -644,49 +678,51 @@ 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!(
"{:?} is not available as a field type at this time",
data_type
),
}
field_ptr = field_ptr.offset(offset as isize) as *mut c_void;
});
Either9::I(js_object)
}
Expand Down
Loading

0 comments on commit 0dc4483

Please sign in to comment.