diff --git a/examples/js_dsl/mod.test.ts b/examples/js_dsl/mod.test.ts index 01b7ad4..9c195e0 100644 --- a/examples/js_dsl/mod.test.ts +++ b/examples/js_dsl/mod.test.ts @@ -148,6 +148,18 @@ describe("typed arrays", () => { expect(result).toBeInstanceOf(Float64Array); expect(Array.from(result)).toEqual([2.5, 5.0, 7.5]); }); + + it("allocUint8 allocates and fills via alloc pattern", () => { + const result = mod.allocUint8(5); + expect(result).toBeInstanceOf(Uint8Array); + expect(Array.from(result)).toEqual([0, 1, 2, 3, 4]); + }); + + it("allocUint8 with zero length", () => { + const result = mod.allocUint8(0); + expect(result).toBeInstanceOf(Uint8Array); + expect(result.length).toEqual(0); + }); }); // Section 7: Promises diff --git a/examples/js_dsl/mod.zig b/examples/js_dsl/mod.zig index 4d29d82..b46afa8 100644 --- a/examples/js_dsl/mod.zig +++ b/examples/js_dsl/mod.zig @@ -178,6 +178,18 @@ pub fn float64Scale(data: Float64Array, factor: Number) !Float64Array { return Float64Array.from(scaled); } +/// Allocate a Uint8Array of given length and fill with 0, 1, 2, ... +/// Demonstrates the zero-copy alloc + toSlice pattern. +pub fn allocUint8(len: Number) !Uint8Array { + const n: usize = @intCast(len.assertU32()); + var arr = try Uint8Array.alloc(n); + const out = try arr.toSlice(); + for (out, 0..) |*byte, i| { + byte.* = @truncate(i); + } + return arr; +} + // ============================================================================ // Section 7: Promises // ============================================================================ diff --git a/src/js/typed_arrays.zig b/src/js/typed_arrays.zig index f053085..d2edae0 100644 --- a/src/js/typed_arrays.zig +++ b/src/js/typed_arrays.zig @@ -67,6 +67,28 @@ pub fn TypedArray(comptime Element: type, comptime array_type: TypedarrayType) t return .{ .val = val }; } + /// Allocates a new JavaScript TypedArray of the given length backed by + /// freshly allocated V8 memory. The contents are uninitialized. + /// + /// Use `toSlice()` on the returned value to get a writable slice into + /// the V8 ArrayBuffer backing store, then fill it before returning to JS. + /// + /// This is the zero-copy construction path for when the size is known + /// upfront and the producer can write directly into a target buffer + /// (e.g. serialization). For cases where data already exists in a Zig + /// slice, use `from(slice)` instead. + /// + /// WARNING: The same lifetime caveats as `toSlice()` apply — the backing + /// store is only valid within the current N-API callback scope. + pub fn alloc(len: usize) !Self { + const e = context.env(); + const byte_len = len * @sizeOf(Element); + var buf_ptr: [*]u8 = undefined; + const arraybuffer = try e.createArrayBuffer(byte_len, &buf_ptr); + const val = try e.createTypedarray(array_type, len, arraybuffer, 0); + return .{ .val = val }; + } + /// Returns the underlying `napi.Value` representation of this JavaScript TypedArray. pub fn toValue(self: Self) napi.Value { return self.val;