node-ctypes 1.1.0 → 1.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -221,15 +221,15 @@ console.log(u.f); // 42 reinterpreted as float
221
221
  ### Bit Fields - Compact Data Structures
222
222
 
223
223
  ```javascript
224
- import { Structure, bitfield, c_uint32 } from 'node-ctypes';
224
+ import { Structure, c_uint32 } from 'node-ctypes';
225
225
 
226
- // Bit fields for flags and compact data
226
+ // Bit fields using Python-style syntax: [name, type, bits]
227
227
  class Flags extends Structure {
228
228
  static _fields_ = [
229
- ["enabled", bitfield(c_uint32, 1)], // 1 bit
230
- ["mode", bitfield(c_uint32, 3)], // 3 bits
231
- ["priority", bitfield(c_uint32, 4)], // 4 bits
232
- ["reserved", bitfield(c_uint32, 24)] // 24 bits
229
+ ["enabled", c_uint32, 1], // 1 bit
230
+ ["mode", c_uint32, 3], // 3 bits
231
+ ["priority", c_uint32, 4], // 4 bits
232
+ ["reserved", c_uint32, 24] // 24 bits
233
233
  ];
234
234
  }
235
235
 
@@ -244,6 +244,19 @@ console.log(flags.mode); // 5
244
244
  console.log(flags.priority); // 12
245
245
  ```
246
246
 
247
+ **Alternative syntax with `bitfield()` helper:**
248
+
249
+ ```javascript
250
+ import { Structure, bitfield, c_uint32 } from 'node-ctypes';
251
+
252
+ class Flags extends Structure {
253
+ static _fields_ = [
254
+ ["enabled", bitfield(c_uint32, 1)],
255
+ ["mode", bitfield(c_uint32, 3)],
256
+ ];
257
+ }
258
+ ```
259
+
247
260
  ### Arrays - Fixed-size and Dynamic
248
261
 
249
262
  ```javascript
@@ -508,9 +521,33 @@ Benchmarked on Windows with Node.js v24.11.0:
508
521
  **Key Insights:**
509
522
  - koffi excels at simple operations and struct access
510
523
  - node-ctypes competitive on complex argument handling
511
- - **Struct performance gap**: koffi 15x faster due to direct object manipulation
524
+ - **Struct performance gap**: koffi ~13x faster due to plain object vs Proxy+N-API
525
+ - **Workaround**: Use `toObject()` for repeated struct reads (see below)
512
526
  - **Callback overhead**: koffi 1.5x faster at callback creation
513
527
 
528
+ ### Struct Performance Tip
529
+
530
+ When reading struct fields repeatedly (e.g., in a tight loop), use `toObject()` to convert to a plain JavaScript object:
531
+
532
+ ```javascript
533
+ const point = Point.create({ x: 10, y: 20 });
534
+
535
+ // ❌ Slow: Each access goes through Proxy → N-API → buffer read
536
+ for (let i = 0; i < 1000000; i++) {
537
+ const x = point.x; // ~80ns per access
538
+ }
539
+
540
+ // ✅ Fast: Convert once, then use plain object access
541
+ const obj = point.toObject(); // { x: 10, y: 20 }
542
+ for (let i = 0; i < 1000000; i++) {
543
+ const x = obj.x; // ~6ns per access (same as koffi!)
544
+ }
545
+ ```
546
+
547
+ **When to use direct access vs toObject():**
548
+ - **Direct access (`point.x`)**: Always synchronized with underlying buffer; required when C code modifies the buffer
549
+ - **`toObject()`**: Snapshot copy; use for read-only loops or when passing data to JS-only code
550
+
514
551
  **Transparent API overhead**: Only **3.5%** for auto `._buffer` extraction!
515
552
 
516
553
  *See `tests/benchmarks/` for full benchmark suite.*
@@ -623,7 +660,8 @@ puts(s);
623
660
 
624
661
  **Types and helpers**
625
662
  - `sizeof(type)` → `number` : size in bytes of a type.
626
- - `POINTER(baseType)` : creates a pointer type with helpers `create()`, `fromBuffer()`, `deref()`, `set()`.
663
+ - `POINTER(baseType)` : creates a pointer type factory (see [POINTER and pointer() API](#pointer-and-pointer-api) below).
664
+ - `pointer(obj)` : creates a pointer to an existing ctypes instance (Python-compatible).
627
665
  - `byref(buffer)` : passes a buffer by reference (Python ctypes compatibility).
628
666
  - `cast(ptr, targetType)` : interprets a pointer as another type (returns wrapper for struct).
629
667
 
@@ -700,6 +738,82 @@ Write a value to memory.
700
738
  #### `sizeof(type)` → `number`
701
739
  Get the size of a type in bytes.
702
740
 
741
+ #### POINTER and pointer() API
742
+
743
+ `node-ctypes` provides a Python ctypes-compatible pointer API:
744
+
745
+ ```javascript
746
+ import { POINTER, pointer, c_int32, Structure } from 'node-ctypes';
747
+
748
+ // Create a pointer type
749
+ const IntPtr = POINTER(c_int32);
750
+
751
+ // Create NULL pointer
752
+ const p1 = IntPtr.create();
753
+ console.log(p1.isNull); // true
754
+
755
+ // Create pointer from buffer
756
+ const buf = Buffer.alloc(12);
757
+ buf.writeInt32LE(10, 0);
758
+ buf.writeInt32LE(20, 4);
759
+ buf.writeInt32LE(30, 8);
760
+
761
+ const p2 = IntPtr.fromBuffer(buf);
762
+
763
+ // .contents property (Python-compatible)
764
+ console.log(p2.contents); // 10
765
+ p2.contents = 100;
766
+ console.log(buf.readInt32LE(0)); // 100
767
+
768
+ // Pointer indexing (Python-compatible)
769
+ console.log(p2[0]); // 100
770
+ console.log(p2[1]); // 20
771
+ console.log(p2[2]); // 30
772
+
773
+ p2[1] = 200;
774
+ console.log(buf.readInt32LE(4)); // 200
775
+
776
+ // pointer() function - create pointer to existing object
777
+ const x = new c_int32(42);
778
+ const px = pointer(x);
779
+ console.log(px.contents); // 42
780
+ px.contents = 100;
781
+ console.log(x.value); // 100
782
+
783
+ // Works with structures too
784
+ class Point extends Structure {
785
+ static _fields_ = [["x", c_int32], ["y", c_int32]];
786
+ }
787
+ const pt = new Point({ x: 10, y: 20 });
788
+ const ppt = pointer(pt);
789
+ ```
790
+
791
+ **POINTER type methods:**
792
+ - `POINTER(baseType)` - creates a pointer type factory
793
+ - `PointerType.create()` - creates a NULL pointer instance
794
+ - `PointerType.fromBuffer(buf)` - creates pointer to buffer
795
+ - `PointerType.fromAddress(addr)` - creates pointer from address
796
+
797
+ **Pointer instance properties:**
798
+ - `.contents` - get/set dereferenced value (Python-compatible)
799
+ - `.address` - get raw address as BigInt
800
+ - `.isNull` - check if pointer is NULL
801
+ - `[n]` - array-style indexing with pointer arithmetic
802
+ - `.deref()` - alias for `.contents` getter
803
+ - `.set(value)` - update pointer target
804
+
805
+ **Using POINTER in function definitions:**
806
+ ```javascript
807
+ // POINTER types can be used as argtypes and restype
808
+ const IntPtr = POINTER(c_int32);
809
+
810
+ // As argument type
811
+ const memset = msvcrt.func("memset", c_void_p, [IntPtr, c_int32, c_size_t]);
812
+
813
+ // As return type
814
+ const memchr = msvcrt.func("memchr", IntPtr, [c_void_p, c_int32, c_size_t]);
815
+ ```
816
+
703
817
  #### `struct(fields)` → `StructDefinition`
704
818
  Create a simple struct definition.
705
819
 
@@ -720,10 +834,11 @@ Base class for Python-like union definitions. Subclasses should define `static _
720
834
  | **Structs** | `class Point(Structure):`<br>&nbsp;&nbsp;`_fields_ = [("x", c_int)]` | `class Point extends Structure`<br>&nbsp;&nbsp;`{ static _fields_ = [["x", c_int]] }` |
721
835
  | **Unions** | `class U(Union):`<br>&nbsp;&nbsp;`_fields_ = [("i", c_int)]` | `class U extends Union`<br>&nbsp;&nbsp;`{ static _fields_ = [["i", c_int]] }` |
722
836
  | **Arrays** | `c_int * 5` | `array(c_int, 5)` |
723
- | **Bit fields** | `("flags", c_uint, 3)` | `bitfield(c_uint32, 3)` |
837
+ | **Bit fields** | `("flags", c_uint, 3)` | `["flags", c_uint32, 3]`<br>**or** `bitfield(c_uint32, 3)` |
724
838
  | **Callbacks** | `CFUNCTYPE(c_int, c_int)` | `callback(fn, c_int, [c_int])` |
725
839
  | **Strings** | `c_char_p(b"hello")` | `create_string_buffer("hello")`<br>**or**<br>`new c_char_p(b"hello")` |
726
- | **Pointers** | `POINTER(c_int)` | `c_void_p` |
840
+ | **Pointers** | `POINTER(c_int)`<br>`p.contents`<br>`p[0]` | `POINTER(c_int)`<br>`p.contents`<br>`p[0]` |
841
+ | **pointer()** | `pointer(obj)` | `pointer(obj)` |
727
842
  | **Variadic** | `sprintf(buf, b"%d", 42)` | `sprintf(buf, fmt, 42)` (auto) |
728
843
  | **Sizeof** | `sizeof(c_int)` | `sizeof(c_int)` |
729
844
 
Binary file
Binary file
@@ -51,262 +51,263 @@
51
51
  * @private
52
52
  */
53
53
  export function createLibraryClasses(Library, LRUCache, _toNativeType, _toNativeTypes, native) {
54
- class FunctionWrapper {
55
- constructor(cdll, name) {
56
- const argtypes = [];
57
- let restype = undefined;
58
- let cachedFunc = null;
54
+ class FunctionWrapper {
55
+ constructor(cdll, name) {
56
+ const argtypes = [];
57
+ let restype = undefined;
58
+ let cachedFunc = null;
59
59
 
60
- // Create a function and proxy it to make it callable
61
- const func = (...args) => {
62
- if (restype === undefined) {
63
- throw new Error(`Function ${name}: restype not set`);
64
- }
65
- if (!cachedFunc) {
66
- cachedFunc = cdll.func(name, restype, argtypes);
67
- }
68
- return cachedFunc(...args);
69
- };
70
-
71
- // Proxy the function to intercept property access
72
- return new Proxy(func, {
73
- get(target, prop) {
74
- if (prop === "argtypes") return argtypes;
75
- if (prop === "restype") return restype;
76
- if (prop === "errcheck") return cachedFunc ? cachedFunc.errcheck : undefined;
77
- return target[prop];
78
- },
79
- set(target, prop, value) {
80
- if (prop === "argtypes") {
81
- argtypes.splice(0, argtypes.length, ...value);
82
- cachedFunc = null; // Invalidate cache
83
- return true;
60
+ // Create a function and proxy it to make it callable
61
+ const func = (...args) => {
62
+ if (restype === undefined) {
63
+ throw new Error(`Function ${name}: restype not set`);
84
64
  }
85
- if (prop === "restype") {
86
- restype = value;
87
- cachedFunc = null; // Invalidate cache
88
- return true;
65
+ if (!cachedFunc) {
66
+ cachedFunc = cdll.func(name, restype, argtypes);
89
67
  }
90
- if (prop === "errcheck") {
91
- if (!cachedFunc) {
92
- if (restype === undefined) {
93
- throw new Error(`Function ${name}: restype not set`);
68
+ return cachedFunc(...args);
69
+ };
70
+
71
+ // Proxy the function to intercept property access
72
+ return new Proxy(func, {
73
+ get(target, prop) {
74
+ if (prop === "argtypes") return argtypes;
75
+ if (prop === "restype") return restype;
76
+ if (prop === "errcheck") return cachedFunc ? cachedFunc.errcheck : undefined;
77
+ return target[prop];
78
+ },
79
+ set(target, prop, value) {
80
+ if (prop === "argtypes") {
81
+ argtypes.splice(0, argtypes.length, ...value);
82
+ cachedFunc = null; // Invalidate cache
83
+ return true;
84
+ }
85
+ if (prop === "restype") {
86
+ restype = value;
87
+ cachedFunc = null; // Invalidate cache
88
+ return true;
89
+ }
90
+ if (prop === "errcheck") {
91
+ if (!cachedFunc) {
92
+ if (restype === undefined) {
93
+ throw new Error(`Function ${name}: restype not set`);
94
+ }
95
+ cachedFunc = cdll.func(name, restype, argtypes);
94
96
  }
95
- cachedFunc = cdll.func(name, restype, argtypes);
97
+ cachedFunc.errcheck = value;
98
+ return true;
96
99
  }
97
- cachedFunc.errcheck = value;
100
+ target[prop] = value;
98
101
  return true;
99
- }
100
- target[prop] = value;
101
- return true;
102
- },
103
- });
104
- }
105
- }
106
-
107
- /**
108
- * Wrapper conveniente per CDLL (come in Python ctypes)
109
- */
110
- class CDLL {
111
- constructor(libPath, options = {}) {
112
- this._lib = new Library(libPath);
113
- // Use LRU cache to prevent unbounded memory growth
114
- const cacheSize = options.cacheSize ?? 1000;
115
- this._cache = new LRUCache(cacheSize);
116
-
117
- // Return a proxy to enable Python-like syntax: libc.abs.argtypes = [...]; libc.abs.restype = ...; libc.abs(...)
118
- return new Proxy(this, {
119
- get(target, prop, receiver) {
120
- // Allow access to existing properties/methods
121
- if (prop in target || typeof prop !== "string") {
122
- return Reflect.get(target, prop, receiver);
123
- }
124
- // Assume it's a function name from the library
125
- return new FunctionWrapper(target, prop);
126
- },
127
- });
102
+ },
103
+ });
104
+ }
128
105
  }
129
106
 
130
107
  /**
131
- * Ottiene una funzione dalla libreria
132
- * @param {string} name - Nome della funzione
133
- * @param {string|CType} returnType - Tipo di ritorno
134
- * @param {Array<string|CType>} argTypes - Tipi degli argomenti
135
- * @param {Object} [options] - Opzioni aggiuntive (es. { abi: 'stdcall' })
136
- * @returns {Function} Funzione callable
108
+ * Wrapper conveniente per CDLL (come in Python ctypes)
137
109
  */
138
- func(name, returnType, argTypes = [], options = {}) {
139
- const cacheKey = `${name}:${returnType}:${argTypes.join(",")}`;
110
+ class CDLL {
111
+ constructor(libPath, options = {}) {
112
+ this._lib = new Library(libPath);
113
+ // Use LRU cache to prevent unbounded memory growth
114
+ const cacheSize = options.cacheSize ?? 1000;
115
+ this._cache = new LRUCache(cacheSize);
116
+ // Cache for FunctionWrapper instances (Python-like syntax)
117
+ this._funcWrapperCache = new Map();
140
118
 
141
- if (this._cache.has(cacheKey)) {
142
- return this._cache.get(cacheKey);
119
+ // Return a proxy to enable Python-like syntax: libc.abs.argtypes = [...]; libc.abs.restype = ...; libc.abs(...)
120
+ return new Proxy(this, {
121
+ get(target, prop, receiver) {
122
+ // Allow access to existing properties/methods
123
+ if (prop in target || typeof prop !== "string") {
124
+ return Reflect.get(target, prop, receiver);
125
+ }
126
+ // Check if we already have a FunctionWrapper for this function name
127
+ if (target._funcWrapperCache.has(prop)) {
128
+ return target._funcWrapperCache.get(prop);
129
+ }
130
+ // Create and cache a new FunctionWrapper
131
+ const wrapper = new FunctionWrapper(target, prop);
132
+ target._funcWrapperCache.set(prop, wrapper);
133
+ return wrapper;
134
+ },
135
+ });
143
136
  }
144
137
 
145
- const ffiFunc = this._lib.func(name, _toNativeType(returnType, native), _toNativeTypes(argTypes, native), options);
138
+ /**
139
+ * Ottiene una funzione dalla libreria
140
+ * @param {string} name - Nome della funzione
141
+ * @param {Function|number|CType} returnType - Tipo di ritorno (SimpleCData class, CType value, o CType)
142
+ * @param {Array<Function|number|CType>} argTypes - Tipi degli argomenti
143
+ * @param {Object} [options] - Opzioni aggiuntive (es. { abi: 'stdcall' })
144
+ * @returns {Function} Funzione callable
145
+ */
146
+ func(name, returnType, argTypes = [], options = {}) {
147
+ const cacheKey = `${name}:${returnType}:${argTypes.join(",")}`;
148
+
149
+ if (this._cache.has(cacheKey)) {
150
+ return this._cache.get(cacheKey);
151
+ }
146
152
 
147
- // =========================================================================
148
- // OPTIMIZATION: Create specialized wrapper based on argument types
149
- // For primitive-only args, bypass the processing loop entirely
150
- // =========================================================================
153
+ const ffiFunc = this._lib.func(name, _toNativeType(returnType, native), _toNativeTypes(argTypes, native), options);
151
154
 
152
- const argCount = argTypes.length;
155
+ // =========================================================================
156
+ // OPTIMIZATION: Create specialized wrapper based on argument types
157
+ // For primitive-only args, bypass the processing loop entirely
158
+ // =========================================================================
153
159
 
154
- // Check if all args are primitive types (no structs/buffers that need _buffer extraction)
155
- const allPrimitive = argTypes.every((t) => {
156
- if (typeof t === "function" && t._isSimpleCData) {
157
- // SimpleCData types that are NOT pointers are primitive
158
- const typeName = t._type;
159
- return typeName !== "pointer" && typeName !== "char_p" && typeName !== "wchar_p";
160
- }
161
- if (typeof t === "string") {
162
- return t !== "pointer" && t !== "char_p" && t !== "wchar_p" && t !== "void_p";
163
- }
164
- // CType objects from native - check if it's a pointer type
165
- if (t && typeof t === "object" && t.name) {
166
- return !t.name.includes("pointer") && !t.name.includes("char_p");
167
- }
168
- return false;
169
- });
160
+ const argCount = argTypes.length;
170
161
 
171
- let callMethod;
162
+ // Check if all args are primitive types (no structs/buffers that need _buffer extraction)
163
+ const allPrimitive = argTypes.every((t) => {
164
+ if (typeof t === "function" && t._isSimpleCData) {
165
+ // SimpleCData types that are NOT pointers are primitive
166
+ const typeName = t._type;
167
+ return typeName !== native.CType.POINTER && typeName !== native.CType.STRING && typeName !== native.CType.WSTRING;
168
+ }
169
+ return false;
170
+ });
172
171
 
173
- if (argCount === 0) {
174
- // FAST PATH: No arguments - direct call
175
- callMethod = function () {
176
- return ffiFunc.call();
177
- };
178
- } else if (allPrimitive) {
179
- // FAST PATH: All primitive args - direct call without processing
180
- switch (argCount) {
181
- case 1:
182
- callMethod = function (a0) {
183
- return ffiFunc.call(a0);
184
- };
185
- break;
186
- case 2:
187
- callMethod = function (a0, a1) {
188
- return ffiFunc.call(a0, a1);
189
- };
190
- break;
191
- case 3:
192
- callMethod = function (a0, a1, a2) {
193
- return ffiFunc.call(a0, a1, a2);
194
- };
195
- break;
196
- case 4:
197
- callMethod = function (a0, a1, a2, a3) {
198
- return ffiFunc.call(a0, a1, a2, a3);
199
- };
200
- break;
201
- default:
202
- // Fallback for many args
203
- callMethod = function (...args) {
204
- return ffiFunc.call(...args);
205
- };
206
- }
207
- } else {
208
- // SLOW PATH: Has buffer/struct args - need to extract _buffer
209
- callMethod = function (...args) {
210
- const processedArgs = [];
172
+ let callMethod;
211
173
 
212
- for (let i = 0; i < args.length; i++) {
213
- const arg = args[i];
214
- // Check for _buffer FIRST (handles Proxy-wrapped structs)
215
- // This avoids calling Buffer.isBuffer() on Proxy which can cause issues
216
- if (arg && typeof arg === "object") {
217
- // Check for struct proxy FIRST - accessing _buffer on Proxy is safe
218
- // but Buffer.isBuffer(proxy) can cause hangs
219
- if (arg._buffer !== undefined && Buffer.isBuffer(arg._buffer)) {
220
- // Struct proxy or object with _buffer
221
- processedArgs.push(arg._buffer);
222
- } else if (Buffer.isBuffer(arg)) {
223
- // Already a buffer, use directly
224
- processedArgs.push(arg);
174
+ if (argCount === 0) {
175
+ // FAST PATH: No arguments - direct call
176
+ callMethod = function () {
177
+ return ffiFunc.call();
178
+ };
179
+ } else if (allPrimitive) {
180
+ // FAST PATH: All primitive args - direct call without processing
181
+ switch (argCount) {
182
+ case 1:
183
+ callMethod = function (a0) {
184
+ return ffiFunc.call(a0);
185
+ };
186
+ break;
187
+ case 2:
188
+ callMethod = function (a0, a1) {
189
+ return ffiFunc.call(a0, a1);
190
+ };
191
+ break;
192
+ case 3:
193
+ callMethod = function (a0, a1, a2) {
194
+ return ffiFunc.call(a0, a1, a2);
195
+ };
196
+ break;
197
+ case 4:
198
+ callMethod = function (a0, a1, a2, a3) {
199
+ return ffiFunc.call(a0, a1, a2, a3);
200
+ };
201
+ break;
202
+ default:
203
+ // Fallback for many args
204
+ callMethod = function (...args) {
205
+ return ffiFunc.call(...args);
206
+ };
207
+ }
208
+ } else {
209
+ // SLOW PATH: Has buffer/struct args - need to extract _buffer
210
+ callMethod = function (...args) {
211
+ const processedArgs = [];
212
+
213
+ for (let i = 0; i < args.length; i++) {
214
+ const arg = args[i];
215
+ // Check for _buffer FIRST (handles Proxy-wrapped structs)
216
+ // This avoids calling Buffer.isBuffer() on Proxy which can cause issues
217
+ if (arg && typeof arg === "object") {
218
+ // Check for struct proxy FIRST - accessing _buffer on Proxy is safe
219
+ // but Buffer.isBuffer(proxy) can cause hangs
220
+ if (arg._buffer !== undefined && Buffer.isBuffer(arg._buffer)) {
221
+ // Struct proxy or object with _buffer
222
+ processedArgs.push(arg._buffer);
223
+ } else if (Buffer.isBuffer(arg)) {
224
+ // Already a buffer, use directly
225
+ processedArgs.push(arg);
226
+ } else {
227
+ // Other object, pass as-is
228
+ processedArgs.push(arg);
229
+ }
225
230
  } else {
226
- // Other object, pass as-is
231
+ // Primitive value (number, string, bigint, null, undefined)
227
232
  processedArgs.push(arg);
228
233
  }
229
- } else {
230
- // Primitive value (number, string, bigint, null, undefined)
231
- processedArgs.push(arg);
232
234
  }
233
- }
234
235
 
235
- return ffiFunc.call(...processedArgs);
236
- };
237
- }
236
+ return ffiFunc.call(...processedArgs);
237
+ };
238
+ }
238
239
 
239
- // Aggiungi metadata come proprietà non-enumerable per non interferire
240
- Object.defineProperties(callMethod, {
241
- funcName: { value: name },
242
- address: { value: ffiFunc.address },
243
- _ffi: { value: ffiFunc },
244
- // Esponi errcheck come setter/getter
245
- errcheck: {
246
- get() {
247
- return ffiFunc._errcheck;
240
+ // Aggiungi metadata come proprietà non-enumerable per non interferire
241
+ Object.defineProperties(callMethod, {
242
+ funcName: { value: name },
243
+ address: { value: ffiFunc.address },
244
+ _ffi: { value: ffiFunc },
245
+ // Esponi errcheck come setter/getter
246
+ errcheck: {
247
+ get() {
248
+ return ffiFunc._errcheck;
249
+ },
250
+ set(callback) {
251
+ ffiFunc._errcheck = callback;
252
+ ffiFunc.setErrcheck(callback);
253
+ },
254
+ enumerable: false,
255
+ configurable: true,
248
256
  },
249
- set(callback) {
250
- ffiFunc._errcheck = callback;
251
- ffiFunc.setErrcheck(callback);
252
- },
253
- enumerable: false,
254
- configurable: true,
255
- },
256
- });
257
+ });
257
258
 
258
- this._cache.set(cacheKey, callMethod);
259
- return callMethod;
260
- }
259
+ this._cache.set(cacheKey, callMethod);
260
+ return callMethod;
261
+ }
261
262
 
262
- /**
263
- * Ottiene l'indirizzo di un simbolo
264
- * @param {string} name - Nome del simbolo
265
- * @returns {BigInt} Indirizzo del simbolo
266
- */
267
- symbol(name) {
268
- return this._lib.symbol(name);
269
- }
263
+ /**
264
+ * Ottiene l'indirizzo di un simbolo
265
+ * @param {string} name - Nome del simbolo
266
+ * @returns {BigInt} Indirizzo del simbolo
267
+ */
268
+ symbol(name) {
269
+ return this._lib.symbol(name);
270
+ }
270
271
 
271
- /**
272
- * Crea un callback JS chiamabile da C
273
- * @param {Function} fn - Funzione JavaScript
274
- * @param {string|CType} returnType - Tipo di ritorno
275
- * @param {Array<string|CType>} argTypes - Tipi degli argomenti
276
- * @returns {Object} Oggetto callback con proprietà pointer e metodi
277
- */
278
- callback(fn, returnType, argTypes = []) {
279
- return this._lib.callback(_toNativeType(returnType, native), _toNativeTypes(argTypes, native), fn);
280
- }
272
+ /**
273
+ * Crea un callback JS chiamabile da C
274
+ * @param {Function} fn - Funzione JavaScript
275
+ * @param {Function|number|CType} returnType - Tipo di ritorno (SimpleCData class, CType value, o CType)
276
+ * @param {Array<Function|number|CType>} argTypes - Tipi degli argomenti
277
+ * @returns {Object} Oggetto callback con proprietà pointer e metodi
278
+ */
279
+ callback(fn, returnType, argTypes = []) {
280
+ return this._lib.callback(_toNativeType(returnType, native), _toNativeTypes(argTypes, native), fn);
281
+ }
281
282
 
282
- /**
283
- * Chiude la libreria
284
- */
285
- close() {
286
- this._lib.close();
287
- this._cache.clear();
288
- }
283
+ /**
284
+ * Chiude la libreria
285
+ */
286
+ close() {
287
+ this._lib.close();
288
+ this._cache.clear();
289
+ }
289
290
 
290
- get path() {
291
- return this._lib.path;
292
- }
291
+ get path() {
292
+ return this._lib.path;
293
+ }
293
294
 
294
- get loaded() {
295
- return this._lib.loaded;
295
+ get loaded() {
296
+ return this._lib.loaded;
297
+ }
296
298
  }
297
- }
298
299
 
299
- /**
300
- * WinDLL - come CDLL ma con stdcall di default (per Windows)
301
- */
302
- class WinDLL extends CDLL {
303
- func(name, returnType, argTypes = [], options = {}) {
304
- return super.func(name, returnType, argTypes, {
305
- abi: "stdcall",
306
- ...options,
307
- });
300
+ /**
301
+ * WinDLL - come CDLL ma con stdcall di default (per Windows)
302
+ */
303
+ class WinDLL extends CDLL {
304
+ func(name, returnType, argTypes = [], options = {}) {
305
+ return super.func(name, returnType, argTypes, {
306
+ abi: "stdcall",
307
+ ...options,
308
+ });
309
+ }
308
310
  }
309
- }
310
311
 
311
312
  return { FunctionWrapper, CDLL, WinDLL };
312
313
  }