node-ctypes 0.1.5 → 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.

@@ -0,0 +1,404 @@
1
+ /**
2
+ * @file buffer.js
3
+ * @module memory/buffer
4
+ * @description Buffer creation and string handling functions for C interoperability.
5
+ *
6
+ * This module provides Python ctypes-compatible functions for creating and managing
7
+ * buffers, C strings, and wide strings. It handles platform-specific differences in
8
+ * character encoding (UTF-16LE on Windows, UTF-32LE on Unix).
9
+ *
10
+ * **Python ctypes Compatibility**:
11
+ * - `create_string_buffer()` ≈ Python's `ctypes.create_string_buffer()`
12
+ * - `create_unicode_buffer()` ≈ Python's `ctypes.create_unicode_buffer()`
13
+ * - `string_at()` ≈ Python's `ctypes.string_at()`
14
+ * - `wstring_at()` ≈ Python's `ctypes.wstring_at()`
15
+ *
16
+ * @example Basic buffer operations
17
+ * ```javascript
18
+ * import { create_string_buffer, create_unicode_buffer } from 'node-ctypes';
19
+ *
20
+ * // Create C string buffer
21
+ * const buf1 = create_string_buffer(64); // 64-byte buffer
22
+ * const buf2 = create_string_buffer("Hello"); // Buffer with string
23
+ *
24
+ * // Create wide string buffer
25
+ * const wbuf1 = create_unicode_buffer(32); // 32 wchar_t buffer
26
+ * const wbuf2 = create_unicode_buffer("Hello"); // Wide string buffer
27
+ * ```
28
+ */
29
+
30
+ /**
31
+ * Allocates a zero-initialized buffer of the specified size.
32
+ *
33
+ * This is a simple wrapper around `Buffer.alloc()` for consistency with
34
+ * the ctypes API. All bytes are initialized to zero.
35
+ *
36
+ * @param {number} size - Size in bytes to allocate
37
+ * @returns {Buffer} Zero-initialized buffer
38
+ *
39
+ * @example
40
+ * ```javascript
41
+ * import { alloc } from 'node-ctypes';
42
+ *
43
+ * const buf = alloc(256); // 256-byte zero-filled buffer
44
+ * console.log(buf[0]); // 0
45
+ * ```
46
+ */
47
+ export function alloc(size) {
48
+ return Buffer.alloc(size);
49
+ }
50
+
51
+ /**
52
+ * Creates a buffer containing a null-terminated C string.
53
+ *
54
+ * The resulting buffer is compatible with C `char*` strings and includes
55
+ * the null terminator.
56
+ *
57
+ * **Platform Notes**:
58
+ * - Uses the native module's cstring implementation
59
+ * - Automatically adds null terminator
60
+ * - Encoding is UTF-8 (standard for C strings)
61
+ *
62
+ * @param {string} str - JavaScript string to convert
63
+ * @param {Object} native - Native module reference
64
+ * @returns {Buffer} Buffer containing null-terminated C string
65
+ *
66
+ * @example
67
+ * ```javascript
68
+ * import { cstring } from 'node-ctypes';
69
+ *
70
+ * const buf = cstring("Hello, World!");
71
+ * // Buffer: [72, 101, 108, 108, 111, 44, 32, 87, 111, 114, 108, 100, 33, 0]
72
+ * // H e l l o , ' ' W o r l d ! \0
73
+ * ```
74
+ */
75
+ export function cstring(str, native) {
76
+ return native.cstring(str);
77
+ }
78
+
79
+ /**
80
+ * Creates a buffer containing a null-terminated wide string (wchar_t*).
81
+ *
82
+ * **Platform-Specific Behavior**:
83
+ * - **Windows**: 2 bytes per character (UTF-16LE)
84
+ * - **Unix/Linux/macOS**: 4 bytes per character (UTF-32LE)
85
+ *
86
+ * The function automatically detects the platform and encodes accordingly.
87
+ *
88
+ * **Python ctypes Compatibility**:
89
+ * Equivalent to creating a wide string in Python ctypes, handling the
90
+ * platform's native wchar_t representation.
91
+ *
92
+ * @param {string} str - JavaScript string to convert
93
+ * @param {Object} native - Native module reference (provides WCHAR_SIZE)
94
+ * @returns {Buffer} Buffer containing null-terminated wide string
95
+ *
96
+ * @example Windows (UTF-16LE)
97
+ * ```javascript
98
+ * import { wstring } from 'node-ctypes';
99
+ *
100
+ * // On Windows (WCHAR_SIZE = 2):
101
+ * const buf = wstring("Hi");
102
+ * // Buffer: [72, 0, 105, 0, 0, 0]
103
+ * // H i \0
104
+ * ```
105
+ *
106
+ * @example Unix (UTF-32LE)
107
+ * ```javascript
108
+ * // On Unix (WCHAR_SIZE = 4):
109
+ * const buf = wstring("Hi");
110
+ * // Buffer: [72, 0, 0, 0, 105, 0, 0, 0, 0, 0, 0, 0]
111
+ * // H i \0
112
+ * ```
113
+ */
114
+ export function wstring(str, native) {
115
+ const wcharSize = native.WCHAR_SIZE;
116
+
117
+ // Windows: UTF-16LE (2 bytes per character)
118
+ if (wcharSize === 2) {
119
+ return Buffer.from(str + "\0", "utf16le");
120
+ }
121
+
122
+ // Unix: UTF-32LE (4 bytes per character)
123
+ // Manually construct UTF-32LE buffer from code points
124
+ const codePoints = [];
125
+ for (const ch of str) {
126
+ codePoints.push(ch.codePointAt(0));
127
+ }
128
+
129
+ const buf = Buffer.alloc((codePoints.length + 1) * 4);
130
+ for (let i = 0; i < codePoints.length; i++) {
131
+ buf.writeUInt32LE(codePoints[i], i * 4);
132
+ }
133
+ // Null terminator already initialized (Buffer.alloc zeros memory)
134
+
135
+ return buf;
136
+ }
137
+
138
+ /**
139
+ * Creates a C string buffer (Python ctypes compatible).
140
+ *
141
+ * **Overloaded Function**:
142
+ * - `create_string_buffer(size)` - Allocates empty buffer of size bytes
143
+ * - `create_string_buffer(string)` - Creates buffer from string (with null terminator)
144
+ * - `create_string_buffer(bytes)` - Copies buffer and adds null terminator
145
+ *
146
+ * **Python ctypes Compatibility**:
147
+ * Direct equivalent to Python's `ctypes.create_string_buffer()`.
148
+ *
149
+ * @param {number|string|Buffer} init - Size, string, or buffer to copy
150
+ * @param {Object} native - Native module reference
151
+ * @returns {Buffer} Created buffer
152
+ * @throws {TypeError} If init is not number, string, or Buffer
153
+ *
154
+ * @example Empty buffer
155
+ * ```javascript
156
+ * import { create_string_buffer } from 'node-ctypes';
157
+ *
158
+ * const buf = create_string_buffer(256);
159
+ * // 256-byte zero-filled buffer
160
+ * ```
161
+ *
162
+ * @example From string
163
+ * ```javascript
164
+ * const buf = create_string_buffer("Hello");
165
+ * // Buffer: "Hello\0" (6 bytes including null terminator)
166
+ * ```
167
+ *
168
+ * @example From buffer
169
+ * ```javascript
170
+ * const src = Buffer.from([72, 101, 108, 108, 111]);
171
+ * const buf = create_string_buffer(src);
172
+ * // Buffer: [72, 101, 108, 108, 111, 0] (adds null terminator)
173
+ * ```
174
+ */
175
+ export function create_string_buffer(init, native) {
176
+ if (typeof init === "number") {
177
+ // create_string_buffer(size) - allocate empty buffer
178
+ return alloc(init);
179
+ } else if (typeof init === "string") {
180
+ // create_string_buffer("string") - create buffer with string
181
+ return cstring(init, native);
182
+ } else if (Buffer.isBuffer(init)) {
183
+ // create_string_buffer(bytes) - copy bytes and add null terminator
184
+ const buf = alloc(init.length + 1);
185
+ init.copy(buf);
186
+ buf[init.length] = 0; // null terminator
187
+ return buf;
188
+ }
189
+
190
+ throw new TypeError("create_string_buffer requires number, string, or Buffer");
191
+ }
192
+
193
+ /**
194
+ * Creates a Unicode (wide string) buffer (Python ctypes compatible).
195
+ *
196
+ * **Overloaded Function**:
197
+ * - `create_unicode_buffer(size)` - Allocates buffer for size characters
198
+ * - `create_unicode_buffer(string)` - Creates wide string buffer from string
199
+ *
200
+ * **Platform-Specific Behavior**:
201
+ * - **Windows**: size * 2 bytes (UTF-16LE)
202
+ * - **Unix**: size * 4 bytes (UTF-32LE)
203
+ *
204
+ * **Python ctypes Compatibility**:
205
+ * Direct equivalent to Python's `ctypes.create_unicode_buffer()`.
206
+ *
207
+ * @param {number|string} init - Size in characters or string
208
+ * @param {Object} native - Native module reference (provides WCHAR_SIZE)
209
+ * @returns {Buffer} Created wide string buffer
210
+ * @throws {TypeError} If init is not number or string
211
+ *
212
+ * @example Empty wide buffer
213
+ * ```javascript
214
+ * import { create_unicode_buffer } from 'node-ctypes';
215
+ *
216
+ * // On Windows (2 bytes per wchar_t):
217
+ * const buf = create_unicode_buffer(64);
218
+ * // 128-byte buffer (64 characters * 2 bytes)
219
+ *
220
+ * // On Unix (4 bytes per wchar_t):
221
+ * const buf = create_unicode_buffer(64);
222
+ * // 256-byte buffer (64 characters * 4 bytes)
223
+ * ```
224
+ *
225
+ * @example From string
226
+ * ```javascript
227
+ * const buf = create_unicode_buffer("Hello");
228
+ * // Wide string buffer with "Hello\0"
229
+ * ```
230
+ */
231
+ export function create_unicode_buffer(init, native) {
232
+ const wcharSize = native.WCHAR_SIZE;
233
+
234
+ if (typeof init === "number") {
235
+ // create_unicode_buffer(size) - allocate empty buffer for N characters
236
+ return alloc(init * wcharSize);
237
+ } else if (typeof init === "string") {
238
+ // create_unicode_buffer("string") - create buffer with wide string
239
+ return wstring(init, native);
240
+ }
241
+
242
+ throw new TypeError("create_unicode_buffer requires number or string");
243
+ }
244
+
245
+ /**
246
+ * Reads a C string from a memory address (Python ctypes compatible).
247
+ *
248
+ * **Python ctypes Compatibility**:
249
+ * Direct equivalent to Python's `ctypes.string_at()`.
250
+ *
251
+ * @param {Buffer|bigint|number} address - Memory address or buffer
252
+ * @param {number} [size] - Number of bytes to read (default: until null terminator)
253
+ * @param {Object} native - Native module reference
254
+ * @returns {string|null} String read from memory
255
+ *
256
+ * @example Read until null terminator
257
+ * ```javascript
258
+ * import { string_at, cstring } from 'node-ctypes';
259
+ *
260
+ * const buf = cstring("Hello");
261
+ * const str = string_at(buf);
262
+ * console.log(str); // "Hello"
263
+ * ```
264
+ *
265
+ * @example Read fixed size
266
+ * ```javascript
267
+ * const buf = Buffer.from("Hello, World!\0");
268
+ * const str = string_at(buf, 5);
269
+ * console.log(str); // "Hello"
270
+ * ```
271
+ */
272
+ export function string_at(address, size, native) {
273
+ return native.readCString(address, size);
274
+ }
275
+
276
+ /**
277
+ * Reads a wide string from a memory address (Python ctypes compatible).
278
+ *
279
+ * **Platform-Specific Behavior**:
280
+ * - **Windows**: Reads UTF-16LE (2 bytes per character)
281
+ * - **Unix**: Reads UTF-32LE (4 bytes per character)
282
+ *
283
+ * **Python ctypes Compatibility**:
284
+ * Direct equivalent to Python's `ctypes.wstring_at()`.
285
+ *
286
+ * @param {Buffer|bigint|number} address - Memory address or buffer
287
+ * @param {number} [size] - Number of wide characters to read (not bytes)
288
+ * @param {Object} native - Native module reference
289
+ * @returns {string|null} Wide string read from memory
290
+ *
291
+ * @example Read wide string
292
+ * ```javascript
293
+ * import { wstring_at, wstring } from 'node-ctypes';
294
+ *
295
+ * const buf = wstring("Hello");
296
+ * const str = wstring_at(buf);
297
+ * console.log(str); // "Hello"
298
+ * ```
299
+ */
300
+ export function wstring_at(address, size, native) {
301
+ if (address === null || address === undefined) {
302
+ return null;
303
+ }
304
+
305
+ const wcharSize = native.WCHAR_SIZE;
306
+ let buf;
307
+
308
+ if (Buffer.isBuffer(address)) {
309
+ buf = address;
310
+ } else {
311
+ // Convert BigInt/number to buffer
312
+ const maxBytes = size ? size * wcharSize : 1024;
313
+ buf = native.ptrToBuffer(address, maxBytes);
314
+ }
315
+
316
+ // Windows: UTF-16LE
317
+ if (wcharSize === 2) {
318
+ if (size !== undefined) {
319
+ return buf.toString("utf16le", 0, size * 2);
320
+ }
321
+ // Read until null terminator
322
+ let end = 0;
323
+ while (end < buf.length - 1 && (buf[end] !== 0 || buf[end + 1] !== 0)) {
324
+ end += 2;
325
+ }
326
+ return buf.toString("utf16le", 0, end);
327
+ }
328
+
329
+ // Unix: UTF-32LE
330
+ const chars = [];
331
+ const limit = size !== undefined ? size : Math.floor(buf.length / 4);
332
+
333
+ for (let i = 0; i < limit; i++) {
334
+ const codePoint = buf.readUInt32LE(i * 4);
335
+ if (codePoint === 0) break;
336
+ chars.push(String.fromCodePoint(codePoint));
337
+ }
338
+
339
+ return chars.join("");
340
+ }
341
+
342
+ /**
343
+ * Copies memory from source to destination (like C's memmove).
344
+ *
345
+ * **Python ctypes Compatibility**:
346
+ * Equivalent to Python's `ctypes.memmove()`.
347
+ *
348
+ * @param {Buffer} dst - Destination buffer
349
+ * @param {Buffer|bigint} src - Source buffer or address
350
+ * @param {number} count - Number of bytes to copy
351
+ * @param {Object} native - Native module reference
352
+ * @throws {TypeError} If dst is not a Buffer
353
+ *
354
+ * @example
355
+ * ```javascript
356
+ * import { memmove } from 'node-ctypes';
357
+ *
358
+ * const dst = Buffer.alloc(10);
359
+ * const src = Buffer.from("Hello");
360
+ * memmove(dst, src, 5);
361
+ * console.log(dst.toString('utf8', 0, 5)); // "Hello"
362
+ * ```
363
+ */
364
+ export function memmove(dst, src, count, native) {
365
+ if (!Buffer.isBuffer(dst)) {
366
+ throw new TypeError("dst must be a Buffer");
367
+ }
368
+
369
+ let srcBuf;
370
+ if (Buffer.isBuffer(src)) {
371
+ srcBuf = src;
372
+ } else {
373
+ srcBuf = native.ptrToBuffer(src, count);
374
+ }
375
+
376
+ srcBuf.copy(dst, 0, 0, count);
377
+ }
378
+
379
+ /**
380
+ * Fills memory with a byte value (like C's memset).
381
+ *
382
+ * **Python ctypes Compatibility**:
383
+ * Equivalent to Python's `ctypes.memset()`.
384
+ *
385
+ * @param {Buffer} dst - Destination buffer
386
+ * @param {number} value - Byte value to fill (0-255)
387
+ * @param {number} count - Number of bytes to fill
388
+ * @throws {TypeError} If dst is not a Buffer
389
+ *
390
+ * @example
391
+ * ```javascript
392
+ * import { memset } from 'node-ctypes';
393
+ *
394
+ * const buf = Buffer.alloc(10);
395
+ * memset(buf, 0xFF, 5);
396
+ * console.log([...buf]); // [255, 255, 255, 255, 255, 0, 0, 0, 0, 0]
397
+ * ```
398
+ */
399
+ export function memset(dst, value, count) {
400
+ if (!Buffer.isBuffer(dst)) {
401
+ throw new TypeError("dst must be a Buffer");
402
+ }
403
+ dst.fill(value, 0, count);
404
+ }
@@ -0,0 +1,295 @@
1
+ /**
2
+ * @file operations.js
3
+ * @module memory/operations
4
+ * @description Memory read/write operations and type size queries.
5
+ *
6
+ * This module provides low-level memory operations for reading and writing
7
+ * typed values to/from buffers, similar to Python ctypes memory access.
8
+ *
9
+ * **Python ctypes Compatibility**:
10
+ * These functions provide similar functionality to Python's struct module
11
+ * and ctypes memory operations.
12
+ *
13
+ * @example
14
+ * ```javascript
15
+ * import { readValue, writeValue, sizeof, c_int32, c_double } from 'node-ctypes';
16
+ *
17
+ * const buf = Buffer.alloc(16);
18
+ *
19
+ * // Write values
20
+ * writeValue(buf, c_int32, 42, 0);
21
+ * writeValue(buf, c_double, 3.14, 8);
22
+ *
23
+ * // Read values
24
+ * const int_val = readValue(buf, c_int32, 0); // 42
25
+ * const double_val = readValue(buf, c_double, 8); // 3.14
26
+ *
27
+ * // Get type sizes
28
+ * console.log(sizeof(c_int32)); // 4
29
+ * console.log(sizeof(c_double)); // 8
30
+ * ```
31
+ */
32
+
33
+ /**
34
+ * Reads a typed value from memory at the specified offset.
35
+ *
36
+ * **Supported Types**:
37
+ * - SimpleCData classes (c_int32, c_uint64, c_float, c_double, etc.)
38
+ * - Structure classes (user-defined structs)
39
+ * - Union classes (user-defined unions)
40
+ *
41
+ * **Python ctypes Compatibility**:
42
+ * Similar to reading from a ctypes pointer or using struct.unpack.
43
+ *
44
+ * @param {Buffer|bigint|number} ptr - Buffer or memory address to read from
45
+ * @param {Function|Object} type - Type to read (SimpleCData class, Structure, or Union)
46
+ * @param {number} [offset=0] - Byte offset from ptr
47
+ * @param {Function} sizeof - sizeof function reference
48
+ * @param {Function} ptrToBuffer - ptrToBuffer function reference
49
+ * @param {Function} Structure - Structure class reference
50
+ * @param {Function} Union - Union class reference
51
+ * @returns {*} Value read from memory
52
+ * @throws {RangeError} If offset is negative or read exceeds buffer bounds
53
+ * @throws {TypeError} If ptr is not a Buffer/address or type is unsupported
54
+ *
55
+ * @example Read primitive types
56
+ * ```javascript
57
+ * import { readValue, c_int32, c_float } from 'node-ctypes';
58
+ *
59
+ * const buf = Buffer.from([0x2A, 0x00, 0x00, 0x00]); // 42 in little-endian
60
+ * const value = readValue(buf, c_int32, 0);
61
+ * console.log(value); // 42
62
+ * ```
63
+ *
64
+ * @example Read from address
65
+ * ```javascript
66
+ * const address = 0x1234567890ABCDEFn;
67
+ * const value = readValue(address, c_int32, 0);
68
+ * ```
69
+ *
70
+ * @example Read struct
71
+ * ```javascript
72
+ * class Point extends Structure {
73
+ * static _fields_ = [['x', c_int32], ['y', c_int32]];
74
+ * }
75
+ *
76
+ * const buf = Buffer.alloc(8);
77
+ * const point = readValue(buf, Point, 0);
78
+ * console.log(point); // { x: 0, y: 0 }
79
+ * ```
80
+ */
81
+ export function readValue(ptr, type, offset = 0, sizeof, ptrToBuffer, Structure, Union) {
82
+ // Validate offset
83
+ if (typeof offset !== "number" || offset < 0) {
84
+ throw new RangeError("offset must be a non-negative number");
85
+ }
86
+
87
+ // SimpleCData class - use its _reader directly
88
+ if (typeof type === "function" && type._isSimpleCData) {
89
+ if (Buffer.isBuffer(ptr)) {
90
+ const size = type._size || sizeof(type);
91
+ // Bounds check for buffer reads
92
+ if (offset + size > ptr.length) {
93
+ throw new RangeError(`Read would exceed buffer bounds (offset: ${offset}, size: ${size}, buffer length: ${ptr.length})`);
94
+ }
95
+ return type._reader(ptr, offset);
96
+ }
97
+
98
+ // Allow passing an address (BigInt or number) and convert to buffer
99
+ if (typeof ptr === "bigint" || typeof ptr === "number") {
100
+ const size = type._size || sizeof(type);
101
+ const buf = ptrToBuffer(ptr, size + offset);
102
+ return type._reader(buf, offset);
103
+ }
104
+
105
+ throw new TypeError("readValue requires a Buffer or pointer address");
106
+ }
107
+
108
+ // Struct type (class)
109
+ if (typeof type === "function" && type.prototype instanceof Structure) {
110
+ const def = type._structDef || type._buildStruct();
111
+ const tempBuf = ptr.subarray(offset, offset + def.size);
112
+ return def.toObject(tempBuf);
113
+ }
114
+
115
+ // Union type (class)
116
+ if (typeof type === "function" && type.prototype instanceof Union) {
117
+ const def = type._unionDef || type._buildUnion();
118
+ const tempBuf = ptr.subarray(offset, offset + def.size);
119
+ return def.toObject(tempBuf);
120
+ }
121
+
122
+ throw new TypeError(`readValue: unsupported type ${type}`);
123
+ }
124
+
125
+ /**
126
+ * Writes a typed value to memory at the specified offset.
127
+ *
128
+ * **Supported Types**:
129
+ * - SimpleCData classes (c_int32, c_uint64, c_float, c_double, etc.)
130
+ * - Structure classes (user-defined structs)
131
+ * - Union classes (user-defined unions)
132
+ *
133
+ * **Python ctypes Compatibility**:
134
+ * Similar to writing to a ctypes pointer or using struct.pack.
135
+ *
136
+ * @param {Buffer} ptr - Buffer to write to (must be a Buffer, not an address)
137
+ * @param {Function|Object} type - Type to write (SimpleCData class, Structure, or Union)
138
+ * @param {*} value - Value to write
139
+ * @param {number} [offset=0] - Byte offset in buffer
140
+ * @param {Function} sizeof - sizeof function reference
141
+ * @param {Function} Structure - Structure class reference
142
+ * @param {Function} Union - Union class reference
143
+ * @returns {number} Number of bytes written
144
+ * @throws {RangeError} If offset is negative or write exceeds buffer bounds
145
+ * @throws {TypeError} If ptr is not a Buffer or type is unsupported
146
+ *
147
+ * @example Write primitive types
148
+ * ```javascript
149
+ * import { writeValue, c_int32, c_double } from 'node-ctypes';
150
+ *
151
+ * const buf = Buffer.alloc(16);
152
+ * writeValue(buf, c_int32, 42, 0);
153
+ * writeValue(buf, c_double, 3.14159, 8);
154
+ * ```
155
+ *
156
+ * @example Write struct
157
+ * ```javascript
158
+ * class Point extends Structure {
159
+ * static _fields_ = [['x', c_int32], ['y', c_int32]];
160
+ * }
161
+ *
162
+ * const buf = Buffer.alloc(8);
163
+ * writeValue(buf, Point, { x: 10, y: 20 }, 0);
164
+ * ```
165
+ */
166
+ export function writeValue(ptr, type, value, offset = 0, sizeof, Structure, Union) {
167
+ // Validate offset
168
+ if (typeof offset !== "number" || offset < 0) {
169
+ throw new RangeError("offset must be a non-negative number");
170
+ }
171
+
172
+ // SimpleCData class - use its _writer directly
173
+ if (typeof type === "function" && type._isSimpleCData) {
174
+ if (!Buffer.isBuffer(ptr)) {
175
+ throw new TypeError("writeValue requires a Buffer");
176
+ }
177
+ const size = type._size || sizeof(type);
178
+ // Bounds check for buffer writes
179
+ if (offset + size > ptr.length) {
180
+ throw new RangeError(`Write would exceed buffer bounds (offset: ${offset}, size: ${size}, buffer length: ${ptr.length})`);
181
+ }
182
+ type._writer(ptr, offset, value);
183
+ return type._size;
184
+ }
185
+
186
+ // Struct type (class)
187
+ if (typeof type === "function" && type.prototype instanceof Structure) {
188
+ const def = type._structDef || type._buildStruct();
189
+ const tempBuf = ptr.subarray(offset, offset + def.size);
190
+ if (Buffer.isBuffer(value)) {
191
+ value.copy(tempBuf, 0, 0, def.size);
192
+ } else if (typeof value === "object" && value !== null) {
193
+ for (const [k, v] of Object.entries(value)) {
194
+ def.set(tempBuf, k, v);
195
+ }
196
+ }
197
+ return def.size;
198
+ }
199
+
200
+ // Union type (class)
201
+ if (typeof type === "function" && type.prototype instanceof Union) {
202
+ const def = type._unionDef || type._buildUnion();
203
+ const tempBuf = ptr.subarray(offset, offset + def.size);
204
+ if (Buffer.isBuffer(value)) {
205
+ value.copy(tempBuf, 0, 0, def.size);
206
+ } else if (typeof value === "object" && value !== null) {
207
+ for (const [k, v] of Object.entries(value)) {
208
+ def.set(tempBuf, k, v);
209
+ }
210
+ }
211
+ return def.size;
212
+ }
213
+
214
+ throw new TypeError(`writeValue: unsupported type ${type}`);
215
+ }
216
+
217
+ /**
218
+ * Returns the size in bytes of a type or type instance.
219
+ *
220
+ * **Supported Inputs**:
221
+ * - SimpleCData classes (c_int32, c_uint64, etc.)
222
+ * - SimpleCData instances (new c_int32())
223
+ * - Structure classes (user-defined structs)
224
+ * - Union classes (user-defined unions)
225
+ * - Struct/Union definition objects
226
+ * - Array type objects
227
+ *
228
+ * **Python ctypes Compatibility**:
229
+ * Direct equivalent to Python's `ctypes.sizeof()`.
230
+ *
231
+ * @param {Function|Object} type - Type or instance to get size of
232
+ * @param {Function} Structure - Structure class reference
233
+ * @param {Function} Union - Union class reference
234
+ * @returns {number} Size in bytes
235
+ * @throws {TypeError} If type is unsupported
236
+ *
237
+ * @example Primitive type sizes
238
+ * ```javascript
239
+ * import { sizeof, c_int32, c_uint64, c_double } from 'node-ctypes';
240
+ *
241
+ * console.log(sizeof(c_int32)); // 4
242
+ * console.log(sizeof(c_uint64)); // 8
243
+ * console.log(sizeof(c_double)); // 8
244
+ * ```
245
+ *
246
+ * @example Struct size
247
+ * ```javascript
248
+ * class Point extends Structure {
249
+ * static _fields_ = [['x', c_int32], ['y', c_int32]];
250
+ * }
251
+ *
252
+ * console.log(sizeof(Point)); // 8
253
+ * ```
254
+ *
255
+ * @example Instance size
256
+ * ```javascript
257
+ * const val = new c_int32(42);
258
+ * console.log(sizeof(val)); // 4
259
+ * ```
260
+ */
261
+ export function sizeof(type, Structure, Union) {
262
+ // SimpleCData class (e.g., sizeof(c_uint64))
263
+ if (typeof type === "function" && type._isSimpleCData) {
264
+ return type._size;
265
+ }
266
+
267
+ // SimpleCData instance (e.g., sizeof(new c_uint64()))
268
+ if (type && type._buffer && type.constructor && type.constructor._isSimpleCData) {
269
+ return type.constructor._size;
270
+ }
271
+
272
+ // Struct type (class)
273
+ if (typeof type === "function" && type.prototype instanceof Structure) {
274
+ const def = type._structDef || type._buildStruct();
275
+ return def.size;
276
+ }
277
+
278
+ // Union type (class)
279
+ if (typeof type === "function" && type.prototype instanceof Union) {
280
+ const def = type._unionDef || type._buildUnion();
281
+ return def.size;
282
+ }
283
+
284
+ // Struct/Union definition object
285
+ if (typeof type === "object" && type !== null && typeof type.size === "number") {
286
+ return type.size;
287
+ }
288
+
289
+ // Array type
290
+ if (typeof type === "object" && type !== null && typeof type.getSize === "function") {
291
+ return type.getSize();
292
+ }
293
+
294
+ throw new TypeError(`sizeof: unsupported type. Use SimpleCData classes like c_int32, c_uint64, etc.`);
295
+ }