bun-memory 1.1.0 → 1.1.2

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/package.json CHANGED
@@ -22,7 +22,7 @@
22
22
  "url": "git://github.com/obscuritysrl/bun-memory.git"
23
23
  },
24
24
  "type": "module",
25
- "version": "1.1.0",
25
+ "version": "1.1.2",
26
26
  "main": "./index.ts",
27
27
  "keywords": [
28
28
  "bun",
@@ -37,7 +37,9 @@
37
37
  ],
38
38
  "files": [
39
39
  "index.ts",
40
+ "runtime/*.ts",
40
41
  "structs/*.ts",
42
+ "types/*.ts",
41
43
  "README.md",
42
44
  "LICENSE"
43
45
  ],
@@ -0,0 +1,238 @@
1
+ /**
2
+ * Runtime definition of a non-enumerable `ptr` getter on Buffer and TypedArray
3
+ * prototypes, returning a native pointer compatible with Bun's FFI layer.
4
+ *
5
+ * This module extends common JavaScript binary view objects (Buffer, TypedArrays, etc.)
6
+ * with a `.ptr` property that provides direct access to the underlying memory address.
7
+ * This pairs with the ambient declarations in `global.d.ts` so that common
8
+ * JavaScript binary views expose a strongly-typed `.ptr` for direct FFI calls.
9
+ *
10
+ * The `ptr` property enables seamless integration between JavaScript memory views
11
+ * and native code through Bun's Foreign Function Interface, allowing efficient
12
+ * data exchange without additional copying or marshaling overhead.
13
+ *
14
+ * @remarks
15
+ * - The property is added lazily only if not already present, avoiding conflicts
16
+ * - The getter calls `bun:ffi.ptr(this)` each time it is accessed; avoid calling
17
+ * it in tight loops when the value can be reused for performance
18
+ * - The property is **non-enumerable** and **configurable**, minimizing surface
19
+ * area and allowing controlled redefinition in tests if necessary
20
+ * - Requires Bun runtime environment (uses `bun:ffi`)
21
+ * - Properties are installed on prototype objects, affecting all instances
22
+ *
23
+ * @example
24
+ * ```typescript
25
+ * import './extensions'; // Import to install ptr getters
26
+ *
27
+ * // Create various binary views
28
+ * const buffer = Buffer.from([1, 2, 3, 4]);
29
+ * const floats = new Float32Array([1.0, 2.0, 3.0]);
30
+ * const ints = new Int32Array([100, 200, 300]);
31
+ *
32
+ * // Access native pointers for FFI calls
33
+ * console.log('Buffer pointer:', buffer.ptr);
34
+ * console.log('Float array pointer:', floats.ptr);
35
+ * console.log('Int array pointer:', ints.ptr);
36
+ *
37
+ * // Use in FFI function calls
38
+ * const success = someNativeFunction(buffer.ptr, buffer.length);
39
+ * ```
40
+ *
41
+ * @example
42
+ * ```typescript
43
+ * import './extensions';
44
+ * import { dlopen, FFIType } from 'bun:ffi';
45
+ *
46
+ * const { symbols } = dlopen('user32.dll', {
47
+ * MessageBoxA: {
48
+ * args: [FFIType.ptr, FFIType.cstring, FFIType.cstring, FFIType.u32],
49
+ * returns: FFIType.i32
50
+ * }
51
+ * });
52
+ *
53
+ * // Create message text in a buffer
54
+ * const messageText = Buffer.from('Hello from FFI!\0', 'utf8');
55
+ * const titleText = Buffer.from('Notification\0', 'utf8');
56
+ *
57
+ * // Use .ptr property to pass buffer addresses to native function
58
+ * symbols.MessageBoxA(0n, messageText.ptr, titleText.ptr, 0);
59
+ * ```
60
+ *
61
+ * @example
62
+ * ```typescript
63
+ * import './extensions';
64
+ *
65
+ * function processAudioData(samples: Float32Array) {
66
+ * // Cache the pointer for multiple uses in tight loop
67
+ * const samplePtr = samples.ptr;
68
+ *
69
+ * for (let i = 0; i < 100; i++) {
70
+ * // Use cached pointer instead of accessing .ptr repeatedly
71
+ * processAudioBuffer(samplePtr, samples.length);
72
+ * }
73
+ * }
74
+ * ```
75
+ */
76
+
77
+ import { ptr, type Pointer } from 'bun:ffi';
78
+
79
+ /**
80
+ * List of binary view constructor functions whose prototypes will be extended
81
+ * with the `ptr` getter property.
82
+ *
83
+ * This array contains all the standard JavaScript binary data types that can
84
+ * hold raw memory data. Each type is extended with a `ptr` getter that returns
85
+ * a native pointer compatible with Bun's FFI system.
86
+ *
87
+ * Supported types:
88
+ * - **ArrayBuffer**: Raw binary data buffer
89
+ * - **SharedArrayBuffer**: Shared memory buffer for worker threads
90
+ * - **Buffer**: Node.js/Bun Buffer object (subclass of Uint8Array)
91
+ * - **DataView**: View for reading/writing various data types from ArrayBuffer
92
+ * - **Typed Arrays**: All standard typed array types for specific numeric types
93
+ * - Int8Array, Uint8Array, Uint8ClampedArray (8-bit integers)
94
+ * - Int16Array, Uint16Array (16-bit integers)
95
+ * - Int32Array, Uint32Array (32-bit integers)
96
+ * - BigInt64Array, BigUint64Array (64-bit integers)
97
+ * - Float32Array, Float64Array (floating-point numbers)
98
+ *
99
+ * @example
100
+ * ```typescript
101
+ * // All these types will have .ptr available after importing extensions
102
+ * const arrayBuffer = new ArrayBuffer(1024);
103
+ * const sharedBuffer = new SharedArrayBuffer(512);
104
+ * const nodeBuffer = Buffer.allocUnsafe(256);
105
+ * const dataView = new DataView(arrayBuffer);
106
+ * const int32View = new Int32Array(arrayBuffer);
107
+ * const float64View = new Float64Array(8);
108
+ *
109
+ * // Each can provide its native pointer
110
+ * console.log(arrayBuffer.ptr, sharedBuffer.ptr, nodeBuffer.ptr);
111
+ * console.log(dataView.ptr, int32View.ptr, float64View.ptr);
112
+ * ```
113
+ */
114
+ const constructors = [
115
+ ArrayBuffer, //
116
+ BigInt64Array,
117
+ BigUint64Array,
118
+ Buffer,
119
+ DataView,
120
+ Float32Array,
121
+ Float64Array,
122
+ Int16Array,
123
+ Int32Array,
124
+ Int8Array,
125
+ SharedArrayBuffer,
126
+ Uint16Array,
127
+ Uint8Array,
128
+ Uint8ClampedArray,
129
+ Uint32Array,
130
+ ] as const;
131
+
132
+ /**
133
+ * Install the `ptr` getter on common binary view prototypes if not already present.
134
+ *
135
+ * This code iterates through all supported binary view types and adds a non-enumerable
136
+ * `ptr` getter property to each prototype. The getter calls `bun:ffi.ptr()` to obtain
137
+ * the native memory address of the underlying buffer.
138
+ *
139
+ * The property is only added if it doesn't already exist, preventing conflicts with
140
+ * existing implementations or multiple imports of this module.
141
+ *
142
+ * Property characteristics:
143
+ * - **configurable: true** - Can be reconfigured or deleted if needed
144
+ * - **enumerable: false** - Won't appear in Object.keys() or for...in loops
145
+ * - **get function** - Computed property that calls bun:ffi.ptr() on each access
146
+ *
147
+ * @example
148
+ * ```typescript
149
+ * // Before importing extensions
150
+ * const buffer = Buffer.from([1, 2, 3]);
151
+ * console.log(buffer.ptr); // undefined or TypeError
152
+ *
153
+ * // After importing extensions
154
+ * import './extensions';
155
+ * console.log(buffer.ptr); // Pointer { [native pointer address] }
156
+ * ```
157
+ *
158
+ * @example
159
+ * ```typescript
160
+ * // Property is non-enumerable
161
+ * const array = new Uint8Array([1, 2, 3]);
162
+ * console.log(Object.keys(array)); // ['0', '1', '2'] - ptr not included
163
+ * console.log(array.ptr); // Pointer { [native pointer address] } - but still accessible
164
+ * ```
165
+ *
166
+ * @example
167
+ * ```typescript
168
+ * // Property can be reconfigured if needed (for testing, etc.)
169
+ * const mockPtr = { mockPointer: true };
170
+ * Object.defineProperty(Uint8Array.prototype, 'ptr', {
171
+ * configurable: true,
172
+ * enumerable: false,
173
+ * value: mockPtr
174
+ * });
175
+ *
176
+ * const testArray = new Uint8Array([1, 2, 3]);
177
+ * console.log(testArray.ptr); // { mockPointer: true }
178
+ * ```
179
+ */
180
+ constructors.forEach(({ prototype }) => {
181
+ if (!Object.getOwnPropertyDescriptor(prototype, 'ptr')) {
182
+ Object.defineProperty(prototype, 'ptr', {
183
+ configurable: true,
184
+ enumerable: false,
185
+ /**
186
+ * Getter function that returns a native pointer to the underlying memory.
187
+ *
188
+ * This getter calls `bun:ffi.ptr()` each time the property is accessed to
189
+ * obtain the current memory address of the buffer. The pointer is computed
190
+ * on-demand to ensure it reflects the current state of the buffer.
191
+ *
192
+ * **Important Performance Note**: The pointer is computed on every access.
193
+ * In performance-critical code with repeated FFI calls, cache the pointer
194
+ * value in a local variable rather than accessing this property repeatedly.
195
+ *
196
+ * **Memory Safety**: The returned pointer is only valid as long as the
197
+ * buffer exists and hasn't been reallocated. Do not store pointers long-term
198
+ * across garbage collection cycles or buffer resizing operations.
199
+ *
200
+ * @returns Native pointer compatible with Bun FFI system
201
+ *
202
+ * @example
203
+ * ```typescript
204
+ * const data = new Float32Array([1.0, 2.0, 3.0, 4.0]);
205
+ *
206
+ * // Inefficient: ptr computed on each call
207
+ * for (let i = 0; i < 1000; i++) {
208
+ * processData(data.ptr, data.length); // ptr computed 1000 times!
209
+ * }
210
+ *
211
+ * // Efficient: cache the pointer
212
+ * const dataPtr = data.ptr; // Computed once
213
+ * for (let i = 0; i < 1000; i++) {
214
+ * processData(dataPtr, data.length); // Reuse cached pointer
215
+ * }
216
+ * ```
217
+ *
218
+ * @example
219
+ * ```typescript
220
+ * // Pointer reflects current buffer state
221
+ * const buffer = Buffer.alloc(10);
222
+ * const ptr1 = buffer.ptr;
223
+ *
224
+ * // Buffer might be reallocated internally
225
+ * buffer.write('Hello World', 0); // May cause reallocation
226
+ * const ptr2 = buffer.ptr;
227
+ *
228
+ * // ptr1 and ptr2 might be different if reallocation occurred
229
+ * console.log('Same pointer?', ptr1 === ptr2);
230
+ * ```
231
+ */
232
+ get(this): Pointer {
233
+ // The pointer is computed on demand; do not cache across GC or growth.
234
+ return ptr(this);
235
+ },
236
+ });
237
+ }
238
+ });