{"id":13636002,"url":"https://github.com/zhangyuang/node-ffi-rs","last_synced_at":"2025-05-15T09:04:27.357Z","repository":{"id":182588794,"uuid":"667338635","full_name":"zhangyuang/node-ffi-rs","owner":"zhangyuang","description":"Implement ffi in Node.js by Rust and NAPI","archived":false,"fork":false,"pushed_at":"2025-04-04T06:14:21.000Z","size":12743,"stargazers_count":244,"open_issues_count":8,"forks_count":10,"subscribers_count":5,"default_branch":"master","last_synced_at":"2025-04-07T10:17:25.144Z","etag":null,"topics":["ffi","napi","node-ffi","nodejs-ffi","rust"],"latest_commit_sha":null,"homepage":"","language":"Rust","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/zhangyuang.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2023-07-17T09:28:16.000Z","updated_at":"2025-04-06T14:00:03.000Z","dependencies_parsed_at":null,"dependency_job_id":"bf228db1-0ca3-413a-95ec-573112f79f7b","html_url":"https://github.com/zhangyuang/node-ffi-rs","commit_stats":{"total_commits":372,"total_committers":4,"mean_commits":93.0,"dds":"0.016129032258064502","last_synced_commit":"a7c4fc8fb27bcbe5e2d30f54a733f065b67b98b1"},"previous_names":["zhangyuang/node-ffi-rs"],"tags_count":108,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/zhangyuang%2Fnode-ffi-rs","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/zhangyuang%2Fnode-ffi-rs/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/zhangyuang%2Fnode-ffi-rs/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/zhangyuang%2Fnode-ffi-rs/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/zhangyuang","download_url":"https://codeload.github.com/zhangyuang/node-ffi-rs/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248891632,"owners_count":21178675,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["ffi","napi","node-ffi","nodejs-ffi","rust"],"created_at":"2024-08-02T00:00:55.282Z","updated_at":"2025-04-14T13:53:17.241Z","avatar_url":"https://github.com/zhangyuang.png","language":"Rust","funding_links":[],"categories":["Development tools"],"sub_categories":["FFI"],"readme":"# ffi-rs\n\n\u003cdiv\u003e\n\u003ca href=\"https://github.com/zhangyuang/node-ffi-rs/blob/master/README.md\"\u003eEnglish\u003c/a\u003e | \u003ca href=\"https://github.com/zhangyuang/node-ffi-rs/blob/master/README_Zh.md\"\u003e简体中文\u003c/a\u003e\n\u003c/div\u003e\n\nA module written in Rust and N-API provides interface (FFI) features for Node.js\n\n\u003cdiv align=\"\"\u003e\n\u003ca href=\"https://github.com/zhangyuang/node-ffi-rs/actions\" target=\"_blank\"\u003e\u003cimg src=\"https://github.com/zhangyuang/ssr/workflows/CI/badge.svg\" alt=\"githubActions\" /\u003e\u003c/a\u003e\n\u003ca href=\"https://www.npmjs.com/package/ffi-rs\" target=\"_blank\"\u003e\u003cimg src=\"https://img.shields.io/npm/dm/ffi-rs\"\u003e\n\u003c/a\u003e\n\u003ca href=\"https://www.npmjs.com/package/ffi-rs\" target=\"_blank\"\u003e\u003cimg src=\"https://img.shields.io/npm/unpacked-size/@yuuang/ffi-rs-linux-x64-gnu\"\u003e\n\u003c/a\u003e\n\u003c/div\u003e\n\n## Description\n\n[ffi-rs](https://github.com/zhangyuang/node-ffi-rs) is a high-performance module with small binary size written in Rust and N-API that provides FFI (Foreign Function Interface) features for Node.js. It allows developers to call functions written in other languages such as C++, C, and Rust directly from JavaScript without writing any C++ code.\n\nThis module aims to provide similar functionality to the node-ffi module but with a completely rewritten underlying codebase. The node-ffi module has been unmaintained for several years and is no longer usable, so ffi-rs was developed to fill that void.\n\n## Features\n\n* High performance ✨\n* Small binary size\n* Better type hints 🧐\n* Simpler data description and API interface 💗\n* Support more different data types between `Node.js` and `C` 😊\n* Support modifying data in place 🥸\n* Provide many ways to handle pointer type directly 🐮\n* Support running ffi task [in a new thread](#runInNewThread) 🤩️\n* Support output [errno](#errno) info 🤔️\n* No need to use [ref](https://www.npmjs.com/package/ref) to handle pointer 🤫\n\n## Benchmark\n\n```bash\n$ node bench/bench.js\nRunning \"ffi\" suite...\nProgress: 100%\n\n  ffi-napi:\n    2 028 ops/s, ±4.87%     | slowest, 99.24% slower\n\n  ffi-rs:\n    318 467 ops/s, ±0.17%   | fastest\n\nFinished 2 cases!\n  Fastest: ffi-rs\n  Slowest: ffi-napi\n```\n\n### How to sponsor me\n\nThere are two ways to sponsor me both Alipay and WeChat\n\nEth address: 0x87a2575a5d4dbD5f965e3e3a3d20641BC9a5d192\n\n\u003cdiv style=\"display:flex\"\u003e\n  \u003cimg src=\"https://res.wx.qq.com/shop/public/2025-02-12/d50454c8-65f0-4a81-956b-b8837c187364.jpg\" width=200\u003e\n  \u003cimg src=\"https://res.wx.qq.com/op_res/9jSx7WJn6FBlfQ0ColL4hnvX91D9MlB_XPCgLFM527qknHp0utXZkLah6MYcumdVejK4884dvgkY0NIbBLPrYg\" width=200\u003e\n\u003c/div\u003e\n\n## Changelog\n\nSee [CHANGELOG.md](./CHANGELOG.md)\n\n## Ecosystem\n\n[abstract-socket-rs](https://github.com/zhangyuang/abstract-socket-rs)\n\n## Install\n\n```bash\n$ npm i ffi-rs\n```\n\n## Supported Types\n\nCurrently, ffi-rs only supports these types of parameters and return values. However, support for more types may be added in the future based on actual usage scenarios.\n\n### Basic Types\n\n* [string](#basic-types)\n* [wideString|wstring](#basic-types)\n* [u8](#basic-types)\n* [i16](#basic-types)\n* [i32](#basic-types)\n* [i64](#basic-types)\n* [bigInt](#basic-types)\n* [u64](#basic-types)\n* [void](#basic-types) (like js undefined)\n* [float](#basic-types) (can only be used as paramsType instead of retType)\n* [double](#basic-types)\n* [boolean](#basic-types)\n\n### Reference Types\n\n* [pointer](#pointer)\n* [u8Array](#buffer) (buffer)\n* [i16Array](#array)\n* [i32Array](#array)\n* [stringArray](#array)\n* [doubleArray](#array)\n* [floatArray](#array) (can only be used as paramsType instead of retType)\n* [structArray](#array)\n* [object](#struct) (Nested object is also supported in the latest version)\n* [function](#function)\n\n### C++ Class\n\nIf you want to call a C++ function whose argument type is a class, you can use the `pointer` type. See [tutorial](#C++)\n\n## Supported Platforms\n\nNote: You need to make sure that the compilation environment of the dynamic library is the same as the installation and runtime environment of the `ffi-rs` call.\n\n* darwin-x64\n* darwin-arm64\n* linux-x64-gnu\n* linux-x64-musl\n* win32-x64-msvc\n* win32-ia32-msvc\n* win32-arm64-msvc\n* linux-arm64-gnu\n* linux-arm64-musl\n* linux-arm-gnueabihf\n* android-arm64\n\n## Usage\n\nView [tests/index.ts](./tests/index.ts) for the latest usage\n\nHere is an example of how to use ffi-rs:\n\nFor the following C++ code, we compile this file into a dynamic library\n\n### Write Foreign Function Code\n\nNote: The return value type of a function must be of type C\n\n```cpp\n#include \u003ccstdio\u003e\n#include \u003ccstring\u003e\n#include \u003ciostream\u003e\n#include \u003cstring\u003e\n\nextern \"C\" int sum(int a, int b) { return a + b; }\n\nextern \"C\" double doubleSum(double a, double b) { return a + b; }\n\nextern \"C\" const char *concatenateStrings(const char *str1, const char *str2) {\n  std::string result = std::string(str1) + std::string(str2);\n  char *cstr = new char[result.length() + 1];\n  strcpy(cstr, result.c_str());\n  return cstr;\n}\n\nextern \"C\" void noRet() { printf(\"%s\", \"hello world\"); }\nextern \"C\" bool return_opposite(bool input) { return !input; }\n```\n\n### Compile C Code into a Dynamic Library\n\n```bash\n$ g++ -dynamiclib -o libsum.so cpp/sum.cpp # macOS\n$ g++ -shared -o libsum.so cpp/sum.cpp # Linux\n$ g++ -shared -o sum.dll cpp/sum.cpp # Windows\n```\n\n### Call Dynamic Library Using ffi-rs\n\nThen you can use `ffi-rs` to invoke the dynamic library file that contains functions.\n\n### Initialization\n\nIt's suggested to develop with TypeScript to get type hints\n\n```js\nconst {\n    equal\n} = require('assert')\nconst {\n    load,\n    DataType,\n    open,\n    close,\n    arrayConstructor,\n    define\n} = require('ffi-rs')\nconst a = 1\nconst b = 100\nconst dynamicLib = platform === 'win32' ? './sum.dll' : \"./libsum.so\"\n// First open dynamic library with key for close\n// It only needs to be opened once.\nopen({\n    library: 'libsum', // key\n    path: dynamicLib // path\n})\nconst r = load({\n    library: \"libsum\", // path to the dynamic library file\n    funcName: 'sum', // the name of the function to call\n    retType: DataType.I32, // the return value type\n    paramsType: [DataType.I32, DataType.I32], // the parameter types\n    paramsValue: [a, b] // the actual parameter values\n    // freeResultMemory: true, // whether or not need to free the result of return value memory automatically, default is false\n})\nequal(r, a + b)\n// Release library memory when you're not using it.\nclose('libsum')\n\n// Use define function to define a function signature\nconst res = define({\n    sum: {\n        library: \"libsum\",\n        retType: DataType.I32,\n        paramsType: [DataType.I32, DataType.I32],\n    },\n    atoi: {\n        library: \"libnative\",\n        retType: DataType.I32,\n        paramsType: [DataType.String],\n    }\n})\nequal(res.sum([1, 2]), 3)\nequal(res.atoi([\"1000\"]), 1000)\n```\n\n### Load Main Program Handle\n\nYou can also pass an empty path string in the `open` function like [ffi-napi](https://github.com/node-ffi-napi/node-ffi-napi?tab=readme-ov-file#example) to get the main program handle. Refer to [dlopen](https://man7.org/linux/man-pages/man3/dlopen.3.html)\n\n```js\nopen({\n    library: \"libnative\",\n    path: \"\",\n});\n// In Darwin/Linux, you can call the atoi function which is included in the basic C library\nequal(\n    load({\n        library: \"libnative\",\n        funcName: \"atoi\",\n        retType: DataType.I32,\n        paramsType: [DataType.String],\n        paramsValue: [\"1000\"],\n    }),\n    1000,\n);\n```\n\n### Basic Types\n\n`number|string|boolean|double|void` are basic types\n\n```js\nconst c = \"foo\"\nconst d = c.repeat(200)\n\nequal(c + d, load({\n    library: 'libsum',\n    funcName: 'concatenateStrings',\n    retType: DataType.String,\n    paramsType: [DataType.String, DataType.String],\n    paramsValue: [c, d]\n}))\n\nequal(undefined, load({\n    library: 'libsum',\n    funcName: 'noRet',\n    retType: DataType.Void,\n    paramsType: [],\n    paramsValue: []\n}))\n\nequal(1.1 + 2.2, load({\n    library: 'libsum',\n    funcName: 'doubleSum',\n    retType: DataType.Double,\n    paramsType: [DataType.Double, DataType.Double],\n    paramsValue: [1.1, 2.2]\n}))\nconst bool_val = true\nequal(!bool_val, load({\n    library: 'libsum',\n    funcName: 'return_opposite',\n    retType: DataType.Boolean,\n    paramsType: [DataType.Boolean],\n    paramsValue: [bool_val],\n}))\n```\n\n### Buffer\n\nIn the latest version, `ffi-rs` supports modifying data in place.\n\nThe sample code is as follows\n\n```c\nextern int modifyData(char* buffer) {\n    // modify buffer data in place\n}\n```\n\n```js\nconst arr = Buffer.alloc(200) // create buffer\nconst res = load({\n    library: \"libsum\",\n    funcName: \"modifyData\",\n    retType: DataType.I32,\n    paramsType: [\n        DataType.U8Array\n    ],\n    paramsValue: [arr]\n})\nconsole.log(arr) // buffer data can be updated\n```\n\n### Array\n\nWhen using `array` as `retType` , you should use `arrayConstructor` to specify the array type with a legal length which is important.\n\nIf the length is incorrect, the program may exit abnormally\n\n```cpp\nextern \"C\" int *createArrayi32(const int *arr, int size) {\n  int *vec = (int *)malloc((size) * sizeof(int));\n\n  for (int i = 0; i \u003c size; i++) {\n    vec[i] = arr[i];\n  }\n  return vec;\n}\nextern \"C\" double *createArrayDouble(const double *arr, int size) {\n  double *vec = (double *)malloc((size) * sizeof(double));\n  for (int i = 0; i \u003c size; i++) {\n    vec[i] = arr[i];\n  }\n  return vec;\n}\n\nextern \"C\" char **createArrayString(char **arr, int size) {\n  char **vec = (char **)malloc((size) * sizeof(char *));\n  for (int i = 0; i \u003c size; i++) {\n    vec[i] = arr[i];\n  }\n  return vec;\n}\n```\n\n```js\nlet bigArr = new Array(100).fill(100)\ndeepStrictEqual(bigArr, load({\n    library: 'libsum',\n    funcName: 'createArrayi32',\n    retType: arrayConstructor({\n        type: DataType.I32Array,\n        length: bigArr.length\n    }),\n    paramsType: [DataType.I32Array, DataType.I32],\n    paramsValue: [bigArr, bigArr.length],\n}))\n\nlet bigDoubleArr = new Array(5).fill(1.1)\ndeepStrictEqual(bigDoubleArr, load({\n    library: 'libsum',\n    funcName: 'createArrayDouble',\n    retType: arrayConstructor({\n        type: DataType.DoubleArray,\n        length: bigDoubleArr.length\n    }),\n    paramsType: [DataType.DoubleArray, DataType.I32],\n    paramsValue: [bigDoubleArr, bigDoubleArr.length],\n}))\nlet stringArr = [c, c.repeat(20)]\n\ndeepStrictEqual(stringArr, load({\n    library: 'libsum',\n    funcName: 'createArrayString',\n    retType: arrayConstructor({\n        type: DataType.StringArray,\n        length: stringArr.length\n    }),\n    paramsType: [DataType.StringArray, DataType.I32],\n    paramsValue: [stringArr, stringArr.length],\n}))\n```\n\n### Pointer\n\nThese functions are used to handle pointer types in `ffi-rs` . We use `DataType.External` to pass pointers between `Node.js` and `C` .\n\n#### Create Pointer\n\nUse `createPointer` to create a pointer for specific type in the code as follows:\n\n```js\nextern \"C\"\nvoid receiveNumPointer(const int * num)\n\n// use the rust type expression the pointer type is *const i32\nconst pointer: JsExternal[] = createPointer({\n    paramsType: [DataType.I32],\n    paramsValue: [100],\n})\n\nload({\n    library: \"libsum\",\n    funcName: \"receiveNumPointer\",\n    paramsType: [DataType.External],\n    paramsValue: pointer,\n    retType: DataType.Void,\n})\n```\n\n#### unwrapPointer\n\nUse `createPointer` to create a data type which store in heap will receive a double pointer means a pointer to a pointer.\nSo we need to use `unwrapPointer` to get the inner pointer when call foreign function.\n\n```js\nextern \"C\"\nvoid receiveStringPointer(const char * str)\n\n// because of string is a pointer, so the pointer is a double pointer means a pointer to a string pointer\n// use the rust type expression pointer type is *mut *const char\nconst pointer: JsExternal[] = createPointer({\n    paramsType: [DataType.String],\n    paramsValue: [\"hello\"],\n})\n\nload({\n    library: \"libsum\",\n    funcName: \"receiveStringPointer\",\n    paramsType: [DataType.External],\n    paramsValue: unwrapPointer(pointer), // use the unwrapPointer to get the inner *mut *const char pointer, which points to a *const char value\n    retType: DataType.Void,\n})\n```\n\n#### restorePointer\n\nIf you want to restore the pointer to the original value, you can use the `restorePointer` function. Corresponds to `createPointer` , \nit can receive the result of `createPointer` and return the original pointer directly without `wrapPointer` or `unwrapPointer` .\n\n```js\nconst pointer: JsExternal[] = createPointer({\n    paramsType: [DataType.String],\n    paramsValue: [\"hello\"],\n})\nconst str = restorePointer({\n    retType: [DataType.String],\n    paramsValue: pointer,\n})\nequal(str, \"hello\")\n```\n\n#### wrapPointer\n\nUse `wrapPointer` when you want to restore the foreign function return value.\n\n```js\nextern \"C\"\nconst char * returnStringPointer() {\n    char * str = new char[6];\n    strcpy(str, \"hello\");\n    return str;\n}\n// the stringPointer type is *const char, we need to convert it to *mut *const char before call restorePointer\nconst stringPointer = load({\n    library: \"libsum\",\n    funcName: \"returnStringPointer\",\n    retType: DataType.External,\n    paramsType: [DataType.String],\n    paramsValue: [\"hello\"],\n})\n\nconst wrapStringPointer = wrapPointer([stringPointer])\n\nconst str = restorePointer({\n    retType: [DataType.String],\n    paramsValue: wrapStringPointer,\n})\nequal(str, \"hello\")\n```\n\n#### freePointer\n\nUse `freePointer` to free the pointer when it is no longer in use.\n\n```js\nconst i32Ptr = createPointer({\n    paramsType: [DataType.I32],\n    paramsValue: [100]\n})\nconst i32Data = restorePointer({\n    paramsValue: i32Ptr\n    retType: [DataType.I32],\n})\nfreePointer({\n    paramsType: [DataType.I32],\n    paramsValue: i32Ptr,\n    pointerType: PointerType.RsPointer\n})\n\nextern \"C\"\nconst char * returnStringPointer() {\n    char * str = new char[6];\n    strcpy(str, \"hello\");\n    return str;\n}\nconst stringPointer = load({\n    library: \"libsum\",\n    funcName: \"returnStringPointer\",\n    retType: DataType.External,\n    paramsType: [DataType.String],\n    paramsValue: [\"hello\"],\n})\nfreePointer({\n    paramsType: [DataType.External],\n    paramsValue: [stringPointer],\n    pointerType: PointerType.CPointer // will use libc::free to free the memory\n})\n```\n\n### Struct\n\nTo create a C struct or get a C struct as a return type, you need to define the types of the parameters strictly in the order in which the fields of the C structure are defined.\n\n`ffi-rs` provides a C struct named `Person` with many types of fields in [sum.cpp](https://github.com/zhangyuang/node-ffi-rs/blob/master/cpp/sum.cpp#L48)\n\nThe example call method about how to call a foreign function to create a `Person` struct or use `Person` struct as a return value is [here](https://github.com/zhangyuang/node-ffi-rs/blob/master/test.ts#L289)\n\n#### Use array in struct\n\nThere are two types of arrays in C language like `int* array` and `int array[100]` that have some different usages.\n\nThe first type `int* array` is a pointer type storing the first address of the array.\n\nThe second type `int array[100]` is a fixed-length array and each element in the array has a continuous address.\n\nIf you use an array as a function parameter, this usually passes an array pointer regardless of which type you define. But if the array type is defined in a struct, the two types of array definitions will cause different sizes and alignments of the struct.\n\nSo, `ffi-rs` needs to distinguish between the two types.\n\nBy default, `ffi-rs` uses dynamic arrays to calculate struct. If you confirm there is a static array, you can define it in this way:\n\n```c\ntypedef struct Person {\n  //...\n  uint8_t staticBytes[16];\n  //...\n} Person;\n\n// use arrayConstructor and set ffiTypeTag field to DataType.StackArray\nstaticBytes: arrayConstructor({\n  type: DataType.U8Array,\n  length: parent.staticBytes.length,\n  ffiTypeTag: FFITypeTag.StackArray\n}),\n```\n\n## Function\n\n`ffi-rs` supports passing JS function pointers to C functions, like this:\n\n```cpp\ntypedef const void (*FunctionPointer)(int a, bool b, char *c, double d,\n                                      char **e, int *f, Person *g);\n\nextern \"C\" void callFunction(FunctionPointer func) {\n  printf(\"callFunction\\n\");\n\n  for (int i = 0; i \u003c 2; i++) {\n    int a = 100;\n    bool b = false;\n    double d = 100.11;\n    char *c = (char *)malloc(14 * sizeof(char));\n    strcpy(c, \"Hello, World!\");\n\n    char **stringArray = (char **)malloc(sizeof(char *) * 2);\n    stringArray[0] = strdup(\"Hello\");\n    stringArray[1] = strdup(\"world\");\n\n    int *i32Array = (int *)malloc(sizeof(int) * 3);\n    i32Array[0] = 101;\n    i32Array[1] = 202;\n    i32Array[2] = 303;\n\n    Person *p = createPerson();\n    func(a, b, c, d, stringArray, i32Array, p);\n  }\n}\n```\n\nCorresponding to the code above, you can use `ffi-rs` like this:\n\n```js\nconst testFunction = () =\u003e {\n    const func = (a, b, c, d, e, f, g) =\u003e {\n        equal(a, 100);\n        equal(b, false);\n        equal(c, \"Hello, World!\");\n        equal(d, \"100.11\");\n        deepStrictEqual(e, [\"Hello\", \"world\"]);\n        deepStrictEqual(f, [101, 202, 303]);\n        deepStrictEqual(g, person);\n        logGreen(\"test function succeed\");\n        // free function memory when it is not in use\n        freePointer({\n            paramsType: [funcConstructor({\n                paramsType: [\n                    DataType.I32,\n                    DataType.Boolean,\n                    DataType.String,\n                    DataType.Double,\n                    arrayConstructor({\n                        type: DataType.StringArray,\n                        length: 2\n                    }),\n                    arrayConstructor({\n                        type: DataType.I32Array,\n                        length: 3\n                    }),\n                    personType,\n                ],\n                retType: DataType.Void,\n            })],\n            paramsValue: funcExternal\n        })\n        if (!process.env.MEMORY) {\n            close(\"libsum\");\n        }\n    };\n    // suggest using createPointer to create a function pointer for manual memory management\n    const funcExternal = createPointer({\n        paramsType: [funcConstructor({\n            paramsType: [\n                DataType.I32,\n                DataType.Boolean,\n                DataType.String,\n                DataType.Double,\n                arrayConstructor({\n                    type: DataType.StringArray,\n                    length: 2\n                }),\n                arrayConstructor({\n                    type: DataType.I32Array,\n                    length: 3\n                }),\n                personType,\n            ],\n            retType: DataType.Void,\n        })],\n        paramsValue: [func]\n    })\n    load({\n        library: \"libsum\",\n        funcName: \"callFunction\",\n        retType: DataType.Void,\n        paramsType: [\n            DataType.External,\n        ],\n        paramsValue: unwrapPointer(funcExternal),\n    });\n}\n```\n\nThe function parameters support all types in the example above.\n\nAttention: since the vast majority of scenarios developers pass JS functions to C as callbacks, `ffi-rs` will create [threadsafe_function](https://nodejs.org/api/n-api.html#napi_threadsafe_function) from JS functions which means the JS function will be called asynchronously, and the Node.js process will not exit automatically.\n\n## C++\n\nWe'll provide more examples from real-world scenarios. If you have any ideas, please submit an issue.\n\n### Class type\n\nIn C++ scenarios, we can use `DataType.External` to get a class type pointer.\n\nIn the code below, we use C types to wrap C++ types such as converting `char *` to `std::string` and returning a class pointer:\n\n```cpp\nMyClass *createMyClass(std::string name, int age) {\n  return new MyClass(name, age);\n}\n\nextern \"C\" MyClass *createMyClassFromC(const char *name, int age) {\n  return createMyClass(std::string(name), age);\n}\n\nextern \"C\" void printMyClass(MyClass *instance) { instance-\u003eprint(); }\n```\n\nAnd then, it can be called by the following code:\n\n```js\nconst classPointer = load({\n    library: \"libsum\",\n    funcName: \"createMyClassFromC\",\n    retType: DataType.External,\n    paramsType: [\n        DataType.String,\n        DataType.I32\n    ],\n    paramsValue: [\"classString\", 26],\n});\nload({\n    library: \"libsum\",\n    funcName: \"printMyClass\",\n    retType: DataType.External,\n    paramsType: [\n        DataType.External,\n    ],\n    paramsValue: [classPointer],\n})\nfreePointer({\n    paramsType: [DataType.External],\n    paramsValue: [classPointer],\n    pointerType: PointerType.CPointer\n})\n```\n\n## errno\n\nBy default, `ffi-rs` will not output [errno](https://man7.org/linux/man-pages/man3/errno.3.html) info. Developers can get it by passing `errno: true` when calling the open method like:\n\n```js\nload({\n    library: 'libnative',\n    funcName: 'setsockopt',\n    retType: DataType.I32,\n    paramsType: [DataType.I32, DataType.I32, DataType.I32, DataType.External, DataType.I32],\n    paramsValue: [socket._handle.fd, level, option, pointer[0], 4],\n    errno: true // set errno as true\n})\n\n// The above code will return an object including three fields: errnoCode, errnoMessage, and the foreign function return value\n// { errnoCode: 22, errnoMessage: 'Invalid argument (os error 22)', value: -1 }\n```\n\n## Memory Management\n\nIt's important to free the memory allocations during a single ffi call to prevent memory leaks.\n\nWhat kinds of data memory are allocated in this?\n\n* Call parameters in the Rust environment which are allocated in the heap like `String`\n* Return value which in the C environment which are allocated in the heap like `char*`\n\nBy default, `ffi-rs` will free call parameters memory which are allocated in Rust.\n\nBut it will not free the return value from the C side since some C dynamic libraries will manage their memory automatically (when ffi-rs \u003e= 1.0.79)\n\nThere are two ways to prevent `ffi-rs` from releasing memory:\n\n* Set `freeResultMemory: false` when calling `load` method, the default value is false\n\nIf you set freeResultMemory to false, `ffi-rs` will not release the return result memory which was allocated in the C environment\n\n* Use `DataType.External` as paramsType or retType\n\nIf developers use `DataType.External` as paramsType or retType, please use `freePointer` to release the memory of the pointer when this memory is no longer in use. ref [test.ts](./test.ts#170)\n\n## runInNewThread\n\n`ffi-rs` supports running ffi tasks in a new thread without blocking the main thread, which is useful for CPU-intensive tasks.\n\nTo use this feature, you can pass the `runInNewThread` option to the load method:\n\n```js\nconst testRunInNewThread = async () =\u003e {\n    // will return a promise but the task will run in a new thread\n    load({\n        library: \"libsum\",\n        funcName: \"sum\",\n        retType: DataType.I32,\n        paramsType: [DataType.I32, DataType.I32],\n        paramsValue: [1, 2],\n        runInNewThread: true,\n    }).then(res =\u003e {\n        equal(res, 3)\n    })\n}\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fzhangyuang%2Fnode-ffi-rs","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fzhangyuang%2Fnode-ffi-rs","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fzhangyuang%2Fnode-ffi-rs/lists"}