node-ctypes 1.2.0 → 1.4.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 +125 -10
- package/build/Release/ctypes-darwin-arm64.node +0 -0
- package/build/Release/ctypes-darwin-x64.node +0 -0
- package/build/Release/ctypes-linux-arm64.node +0 -0
- package/build/Release/ctypes-linux-x64.node +0 -0
- package/build/Release/ctypes-win32-arm64.node +0 -0
- package/build/Release/ctypes-win32-x64.node +0 -0
- package/lib/core/Library.js +251 -211
- package/lib/core/types.js +7 -0
- package/lib/index.d.ts +28 -2
- package/lib/index.js +56 -59
- package/lib/memory/pointer.js +243 -25
- package/lib/structures/Structure.js +261 -230
- package/lib/structures/Union.js +10 -2
- package/lib/structures/helpers/common.js +9 -1
- package/lib/structures/helpers/struct.js +6 -1
- package/lib/structures/helpers/union.js +9 -19
- package/lib/types/primitives.js +1 -1
- package/package.json +1 -1
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,
|
|
224
|
+
import { Structure, c_uint32 } from 'node-ctypes';
|
|
225
225
|
|
|
226
|
-
// Bit fields
|
|
226
|
+
// Bit fields using Python-style syntax: [name, type, bits]
|
|
227
227
|
class Flags extends Structure {
|
|
228
228
|
static _fields_ = [
|
|
229
|
-
["enabled",
|
|
230
|
-
["mode",
|
|
231
|
-
["priority",
|
|
232
|
-
["reserved",
|
|
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
|
|
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
|
|
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> `_fields_ = [("x", c_int)]` | `class Point extends Structure`<br> `{ static _fields_ = [["x", c_int]] }` |
|
|
721
835
|
| **Unions** | `class U(Union):`<br> `_fields_ = [("i", c_int)]` | `class U extends Union`<br> `{ 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)` | `
|
|
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
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|