node-ctypes 0.1.7 → 1.0.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.
Potentially problematic release.
This version of node-ctypes might be problematic. Click here for more details.
- package/README.md +13 -8
- 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 +312 -0
- package/lib/core/callback.js +275 -0
- package/lib/core/types.js +140 -0
- package/lib/index.d.ts +71 -124
- package/lib/index.js +215 -3096
- package/lib/memory/buffer.js +404 -0
- package/lib/memory/operations.js +295 -0
- package/lib/memory/pointer.js +358 -0
- package/lib/platform/constants.js +110 -0
- package/lib/platform/errors.js +403 -0
- package/lib/structures/Structure.js +414 -0
- package/lib/structures/Union.js +102 -0
- package/lib/structures/helpers/array.js +261 -0
- package/lib/structures/helpers/bitfield.js +147 -0
- package/lib/structures/helpers/common.js +129 -0
- package/lib/structures/helpers/struct.js +925 -0
- package/lib/structures/helpers/union.js +465 -0
- package/lib/types/SimpleCData.js +193 -0
- package/lib/types/primitives.js +392 -0
- package/lib/utils/cache.js +142 -0
- package/package.json +1 -1
|
@@ -0,0 +1,261 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file array.js
|
|
3
|
+
* @module structures/array
|
|
4
|
+
* @description Array type implementation for fixed-size arrays of C types.
|
|
5
|
+
*
|
|
6
|
+
* This module provides Python ctypes-compatible array types that support:
|
|
7
|
+
* - Fixed-size arrays of any C type (primitives, structs, unions)
|
|
8
|
+
* - Python-like indexing with bracket notation
|
|
9
|
+
* - Iteration support (for...of, spread operator)
|
|
10
|
+
* - String initialization for character arrays
|
|
11
|
+
*
|
|
12
|
+
* **Python ctypes Compatibility**:
|
|
13
|
+
* Similar to Python's `type * count` array syntax or explicit array types.
|
|
14
|
+
*
|
|
15
|
+
* @example Basic usage
|
|
16
|
+
* ```javascript
|
|
17
|
+
* import { array, c_int32 } from 'node-ctypes';
|
|
18
|
+
*
|
|
19
|
+
* const IntArray5 = array(c_int32, 5);
|
|
20
|
+
* const arr = IntArray5.create([1, 2, 3, 4, 5]);
|
|
21
|
+
* console.log(arr[0]); // 1
|
|
22
|
+
* arr[2] = 42;
|
|
23
|
+
* console.log(arr[2]); // 42
|
|
24
|
+
* ```
|
|
25
|
+
*
|
|
26
|
+
* @example Array of structs
|
|
27
|
+
* ```javascript
|
|
28
|
+
* class Point extends Structure {
|
|
29
|
+
* static _fields_ = [['x', c_int32], ['y', c_int32]];
|
|
30
|
+
* }
|
|
31
|
+
*
|
|
32
|
+
* const PointArray = array(Point, 3);
|
|
33
|
+
* const points = PointArray.create();
|
|
34
|
+
* points[0].x = 10;
|
|
35
|
+
* points[0].y = 20;
|
|
36
|
+
* ```
|
|
37
|
+
*
|
|
38
|
+
* @example Iteration
|
|
39
|
+
* ```javascript
|
|
40
|
+
* const arr = IntArray5.create([1, 2, 3, 4, 5]);
|
|
41
|
+
* for (const val of arr) {
|
|
42
|
+
* console.log(val);
|
|
43
|
+
* }
|
|
44
|
+
* const values = [...arr]; // Spread operator
|
|
45
|
+
* ```
|
|
46
|
+
*/
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Creates a fixed-size array type for a given element type.
|
|
50
|
+
*
|
|
51
|
+
* Returns an array type definition that can create instances of fixed-size
|
|
52
|
+
* arrays. The created arrays support Python-like indexing, iteration, and
|
|
53
|
+
* automatic memory management.
|
|
54
|
+
*
|
|
55
|
+
* **Python ctypes Compatibility**:
|
|
56
|
+
* Similar to Python's `type * count` syntax (e.g., `c_int * 5`).
|
|
57
|
+
*
|
|
58
|
+
* @param {Function|Object} elementType - Element type (SimpleCData class, Structure/Union class, or type object)
|
|
59
|
+
* @param {number} count - Number of elements in the array
|
|
60
|
+
* @param {Function} sizeof - sizeof function reference
|
|
61
|
+
* @param {Function} alloc - alloc function reference
|
|
62
|
+
* @param {Function} readValue - readValue function reference
|
|
63
|
+
* @param {Function} writeValue - writeValue function reference
|
|
64
|
+
* @param {Function} Structure - Structure class reference
|
|
65
|
+
* @param {Function} Union - Union class reference
|
|
66
|
+
* @param {Function} ArrayType - Native ArrayType class reference (if available)
|
|
67
|
+
* @returns {Object} Array type definition with create and wrap methods
|
|
68
|
+
* @throws {TypeError} If elementType is not a valid type
|
|
69
|
+
*
|
|
70
|
+
* @example Create integer array
|
|
71
|
+
* ```javascript
|
|
72
|
+
* import { array, c_int32 } from 'node-ctypes';
|
|
73
|
+
*
|
|
74
|
+
* const IntArray5 = array(c_int32, 5);
|
|
75
|
+
* const arr = IntArray5.create([1, 2, 3, 4, 5]);
|
|
76
|
+
* console.log(arr[0]); // 1
|
|
77
|
+
* arr[2] = 42;
|
|
78
|
+
* console.log(arr[2]); // 42
|
|
79
|
+
* ```
|
|
80
|
+
*
|
|
81
|
+
* @example Partial initialization
|
|
82
|
+
* ```javascript
|
|
83
|
+
* const arr = IntArray5.create([1, 2]); // Rest are zeros
|
|
84
|
+
* console.log(arr[0]); // 1
|
|
85
|
+
* console.log(arr[4]); // 0
|
|
86
|
+
* ```
|
|
87
|
+
*
|
|
88
|
+
* @example String initialization (character arrays)
|
|
89
|
+
* ```javascript
|
|
90
|
+
* const CharArray10 = array(c_char, 10);
|
|
91
|
+
* const arr = CharArray10.create("hello");
|
|
92
|
+
* // arr contains ASCII codes: [104, 101, 108, 108, 111, 0, 0, 0, 0, 0]
|
|
93
|
+
* ```
|
|
94
|
+
*
|
|
95
|
+
* @example Array of structs
|
|
96
|
+
* ```javascript
|
|
97
|
+
* class Point extends Structure {
|
|
98
|
+
* static _fields_ = [['x', c_int32], ['y', c_int32]];
|
|
99
|
+
* }
|
|
100
|
+
*
|
|
101
|
+
* const PointArray = array(Point, 3);
|
|
102
|
+
* const points = PointArray.create();
|
|
103
|
+
* points[0].x = 10;
|
|
104
|
+
* points[0].y = 20;
|
|
105
|
+
* ```
|
|
106
|
+
*/
|
|
107
|
+
export function array(elementType, count, sizeof, alloc, readValue, writeValue, Structure, Union, ArrayType) {
|
|
108
|
+
// Validate elementType: accept SimpleCData classes, Structure/Union classes,
|
|
109
|
+
// or native CType-like objects.
|
|
110
|
+
const isSimple = typeof elementType === "function" && elementType._isSimpleCData;
|
|
111
|
+
const isStruct = typeof elementType === "function" && (elementType.prototype instanceof Structure || elementType.prototype instanceof Union);
|
|
112
|
+
const isNativeTypeObj = typeof elementType === "object" && elementType !== null && (typeof elementType.getSize === "function" || elementType.size !== undefined);
|
|
113
|
+
if (!isSimple && !isStruct && !isNativeTypeObj) {
|
|
114
|
+
throw new TypeError("array elementType must be a SimpleCData class or a Structure/Union class");
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
const elementSize = sizeof(elementType);
|
|
118
|
+
let nativeArray;
|
|
119
|
+
if (isNativeTypeObj && ArrayType) {
|
|
120
|
+
nativeArray = new ArrayType(elementType, count);
|
|
121
|
+
} else {
|
|
122
|
+
// Provide a small JS-side shim implementing the minimal ArrayType API
|
|
123
|
+
nativeArray = {
|
|
124
|
+
getSize: () => count * elementSize,
|
|
125
|
+
getLength: () => count,
|
|
126
|
+
getAlignment: () => elementSize,
|
|
127
|
+
create: (values) => {
|
|
128
|
+
// JS create is implemented below; this should not be invoked by JS code
|
|
129
|
+
const size = count * elementSize;
|
|
130
|
+
const buffer = alloc(size);
|
|
131
|
+
buffer.fill(0);
|
|
132
|
+
return buffer;
|
|
133
|
+
},
|
|
134
|
+
};
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
// Wrap function that returns a Proxy for array-like indexing
|
|
138
|
+
const wrap = function (buffer) {
|
|
139
|
+
return new Proxy(buffer, {
|
|
140
|
+
get(target, prop, receiver) {
|
|
141
|
+
// Special case for _buffer to return the underlying buffer
|
|
142
|
+
if (prop === "_buffer") {
|
|
143
|
+
return target;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
// Special case for toString to show array contents
|
|
147
|
+
if (prop === "toString") {
|
|
148
|
+
return function () {
|
|
149
|
+
try {
|
|
150
|
+
const arr = Array.from(this);
|
|
151
|
+
return `[${arr.join(", ")}]`;
|
|
152
|
+
} catch (e) {
|
|
153
|
+
return "[error]";
|
|
154
|
+
}
|
|
155
|
+
}.bind(receiver);
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
// Intercept Symbol.iterator to iterate over elements, not bytes
|
|
159
|
+
if (prop === Symbol.iterator) {
|
|
160
|
+
return function* () {
|
|
161
|
+
for (let i = 0; i < count; i++) {
|
|
162
|
+
const off = i * elementSize;
|
|
163
|
+
// If elementType is a struct/union class, return an instance bound to the slice
|
|
164
|
+
if (typeof elementType === "function" && (elementType.prototype instanceof Structure || elementType.prototype instanceof Union)) {
|
|
165
|
+
yield new elementType(target.subarray(off, off + elementSize));
|
|
166
|
+
} else {
|
|
167
|
+
yield readValue(target, elementType, off);
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
};
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
// Ignore other Symbols
|
|
174
|
+
if (typeof prop === "symbol") {
|
|
175
|
+
const value = Reflect.get(target, prop, target);
|
|
176
|
+
if (typeof value === "function") {
|
|
177
|
+
return value.bind(target);
|
|
178
|
+
}
|
|
179
|
+
return value;
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
// If it's a number (index) - intercept BEFORE checking target
|
|
183
|
+
const index = Number(prop);
|
|
184
|
+
if (Number.isInteger(index) && !isNaN(index)) {
|
|
185
|
+
if (index >= 0 && index < count) {
|
|
186
|
+
const off = index * elementSize;
|
|
187
|
+
if (typeof elementType === "function" && (elementType.prototype instanceof Structure || elementType.prototype instanceof Union)) {
|
|
188
|
+
return new elementType(target.subarray(off, off + elementSize));
|
|
189
|
+
}
|
|
190
|
+
return readValue(target, elementType, off);
|
|
191
|
+
}
|
|
192
|
+
// Numeric index out of bounds -> undefined (JavaScript behavior)
|
|
193
|
+
return undefined;
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
// For everything else, use the normal buffer
|
|
197
|
+
const value = Reflect.get(target, prop, target);
|
|
198
|
+
// If it's a function, bind it to the target
|
|
199
|
+
if (typeof value === "function") {
|
|
200
|
+
return value.bind(target);
|
|
201
|
+
}
|
|
202
|
+
return value;
|
|
203
|
+
},
|
|
204
|
+
set(target, prop, value) {
|
|
205
|
+
// Ignore Symbols
|
|
206
|
+
if (typeof prop === "symbol") {
|
|
207
|
+
return Reflect.set(target, prop, value, target);
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
const index = Number(prop);
|
|
211
|
+
if (Number.isInteger(index) && !isNaN(index)) {
|
|
212
|
+
if (index >= 0 && index < count) {
|
|
213
|
+
writeValue(target, elementType, value, index * elementSize);
|
|
214
|
+
return true;
|
|
215
|
+
}
|
|
216
|
+
// Index out of bounds - don't write anything but return false
|
|
217
|
+
return false;
|
|
218
|
+
}
|
|
219
|
+
return Reflect.set(target, prop, value, target);
|
|
220
|
+
},
|
|
221
|
+
});
|
|
222
|
+
};
|
|
223
|
+
|
|
224
|
+
// Return a wrapper object that delegates to nativeArray but overrides create()
|
|
225
|
+
return {
|
|
226
|
+
// Type information
|
|
227
|
+
elementType,
|
|
228
|
+
length: count,
|
|
229
|
+
|
|
230
|
+
// Delegated methods
|
|
231
|
+
getSize: () => nativeArray.getSize(),
|
|
232
|
+
getLength: () => nativeArray.getLength(),
|
|
233
|
+
getAlignment: () => nativeArray.getAlignment(),
|
|
234
|
+
|
|
235
|
+
// create automatically returns the proxy
|
|
236
|
+
create: (values) => {
|
|
237
|
+
const size = count * sizeof(elementType);
|
|
238
|
+
const buffer = alloc(size);
|
|
239
|
+
buffer.fill(0);
|
|
240
|
+
if (Array.isArray(values)) {
|
|
241
|
+
for (let i = 0; i < Math.min(values.length, count); i++) {
|
|
242
|
+
writeValue(buffer, elementType, values[i], i * sizeof(elementType));
|
|
243
|
+
}
|
|
244
|
+
} else if (typeof values === "string") {
|
|
245
|
+
for (let i = 0; i < Math.min(values.length, count); i++) {
|
|
246
|
+
writeValue(buffer, elementType, values.charCodeAt(i), i * sizeof(elementType));
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
return wrap(buffer);
|
|
250
|
+
},
|
|
251
|
+
|
|
252
|
+
// Explicit wrap method
|
|
253
|
+
wrap: wrap,
|
|
254
|
+
|
|
255
|
+
// For compatibility, expose the native array (needed for StructType.addField)
|
|
256
|
+
_native: nativeArray,
|
|
257
|
+
|
|
258
|
+
// Helper to check if this is an ArrayType wrapper
|
|
259
|
+
_isArrayType: true,
|
|
260
|
+
};
|
|
261
|
+
}
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file bitfield-helpers.js
|
|
3
|
+
* @module structures/bitfield-helpers
|
|
4
|
+
* @description Helper functions for reading and writing bitfield values in structs.
|
|
5
|
+
*
|
|
6
|
+
* This module provides low-level bitfield manipulation functions used by struct
|
|
7
|
+
* and union implementations to pack multiple small integer values into single bytes.
|
|
8
|
+
*
|
|
9
|
+
* @example
|
|
10
|
+
* ```javascript
|
|
11
|
+
* import { _readBitField, _writeBitField } from './structures/bitfield-helpers.js';
|
|
12
|
+
*
|
|
13
|
+
* const buf = Buffer.alloc(4);
|
|
14
|
+
* _writeBitField(buf, 0, c_uint32, 0, 3, 5); // Write 5 to bits 0-2
|
|
15
|
+
* const value = _readBitField(buf, 0, c_uint32, 0, 3); // Read bits 0-2
|
|
16
|
+
* ```
|
|
17
|
+
*/
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Reads an unsigned integer value from a buffer.
|
|
21
|
+
*
|
|
22
|
+
* @param {Buffer} buf - Buffer to read from
|
|
23
|
+
* @param {number} offset - Byte offset in buffer
|
|
24
|
+
* @param {number} byteSize - Size in bytes (1, 2, 4, or 8)
|
|
25
|
+
* @param {Function} sizeof - sizeof function reference
|
|
26
|
+
* @returns {number|bigint} Value read from buffer
|
|
27
|
+
* @throws {Error} If byteSize is not supported
|
|
28
|
+
* @private
|
|
29
|
+
*/
|
|
30
|
+
export function _readUintFromBuffer(buf, offset, byteSize) {
|
|
31
|
+
switch (byteSize) {
|
|
32
|
+
case 1:
|
|
33
|
+
return buf.readUInt8(offset);
|
|
34
|
+
case 2:
|
|
35
|
+
return buf.readUInt16LE(offset);
|
|
36
|
+
case 4:
|
|
37
|
+
return buf.readUInt32LE(offset);
|
|
38
|
+
case 8:
|
|
39
|
+
return buf.readBigUInt64LE(offset);
|
|
40
|
+
default:
|
|
41
|
+
throw new Error(`Unsupported byte size: ${byteSize}`);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Writes an unsigned integer value to a buffer.
|
|
47
|
+
*
|
|
48
|
+
* @param {Buffer} buf - Buffer to write to
|
|
49
|
+
* @param {number} offset - Byte offset in buffer
|
|
50
|
+
* @param {number} byteSize - Size in bytes (1, 2, 4, or 8)
|
|
51
|
+
* @param {number|bigint} value - Value to write
|
|
52
|
+
* @throws {Error} If byteSize is not supported
|
|
53
|
+
* @private
|
|
54
|
+
*/
|
|
55
|
+
export function _writeUintToBuffer(buf, offset, byteSize, value) {
|
|
56
|
+
switch (byteSize) {
|
|
57
|
+
case 1:
|
|
58
|
+
buf.writeUInt8(value, offset);
|
|
59
|
+
break;
|
|
60
|
+
case 2:
|
|
61
|
+
buf.writeUInt16LE(value, offset);
|
|
62
|
+
break;
|
|
63
|
+
case 4:
|
|
64
|
+
buf.writeUInt32LE(value, offset);
|
|
65
|
+
break;
|
|
66
|
+
case 8:
|
|
67
|
+
buf.writeBigUInt64LE(value, offset);
|
|
68
|
+
break;
|
|
69
|
+
default:
|
|
70
|
+
throw new Error(`Unsupported byte size: ${byteSize}`);
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* Reads a bitfield value from a buffer.
|
|
76
|
+
*
|
|
77
|
+
* Extracts a specific range of bits from an integer value stored in memory.
|
|
78
|
+
* Used by struct/union implementations to support packed bitfields.
|
|
79
|
+
*
|
|
80
|
+
* @param {Buffer} buf - Buffer to read from
|
|
81
|
+
* @param {number} offset - Byte offset of the containing integer
|
|
82
|
+
* @param {Function|Object} baseType - Base integer type (c_uint8, c_uint16, c_uint32, c_uint64)
|
|
83
|
+
* @param {number} bitOffset - Starting bit position (0-based)
|
|
84
|
+
* @param {number} bitSize - Number of bits to read
|
|
85
|
+
* @param {Function} sizeof - sizeof function reference
|
|
86
|
+
* @returns {number} Extracted bitfield value
|
|
87
|
+
*
|
|
88
|
+
* @example
|
|
89
|
+
* ```javascript
|
|
90
|
+
* // Read 3-bit field starting at bit 5
|
|
91
|
+
* const value = _readBitField(buf, 0, c_uint32, 5, 3);
|
|
92
|
+
* ```
|
|
93
|
+
* @private
|
|
94
|
+
*/
|
|
95
|
+
export function _readBitField(buf, offset, baseType, bitOffset, bitSize, sizeof) {
|
|
96
|
+
const baseSize = sizeof(baseType);
|
|
97
|
+
const value = _readUintFromBuffer(buf, offset, baseSize);
|
|
98
|
+
|
|
99
|
+
// Extract the bits
|
|
100
|
+
if (baseSize === 8) {
|
|
101
|
+
const mask = (1n << BigInt(bitSize)) - 1n;
|
|
102
|
+
return Number((value >> BigInt(bitOffset)) & mask);
|
|
103
|
+
} else {
|
|
104
|
+
const mask = (1 << bitSize) - 1;
|
|
105
|
+
return (value >> bitOffset) & mask;
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* Writes a bitfield value to a buffer.
|
|
111
|
+
*
|
|
112
|
+
* Modifies a specific range of bits in an integer value stored in memory,
|
|
113
|
+
* preserving other bits. Used by struct/union implementations to support
|
|
114
|
+
* packed bitfields.
|
|
115
|
+
*
|
|
116
|
+
* @param {Buffer} buf - Buffer to write to
|
|
117
|
+
* @param {number} offset - Byte offset of the containing integer
|
|
118
|
+
* @param {Function|Object} baseType - Base integer type (c_uint8, c_uint16, c_uint32, c_uint64)
|
|
119
|
+
* @param {number} bitOffset - Starting bit position (0-based)
|
|
120
|
+
* @param {number} bitSize - Number of bits to write
|
|
121
|
+
* @param {number} newValue - Value to write (will be masked to bitSize)
|
|
122
|
+
* @param {Function} sizeof - sizeof function reference
|
|
123
|
+
*
|
|
124
|
+
* @example
|
|
125
|
+
* ```javascript
|
|
126
|
+
* // Write 5 to a 3-bit field starting at bit 2
|
|
127
|
+
* _writeBitField(buf, 0, c_uint32, 2, 3, 5);
|
|
128
|
+
* ```
|
|
129
|
+
* @private
|
|
130
|
+
*/
|
|
131
|
+
export function _writeBitField(buf, offset, baseType, bitOffset, bitSize, newValue, sizeof) {
|
|
132
|
+
const baseSize = sizeof(baseType);
|
|
133
|
+
let value = _readUintFromBuffer(buf, offset, baseSize);
|
|
134
|
+
|
|
135
|
+
// Modify the bits
|
|
136
|
+
if (baseSize === 8) {
|
|
137
|
+
const mask = (1n << BigInt(bitSize)) - 1n;
|
|
138
|
+
const clearMask = ~(mask << BigInt(bitOffset));
|
|
139
|
+
value = (value & clearMask) | ((BigInt(newValue) & mask) << BigInt(bitOffset));
|
|
140
|
+
} else {
|
|
141
|
+
const mask = (1 << bitSize) - 1;
|
|
142
|
+
const clearMask = ~(mask << bitOffset);
|
|
143
|
+
value = (value & clearMask) | ((newValue & mask) << bitOffset);
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
_writeUintToBuffer(buf, offset, baseSize, value);
|
|
147
|
+
}
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file helpers.js
|
|
3
|
+
* @module structures/helpers
|
|
4
|
+
* @description Helper functions and type checks for structure and type system.
|
|
5
|
+
*
|
|
6
|
+
* This module provides utility functions for working with structures, arrays,
|
|
7
|
+
* and bitfields in the node-ctypes type system.
|
|
8
|
+
*
|
|
9
|
+
* @example
|
|
10
|
+
* ```javascript
|
|
11
|
+
* import { bitfield, _isStruct, _isArrayType } from './structures/helpers.js';
|
|
12
|
+
*
|
|
13
|
+
* // Create a bitfield
|
|
14
|
+
* const flags = bitfield(c_uint32, 8); // 8-bit field
|
|
15
|
+
*
|
|
16
|
+
* // Check if type is a struct
|
|
17
|
+
* if (_isStruct(myType)) {
|
|
18
|
+
* // Handle struct type
|
|
19
|
+
* }
|
|
20
|
+
* ```
|
|
21
|
+
*/
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Creates a bitfield definition.
|
|
25
|
+
*
|
|
26
|
+
* Bitfields allow packing multiple boolean or small integer values into a single
|
|
27
|
+
* integer type, useful for flags and compact data structures.
|
|
28
|
+
*
|
|
29
|
+
* **Python ctypes Compatibility**:
|
|
30
|
+
* Similar to Python's ctypes bitfield syntax in Structure _fields_.
|
|
31
|
+
*
|
|
32
|
+
* @param {Function|Object} baseType - Base integer type (c_uint8, c_uint16, c_uint32, c_uint64)
|
|
33
|
+
* @param {number} bits - Number of bits to allocate (1 to baseSize*8)
|
|
34
|
+
* @param {Function} sizeof - sizeof function reference
|
|
35
|
+
* @returns {Object} Bitfield definition object
|
|
36
|
+
* @throws {Error} If bits is out of valid range for base type
|
|
37
|
+
*
|
|
38
|
+
* @example 8-bit flags in uint32
|
|
39
|
+
* ```javascript
|
|
40
|
+
* import { struct, bitfield, c_uint32 } from 'node-ctypes';
|
|
41
|
+
*
|
|
42
|
+
* const Flags = struct({
|
|
43
|
+
* isActive: bitfield(c_uint32, 1), // 1 bit
|
|
44
|
+
* priority: bitfield(c_uint32, 3), // 3 bits
|
|
45
|
+
* category: bitfield(c_uint32, 4), // 4 bits
|
|
46
|
+
* });
|
|
47
|
+
* ```
|
|
48
|
+
*
|
|
49
|
+
* @example Using different base types
|
|
50
|
+
* ```javascript
|
|
51
|
+
* // Small bitfield (up to 8 bits)
|
|
52
|
+
* const smallFlags = bitfield(c_uint8, 5);
|
|
53
|
+
*
|
|
54
|
+
* // Large bitfield (up to 64 bits)
|
|
55
|
+
* const largeFlags = bitfield(c_uint64, 48);
|
|
56
|
+
* ```
|
|
57
|
+
*/
|
|
58
|
+
export function bitfield(baseType, bits, sizeof) {
|
|
59
|
+
const baseSize = sizeof(baseType);
|
|
60
|
+
const maxBits = baseSize * 8;
|
|
61
|
+
|
|
62
|
+
if (bits < 1 || bits > maxBits) {
|
|
63
|
+
throw new Error(`Bit field size must be between 1 and ${maxBits} for ${baseType}`);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
return {
|
|
67
|
+
_isBitField: true,
|
|
68
|
+
baseType: baseType,
|
|
69
|
+
bits: bits,
|
|
70
|
+
baseSize: baseSize,
|
|
71
|
+
};
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* Checks if a type is a struct definition.
|
|
76
|
+
*
|
|
77
|
+
* @param {*} type - Type to check
|
|
78
|
+
* @returns {boolean} True if type is a struct definition
|
|
79
|
+
*
|
|
80
|
+
* @example
|
|
81
|
+
* ```javascript
|
|
82
|
+
* const myStruct = struct({ x: c_int32, y: c_int32 });
|
|
83
|
+
* console.log(_isStruct(myStruct)); // true
|
|
84
|
+
* console.log(_isStruct(c_int32)); // false
|
|
85
|
+
* ```
|
|
86
|
+
*
|
|
87
|
+
* @private
|
|
88
|
+
*/
|
|
89
|
+
export function _isStruct(type) {
|
|
90
|
+
return typeof type === "object" && type !== null && typeof type.size === "number" && Array.isArray(type.fields) && typeof type.create === "function";
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* Checks if a type is an array type definition.
|
|
95
|
+
*
|
|
96
|
+
* @param {*} type - Type to check
|
|
97
|
+
* @returns {boolean} True if type is an array type
|
|
98
|
+
*
|
|
99
|
+
* @example
|
|
100
|
+
* ```javascript
|
|
101
|
+
* const intArray = array(c_int32, 10);
|
|
102
|
+
* console.log(_isArrayType(intArray)); // true
|
|
103
|
+
* console.log(_isArrayType(c_int32)); // false
|
|
104
|
+
* ```
|
|
105
|
+
*
|
|
106
|
+
* @private
|
|
107
|
+
*/
|
|
108
|
+
export function _isArrayType(type) {
|
|
109
|
+
return typeof type === "object" && type !== null && type._isArrayType === true;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
/**
|
|
113
|
+
* Checks if a type is a bitfield definition.
|
|
114
|
+
*
|
|
115
|
+
* @param {*} type - Type to check
|
|
116
|
+
* @returns {boolean} True if type is a bitfield
|
|
117
|
+
*
|
|
118
|
+
* @example
|
|
119
|
+
* ```javascript
|
|
120
|
+
* const flags = bitfield(c_uint32, 8);
|
|
121
|
+
* console.log(_isBitField(flags)); // true
|
|
122
|
+
* console.log(_isBitField(c_int32)); // false
|
|
123
|
+
* ```
|
|
124
|
+
*
|
|
125
|
+
* @private
|
|
126
|
+
*/
|
|
127
|
+
export function _isBitField(type) {
|
|
128
|
+
return typeof type === "object" && type !== null && type._isBitField === true;
|
|
129
|
+
}
|