Skip to content

Commit

Permalink
feat: support static array in c struct field
Browse files Browse the repository at this point in the history
  • Loading branch information
zhangyuang committed Apr 13, 2024
1 parent 293c575 commit 890a310
Show file tree
Hide file tree
Showing 14 changed files with 315 additions and 108 deletions.
19 changes: 0 additions & 19 deletions build.rs
Original file line number Diff line number Diff line change
@@ -1,25 +1,6 @@
extern crate napi_build;
macro_rules! p {
($($tokens: tt)*) => {
println!("cargo:warning={}", format!($($tokens)*))
}
}

fn main() {
let env = std::env::var("env").unwrap_or_else(|_| String::from("production"));
println!("cargo:rustc-link-search=native=.");
if env == "development" {
let bindings = bindgen::Builder::default()
.header("./cpp/sum.h")
.parse_callbacks(Box::new(bindgen::CargoCallbacks))
.allowlist_function(".*")
.raw_line("#[link(name = \"sum\")]")
.generate()
.expect("Unable to generate bindings");
bindings
.write_to_file("./src/bindings.rs")
.expect("Couldn't write bindings!");
}

napi_build::setup();
}
8 changes: 8 additions & 0 deletions cpp/sum.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ typedef struct Person {
const char *name;
char **stringArray;
int *i32Array;
uint8_t staticBytes[16];
bool boolTrue;
bool boolFalse;
int64_t longVal;
Expand All @@ -74,6 +75,10 @@ extern "C" Person *createPerson() {
person->age = 23;
person->doubleProps = 1.1;
person->byte = 'A';
uint8_t bytes[16];
memset(bytes, 99, sizeof(bytes));

memcpy(person->staticBytes, bytes, sizeof(bytes));

// Allocate and initialize name
person->name = strdup("tom");
Expand Down Expand Up @@ -105,6 +110,9 @@ extern "C" Person *createPerson() {
person->parent->age = 43;
person->parent->doubleProps = 3.3;
person->parent->name = strdup("tom father");
uint8_t pbytes[16];
memset(pbytes, 88, sizeof(bytes));
memcpy(person->parent->staticBytes, pbytes, sizeof(pbytes));

char *pstringArray[] = {strdup("tom"), strdup("father")};
person->parent->stringArray = (char **)malloc(sizeof(pstringArray));
Expand Down
23 changes: 4 additions & 19 deletions cpp/sum.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,26 +13,11 @@ extern void noRet();
extern int *createArrayi32(const int *arr, int size);
extern double *createArrayDouble(const double *arr, int size);
extern char **createArrayString(char **arr, int size);
typedef struct Parent {
const char *name;
int age;
} Parent;
class MyClass {
public:
MyClass();
void method();
};
typedef void (*FunctionPointer)(double a);

extern void callFunction(FunctionPointer func);

typedef struct Person {
const char *name;
int age;
Parent parent;
} Person;
extern const Person *getStruct(const Person *p);
typedef struct {
int bytes[2];
} cpu_svn_t;

extern int pck_cert_select(const cpu_svn_t *platform_svn, int bytes[2]);
#ifdef __cplusplus
}
#endif
Expand Down
2 changes: 1 addition & 1 deletion scripts/type.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,11 @@ const { resolve } = require("path");
`
${entryContent}
module.exports.arrayConstructor = (options) => ({
dynamicArray: true,
...options,
ffiTypeTag: 'array'
})
module.exports.funcConstructor = (options) => (() => ({
permanent: false,
ffiTypeTag: 'function',
...options,
}))
Expand Down
1 change: 1 addition & 0 deletions scripts/types.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ export type ArrayConstructorOptions<T extends DataType> = {
type: T;
length: number;
ffiTypeTag?: string;
dynamicArray?: boolean
};

export type FuncConstructorOptions<T extends DataType> = {
Expand Down
12 changes: 10 additions & 2 deletions src/datatype/function.rs
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,11 @@ pub unsafe fn get_js_function_call_value_from_ptr(
RsArgsValue::Object(obj) => {
let array_desc = get_array_desc(obj);
if array_desc.is_some() {
let (array_len, array_type) = array_desc.unwrap();
let FFIARRARYDESC {
array_type,
array_len,
..
} = array_desc.unwrap();
match array_type {
RefDataType::StringArray => {
let arr =
Expand Down Expand Up @@ -119,7 +123,11 @@ pub unsafe fn get_js_function_call_value(
RsArgsValue::Object(obj) => {
let array_desc = get_array_desc(obj);
if array_desc.is_some() {
let (array_len, array_type) = array_desc.unwrap();
let FFIARRARYDESC {
array_type,
array_len,
..
} = array_desc.unwrap();
match array_type {
RefDataType::StringArray => {
let arr = create_array_from_pointer(func_val_ptr as *mut *mut c_char, array_len);
Expand Down
113 changes: 96 additions & 17 deletions src/datatype/object_calculate.rs
Original file line number Diff line number Diff line change
@@ -1,16 +1,14 @@
use crate::define::RsArgsValue;
use crate::utils::dataprocess::get_js_external_wrap_data;
use crate::define::{RsArgsValue, FFIARRARYDESC};
use crate::utils::dataprocess::{get_array_desc, get_js_external_wrap_data};
use crate::utils::object_utils::get_size_align;
use crate::{FFIError, RefDataType};
use indexmap::IndexMap;
use libc::{c_ulonglong, c_void};
use napi::{Env, Result};
use std::alloc::{alloc, Layout};
use std::ffi::CString;
use std::ffi::{c_char, c_double, c_int, c_longlong, c_uchar};

pub fn get_size_align<T: Sized>() -> (usize, usize) {
(std::mem::size_of::<T>(), std::mem::align_of::<T>())
}

macro_rules! calculate_layout_for {
($variant:ident, $type:ty) => {
fn $variant(size: usize, align: usize, offset: usize) -> (usize, usize, usize) {
Expand Down Expand Up @@ -44,8 +42,34 @@ pub fn calculate_struct_size(map: &IndexMap<String, RsArgsValue>) -> (usize, usi
RsArgsValue::String(_) => calculate_string(size, align, offset),
RsArgsValue::Boolean(_) => calculate_boolean(size, align, offset),
RsArgsValue::Void(_) => calculate_void(size, align, offset),
RsArgsValue::Object(_)
| RsArgsValue::StringArray(_)
RsArgsValue::Object(obj) => {
let array_desc = get_array_desc(obj);
if array_desc.is_some() {
let FFIARRARYDESC {
array_type,
array_len,
..
} = array_desc.unwrap();
let (mut type_size, type_align) = match array_type {
RefDataType::U8Array => get_size_align::<u8>(),
RefDataType::I32Array => get_size_align::<i32>(),
RefDataType::DoubleArray => get_size_align::<f64>(),
_ => panic!(
"write {:?} static array in struct is unsupported",
array_type
),
};
type_size = type_size * array_len;
let align = align.max(type_align);
let padding = (type_align - (offset % type_align)) % type_align;
let size = size + padding + type_size;
let offset = offset + padding + type_size;
(size, align, offset)
} else {
calculate_pointer(size, align, offset)
}
}
RsArgsValue::StringArray(_)
| RsArgsValue::DoubleArray(_)
| RsArgsValue::I32Array(_)
| RsArgsValue::U8Array(_, _)
Expand Down Expand Up @@ -147,7 +171,7 @@ pub unsafe fn generate_c_struct(
let c_string = CString::new(str).unwrap();
let ptr = c_string.as_ptr();
std::mem::forget(c_string);
return ptr;
ptr
})
.collect();
(field_ptr as *mut *const *const c_char).write(c_char_vec.as_ptr());
Expand All @@ -173,7 +197,7 @@ pub unsafe fn generate_c_struct(
offset += size + padding;
size
}
RsArgsValue::U8Array(buffer, arr) => {
RsArgsValue::U8Array(buffer, _) => {
let buffer = buffer.unwrap();
let (size, align) = get_size_align::<*mut c_void>();
let padding = (align - (offset % align)) % align;
Expand All @@ -184,13 +208,68 @@ pub unsafe fn generate_c_struct(
size
}
RsArgsValue::Object(val) => {
let (size, align) = get_size_align::<*mut c_void>();
let padding = (align - (offset % align)) % align;
field_ptr = field_ptr.offset(padding as isize);
let obj_ptr = generate_c_struct(env, val)?;
(field_ptr as *mut *const c_void).write(obj_ptr);
offset += size + padding;
size
let array_desc = get_array_desc(&val);
if array_desc.is_some() {
// write static array data to struct
let FFIARRARYDESC {
array_type,
array_len,
array_value,
dynamic_array,
..
} = array_desc.unwrap();
if dynamic_array {
panic!("generate struct field unsupport use object describe array")
}
match array_type {
RefDataType::U8Array => {
let (size, align) = get_size_align::<u8>();
let field_size = size * array_len;
let padding = (align - (offset % align)) % align;
field_ptr = field_ptr.offset(padding as isize);
if let RsArgsValue::U8Array(buffer, _) = array_value.unwrap() {
let buffer = buffer.as_ref().unwrap();
std::ptr::copy(buffer.as_ptr(), field_ptr as *mut u8, array_len);
offset += field_size + padding;
}
field_size
}
RefDataType::I32Array => {
let (size, align) = get_size_align::<i32>();
let field_size = size * array_len;
let padding = (align - (offset % align)) % align;
field_ptr = field_ptr.offset(padding as isize);
if let RsArgsValue::I32Array(arr) = array_value.unwrap() {
std::ptr::copy(arr.as_ptr(), field_ptr as *mut i32, array_len);
offset += field_size + padding;
}
field_size
}
RefDataType::DoubleArray => {
let (size, align) = get_size_align::<f64>();
let field_size = size * array_len;
let padding = (align - (offset % align)) % align;
field_ptr = field_ptr.offset(padding as isize);
if let RsArgsValue::DoubleArray(arr) = array_value.unwrap() {
std::ptr::copy(arr.as_ptr(), field_ptr as *mut f64, array_len);
offset += field_size + padding;
}
field_size
}
_ => panic!(
"write {:?} static array in struct is unsupported",
array_type
),
}
} else {
let (size, align) = get_size_align::<*mut c_void>();
let padding = (align - (offset % align)) % align;
field_ptr = field_ptr.offset(padding as isize);
let obj_ptr = generate_c_struct(env, val)?;
(field_ptr as *mut *const c_void).write(obj_ptr);
offset += size + padding;
size
}
}
RsArgsValue::External(val) => {
let (size, align) = get_size_align::<*mut c_void>();
Expand Down
71 changes: 54 additions & 17 deletions src/datatype/object_generate.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
use super::array::*;
use super::buffer::*;
use super::object_calculate::get_size_align;
use super::pointer::*;
use crate::utils::dataprocess::get_array_desc;
use crate::utils::object_utils::{create_static_array_from_pointer, get_size_align};

use crate::define::*;
use indexmap::IndexMap;
Expand Down Expand Up @@ -118,50 +118,87 @@ pub unsafe fn create_rs_struct_from_pointer(
let array_desc = get_array_desc(obj);
if array_desc.is_some() {
// array
let (array_len, array_type) = array_desc.unwrap();
let size = match array_type {
let array_desc = array_desc.unwrap();
let FFIARRARYDESC {
array_type,
array_len,
dynamic_array,
..
} = &array_desc;
match array_type {
RefDataType::StringArray => {
let (size, align) = get_size_align::<*const c_void>();
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 arr = create_array_from_pointer(*type_field_ptr, *array_len);
rs_struct.insert(field, RsArgsValue::StringArray(arr));
offset += size + padding;
field_size = size
}
RefDataType::DoubleArray => {
let (size, align) = get_size_align::<*const c_void>();
let (size, align) = if *dynamic_array {
get_size_align::<*const c_void>()
} else {
let (size, align) = get_size_align::<c_double>();
(size * array_len, align)
};
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);
rs_struct.insert(field, RsArgsValue::DoubleArray(arr));
if *dynamic_array {
let type_field_ptr = field_ptr as *mut *mut c_double;
let arr = create_array_from_pointer(*type_field_ptr, *array_len);
rs_struct.insert(field, RsArgsValue::DoubleArray(arr));
} else {
let arr = create_static_array_from_pointer(field_ptr as *mut c_void, &array_desc);
rs_struct.insert(field, arr);
}
offset += size + padding;
field_size = size
}
RefDataType::I32Array => {
let (size, align) = get_size_align::<*const c_void>();
let (size, align) = if *dynamic_array {
get_size_align::<*const c_void>()
} else {
let (size, align) = get_size_align::<c_int>();
(size * array_len, align)
};
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);
rs_struct.insert(field, RsArgsValue::I32Array(arr));
if *dynamic_array {
let type_field_ptr = field_ptr as *mut *mut c_int;
let arr = create_array_from_pointer(*type_field_ptr, *array_len);
rs_struct.insert(field, RsArgsValue::I32Array(arr));
} else {
let arr = create_static_array_from_pointer(field_ptr as *mut c_void, &array_desc);
rs_struct.insert(field, arr);
}
offset += size + padding;
field_size = size
}
RefDataType::U8Array => {
let (size, align) = get_size_align::<*const c_void>();
let (size, align) = if *dynamic_array {
get_size_align::<*const c_void>()
} else {
let (size, align) = get_size_align::<u8>();
(size * array_len, align)
};
let padding = (align - (offset % align)) % align;
field_ptr = field_ptr.offset(padding as isize);
let type_field_ptr = field_ptr as *mut *mut c_uchar;
let arr = create_array_from_pointer(*type_field_ptr, array_len);
rs_struct.insert(field, get_safe_buffer(env, arr, need_thread_safe));
if *dynamic_array {
let type_field_ptr = field_ptr as *mut *mut c_uchar;
let arr = create_array_from_pointer(*type_field_ptr, array_desc.array_len);
rs_struct.insert(field, get_safe_buffer(env, arr, need_thread_safe));
} else {
let arr = create_static_array_from_pointer(field_ptr as *mut c_void, &array_desc);
if let RsArgsValue::U8Array(_, arr) = arr {
rs_struct.insert(field, get_safe_buffer(env, arr.unwrap(), need_thread_safe));
}
}
offset += size + padding;
field_size = size
}
};
size
} else {
// function | raw object
let (size, align) = get_size_align::<*const c_void>();
Expand Down

0 comments on commit 890a310

Please sign in to comment.