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.

@@ -0,0 +1,392 @@
1
+ /**
2
+ * @file primitives.js
3
+ * @module types/primitives
4
+ * @description Primitive C type definitions (integers, floats, chars, pointers).
5
+ *
6
+ * This module provides all primitive C types that extend SimpleCData. Each type
7
+ * defines its size, type name, and read/write functions for buffer operations.
8
+ *
9
+ * **Python ctypes Compatibility**:
10
+ * All types are compatible with Python's ctypes module equivalents.
11
+ *
12
+ * @example Using integer types
13
+ * ```javascript
14
+ * import { c_int32, c_uint64 } from 'node-ctypes';
15
+ *
16
+ * const x = new c_int32(42);
17
+ * console.log(x.value); // 42
18
+ * x.value = -100;
19
+ *
20
+ * const big = new c_uint64(9007199254740991n);
21
+ * console.log(big.value); // 9007199254740991n
22
+ * ```
23
+ *
24
+ * @example Using float types
25
+ * ```javascript
26
+ * import { c_float, c_double } from 'node-ctypes';
27
+ *
28
+ * const pi = new c_float(3.14159);
29
+ * console.log(pi.value); // ~3.1415898799896240 (float precision)
30
+ *
31
+ * const precise = new c_double(3.141592653589793);
32
+ * console.log(precise.value); // 3.141592653589793
33
+ * ```
34
+ *
35
+ * @example Using character types
36
+ * ```javascript
37
+ * import { c_char, c_wchar } from 'node-ctypes';
38
+ *
39
+ * const ch = new c_char('A'.charCodeAt(0));
40
+ * console.log(ch.value); // 65
41
+ *
42
+ * const wide = new c_wchar(0x4E2D); // Chinese character
43
+ * console.log(wide.value); // 20013
44
+ * ```
45
+ *
46
+ * @example Using pointer types
47
+ * ```javascript
48
+ * import { c_void_p, c_char_p } from 'node-ctypes';
49
+ *
50
+ * const ptr = new c_void_p(0x1234n);
51
+ * console.log(ptr.value); // 4660n
52
+ *
53
+ * const str = new c_char_p("Hello");
54
+ * console.log(str.value); // "Hello"
55
+ * ```
56
+ */
57
+
58
+ /**
59
+ * Creates all primitive type classes with required dependencies injected.
60
+ *
61
+ * @param {Class} SimpleCData - SimpleCData base class
62
+ * @param {Object} native - Native module with POINTER_SIZE
63
+ * @param {Function} addressOf - addressOf function for pointers
64
+ * @param {Function} cstring - cstring function for c_char_p
65
+ * @param {Function} wstring - wstring function for c_wchar_p
66
+ * @param {Function} readCString - readCString function for c_char_p
67
+ * @param {Function} readWString - readWString function for c_wchar_p
68
+ * @returns {Object} Object containing all primitive type classes
69
+ * @private
70
+ */
71
+ export function createPrimitiveTypes(SimpleCData, native, addressOf, cstring, wstring, readCString, readWString) {
72
+ // ============================================================================
73
+ // Void type
74
+ // ============================================================================
75
+
76
+ class c_void extends SimpleCData {
77
+ static _size = 0;
78
+ static _type = "void";
79
+ static _reader = (buf, off) => undefined;
80
+ static _writer = (buf, off, val) => {};
81
+ }
82
+
83
+ // ============================================================================
84
+ // Integer types - signed
85
+ // ============================================================================
86
+
87
+ class c_int8 extends SimpleCData {
88
+ static _size = 1;
89
+ static _type = "int8";
90
+ static _reader = (buf, off) => buf.readInt8(off);
91
+ static _writer = (buf, off, val) => buf.writeInt8(val, off);
92
+ }
93
+
94
+ class c_int16 extends SimpleCData {
95
+ static _size = 2;
96
+ static _type = "int16";
97
+ static _reader = (buf, off) => buf.readInt16LE(off);
98
+ static _writer = (buf, off, val) => buf.writeInt16LE(val, off);
99
+ }
100
+
101
+ class c_int32 extends SimpleCData {
102
+ static _size = 4;
103
+ static _type = "int32";
104
+ static _reader = (buf, off) => buf.readInt32LE(off);
105
+ static _writer = (buf, off, val) => {
106
+ const v = Number(val) | 0; // coerce to signed 32-bit
107
+ return buf.writeInt32LE(v, off);
108
+ };
109
+ }
110
+
111
+ class c_int64 extends SimpleCData {
112
+ static _size = 8;
113
+ static _type = "int64";
114
+ static _reader = (buf, off) => buf.readBigInt64LE(off);
115
+ static _writer = (buf, off, val) => buf.writeBigInt64LE(BigInt(val), off);
116
+ }
117
+
118
+ // ============================================================================
119
+ // Integer types - unsigned
120
+ // ============================================================================
121
+
122
+ class c_uint8 extends SimpleCData {
123
+ static _size = 1;
124
+ static _type = "uint8";
125
+ static _reader = (buf, off) => buf.readUInt8(off);
126
+ static _writer = (buf, off, val) => buf.writeUInt8(val, off);
127
+ }
128
+
129
+ class c_uint16 extends SimpleCData {
130
+ static _size = 2;
131
+ static _type = "uint16";
132
+ static _reader = (buf, off) => buf.readUInt16LE(off);
133
+ static _writer = (buf, off, val) => buf.writeUInt16LE(val, off);
134
+ }
135
+
136
+ class c_uint32 extends SimpleCData {
137
+ static _size = 4;
138
+ static _type = "uint32";
139
+ static _reader = (buf, off) => buf.readUInt32LE(off);
140
+ static _writer = (buf, off, val) => {
141
+ const v = Number(val) >>> 0; // coerce to unsigned 32-bit
142
+ return buf.writeUInt32LE(v, off);
143
+ };
144
+ }
145
+
146
+ class c_uint64 extends SimpleCData {
147
+ static _size = 8;
148
+ static _type = "uint64";
149
+ static _reader = (buf, off) => buf.readBigUInt64LE(off);
150
+ static _writer = (buf, off, val) => buf.writeBigUInt64LE(BigInt(val), off);
151
+ }
152
+
153
+ // ============================================================================
154
+ // Floating point types
155
+ // ============================================================================
156
+
157
+ class c_float extends SimpleCData {
158
+ static _size = 4;
159
+ static _type = "float";
160
+ static _reader = (buf, off) => buf.readFloatLE(off);
161
+ static _writer = (buf, off, val) => buf.writeFloatLE(val, off);
162
+ }
163
+
164
+ class c_double extends SimpleCData {
165
+ static _size = 8;
166
+ static _type = "double";
167
+ static _reader = (buf, off) => buf.readDoubleLE(off);
168
+ static _writer = (buf, off, val) => buf.writeDoubleLE(val, off);
169
+ }
170
+
171
+ // ============================================================================
172
+ // Boolean type
173
+ // ============================================================================
174
+
175
+ class c_bool extends SimpleCData {
176
+ static _size = 1;
177
+ static _type = "bool";
178
+ static _reader = (buf, off) => buf.readUInt8(off) !== 0;
179
+ static _writer = (buf, off, val) => buf.writeUInt8(val ? 1 : 0, off);
180
+ }
181
+
182
+ // ============================================================================
183
+ // Character types
184
+ // ============================================================================
185
+
186
+ class c_char extends SimpleCData {
187
+ static _size = 1;
188
+ static _type = "char";
189
+ static _reader = (buf, off) => buf.readInt8(off);
190
+ static _writer = (buf, off, val) => {
191
+ if (typeof val === "string") val = val.charCodeAt(0);
192
+ buf.writeInt8(val, off);
193
+ };
194
+ }
195
+
196
+ class c_wchar extends SimpleCData {
197
+ static _size = native.WCHAR_SIZE || 4;
198
+ static _type = "wchar";
199
+ static _reader = (buf, off) => {
200
+ return this._size === 2 ? buf.readUInt16LE(off) : buf.readUInt32LE(off);
201
+ };
202
+ static _writer = (buf, off, val) => {
203
+ if (typeof val === "string") val = val.charCodeAt(0);
204
+ if (this._size === 2) {
205
+ buf.writeUInt16LE(val, off);
206
+ } else {
207
+ buf.writeUInt32LE(val, off);
208
+ }
209
+ };
210
+ }
211
+
212
+ // ============================================================================
213
+ // Pointer types
214
+ // ============================================================================
215
+
216
+ class c_void_p extends SimpleCData {
217
+ static _size = native.POINTER_SIZE;
218
+ static _type = "pointer";
219
+ static _reader = (buf, off) => {
220
+ return native.POINTER_SIZE === 8 ? buf.readBigUInt64LE(off) : BigInt(buf.readUInt32LE(off));
221
+ };
222
+ static _writer = (buf, off, val) => {
223
+ const v = typeof val === "bigint" ? val : BigInt(val || 0);
224
+ if (native.POINTER_SIZE === 8) {
225
+ buf.writeBigUInt64LE(v, off);
226
+ } else {
227
+ buf.writeUInt32LE(Number(v), off);
228
+ }
229
+ };
230
+ }
231
+
232
+ // ============================================================================
233
+ // Platform-specific types
234
+ // ============================================================================
235
+
236
+ class c_size_t extends SimpleCData {
237
+ static _size = native.POINTER_SIZE;
238
+ static _type = "size_t";
239
+ static _reader = (buf, off) => {
240
+ return native.POINTER_SIZE === 8 ? buf.readBigUInt64LE(off) : buf.readUInt32LE(off);
241
+ };
242
+ static _writer = (buf, off, val) => {
243
+ if (native.POINTER_SIZE === 8) {
244
+ buf.writeBigUInt64LE(BigInt(val), off);
245
+ } else {
246
+ buf.writeUInt32LE(Number(val), off);
247
+ }
248
+ };
249
+ }
250
+
251
+ class c_long extends SimpleCData {
252
+ static _size = native.POINTER_SIZE;
253
+ static _type = "long";
254
+ static _reader = c_size_t._reader;
255
+ static _writer = c_size_t._writer;
256
+ }
257
+
258
+ class c_ulong extends SimpleCData {
259
+ static _size = native.POINTER_SIZE;
260
+ static _type = "ulong";
261
+ static _reader = (buf, off) => {
262
+ return native.POINTER_SIZE === 8 ? buf.readBigUInt64LE(off) : buf.readUInt32LE(off);
263
+ };
264
+ static _writer = (buf, off, val) => {
265
+ if (native.POINTER_SIZE === 8) {
266
+ buf.writeBigUInt64LE(BigInt(val), off);
267
+ } else {
268
+ buf.writeUInt32LE(Number(val), off);
269
+ }
270
+ };
271
+ }
272
+
273
+ // ============================================================================
274
+ // String pointer types (special handling)
275
+ // ============================================================================
276
+
277
+ class c_char_p extends SimpleCData {
278
+ static _size = native.POINTER_SIZE;
279
+ static _type = "char_p";
280
+ static _reader = (buf, off) => {
281
+ const ptr = native.POINTER_SIZE === 8 ? buf.readBigUInt64LE(off) : BigInt(buf.readUInt32LE(off));
282
+ if (!ptr) return null;
283
+ return readCString(ptr);
284
+ };
285
+ static _writer = (buf, off, val) => {
286
+ if (typeof val === "string") {
287
+ val = cstring(val);
288
+ }
289
+ if (Buffer.isBuffer(val)) {
290
+ const addr = addressOf(val);
291
+ const v = typeof addr === "bigint" ? addr : BigInt(addr || 0);
292
+ if (native.POINTER_SIZE === 8) {
293
+ buf.writeBigUInt64LE(v, off);
294
+ } else {
295
+ buf.writeUInt32LE(Number(v), off);
296
+ }
297
+ } else {
298
+ const v = typeof val === "bigint" ? val : BigInt(val || 0);
299
+ if (native.POINTER_SIZE === 8) {
300
+ buf.writeBigUInt64LE(v, off);
301
+ } else {
302
+ buf.writeUInt32LE(Number(v), off);
303
+ }
304
+ }
305
+ };
306
+ }
307
+
308
+ class c_wchar_p extends SimpleCData {
309
+ static _size = native.POINTER_SIZE;
310
+ static _type = "wchar_p";
311
+ static _reader = (buf, off) => {
312
+ const ptr = native.POINTER_SIZE === 8 ? buf.readBigUInt64LE(off) : BigInt(buf.readUInt32LE(off));
313
+ if (!ptr) return null;
314
+ return readWString(ptr);
315
+ };
316
+ static _writer = (buf, off, val) => {
317
+ if (typeof val === "string") {
318
+ val = wstring(val);
319
+ }
320
+ if (Buffer.isBuffer(val)) {
321
+ const addr = addressOf(val);
322
+ const v = typeof addr === "bigint" ? addr : BigInt(addr || 0);
323
+ if (native.POINTER_SIZE === 8) {
324
+ buf.writeBigUInt64LE(v, off);
325
+ } else {
326
+ buf.writeUInt32LE(Number(v), off);
327
+ }
328
+ } else {
329
+ const v = typeof val === "bigint" ? val : BigInt(val || 0);
330
+ if (native.POINTER_SIZE === 8) {
331
+ buf.writeBigUInt64LE(v, off);
332
+ } else {
333
+ buf.writeUInt32LE(Number(v), off);
334
+ }
335
+ }
336
+ };
337
+ }
338
+
339
+ // ============================================================================
340
+ // Python-compatible aliases
341
+ // ============================================================================
342
+
343
+ const c_byte = c_int8;
344
+ const c_ubyte = c_uint8;
345
+ const c_short = c_int16;
346
+ const c_ushort = c_uint16;
347
+ const c_int = c_int32;
348
+ const c_uint = c_uint32;
349
+ const c_longlong = c_int64;
350
+ const c_ulonglong = c_uint64;
351
+
352
+ // Return all types
353
+ return {
354
+ // Void
355
+ c_void,
356
+ // Signed integers
357
+ c_int8,
358
+ c_int16,
359
+ c_int32,
360
+ c_int64,
361
+ // Unsigned integers
362
+ c_uint8,
363
+ c_uint16,
364
+ c_uint32,
365
+ c_uint64,
366
+ // Floating point
367
+ c_float,
368
+ c_double,
369
+ // Boolean
370
+ c_bool,
371
+ // Characters
372
+ c_char,
373
+ c_wchar,
374
+ // Pointers
375
+ c_void_p,
376
+ c_char_p,
377
+ c_wchar_p,
378
+ // Platform-specific
379
+ c_size_t,
380
+ c_long,
381
+ c_ulong,
382
+ // Python-compatible aliases
383
+ c_byte,
384
+ c_ubyte,
385
+ c_short,
386
+ c_ushort,
387
+ c_int,
388
+ c_uint,
389
+ c_longlong,
390
+ c_ulonglong,
391
+ };
392
+ }
@@ -0,0 +1,142 @@
1
+ /**
2
+ * @file cache.js
3
+ * @module utils/cache
4
+ * @description Simple LRU (Least Recently Used) cache implementation for function caching.
5
+ * Prevents unbounded memory growth in long-running applications.
6
+ *
7
+ * @example
8
+ * import { LRUCache } from './utils/cache.js';
9
+ *
10
+ * const cache = new LRUCache(1000); // Max 1000 entries
11
+ * cache.set('key1', 'value1');
12
+ * const value = cache.get('key1'); // 'value1'
13
+ */
14
+
15
+ /**
16
+ * LRU Cache implementation using Map for O(1) operations.
17
+ * When the cache reaches maxSize, the least recently used item is evicted.
18
+ *
19
+ * @class LRUCache
20
+ * @example
21
+ * const cache = new LRUCache(100);
22
+ * cache.set('user:1', { name: 'John' });
23
+ * cache.get('user:1'); // { name: 'John' }
24
+ * cache.has('user:1'); // true
25
+ * cache.size; // 1
26
+ */
27
+ export class LRUCache {
28
+ /**
29
+ * Creates a new LRU cache instance
30
+ * @param {number} [maxSize=1000] - Maximum number of entries before eviction
31
+ */
32
+ constructor(maxSize = 1000) {
33
+ /**
34
+ * Maximum cache size before LRU eviction
35
+ * @type {number}
36
+ * @private
37
+ */
38
+ this.maxSize = maxSize;
39
+
40
+ /**
41
+ * Internal Map storage for cache entries
42
+ * Map maintains insertion order, which we use for LRU tracking
43
+ * @type {Map<string, any>}
44
+ * @private
45
+ */
46
+ this.cache = new Map();
47
+ }
48
+
49
+ /**
50
+ * Retrieves a value from the cache and marks it as recently used.
51
+ * Moves the entry to the end of the Map (most recently used position).
52
+ *
53
+ * @param {string} key - Cache key to retrieve
54
+ * @returns {any|undefined} The cached value, or undefined if not found
55
+ *
56
+ * @example
57
+ * cache.set('key', 'value');
58
+ * cache.get('key'); // 'value'
59
+ * cache.get('missing'); // undefined
60
+ */
61
+ get(key) {
62
+ if (!this.cache.has(key)) {
63
+ return undefined;
64
+ }
65
+
66
+ // Move to end (most recently used) by deleting and re-inserting
67
+ const value = this.cache.get(key);
68
+ this.cache.delete(key);
69
+ this.cache.set(key, value);
70
+ return value;
71
+ }
72
+
73
+ /**
74
+ * Adds or updates a value in the cache.
75
+ * If the key exists, it's moved to the most recently used position.
76
+ * If the cache is full, the least recently used entry is evicted.
77
+ *
78
+ * @param {string} key - Cache key
79
+ * @param {any} value - Value to store
80
+ *
81
+ * @example
82
+ * cache.set('user:1', { name: 'John' });
83
+ * cache.set('user:1', { name: 'Jane' }); // Updates existing entry
84
+ */
85
+ set(key, value) {
86
+ // If key exists, remove it first (will re-add at end)
87
+ if (this.cache.has(key)) {
88
+ this.cache.delete(key);
89
+ }
90
+ // If at capacity, evict oldest entry (first in Map)
91
+ else if (this.cache.size >= this.maxSize) {
92
+ const firstKey = this.cache.keys().next().value;
93
+ this.cache.delete(firstKey);
94
+ }
95
+
96
+ // Add to end (most recently used position)
97
+ this.cache.set(key, value);
98
+ }
99
+
100
+ /**
101
+ * Checks if a key exists in the cache.
102
+ * Does NOT update the LRU position.
103
+ *
104
+ * @param {string} key - Cache key to check
105
+ * @returns {boolean} True if the key exists
106
+ *
107
+ * @example
108
+ * cache.set('key', 'value');
109
+ * cache.has('key'); // true
110
+ * cache.has('missing'); // false
111
+ */
112
+ has(key) {
113
+ return this.cache.has(key);
114
+ }
115
+
116
+ /**
117
+ * Removes all entries from the cache.
118
+ *
119
+ * @example
120
+ * cache.set('key1', 'value1');
121
+ * cache.set('key2', 'value2');
122
+ * cache.clear();
123
+ * cache.size; // 0
124
+ */
125
+ clear() {
126
+ this.cache.clear();
127
+ }
128
+
129
+ /**
130
+ * Returns the current number of entries in the cache.
131
+ *
132
+ * @returns {number} Number of cached entries
133
+ *
134
+ * @example
135
+ * cache.set('key1', 'value1');
136
+ * cache.set('key2', 'value2');
137
+ * cache.size; // 2
138
+ */
139
+ get size() {
140
+ return this.cache.size;
141
+ }
142
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "node-ctypes",
3
- "version": "0.1.7",
3
+ "version": "1.0.0",
4
4
  "description": "Python ctypes-like FFI for Node.js using libffi",
5
5
  "author": "Damiano Mazzella",
6
6
  "license": "MIT",