node-ffi-rs
Advanced tools
Comparing version 1.0.58 to 1.0.59
@@ -56,2 +56,3 @@ /* eslint-disable */ | ||
ffiTypeTag?: string; | ||
dynamicArray?: boolean | ||
}; | ||
@@ -58,0 +59,0 @@ |
37
index.js
@@ -228,13 +228,28 @@ | ||
case 'arm': | ||
localFileExisted = existsSync( | ||
join(__dirname, 'ffi-rs.linux-arm-gnueabihf.node') | ||
) | ||
try { | ||
if (localFileExisted) { | ||
nativeBinding = require('./ffi-rs.linux-arm-gnueabihf.node') | ||
} else { | ||
nativeBinding = require('@yuuang/ffi-rs-linux-arm-gnueabihf') | ||
if (isMusl()) { | ||
localFileExisted = existsSync( | ||
join(__dirname, 'ffi-rs.linux-arm-musleabihf.node') | ||
) | ||
try { | ||
if (localFileExisted) { | ||
nativeBinding = require('./ffi-rs.linux-arm-musleabihf.node') | ||
} else { | ||
nativeBinding = require('@yuuang/ffi-rs-linux-arm-musleabihf') | ||
} | ||
} catch (e) { | ||
loadError = e | ||
} | ||
} catch (e) { | ||
loadError = e | ||
} else { | ||
localFileExisted = existsSync( | ||
join(__dirname, 'ffi-rs.linux-arm-gnueabihf.node') | ||
) | ||
try { | ||
if (localFileExisted) { | ||
nativeBinding = require('./ffi-rs.linux-arm-gnueabihf.node') | ||
} else { | ||
nativeBinding = require('@yuuang/ffi-rs-linux-arm-gnueabihf') | ||
} | ||
} catch (e) { | ||
loadError = e | ||
} | ||
} | ||
@@ -312,2 +327,3 @@ break | ||
module.exports.arrayConstructor = (options) => ({ | ||
dynamicArray: true, | ||
...options, | ||
@@ -317,3 +333,2 @@ ffiTypeTag: 'array' | ||
module.exports.funcConstructor = (options) => (() => ({ | ||
permanent: false, | ||
ffiTypeTag: 'function', | ||
@@ -320,0 +335,0 @@ ...options, |
{ | ||
"name": "node-ffi-rs", | ||
"version": "1.0.58", | ||
"version": "1.0.59", | ||
"main": "index.js", | ||
@@ -47,5 +47,2 @@ "types": "index.d.ts", | ||
}, | ||
"engines": { | ||
"node": ">= 16" | ||
}, | ||
"scripts": { | ||
@@ -63,11 +60,11 @@ "artifacts": "napi artifacts", | ||
"optionalDependencies": { | ||
"@yuuang/ffi-rs-win32-x64-msvc": "1.0.58", | ||
"@yuuang/ffi-rs-darwin-x64": "1.0.58", | ||
"@yuuang/ffi-rs-linux-x64-gnu": "1.0.58", | ||
"@yuuang/ffi-rs-darwin-arm64": "1.0.58", | ||
"@yuuang/ffi-rs-linux-arm64-gnu": "1.0.58", | ||
"@yuuang/ffi-rs-linux-arm64-musl": "1.0.58", | ||
"@yuuang/ffi-rs-win32-ia32-msvc": "1.0.58", | ||
"@yuuang/ffi-rs-linux-x64-musl": "1.0.58" | ||
"@yuuang/ffi-rs-win32-x64-msvc": "1.0.59", | ||
"@yuuang/ffi-rs-darwin-x64": "1.0.59", | ||
"@yuuang/ffi-rs-linux-x64-gnu": "1.0.59", | ||
"@yuuang/ffi-rs-darwin-arm64": "1.0.59", | ||
"@yuuang/ffi-rs-linux-arm64-gnu": "1.0.59", | ||
"@yuuang/ffi-rs-linux-arm64-musl": "1.0.59", | ||
"@yuuang/ffi-rs-win32-ia32-msvc": "1.0.59", | ||
"@yuuang/ffi-rs-linux-x64-musl": "1.0.59" | ||
} | ||
} |
302
README.md
@@ -11,4 +11,2 @@ # ffi-rs | ||
<a href="https://github.com/zhangyuang/node-ffi-rs/actions" target="_blank"><img src="https://github.com/zhangyuang/ssr/workflows/CI/badge.svg" alt="githubActions" /> | ||
<a href="https://github.com/zhangyuang/node-ffi-rs" target="_blank"><img src="https://img.shields.io/badge/node-%3E=14-green.svg?color=4dc71f" alt="Node" ></a> | ||
<a href="https://github.com/zhangyuang/node-ffi-rs" target="_blank"><img src="https://badge.fury.io/js/ffi-rs.svg" alt="Node" ></a> | ||
</div> | ||
@@ -26,5 +24,5 @@ | ||
- Simpler data description and API interface 💗 | ||
- Support more data types between `Node.js` and `c type` 😊 | ||
- Support more different data types between `Node.js` and `c` 😊 | ||
- Support modify data in place 🥸 | ||
- Provide many functions to handle pointer type | ||
- Provide many ways to handle pointer type directly | ||
@@ -411,3 +409,3 @@ ## benchmark | ||
Similarly, you can use `restorePointer` to restore data from `pointer` which is wrapped by `createPointer` | ||
Similarly, you can use `restorePointer` to restore data from `pointer` which is wrapped by `createPointer` or as a return value of foreign function | ||
@@ -459,3 +457,3 @@ ```js | ||
paramsType: [DataType.String], | ||
paramsValue: ["foo] | ||
paramsValue: ["foo"] | ||
}) | ||
@@ -471,214 +469,33 @@ | ||
```cpp | ||
typedef struct Person { | ||
int age; | ||
double *doubleArray; | ||
Person *parent; | ||
double doubleProps; | ||
const char *name; | ||
char **stringArray; | ||
int *i32Array; | ||
bool boolTrue; | ||
bool boolFalse; | ||
int64_t longVal; | ||
char byte; | ||
char *byteArray; | ||
} Person; | ||
extern "C" Person *getStruct(Person *person) { | ||
return person; | ||
} | ||
`ffi-rs` provide a c struct named `Person` with many types of field in [sum.cpp](https://github.com/zhangyuang/node-ffi-rs/blob/master/cpp/sum.cpp#L48) | ||
extern "C" Person *createPerson() { | ||
Person *person = (Person *)malloc(sizeof(Person)); | ||
The example call method about how to call foreign function to create `Person` struct or use `Person` struct as a return value is [here](https://github.com/zhangyuang/node-ffi-rs/blob/master/test.ts#L289) | ||
// Allocate and initialize doubleArray | ||
double initDoubleArray[] = {1.1, 2.2, 3.3}; | ||
person->doubleArray = (double *)malloc(sizeof(initDoubleArray)); | ||
memcpy(person->doubleArray, initDoubleArray, sizeof(initDoubleArray)); | ||
#### Use array in struct | ||
// Initialize age and doubleProps | ||
person->age = 23; | ||
person->doubleProps = 1.1; | ||
person->byte = 'A'; | ||
There are two types of array in c language like `int* array` and `int array[100]` yhat have some different usages. | ||
// Allocate and initialize name | ||
person->name = strdup("tom"); | ||
The first type `int* array` is a pointer type store the first address of the array. | ||
char *stringArray[] = {strdup("tom")}; | ||
person->stringArray = (char **)malloc(sizeof(stringArray)); | ||
memcpy(person->stringArray, stringArray, sizeof(stringArray)); | ||
The second type `int array[100]` is a fixed length array and each element in array has continous address. | ||
// Allocate and initialize byteArray | ||
char initByteArray[] = {101, 102}; | ||
person->byteArray = (char *)malloc(sizeof(initByteArray)); | ||
memcpy(person->byteArray, initByteArray, sizeof(initByteArray)); | ||
If you use a array as function parameter, this usually passes an array pointer regardless of which type you define.But if the array type is defined in struct, the two types of array define will cause different size and align of struct. | ||
int initI32Array[] = {1, 2, 3, 4}; | ||
person->i32Array = (int *)malloc(sizeof(initI32Array)); | ||
memcpy(person->i32Array, initI32Array, sizeof(initI32Array)); | ||
So, `ffi-rs` need to distinguish between the two types. | ||
person->boolTrue = true; | ||
person->boolFalse = false; | ||
person->longVal = 4294967296; | ||
By default, `ffi-rs` use pointer array to calculate struct. If you confirm there should use static array, you can define it in the way | ||
// Allocate and initialize parent | ||
person->parent = (Person *)malloc(sizeof(Person)); | ||
double parentDoubleArray[] = {1.1, 2.2, 3.3}; | ||
person->parent->doubleArray = (double *)malloc(sizeof(parentDoubleArray)); | ||
memcpy(person->parent->doubleArray, parentDoubleArray, | ||
sizeof(parentDoubleArray)); | ||
person->parent->age = 43; | ||
person->parent->doubleProps = 3.3; | ||
person->parent->name = strdup("tom father"); | ||
char *pstringArray[] = {strdup("tom"), strdup("father")}; | ||
person->parent->stringArray = (char **)malloc(sizeof(pstringArray)); | ||
memcpy(person->parent->stringArray, pstringArray, sizeof(pstringArray)); | ||
int parentI32Array[] = {5, 6, 7}; | ||
person->parent->i32Array = (int *)malloc(sizeof(parentI32Array)); | ||
memcpy(person->parent->i32Array, parentI32Array, sizeof(parentI32Array)); | ||
person->parent->boolTrue = true; | ||
person->parent->boolFalse = false; | ||
person->parent->longVal = 5294967296; | ||
person->parent->byte = 'B'; | ||
char parentByteArray[] = {103, 104}; | ||
person->parent->byteArray = (char *)malloc(sizeof(parentByteArray)); | ||
memcpy(person->parent->byteArray, parentByteArray, sizeof(parentByteArray)); | ||
return person; | ||
} | ||
``` | ||
```js | ||
const parent = { | ||
age: 43, | ||
doubleArray: [1.1, 2.2, 3.3], | ||
parent: {}, | ||
doubleProps: 3.3, | ||
name: "tom father", | ||
stringArray: ["tom", "father"], | ||
i32Array: [5, 6, 7], | ||
boolTrue: true, | ||
boolFalse: false, | ||
longVal: 5294967296, | ||
byte: 66, | ||
byteArray: Buffer.from([103, 104]), | ||
}; | ||
const person = { | ||
age: 23, | ||
doubleArray: [1.1, 2.2, 3.3], | ||
parent, | ||
doubleProps: 1.1, | ||
name: "tom", | ||
stringArray: ["tom"], | ||
i32Array: [1, 2, 3, 4], | ||
boolTrue: true, | ||
boolFalse: false, | ||
longVal: 4294967296, | ||
byte: 65, | ||
byteArray: Buffer.from([101, 102]), | ||
}; | ||
const parentType = { | ||
age: DataType.I32, | ||
doubleArray: arrayConstructor({ | ||
type: DataType.DoubleArray, | ||
length: parent.doubleArray.length, | ||
}), | ||
parent: {}, | ||
doubleProps: DataType.Double, | ||
name: DataType.String, | ||
stringArray: arrayConstructor({ | ||
type: DataType.StringArray, | ||
length: parent.stringArray.length, | ||
}), | ||
i32Array: arrayConstructor({ | ||
type: DataType.I32Array, | ||
length: parent.i32Array.length, | ||
}), | ||
boolTrue: DataType.Boolean, | ||
boolFalse: DataType.Boolean, | ||
longVal: DataType.I64, | ||
byte: DataType.U8, | ||
byteArray: arrayConstructor({ | ||
type: DataType.U8Array, | ||
length: parent.byteArray.length, | ||
}), | ||
}; | ||
const personType = { | ||
age: DataType.I32, | ||
doubleArray: arrayConstructor({ | ||
type: DataType.DoubleArray, | ||
length: person.doubleArray.length, | ||
}), | ||
parent: parentType, | ||
doubleProps: DataType.Double, | ||
name: DataType.String, | ||
stringArray: arrayConstructor({ | ||
type: DataType.StringArray, | ||
length: person.stringArray.length, | ||
}), | ||
i32Array: arrayConstructor({ | ||
type: DataType.I32Array, | ||
length: person.i32Array.length, | ||
}), | ||
boolTrue: DataType.Boolean, | ||
boolFalse: DataType.Boolean, | ||
longVal: DataType.I64, | ||
byte: DataType.U8, | ||
byteArray: arrayConstructor({ | ||
type: DataType.U8Array, | ||
length: person.byteArray.length, | ||
}), | ||
}; | ||
const personObj = load({ | ||
library: "libsum", | ||
funcName: "getStruct", | ||
retType: personType, | ||
paramsType: [ | ||
{ | ||
age: DataType.I32, | ||
doubleArray: DataType.DoubleArray, | ||
parent: { | ||
parent: {}, | ||
age: DataType.I32, | ||
doubleProps: DataType.Double, | ||
name: DataType.String, | ||
stringArray: DataType.StringArray, | ||
doubleArray: DataType.DoubleArray, | ||
i32Array: DataType.I32Array, | ||
boolTrue: DataType.Boolean, | ||
boolFalse: DataType.Boolean, | ||
longVal: DataType.I64, | ||
byte: DataType.U8, | ||
byteArray: DataType.U8Array, | ||
}, | ||
doubleProps: DataType.Double, | ||
name: DataType.String, | ||
stringArray: DataType.StringArray, | ||
i32Array: DataType.I32Array, | ||
boolTrue: DataType.Boolean, | ||
boolFalse: DataType.Boolean, | ||
longVal: DataType.I64, | ||
byte: DataType.U8, | ||
byteArray: DataType.U8Array, | ||
}, | ||
], | ||
paramsValue: [person], | ||
}); | ||
deepStrictEqual(person, personObj); | ||
const createdPerson = load({ | ||
library: "libsum", | ||
funcName: "createPerson", | ||
retType: personType, | ||
paramsType: [], | ||
paramsValue: [], | ||
}); | ||
typedef struct Person { | ||
//... | ||
uint8_t staticBytes[16]; | ||
//... | ||
} Person; | ||
deepStrictEqual(createdPerson, person); | ||
// use arrayConstructor and set dynamicArray field to false | ||
staticBytes: arrayConstructor({ | ||
type: DataType.U8Array, | ||
length: parent.staticBytes.length, | ||
dynamicArray: false | ||
}), | ||
``` | ||
@@ -691,4 +508,4 @@ | ||
```cpp | ||
typedef void (*FunctionPointer)(int a, bool b, char *c, char **d, int *e, | ||
Person *p); | ||
typedef const void (*FunctionPointer)(int a, bool b, char *c, double d, | ||
char **e, int *f, Person *g); | ||
@@ -701,3 +518,3 @@ extern "C" void callFunction(FunctionPointer func) { | ||
bool b = false; | ||
double ddd = 100.11; | ||
double d = 100.11; | ||
char *c = (char *)malloc(14 * sizeof(char)); | ||
@@ -716,3 +533,3 @@ strcpy(c, "Hello, World!"); | ||
Person *p = createPerson(); | ||
func(a, b, c, stringArray, i32Array, p); | ||
func(a, b, c, d, stringArray, i32Array, p); | ||
} | ||
@@ -726,17 +543,32 @@ } | ||
let count = 0; | ||
const func = (a, b, c, d, e, f) => { | ||
const func = (a, b, c, d, e, f, g) => { | ||
equal(a, 100); | ||
equal(b, false); | ||
equal(c, "Hello, World!"); | ||
deepStrictEqual(d, ["Hello", "world"]); | ||
deepStrictEqual(e, [101, 202, 303]); | ||
deepStrictEqual(f, person); | ||
equal(d, "100.11"); | ||
deepStrictEqual(e, ["Hello", "world"]); | ||
deepStrictEqual(f, [101, 202, 303]); | ||
deepStrictEqual(g, person); | ||
console.log("callback called"); | ||
count++; | ||
if (count === 2) { | ||
console.log("test succeed"); | ||
if (count === 4) { | ||
logGreen("test succeed"); | ||
process.exit(0); | ||
} | ||
}; | ||
const funcExternal = createPointer({ | ||
paramsType: [funcConstructor({ | ||
paramsType: [ | ||
DataType.I32, | ||
DataType.Boolean, | ||
DataType.String, | ||
DataType.Double, | ||
arrayConstructor({ type: DataType.StringArray, length: 2 }), | ||
arrayConstructor({ type: DataType.I32Array, length: 3 }), | ||
personType, | ||
], | ||
retType: DataType.Void, | ||
})], | ||
paramsValue: [func] | ||
}) | ||
load({ | ||
@@ -746,20 +578,28 @@ library: "libsum", | ||
retType: DataType.Void, | ||
paramsType: [funcConstructor({ | ||
paramsType: [ | ||
DataType.I32, | ||
DataType.Boolean, | ||
DataType.String, | ||
DataType.Double, | ||
arrayConstructor({ type: DataType.StringArray, length: 2 }), | ||
arrayConstructor({ type: DataType.I32Array, length: 3 }), | ||
personType, | ||
], | ||
retType: DataType.Void, | ||
})], | ||
paramsValue: [func] | ||
}); | ||
load({ | ||
library: "libsum", | ||
funcName: "callFunction", | ||
retType: DataType.Void, | ||
paramsType: [ | ||
funcConstructor({ | ||
paramsType: [ | ||
DataType.I32, | ||
DataType.Boolean, | ||
DataType.String, | ||
arrayConstructor({ type: DataType.StringArray, length: 2 }), | ||
arrayConstructor({ type: DataType.I32Array, length: 3 }), | ||
personType, | ||
], | ||
retType: DataType.Void, | ||
}), | ||
DataType.External, | ||
], | ||
paramsValue: [func], | ||
paramsValue: unwrapPointer(funcExternal), | ||
}); | ||
``` | ||
The function parameters supports type are all in the example above (double type is unsupported at this time), we will support more types in the future | ||
The function parameters supports type are all in the example above | ||
@@ -766,0 +606,0 @@ Attention,since the vast majority of scenarios developers pass js function to c as a callback, so `ffi-rs` will create [threadsafe_function](https://nodejs.org/api/n-api.html#napi_threadsafe_function) from jsfunction which means the jsfunction will be called asynchronous, and Node.js process will not be exited automatically |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
449
32510
644