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 +3 -1
- package/runtime/extensions.ts +238 -0
- package/types/Memory.ts +734 -0
- package/types/global.d.ts +751 -0
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.
|
|
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
|
+
});
|