Maintainers
Pricing
Enterprise
More
More
Documentation
Try Live
Rankings
Install
Blog
Docs7
Ask
New
Add Docs
Node FFI RS
https://github.com/zhangyuang/node-ffi-rs
Admin
Implement ffi in Node.js by Rust and NAPI
Tokens:
15,963
Snippets:
119
Trust Score:
9.4
License:
MIT
Update:
6 months ago
Context
Chat
Benchmark
58.29
Latest
Show doc for...
Code
Info
Show Results
Tokens:
Raw
Copy
Link
Tokens:
Raw
Copy
Link
### Install and Build Commands Source: https://github.com/zhangyuang/node-ffi-rs/blob/master/CLAUDE.md Standard shell commands for installing dependencies, building the native module, and running tests. ```bash # Install dependencies pnpm install # Build Rust native module + compile test C++ library npm run build # runs napi build + copies type files npm run build:c # compiles cpp/sum.cpp -> libsum.so (or sum.dll) npm run build:dev # development build # Run tests npm test # runs: esno ./tests/index.ts # TypeScript runner: project uses esno (not ts-node) npx esno tests/some_test.ts ``` -------------------------------- ### Install ffi-rs Source: https://github.com/zhangyuang/node-ffi-rs/blob/master/README.md Install the ffi-rs package using npm. ```bash $ npm i ffi-rs ``` -------------------------------- ### Install ffi-rs Source: https://context7.com/zhangyuang/node-ffi-rs/llms.txt Install the ffi-rs package using npm. ```bash npm install ffi-rs ``` -------------------------------- ### Defining Structs with Static Arrays in C Source: https://github.com/zhangyuang/node-ffi-rs/blob/master/README.md Example of defining a C struct with a static array. Use `arrayConstructor` and set `ffiTypeTag` to `DataType.StackArray` to distinguish it from dynamic arrays. ```c typedef struct Person { //... uint8_t staticBytes[16]; //... } Person; ``` -------------------------------- ### C++ Foreign Function Code Source: https://github.com/zhangyuang/node-ffi-rs/blob/master/README.md Example C++ code demonstrating functions that can be called from Node.js using ffi-rs. Ensure these functions are compiled into a dynamic library. ```cpp #include <cstdio> #include <cstring> #include <iostream> #include <string> extern "C" int sum(int a, int b) { return a + b; } extern "C" double doubleSum(double a, double b) { return a + b; } 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 noRet() { printf("%s", "hello world"); } extern "C" bool return_opposite(bool input) { return !input; } extern "C" uint32_t testU32(uint32_t a, uint32_t b) { return a + b; } ``` -------------------------------- ### Enable and Get Errno Info Source: https://github.com/zhangyuang/node-ffi-rs/blob/master/README.md Pass `errno: true` to the load method to retrieve errno information. The returned object includes `errnoCode`, `errnoMessage`, and the function's return value. ```javascript load({ library: 'libnative', funcName: 'setsockopt', retType: DataType.I32, paramsType: [DataType.I32, DataType.I32, DataType.I32, DataType.External, DataType.I32], paramsValue: [socket._handle.fd, level, option, pointer[0], 4], errno: true // set errno as true }) ``` ```javascript // The above code will return an object including three fields: errnoCode, errnoMessage, and the foreign function return value // { errnoCode: 22, errnoMessage: 'Invalid argument (os error 22)', value: -1 } ``` -------------------------------- ### errno - Get Error Information Source: https://context7.com/zhangyuang/node-ffi-rs/llms.txt Enables retrieval of the C errno value after a function call for debugging system-level errors. ```APIDOC ## load (with errno) ### Description Retrieves the C errno value after a function call when the errno option is enabled. ### Parameters #### Request Body - **errno** (Boolean) - Optional - Set to true to enable errno reporting. ### Response #### Success Response (200) - **value** (Any) - The return value of the C function. - **errnoCode** (Number) - The numeric errno value. - **errnoMessage** (String) - The descriptive error message. ``` -------------------------------- ### Initialize and Load Dynamic Library Functions Source: https://github.com/zhangyuang/node-ffi-rs/blob/master/README.md Open a dynamic library using a key and path, then load functions with specified return and parameter types. Ensure to close the library when done. Use `define` for pre-defining function signatures. ```javascript const { equal } = require('assert') const { load, DataType, open, close, arrayConstructor, define } = require('ffi-rs') const a = 1 const b = 100 const dynamicLib = platform === 'win32' ? './sum.dll' : "./libsum.so" // First open dynamic library with key for close // It only needs to be opened once. open({ library: 'libsum', // key path: dynamicLib // path }) const r = load({ library: "libsum", // path to the dynamic library file funcName: 'sum', // the name of the function to call retType: DataType.I32, // the return value type paramsType: [DataType.I32, DataType.I32], // the parameter types paramsValue: [a, b] // the actual parameter values // freeResultMemory: true, // whether or not need to free the result of return value memory automatically, default is false }) equal(r, a + b) // Release library memory when you're not using it. close('libsum') // Use define function to define a function signature const res = define({ sum: { library: "libsum", retType: DataType.I32, paramsType: [DataType.I32, DataType.I32], }, atoi: { library: "libnative", retType: DataType.I32, paramsType: [DataType.String], } }) equal(res.sum([1, 2]), 3) equal(res.atoi(["1000"])), 1000) ``` -------------------------------- ### Load Main Program Handle Source: https://github.com/zhangyuang/node-ffi-rs/blob/master/README.md Load the main program handle by passing an empty path string to the `open` function. This allows calling functions from the basic C library on Darwin/Linux. ```javascript open({ library: "libnative", path: "", }); // In Darwin/Linux, you can call the atoi function which is included in the basic C library equal( load({ library: "libnative", funcName: "atoi", retType: DataType.I32, paramsType: [DataType.String], paramsValue: ["1000"], }), 1000, ); ``` -------------------------------- ### Using the define Convenience API Source: https://github.com/zhangyuang/node-ffi-rs/blob/master/CLAUDE.md Pre-bind function signatures to a library object for easier invocation. ```ts const lib = define({ sum: { library: "mylib", retType: DataType.I32, paramsType: [DataType.I32, DataType.I32] }, }); lib.sum([1, 2]); // => 3 ``` -------------------------------- ### Benchmark Comparison Source: https://github.com/zhangyuang/node-ffi-rs/blob/master/README.md Compares the performance of ffi-rs against ffi-napi, showing ffi-rs as significantly faster. ```bash $ node bench/bench.js Running "ffi" suite... Progress: 100% ffi-napi: 2 028 ops/s, ±4.87% | slowest, 99.24% slower ffi-rs: 318 467 ops/s, ±0.17% | fastest Finished 2 cases! Fastest: ffi-rs Slowest: ffi-napi ``` -------------------------------- ### Open a Dynamic Library with ffi-rs Source: https://context7.com/zhangyuang/node-ffi-rs/llms.txt Use the `open` function to load a dynamic library into memory. Pass an empty string for the path to access the main program handle for standard C library functions. ```javascript const { open } = require('ffi-rs'); // Load a custom dynamic library open({ library: 'libsum', path: process.platform === 'win32' ? './sum.dll' : './libsum.so' }); // Load the main program handle to access standard C library functions open({ library: 'libnative', path: '' }); ``` -------------------------------- ### define() Convenience API Source: https://github.com/zhangyuang/node-ffi-rs/blob/master/CLAUDE.md A high-level API to pre-bind function signatures from native libraries. ```APIDOC ## define() Convenience API ### Description Allows pre-binding of native function signatures to simplify calling C/C++ functions from JavaScript. ### Request Example const lib = define({ sum: { library: "mylib", retType: DataType.I32, paramsType: [DataType.I32, DataType.I32] }, }); lib.sum([1, 2]); // => 3 ``` -------------------------------- ### Pointer Management Source: https://github.com/zhangyuang/node-ffi-rs/blob/master/README.md Demonstrates how to create, restore, and free pointers using node-ffi-rs. It covers freeing both C-style and Rust-style pointers. ```APIDOC ## Pointer Management This section covers the management of pointers within the `node-ffi-rs` library, including creation, data retrieval, and memory deallocation. ### `createPointer` Creates a pointer to a value. **Parameters:** - `paramsType` (Array<DataType>) - Required - The data types of the parameters. - `paramsValue` (Array<any>) - Required - The values of the parameters. ### `restorePointer` Restores data from a pointer. **Parameters:** - `paramsValue` (Pointer) - Required - The pointer to restore data from. - `retType` (Array<DataType>) - Required - The data type of the return value. ### `freePointer` Frees a pointer when it is no longer in use. This is crucial for preventing memory leaks. **Parameters:** - `paramsType` (Array<DataType>) - Required - The data types associated with the pointer. - `paramsValue` (Pointer | Array<Pointer>) - Required - The pointer(s) to free. - `pointerType` (PointerType) - Optional - Specifies the type of pointer (e.g., `PointerType.RsPointer`, `PointerType.CPointer`). Defaults to CPointer. **Example Usage:** ```js // Freeing an i32 pointer const i32Ptr = createPointer({ paramsType: [DataType.I32], paramsValue: [100] }); freePointer({ paramsType: [DataType.I32], paramsValue: i32Ptr, pointerType: PointerType.RsPointer }); // Freeing a string pointer (CPointer) const stringPointer = load({ library: "libsum", funcName: "returnStringPointer", retType: DataType.External, paramsType: [DataType.String], paramsValue: ["hello"] }); freePointer({ paramsType: [DataType.External], paramsValue: [stringPointer], pointerType: PointerType.CPointer }); ``` ``` -------------------------------- ### Basic Type Usage with ffi-rs Source: https://github.com/zhangyuang/node-ffi-rs/blob/master/README.md Demonstrates calling functions with basic data types like String, Void, Double, Boolean, and U32. Ensure the C function signature matches the types defined in `load`. ```javascript const c = "foo" const d = c.repeat(200) equal(c + d, load({ library: 'libsum', funcName: 'concatenateStrings', retType: DataType.String, paramsType: [DataType.String, DataType.String], paramsValue: [c, d] })) equal(undefined, load({ library: 'libsum', funcName: 'noRet', retType: DataType.Void, paramsType: [], paramsValue: [] })) equal(1.1 + 2.2, load({ library: 'libsum', funcName: 'doubleSum', retType: DataType.Double, paramsType: [DataType.Double, DataType.Double], paramsValue: [1.1, 2.2] })) const bool_val = true equal(!bool_val, load({ library: 'libsum', funcName: 'return_opposite', retType: DataType.Boolean, paramsType: [DataType.Boolean], paramsValue: [bool_val], })) // U32 type usage equal(3147483647, load({ library: 'libsum', funcName: 'testU32', retType: DataType.U32, paramsType: [DataType.U32, DataType.U32], paramsValue: [2147483647, 1000000000], })) ``` -------------------------------- ### open - Open a Dynamic Library Source: https://context7.com/zhangyuang/node-ffi-rs/llms.txt Loads a dynamic library into memory and registers it with a unique identifier for subsequent function calls. ```APIDOC ## open ### Description Loads a dynamic library into memory and registers it with a unique identifier. This must be called before using load to invoke any functions from the library. ### Request Body - **library** (string) - Required - Unique identifier for this library - **path** (string) - Required - File path to the dynamic library (.so, .dll, .dylib). Pass an empty string to access the main program handle. ### Request Example { "library": "libsum", "path": "./libsum.so" } ``` -------------------------------- ### Struct Handling Source: https://github.com/zhangyuang/node-ffi-rs/blob/master/README.md Explains how to define and use C structs within node-ffi-rs, including handling different field types and arrays within structs. ```APIDOC ## Struct Handling This section details how to work with C structures (`struct`) in `node-ffi-rs`, covering their definition and usage as function parameters or return types. ### Defining Structs To create a C struct or use one as a return type, you must strictly define the types of its fields in the order they appear in the C definition. `ffi-rs` provides examples of C structs, such as `Person`, with various field types in its `sum.cpp` file. Refer to the provided test files for detailed examples of calling foreign functions that involve creating or returning `Person` structs. ### Using Arrays in Structs C language has two primary ways of defining arrays: pointers (`type* array`) and fixed-size arrays (`type array[N]`). These have different implications, especially when part of a struct, affecting size and alignment. `ffi-rs` needs to differentiate between these two array types when defining structs. By default, `ffi-rs` assumes dynamic arrays for struct calculations. To explicitly define a static (fixed-size) array within a struct, use the `arrayConstructor` with the `ffiTypeTag` set to `DataType.StackArray`. **Example for Static Array:** ```c typedef struct Person { //... uint8_t staticBytes[16]; //... } Person; ``` **TypeScript Definition:** ```typescript // Assuming 'parent' is the context for the struct definition staticBytes: arrayConstructor({ type: DataType.U8Array, length: parent.staticBytes.length, ffiTypeTag: FFITypeTag.StackArray }), ``` ``` -------------------------------- ### Library Lifecycle Management Source: https://github.com/zhangyuang/node-ffi-rs/blob/master/CLAUDE.md The standard pattern for loading a dynamic library, executing functions, and releasing resources. ```typescript import { open, load, close, DataType } from "ffi-rs"; // 1. Register library with a key name open({ library: "mylib", path: "./libmylib.dylib" }); // Pass path="" to open main program handle (access libc functions like atoi) // 2. Call functions const result = load({ library: "mylib", funcName: "my_func", retType: DataType.I32, paramsType: [DataType.I32, DataType.String], paramsValue: [42, "hello"], }); // 3. Release close("mylib"); ``` -------------------------------- ### Create and Pass Pointers Source: https://github.com/zhangyuang/node-ffi-rs/blob/master/README.md Use createPointer to generate pointers for passing data to C functions. ```javascript extern "C" void receiveNumPointer(const int * num) // use the rust type expression the pointer type is *const i32 const pointer: JsExternal[] = createPointer({ paramsType: [DataType.I32], paramsValue: [100], }) load({ library: "libsum", funcName: "receiveNumPointer", paramsType: [DataType.External], paramsValue: pointer, retType: DataType.Void, }) ``` -------------------------------- ### Compile C++ to Dynamic Library Source: https://github.com/zhangyuang/node-ffi-rs/blob/master/README.md Compile C++ code into a dynamic library. Use -dynamiclib for macOS, -shared for Linux, and -shared for Windows DLLs. ```bash g++ -dynamiclib -o libsum.so cpp/sum.cpp # macOS ``` ```bash g++ -shared -o libsum.so cpp/sum.cpp # Linux ``` ```bash g++ -shared -o sum.dll cpp/sum.cpp # Windows ``` -------------------------------- ### Invoke C Function from JavaScript Source: https://github.com/zhangyuang/node-ffi-rs/blob/master/README.md Demonstrates passing a JavaScript function to C, including manual memory management for the function pointer. ```javascript const testFunction = () => { const func = (a, b, c, d, e, f, g) => { equal(a, 100); equal(b, false); equal(c, "Hello, World!"); equal(d, "100.11"); deepStrictEqual(e, ["Hello", "world"]); deepStrictEqual(f, [101, 202, 303]); deepStrictEqual(g, person); logGreen("test function succeed"); // free function memory when it is not in use freePointer({ 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: funcExternal }) if (!process.env.MEMORY) { close("libsum"); } }; // suggest using createPointer to create a function pointer for manual memory management 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({ library: "libsum", funcName: "callFunction", retType: DataType.Void, paramsType: [ DataType.External, ], paramsValue: unwrapPointer(funcExternal), }); } ``` -------------------------------- ### JavaScript Class Instance Management Source: https://github.com/zhangyuang/node-ffi-rs/blob/master/README_Zh.md Shows how to call C++ functions to create, use, and free class instances from JavaScript using node-ffi-rs. `DataType.External` is used for class pointers, and `freePointer` with `PointerType.CPointer` is used for manual memory deallocation. ```javascript const classPointer = load({ library: "libsum", funcName: "createMyClassFromC", retType: DataType.External, paramsType: [ DataType.String, DataType.I32 ], paramsValue: ["classString", 26], }); load({ library: "libsum", funcName: "printMyClass", retType: DataType.External, paramsType: [ DataType.External, ], paramsValue: [classPointer], }) freePointer({ paramsType: [DataType.External], paramsValue: [classPointer], pointerType: PointerType.CPointer }) ``` -------------------------------- ### JavaScript Usage of C++ Function Pointer Source: https://github.com/zhangyuang/node-ffi-rs/blob/master/README_Zh.md Demonstrates how to use node-ffi-rs to pass a JavaScript function as a callback to a C++ function. Manual memory management for the pointer is recommended using `createPointer` and `freePointer`. ```javascript const testFunction = () => { const func = (a, b, c, d, e, f, g) => { equal(a, 100); equal(b, false); equal(c, "Hello, World!"); equal(d, "100.11"); deepStrictEqual(e, ["Hello", "world"]); deepStrictEqual(f, [101, 202, 303]); deepStrictEqual(g, person); logGreen("test function succeed"); // 当不再使用时释放函数内存 freePointer({ 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: funcExternal }) if (!process.env.MEMORY) { close("libsum"); } }; // 建议使用createPointer创建函数指针以进行手动内存管理 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({ library: "libsum", funcName: "callFunction", retType: DataType.Void, paramsType: [ DataType.External, ], paramsValue: unwrapPointer(funcExternal), }); } ``` -------------------------------- ### Run FFI Tasks in a New Thread Source: https://github.com/zhangyuang/node-ffi-rs/blob/master/README.md Utilize the `runInNewThread: true` option in the load method to execute FFI tasks asynchronously without blocking the main thread. This is beneficial for CPU-intensive operations. ```javascript const testRunInNewThread = async () => { // will return a promise but the task will run in a new thread load({ library: "libsum", funcName: "sum", retType: DataType.I32, paramsType: [DataType.I32, DataType.I32], paramsValue: [1, 2], runInNewThread: true, }).then(res => { equal(res, 3) }) } ``` -------------------------------- ### Create and Manage Native Pointers Source: https://context7.com/zhangyuang/node-ffi-rs/llms.txt Allocates memory for various data types and cleans up using freePointer. Use these functions when C interfaces require manual pointer management. ```javascript const { createPointer, restorePointer, freePointer, DataType, PointerType } = require('ffi-rs'); // Create a pointer to an integer const i32Ptr = createPointer({ paramsType: [DataType.I32], paramsValue: [100] }); // Restore the value from the pointer const value = restorePointer({ retType: [DataType.I32], paramsValue: i32Ptr }); console.log(value[0]); // 100 // Free the pointer when done freePointer({ paramsType: [DataType.I32], paramsValue: i32Ptr, pointerType: PointerType.RsPointer }); // Create a pointer to a string const stringPtr = createPointer({ paramsType: [DataType.String], paramsValue: ['Hello, World!'] }); const strValue = restorePointer({ retType: [DataType.String], paramsValue: stringPtr }); console.log(strValue[0]); // "Hello, World!" freePointer({ paramsType: [DataType.String], paramsValue: stringPtr, pointerType: PointerType.RsPointer }); // Create a pointer to an array const arrayPtr = createPointer({ paramsType: [DataType.DoubleArray], paramsValue: [[1.1, 2.2, 3.3]] }); const arrayValue = restorePointer({ retType: [arrayConstructor({ type: DataType.DoubleArray, length: 3 })], paramsValue: arrayPtr }); console.log(arrayValue[0]); // [1.1, 2.2, 3.3] ``` -------------------------------- ### C++ Class Creation and Usage Source: https://github.com/zhangyuang/node-ffi-rs/blob/master/README_Zh.md Defines C++ functions to create and print class instances, demonstrating how to wrap C++ types for use with node-ffi-rs. `DataType.External` is used to handle class pointers. ```cpp MyClass *createMyClass(std::string name, int age) { return new MyClass(name, age); } extern "C" MyClass *createMyClassFromC(const char *name, int age) { return createMyClass(std::string(name), age); } extern "C" void printMyClass(MyClass *instance) { instance->print(); } ``` -------------------------------- ### Define Multiple Function Signatures with ffi-rs Source: https://context7.com/zhangyuang/node-ffi-rs/llms.txt Use the `define` function to create reusable bindings for multiple foreign functions at once. This reduces boilerplate for repeated calls. ```javascript const { define, open, DataType } = require('ffi-rs'); open({ library: 'libsum', path: './libsum.so' }); open({ library: 'libnative', path: '' }); // Define multiple function signatures const ffi = define({ sum: { library: 'libsum', retType: DataType.I32, paramsType: [DataType.I32, DataType.I32] }, doubleSum: { library: 'libsum', retType: DataType.Double, paramsType: [DataType.Double, DataType.Double] }, atoi: { library: 'libnative', retType: DataType.I32, paramsType: [DataType.String] } }); // Call the defined functions console.log(ffi.sum([1, 2])); // 3 console.log(ffi.doubleSum([1.1, 2.2])); // 3.3 console.log(ffi.atoi(['42'])); // 42 ``` -------------------------------- ### Pointer Management API Source: https://github.com/zhangyuang/node-ffi-rs/blob/master/CLAUDE.md Functions for managing memory allocation, dereferencing, and lifecycle of pointers in the FFI context. ```APIDOC ## Pointer Management API ### Description Provides utilities to handle memory pointers, including allocation, wrapping/unwrapping, and manual memory freeing. ### Methods - **createPointer({ paramsType, paramsValue })**: Allocates memory and returns JsExternal array. - **unwrapPointer(externals)**: Dereferences one level (pointer-to-pointer to pointer). - **wrapPointer(externals)**: Adds one level of indirection. - **restorePointer({ retType, paramsValue })**: Reads a value back to JavaScript. - **freePointer({ paramsType, paramsValue, pointerType })**: Frees allocated memory. - **isNullPointer(external)**: Performs a null check on the pointer. ``` -------------------------------- ### Enabling and Handling Errno in Node-FFI-RS Source: https://github.com/zhangyuang/node-ffi-rs/blob/master/README_Zh.md Demonstrates how to enable `errno` reporting when calling C functions by setting `errno: true` in the `load` options. The returned object includes `errnoCode`, `errnoMessage`, and the function's return value. ```javascript load({ library: 'libnative', funcName: 'setsockopt', retType: DataType.I32, paramsType: [DataType.I32, DataType.I32, DataType.I32, DataType.External, DataType.I32], paramsValue: [socket._handle.fd, level, option, pointer[0], 4], errno: true // 将errno设置为true }) // 上面的代码将返回一个包含三个字段的对象,包括errnoCode、errnoMessage和外部函数返回值 // { errnoCode: 22, errnoMessage: 'Invalid argument (os error 22)', value: -1 } ``` -------------------------------- ### Configuring Static Arrays in Node-FFI-RS Source: https://github.com/zhangyuang/node-ffi-rs/blob/master/README.md Configuration for defining static arrays within structs in Node-FFI-RS. This ensures correct memory layout and alignment for fixed-size arrays. ```javascript staticBytes: arrayConstructor({ type: DataType.U8Array, length: parent.staticBytes.length, ffiTypeTag: FFITypeTag.StackArray }), ``` -------------------------------- ### define - Define Multiple Function Signatures Source: https://context7.com/zhangyuang/node-ffi-rs/llms.txt Creates reusable function bindings for multiple foreign functions at once to reduce boilerplate. ```APIDOC ## define ### Description Creates reusable function bindings for multiple foreign functions at once. It returns an object with methods that can be called directly with parameter arrays. ### Request Body - **definitions** (Object) - Required - An object where keys are function names and values are objects containing library, retType, and paramsType. ``` -------------------------------- ### close - Close a Dynamic Library Source: https://context7.com/zhangyuang/node-ffi-rs/llms.txt Releases a previously opened dynamic library from memory to free system resources. ```APIDOC ## close ### Description Releases a previously opened dynamic library from memory. Call this when you no longer need to invoke functions from the library. ### Parameters - **library** (string) - Required - The unique identifier of the library to close. ``` -------------------------------- ### Define and Use JavaScript Callbacks in C Source: https://context7.com/zhangyuang/node-ffi-rs/llms.txt Use `funcConstructor` to define a callback function signature that can be passed from JavaScript to C. Ensure the callback is created with `createPointer` and freed with `freePointer` when no longer needed. ```javascript const { load, open, createPointer, unwrapPointer, freePointer, funcConstructor, arrayConstructor, DataType, PointerType } = require('ffi-rs'); open({ library: 'libsum', path: './libsum.so' }); // Define the callback function signature const callbackType = funcConstructor({ paramsType: [ DataType.I32, DataType.Boolean, DataType.String, DataType.Double, arrayConstructor({ type: DataType.StringArray, length: 2 }), arrayConstructor({ type: DataType.I32Array, length: 3 }) ], retType: DataType.I32 }); // Create the JavaScript callback const callback = (num, bool, str, dbl, strArr, intArr) => { console.log('Called from C with:', { num, bool, str, dbl, strArr, intArr }); // num: 100, bool: false, str: "Hello, World!" // dbl: "100.11", strArr: ["Hello", "world"], intArr: [101, 202, 303] return 42; // Return value to C }; // Create a pointer to the callback const funcPtr = createPointer({ paramsType: [callbackType], paramsValue: [callback] }); // Call C function that will invoke our callback load({ library: 'libsum', funcName: 'callFunction', retType: DataType.Void, paramsType: [DataType.External], paramsValue: unwrapPointer(funcPtr), runInNewThread: true // Required to get return value in C }); // Free the function pointer when no longer needed // (typically after the C function completes) setTimeout(() => { freePointer({ paramsType: [callbackType], paramsValue: funcPtr, pointerType: PointerType.RsPointer }); }, 1000); ``` -------------------------------- ### Define C Array Functions Source: https://github.com/zhangyuang/node-ffi-rs/blob/master/README.md C functions for creating arrays of integers, doubles, and strings to be used with FFI. ```cpp extern "C" int *createArrayi32(const int *arr, int size) { int *vec = (int *)malloc((size) * sizeof(int)); for (int i = 0; i < size; i++) { vec[i] = arr[i]; } return vec; } extern "C" double *createArrayDouble(const double *arr, int size) { double *vec = (double *)malloc((size) * sizeof(double)); for (int i = 0; i < size; i++) { vec[i] = arr[i]; } return vec; } extern "C" char **createArrayString(char **arr, int size) { char **vec = (char **)malloc((size) * sizeof(char *)); for (int i = 0; i < size; i++) { vec[i] = arr[i]; } return vec; } ``` -------------------------------- ### Close a Dynamic Library with ffi-rs Source: https://context7.com/zhangyuang/node-ffi-rs/llms.txt Use the `close` function to release a previously opened dynamic library from memory, freeing system resources. This should be called when the library is no longer needed. ```javascript const { open, close } = require('ffi-rs'); open({ library: 'libsum', path: './libsum.so' }); // Use the library... // Release the library when done close('libsum'); ``` -------------------------------- ### DataType Reference Source: https://context7.com/zhangyuang/node-ffi-rs/llms.txt Supported data types for parameter and return value definitions in ffi-rs. ```javascript const { DataType } = require('ffi-rs'); // Primitive types DataType.String // char* (UTF-8 string) DataType.WString // wchar_t* (wide string) DataType.I16 // int16_t (16-bit signed integer) DataType.I32 // int32_t (32-bit signed integer) DataType.I64 // int64_t (64-bit signed integer) DataType.U8 // uint8_t (8-bit unsigned integer / char) DataType.U32 // uint32_t (32-bit unsigned integer) DataType.U64 // uint64_t (64-bit unsigned integer) DataType.BigInt // Mapped to i64, returns JavaScript BigInt DataType.Float // float (32-bit, params only) DataType.Double // double (64-bit floating point) DataType.Boolean // bool DataType.Void // void (returns undefined) // Array types (use with arrayConstructor) DataType.U8Array // uint8_t[] / Buffer DataType.I16Array // int16_t[] DataType.I32Array // int32_t[] DataType.StringArray // char*[] DataType.DoubleArray // double[] DataType.FloatArray // float[] (params only) DataType.StructArray // Array of structs // Pointer type DataType.External // void* (native pointer) // Struct markers (for struct definitions) DataType.StackStruct // Embedded struct (not pointer) DataType.StackArray // Fixed-size array in struct ``` -------------------------------- ### Call a Foreign Function with ffi-rs Source: https://context7.com/zhangyuang/node-ffi-rs/llms.txt Use the `load` function to invoke a function from a loaded dynamic library. Specify the function name, return type, parameter types, and values. Automatic type conversion is handled. ```javascript const { load, open, DataType } = require('ffi-rs'); open({ library: 'libsum', path: './libsum.so' }); // Call a function that adds two integers const result = load({ library: 'libsum', funcName: 'sum', retType: DataType.I32, paramsType: [DataType.I32, DataType.I32], paramsValue: [10, 20] }); console.log(result); // 30 // Call a function that concatenates strings const greeting = load({ library: 'libsum', funcName: 'concatenateStrings', retType: DataType.String, paramsType: [DataType.String, DataType.String], paramsValue: ['Hello, ', 'World!'] }); console.log(greeting); // "Hello, World!" // Call a function with double precision floating point const sum = load({ library: 'libsum', funcName: 'doubleSum', retType: DataType.Double, paramsType: [DataType.Double, DataType.Double], paramsValue: [1.5, 2.5] }); console.log(sum); // 4.0 // Call a void function (returns undefined) const voidResult = load({ library: 'libsum', funcName: 'noRet', retType: DataType.Void, paramsType: [], paramsValue: [] }); console.log(voidResult); // undefined // Call standard C library function (atoi) open({ library: 'libnative', path: '' }); const num = load({ library: 'libnative', funcName: 'atoi', retType: DataType.I32, paramsType: [DataType.String], paramsValue: ['1000'] }); console.log(num); // 1000 ``` -------------------------------- ### funcConstructor - Pass JavaScript Functions to C Source: https://context7.com/zhangyuang/node-ffi-rs/llms.txt Creates a function type descriptor to pass JavaScript callbacks to C functions, enabling event-driven patterns. ```APIDOC ## funcConstructor ### Description Creates a function type descriptor for passing JavaScript callbacks to C functions. ### Parameters #### Request Body - **paramsType** (Array) - Required - Array of DataType definitions for callback arguments. - **retType** (DataType) - Required - The return type of the callback function. ``` -------------------------------- ### Pointer Management API Source: https://github.com/zhangyuang/node-ffi-rs/blob/master/CLAUDE.md Utility functions for memory allocation, dereferencing, and pointer lifecycle management. ```ts createPointer({ paramsType, paramsValue }) // Allocate, returns JsExternal[] unwrapPointer(externals) // Dereference one level (pointer-to-pointer -> pointer) wrapPointer(externals) // Add one level of indirection restorePointer({ retType, paramsValue }) // Read value back to JS freePointer({ paramsType, paramsValue, pointerType }) // Free memory isNullPointer(external) // Null check ``` -------------------------------- ### Wrap Foreign Function Pointers Source: https://github.com/zhangyuang/node-ffi-rs/blob/master/README.md Use wrapPointer to convert foreign function return values into a format compatible with restorePointer. ```javascript extern "C" const char * returnStringPointer() { char * str = new char[6]; strcpy(str, "hello"); return str; } // the stringPointer type is *const char, we need to convert it to *mut *const char before call restorePointer const stringPointer = load({ library: "libsum", funcName: "returnStringPointer", retType: DataType.External, paramsType: [DataType.String], paramsValue: ["hello"], }) const wrapStringPointer = wrapPointer([stringPointer]) const str = restorePointer({ retType: [DataType.String], paramsValue: wrapStringPointer, }) equal(str, "hello") ``` -------------------------------- ### Callback Function Pointer Pattern Source: https://github.com/zhangyuang/node-ffi-rs/blob/master/CLAUDE.md Passing a JavaScript function to C as a callback requires creating a pointer and ensuring the execution context is handled correctly. ```typescript import { funcConstructor, arrayConstructor, createPointer, unwrapPointer, freePointer, PointerType } from "ffi-rs"; // 1. Describe callback signature with funcConstructor const cbDesc = funcConstructor({ paramsType: [DataType.I32, DataType.String], retType: DataType.Void, }); // 2. Create function pointer from JS function const cbExternal = createPointer({ paramsType: [cbDesc], paramsValue: [(a, b) => { console.log(a, b); }], }); // 3. Pass to C as DataType.External, unwrap one level of indirection load({ library: "mylib", funcName: "register_callback", retType: DataType.Void, paramsType: [DataType.External], paramsValue: unwrapPointer(cbExternal), runInNewThread: true, // IMPORTANT: required for callbacks to work properly }); // 4. Free when done freePointer({ paramsType: [cbDesc], paramsValue: cbExternal, pointerType: PointerType.RsPointer }); ``` -------------------------------- ### Load Array Types in Node.js Source: https://github.com/zhangyuang/node-ffi-rs/blob/master/README.md Use arrayConstructor to specify array types and lengths when loading foreign functions. ```javascript let bigArr = new Array(100).fill(100) deepStrictEqual(bigArr, load({ library: 'libsum', funcName: 'createArrayi32', retType: arrayConstructor({ type: DataType.I32Array, length: bigArr.length }), paramsType: [DataType.I32Array, DataType.I32], paramsValue: [bigArr, bigArr.length], })) let bigDoubleArr = new Array(5).fill(1.1) deepStrictEqual(bigDoubleArr, load({ library: 'libsum', funcName: 'createArrayDouble', retType: arrayConstructor({ type: DataType.DoubleArray, length: bigDoubleArr.length }), paramsType: [DataType.DoubleArray, DataType.I32], paramsValue: [bigDoubleArr, bigDoubleArr.length], })) let stringArr = [c, c.repeat(20)] deepStrictEqual(stringArr, load({ library: 'libsum', funcName: 'createArrayString', retType: arrayConstructor({ type: DataType.StringArray, length: stringArr.length }), paramsType: [DataType.StringArray, DataType.I32], paramsValue: [stringArr, stringArr.length], })) ``` -------------------------------- ### Buffer Manipulation with ffi-rs Source: https://github.com/zhangyuang/node-ffi-rs/blob/master/README.md Use `ffi-rs` to modify buffer data in place. Create a buffer using `Buffer.alloc` and pass it as `DataType.U8Array` to the C function. ```c extern int modifyData(char* buffer) { // modify buffer data in place } ``` ```javascript const arr = Buffer.alloc(200) // create buffer const res = load({ library: "libsum", funcName: "modifyData", retType: DataType.I32, paramsType: [ DataType.U8Array ], paramsValue: [arr] }) console.log(arr) // buffer data can be updated ``` -------------------------------- ### load - Async FFI Calls Source: https://context7.com/zhangyuang/node-ffi-rs/llms.txt Executes FFI calls in a separate thread using the runInNewThread option, returning a Promise to avoid blocking the event loop. ```APIDOC ## load ### Description Loads and executes a function from a native library. Supports synchronous and asynchronous execution. ### Parameters #### Request Body - **library** (String) - Required - Name of the loaded library. - **funcName** (String) - Required - Name of the function to call. - **retType** (DataType) - Required - Return type of the function. - **paramsType** (Array) - Required - Array of parameter types. - **paramsValue** (Array) - Required - Array of parameter values. - **runInNewThread** (Boolean) - Optional - If true, executes in a separate thread and returns a Promise. ``` -------------------------------- ### Restore Pointer Values Source: https://github.com/zhangyuang/node-ffi-rs/blob/master/README.md Use restorePointer to retrieve the original value from a pointer created by createPointer. ```javascript const pointer: JsExternal[] = createPointer({ paramsType: [DataType.String], paramsValue: ["hello"], }) const str = restorePointer({ retType: [DataType.String], paramsValue: pointer, }) equal(str, "hello") ``` -------------------------------- ### load - Call a Foreign Function Source: https://context7.com/zhangyuang/node-ffi-rs/llms.txt Invokes a function from a loaded dynamic library with automatic type conversion. ```APIDOC ## load ### Description Invokes a function from a loaded dynamic library. It handles automatic type conversion between JavaScript and native types. ### Request Body - **library** (string) - Required - The unique identifier of the library - **funcName** (string) - Required - The name of the function to call - **retType** (DataType) - Required - The return type of the function - **paramsType** (Array<DataType>) - Required - An array of parameter types - **paramsValue** (Array<any>) - Required - An array of parameter values ### Response - **result** (any) - The return value of the foreign function. ``` -------------------------------- ### Handle C++ Class Instances Source: https://context7.com/zhangyuang/node-ffi-rs/llms.txt Use DataType.External to pass class pointers between JavaScript and C++. Ensure C++ code exposes extern "C" wrapper functions for lifecycle management. ```javascript const { load, open, freePointer, DataType, PointerType } = require('ffi-rs'); open({ library: 'libsum', path: './libsum.so' }); // Create a C++ class instance (returns pointer) const classPointer = load({ library: 'libsum', funcName: 'createMyClassFromC', retType: DataType.External, paramsType: [DataType.String, DataType.I32], paramsValue: ['MyClassName', 42] }); // Call a method on the class instance load({ library: 'libsum', funcName: 'printMyClass', retType: DataType.Void, paramsType: [DataType.External], paramsValue: [classPointer] }); // Output: "Name: MyClassName, Age: 42" // Free the class instance (call C++ destructor) load({ library: 'libsum', funcName: 'freeClass', retType: DataType.Void, paramsType: [DataType.External], paramsValue: [classPointer] }); ``` -------------------------------- ### Manipulate Pointer Levels Source: https://context7.com/zhangyuang/node-ffi-rs/llms.txt Uses unwrapPointer to extract inner pointers for C functions and wrapPointer to prepare pointers for restoration or double-pointer parameters. ```javascript const { load, open, createPointer, unwrapPointer, wrapPointer, restorePointer, DataType } = require('ffi-rs'); open({ library: 'libsum', path: './libsum.so' }); // Create a string pointer (which is actually a double pointer: *mut *const char) const stringPtr = createPointer({ paramsType: [DataType.String], paramsValue: ['foo'] }); // Use unwrapPointer to get the inner pointer (*const char) for C functions const result = load({ library: 'libsum', funcName: 'getStringFromPtr', retType: DataType.String, paramsType: [DataType.External], paramsValue: unwrapPointer(stringPtr) // Unwrap to pass inner pointer }); console.log(result); // "foo" // When receiving a pointer from C, use wrapPointer before restoring const cPtr = load({ library: 'libsum', funcName: 'concatenateStrings', retType: DataType.External, // Returns *const char paramsType: [DataType.String, DataType.String], paramsValue: ['Hello, ', 'World!'] }); // Wrap the C pointer to convert it to double pointer format for restorePointer const wrappedPtr = wrapPointer([cPtr]); const str = restorePointer({ retType: [DataType.String], paramsValue: wrappedPtr }); console.log(str[0]); // "Hello, World!" // Use wrapPointer to create a pointer to a pointer for double pointer params const i32Ptr = createPointer({ paramsType: [DataType.I32], paramsValue: [100] }); const doublePtr = wrapPointer(i32Ptr); const valueFromDoublePtr = load({ library: 'libsum', funcName: 'getValueFromDoublePointer', retType: DataType.I32, paramsType: [DataType.External], paramsValue: doublePtr }); console.log(valueFromDoublePtr); // 100 ``` -------------------------------- ### Freeing Pointers in Node-FFI-RS Source: https://github.com/zhangyuang/node-ffi-rs/blob/master/README.md Use `freePointer` to release memory allocated for pointers. Ensure the correct pointer type (e.g., RsPointer, CPointer) is specified for proper deallocation. ```javascript const i32Ptr = createPointer({ paramsType: [DataType.I32], paramsValue: [100] }) const i32Data = restorePointer({ paramsValue: i32Ptr, retType: [DataType.I32], }) freePointer({ paramsType: [DataType.I32], paramsValue: i32Ptr, pointerType: PointerType.RsPointer }) ``` ```javascript const stringPointer = load({ library: "libsum", funcName: "returnStringPointer", retType: DataType.External, paramsType: [DataType.String], paramsValue: ["hello"], }) freePointer({ paramsType: [DataType.External], paramsValue: [stringPointer], pointerType: PointerType.CPointer // will use libc::free to free the memory }) ```