From 52418932b11e248bbac128d6a7b03dcc15327587 Mon Sep 17 00:00:00 2001 From: Halil Durak Date: Sun, 15 Feb 2026 02:03:11 +0300 Subject: [PATCH] `simpleZigValueToJs`: support `Uint8ClampedArray` Needed this to implement `ImageData#data` getter. This works differently than other typed arrays since returned object can be mutated from both Zig and JS ends. --- src/browser/js/js.zig | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/src/browser/js/js.zig b/src/browser/js/js.zig index 49842fa7..cd569b09 100644 --- a/src/browser/js/js.zig +++ b/src/browser/js/js.zig @@ -77,6 +77,14 @@ pub const ArrayBuffer = struct { } }; +/// `mutable` indicates bytes are not copied by `simpleZigValueToJs`; +/// instead, `BackingStore` takes ownership of already allocated `values`. +pub fn Uint8ClampedArray(comptime state: enum(u1) { immutable, mutable }) type { + return struct { + values: if (state == .mutable) []u8 else []const u8, + }; +} + pub const Exception = struct { local: *const Local, handle: *const v8.Value, @@ -194,6 +202,24 @@ pub fn simpleZigValueToJs(isolate: Isolate, value: anytype, comptime fail: bool, // but this can never be valid. @compileError("Invalid TypeArray type: " ++ @typeName(value_type)); }, + Uint8ClampedArray(.mutable) => { + const values = value.values; + const len = values.len; + var array_buffer: *const v8.ArrayBuffer = undefined; + if (len == 0) { + array_buffer = v8.v8__ArrayBuffer__New(isolate.handle, 0).?; + } else { + // `deleter` cannot be null. + const empty_deleter = struct { + fn deleter(_: ?*anyopaque, _: usize, _: ?*anyopaque) callconv(.c) void {} + }.deleter; + const backing_store = v8.v8__ArrayBuffer__NewBackingStore2(values.ptr, len, empty_deleter, null); + const backing_store_ptr = v8.v8__BackingStore__TO_SHARED_PTR(backing_store); + // Attach store to array buffer. + array_buffer = v8.v8__ArrayBuffer__New2(isolate.handle, &backing_store_ptr).?; + } + return @ptrCast(v8.v8__Uint8ClampedArray__New(array_buffer, 0, len)); + }, inline String, BigInt, Integer, Number, Value, Object => return value.handle, else => {}, }