Skip to content

Commit

Permalink
feat: support struct array
Browse files Browse the repository at this point in the history
  • Loading branch information
zhangyuang committed Dec 23, 2024
1 parent ef2c51d commit cbf3908
Show file tree
Hide file tree
Showing 18 changed files with 550 additions and 170 deletions.
6 changes: 3 additions & 3 deletions .github/workflows/CI.yml
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ jobs:
build: |-
set -e &&
target=x86_64-unknown-linux-gnu yarn build &&
strip *.node &&
strip *.node && yarn test &&
ls
- host: macos-latest
target: aarch64-apple-darwin
Expand All @@ -72,7 +72,7 @@ jobs:
ls
# - host: ubuntu-latest
# target: arm-unknown-linux-gnueabihf

- host: ubuntu-latest
target: arm-unknown-linux-gnueabihf
docker: ghcr.io/catthehacker/ubuntu:custom-20.04-dev
Expand All @@ -86,7 +86,7 @@ jobs:
ls
- host: ubuntu-latest
target: x86_64-unknown-linux-musl
docker: ghcr.io/napi-rs/napi-rs/nodejs-rust:stable-2023-09-17-alpine
docker: ghcr.io/napi-rs/napi-rs/nodejs-rust:lts-alpine
build: |
set -e && uname -a && apk update &&
apk add linux-headers &&
Expand Down
8 changes: 8 additions & 0 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"editor.formatOnSave": true,
"[rust]": {
"editor.formatOnSave": true,
},
"files.trimTrailingWhitespace": true

}
12 changes: 7 additions & 5 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -9,25 +9,27 @@ crate-type = ["cdylib"]
[dependencies]

# Default enable napi4 feature, see https://nodejs.org/api/n-api.html#node-api-version-matrix
napi = { version = "2.16.13", default-features = false, features = ["napi4", "napi6"] }
napi = { version = "2.16.13", default-features = false, features = [
"napi4",
"napi6",
] }
napi-derive = "2.13.0"
napi-derive-backend = "1.0.52"
dlopen = "0.1.8"
libffi = { version = "3.2.0" }
libffi-sys = { version = "^2.3.0" }
libc = "0.2"
indexmap = "2.0"
indexmap = "2.7.0"
widestring = "1.1.0"
strum = "0.26"
strum_macros = "0.26"

[build-dependencies]
napi-build = "2.0.1"
bindgen = "^0.66.0"
napi-build = "=2.0.1"


[profile.release]
lto = true

[lints.rust]
static-mut-refs="allow"
static-mut-refs = "allow"
99 changes: 76 additions & 23 deletions cpp/sum.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,23 +11,27 @@ extern "C" double doubleSum(double a, double b) { return a + b; }

extern "C" double floatSum(float a, float b) { return a + b; }

extern "C" int64_t testbigint(int64_t a) {
return a;
extern "C" int64_t testbigint(int64_t a)
{
return a;
}

extern "C" const char *concatenateStrings(const char *str1, const char *str2) {
extern "C" const char *concatenateStrings(const char *str1, const char *str2)
{
std::string result = std::string(str1) + std::string(str2);
char *cstr = new char[result.length() + 1];
strcpy(cstr, result.c_str());
return cstr;
}

extern "C" void* returnNullPointer() {
return NULL;
extern "C" void *returnNullPointer()
{
return NULL;
}

extern "C" const wchar_t *concatenateWideStrings(const wchar_t *str1,
const wchar_t *str2) {
const wchar_t *str2)
{
std::wstring result = std::wstring(str1) + std::wstring(str2);
wchar_t *wcstr = new wchar_t[result.length() + 1];
wcscpy(wcstr, result.c_str());
Expand All @@ -40,48 +44,59 @@ extern "C" int getValueFromDoublePointer(int **ptr) { return *ptr[0]; };

extern "C" void noRet() { printf("%s", "hello world\n"); }

extern "C" int *createArrayi32(const int *arr, int size) {
extern "C" int *createArrayi32(const int *arr, int size)
{
int *vec = (int *)malloc((size) * sizeof(int));
for (int i = 0; i < size; i++) {
for (int i = 0; i < size; i++)
{
vec[i] = arr[i];
}
return vec;
}

extern "C" double *createArrayDouble(const double *arr, int size) {
extern "C" double *createArrayDouble(const double *arr, int size)
{
double *vec = (double *)malloc((size) * sizeof(double));
for (int i = 0; i < size; i++) {
for (int i = 0; i < size; i++)
{
vec[i] = arr[i];
}
return vec;
}

extern "C" double *createArrayFloat(const float *arr, int size) {
extern "C" double *createArrayFloat(const float *arr, int size)
{
double *vec = (double *)malloc((size) * sizeof(double));
for (int i = 0; i < size; i++) {
for (int i = 0; i < size; i++)
{
vec[i] = arr[i];
}
return vec;
}

extern "C" char **createArrayString(char **arr, int size) {
extern "C" char **createArrayString(char **arr, int size)
{
char **vec = (char **)malloc(size * sizeof(char *));
if (vec == NULL) {
if (vec == NULL)
{
return NULL;
}

for (int i = 0; i < size; i++) {
for (int i = 0; i < size; i++)
{
vec[i] = strdup(arr[i]);
}
return vec;
}
extern "C" bool return_opposite(bool input) { return !input; }

typedef struct stackStruct {
typedef struct stackStruct
{
int age;
} stackStruct;

typedef struct Person {
typedef struct Person
{
int age;
double *doubleArray;
Person *parent;
Expand All @@ -100,7 +115,8 @@ typedef struct Person {

extern "C" Person *getStruct(Person *person) { return person; }

extern "C" Person *createPerson() {
extern "C" Person *createPerson()
{
Person *person = (Person *)malloc(sizeof(Person));

// Allocate and initialize doubleArray
Expand Down Expand Up @@ -175,7 +191,8 @@ extern "C" Person *createPerson() {
typedef const int (*FunctionPointer)(int a, bool b, char *c, double d, char **e,
int *f, Person *g);

extern "C" void callFunction(FunctionPointer func) {
extern "C" void callFunction(FunctionPointer func)
{
int a = 100;
bool b = false;
double d = 100.11;
Expand All @@ -199,28 +216,64 @@ extern "C" void callFunction(FunctionPointer func) {
}

// 定义 C++ 类
class MyClass {
class MyClass
{
public:
std::string name;
int age;

MyClass(std::string n, int a) : name(n), age(a) {}

void print() {
void print()
{
std::cout << "Name: " << name << ", Age: " << age << std::endl;
}
};

MyClass *createMyClass(std::string name, int age) {
MyClass *createMyClass(std::string name, int age)
{
return new MyClass(name, age);
}

extern "C" MyClass *createMyClassFromC(const char *name, int age) {
extern "C" MyClass *createMyClassFromC(const char *name, int age)
{
return createMyClass(std::string(name), age);
}

extern "C" void printMyClass(MyClass *instance) { instance->print(); }

typedef struct
{
short x;
short y;
short dir;
unsigned char kind;
} MINUTIA;

typedef struct
{
short nNumber;
MINUTIA item[3];
} MINUTIAE;

extern "C" MINUTIAE *printAndReturnMinutiae(MINUTIAE *minutiae)
{

MINUTIAE *result = new MINUTIAE;
result->nNumber = minutiae->nNumber;
printf("nNumber=%d\n", minutiae->nNumber);

for (int i = 0; i < result->nNumber; i++)
{
result->item[i] = minutiae->item[i];
printf("Result item[%d]: x=%d, y=%d, dir=%d, kind=%d\n",
i, result->item[i].x, result->item[i].y,
result->item[i].dir, (int)result->item[i].kind);
}

return result;
}

// typedef void (*CallbackType)(const char *);
// extern "C" void call_callback_async() {
// dispatch_async(dispatch_get_main_queue(), ^{
Expand Down
1 change: 1 addition & 0 deletions scripts/types.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ export const enum DataType {
*/
BigInt = 16,
I16 = 17,
StructArray = 18,
StackStruct = 999, // reserve keyword
StackArray = 996,
Function = 998,
Expand Down
67 changes: 51 additions & 16 deletions src/datatype/create_struct.rs
Original file line number Diff line number Diff line change
Expand Up @@ -136,11 +136,13 @@ pub unsafe fn generate_c_struct(
}
RsArgsValue::Object(mut obj_value) => {
if let FFITypeTag::Array | FFITypeTag::StackArray = get_ffi_tag(&obj_value) {
let array_desc = get_array_desc(&obj_value);
let array_desc = get_array_desc(&mut obj_value);
let array_value = get_array_value(&mut obj_value).unwrap();
let FFIARRARYDESC {
array_type,
array_len,
struct_item_type,
..
} = array_desc;
let field_size = match array_type {
RefDataType::U8Array => {
Expand Down Expand Up @@ -264,35 +266,67 @@ pub unsafe fn generate_c_struct(
return Err(FFIError::Panic(format!("error array type {:?}", array_type)).into());
}
}
RefDataType::StructArray => {
let is_stack_struct =
get_ffi_tag(struct_item_type.as_ref().unwrap()) == FFITypeTag::StackStruct;
if let RsArgsValue::StructArray(arr) = array_value {
if is_stack_struct {
let (size, align) = calculate_struct_size(struct_item_type.as_ref().unwrap());
let field_size = size * array_len;
for i in 0..array_len {
let padding = (align - (offset % align)) % align;
field_ptr = field_ptr.offset(padding as isize);
generate_c_struct(
env,
struct_item_type.as_ref().unwrap(),
arr[i].clone(),
Some(field_ptr),
)
.unwrap();
field_ptr = field_ptr.offset(size as isize);
offset += size;
}
field_size
} else {
panic!("!struct array not supported");
}
} else {
return Err(FFIError::Panic(format!("error array type {:?}", array_type)).into());
}
}
};
field_size
} else {
let is_stack_struct =
if let Some(RsArgsValue::Object(field_type)) = struct_type.get(&field) {
let is_stack_struct = match struct_type.get(&field) {
Some(RsArgsValue::Object(field_type)) => {
get_ffi_tag(field_type) == FFITypeTag::StackStruct
} else {
false
};
}
_ => get_ffi_tag(struct_type) == FFITypeTag::StackStruct,
};
// struct
if is_stack_struct {
// stack struct
if let RsArgsValue::Object(val_type) = struct_type.get(&field).unwrap() {
let (size, align) = calculate_struct_size(val_type);
let padding = (align - (offset % align)) % align;
field_ptr = field_ptr.offset(padding as isize);
generate_c_struct(env, val_type, obj_value, Some(field_ptr))?;
offset += size + padding;
size
let target_type = if let Some(RsArgsValue::Object(val_type)) = struct_type.get(&field) {
val_type
} else if get_ffi_tag(struct_type) == FFITypeTag::StackStruct {
struct_type
} else {
return Err(FFIError::Panic(format!("unknown field type {:?}", struct_type)).into());
}
};

let (size, align) = calculate_struct_size(target_type);
let padding = (align - (offset % align)) % align;
field_ptr = field_ptr.offset(padding as isize);
generate_c_struct(env, target_type, obj_value, Some(field_ptr))?;
offset += size + padding;
size
} else {
let (size, align) = get_size_align::<*mut c_void>();
let padding = (align - (offset % align)) % align;
field_ptr = field_ptr.offset(padding as isize);
if let RsArgsValue::Object(val_type) = struct_type.get(&field).unwrap() {
let obj_ptr = generate_c_struct(env, val_type, obj_value, None)?;
(field_ptr as *mut *const c_void).write(obj_ptr);
let start_ptr = generate_c_struct(env, val_type, obj_value, None)?;
(field_ptr as *mut *const c_void).write(start_ptr);
}
offset += size + padding;
size
Expand All @@ -304,6 +338,7 @@ pub unsafe fn generate_c_struct(
| RsArgsValue::FloatArray(_)
| RsArgsValue::I32Array(_)
| RsArgsValue::DoubleArray(_)
| RsArgsValue::StructArray(_)
| RsArgsValue::U8Array(_, _) => {
return Err(
FFIError::Panic(format!(
Expand Down
3 changes: 3 additions & 0 deletions src/datatype/function.rs
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,9 @@ pub unsafe fn get_rs_value_from_pointer(
let arr = create_array_from_pointer(*(pointer as *mut *mut c_float), array_len);
RsArgsValue::FloatArray(arr)
}
RefDataType::StructArray => {
panic!("struct array not supported");
}
}
} else {
// function | raw object
Expand Down
Loading

0 comments on commit cbf3908

Please sign in to comment.