diff --git a/src/browser/js/Array.zig b/src/browser/js/Array.zig index 95ccf4e3..f2ae8348 100644 --- a/src/browser/js/Array.zig +++ b/src/browser/js/Array.zig @@ -42,3 +42,10 @@ pub fn get(self: Array, index: u32) !js.Value { .handle = handle, }; } + +pub fn asObject(self: Array) js.Object { + return .{ + .ctx = self.ctx, + .handle = @ptrCast(self.handle), + }; +} diff --git a/src/browser/js/Context.zig b/src/browser/js/Context.zig index c8fc312c..e9ad00be 100644 --- a/src/browser/js/Context.zig +++ b/src/browser/js/Context.zig @@ -80,9 +80,8 @@ identity_map: std.AutoHashMapUnmanaged(usize, PersistentObject) = .empty, // the @intFromPtr(js_obj.handle). But v8 can re-use address. Without // a reliable way to know if an object has already been persisted, // we now simply persist every time persist() is called. -js_object_list: std.ArrayListUnmanaged(PersistentObject) = .empty, - global_values: std.ArrayList(js.Global(js.Value)) = .empty, +global_objects: std.ArrayList(js.Global(js.Object)) = .empty, global_functions: std.ArrayList(js.Global(js.Function)) = .empty, // Various web APIs depend on having a persistent promise resolver. They @@ -157,11 +156,11 @@ pub fn deinit(self: *Context) void { } } - for (self.js_object_list.items) |*p| { - p.deinit(); + for (self.global_values.items) |*global| { + global.deinit(); } - for (self.global_values.items) |*global| { + for (self.global_objects.items) |*global| { global.deinit(); } @@ -352,11 +351,11 @@ fn postCompileModule(self: *Context, mod: v8.Module, url: [:0]const u8) !void { } // == Creators == -pub fn createArray(self: *Context, len: u32) js.Object { - const arr = v8.Array.init(self.isolate, len); +pub fn createArray(self: *Context, len: u32) js.Array { + const handle = v8.c.v8__Array__New(self.isolate.handle, @intCast(len)).?; return .{ - .context = self, - .js_obj = arr.castTo(v8.Object), + .ctx = self, + .handle = handle, }; } @@ -376,8 +375,8 @@ pub fn createValue(self: *Context, value: v8.Value) js.Value { pub fn createObject(self: *Context, js_value: v8.Value) js.Object { return .{ - .js_obj = js_value.castTo(v8.Object), - .context = self, + .ctx = self, + .handle = @ptrCast(js_value.handle), }; } @@ -482,7 +481,7 @@ pub fn zigValueToJs(self: *Context, value: anytype, comptime opts: Caller.CallOp if (T == js.Object) { // we're returning a v8.Object - return value.js_obj.toValue(); + return .{ .handle = @ptrCast(value.handle) }; } if (T == js.Value) { @@ -658,15 +657,15 @@ pub fn jsValueToZig(self: *Context, comptime T: type, js_value: v8.Value) !T { // or whether no parameter was passed. if (comptime o.child == js.Value) { return js.Value{ - .context = self, - .js_val = js_value, + .ctx = self, + .handle = js_value.handle, }; } if (comptime o.child == js.Object) { return js.Object{ - .context = self, - .js_obj = js_value.castTo(v8.Object), + .ctx = self, + .handle = @ptrCast(js_value.handle), }; } @@ -829,9 +828,14 @@ fn jsValueToStruct(self: *Context, comptime T: type, js_value: v8.Value) !?T { }, // Caller wants an opaque js.Object. Probably a parameter // that it needs to pass back into a callback. - js.Object => js.Object{ - .js_obj = js_value.castTo(v8.Object), - .context = self, + js.Object => { + if (!js_value.isObject()) { + return null; + } + return js.Object{ + .ctx = self, + .handle = @ptrCast(js_value.handle), + }; }, else => { if (!js_value.isObject()) { diff --git a/src/browser/js/Function.zig b/src/browser/js/Function.zig index bafb1e40..06aa68ba 100644 --- a/src/browser/js/Function.zig +++ b/src/browser/js/Function.zig @@ -25,7 +25,7 @@ const Allocator = std.mem.Allocator; const Function = @This(); ctx: *js.Context, -this: ?v8.Object = null, +this: ?*const v8.c.Object = null, handle: *const v8.c.Function, pub const Result = struct { @@ -39,9 +39,9 @@ pub fn id(self: *const Function) u32 { pub fn withThis(self: *const Function, value: anytype) !Function { const this_obj = if (@TypeOf(value) == js.Object) - value.js_obj + value.handle else - (try self.ctx.zigValueToJs(value, .{})).castTo(v8.Object); + (try self.ctx.zigValueToJs(value, .{})).handle; return .{ .ctx = self.ctx, @@ -72,8 +72,8 @@ pub fn newInstance(self: *const Function, result: *Result) !js.Object { }; return .{ - .context = ctx, - .js_obj = .{ .handle = handle }, + .ctx = ctx, + .handle = handle, }; } @@ -166,8 +166,12 @@ pub fn callWithThis(self: *const Function, comptime T: type, this: anytype, args return ctx.jsValueToZig(T, .{ .handle = handle }); } -fn getThis(self: *const Function) v8.Object { - return self.this orelse self.ctx.v8_context.getGlobal(); +fn getThis(self: *const Function) js.Object { + const handle = self.this orelse self.ctx.v8_context.getGlobal().handle; + return .{ + .ctx = self.ctx, + .handle = handle, + }; } pub fn src(self: *const Function) ![]const u8 { diff --git a/src/browser/js/Object.zig b/src/browser/js/Object.zig index 4520e396..589d01c8 100644 --- a/src/browser/js/Object.zig +++ b/src/browser/js/Object.zig @@ -28,11 +28,12 @@ const PersistentObject = v8.Persistent(v8.Object); const Allocator = std.mem.Allocator; const Object = @This(); -js_obj: v8.Object, -context: *js.Context, + +ctx: *js.Context, +handle: *const v8.c.Object, pub fn getId(self: Object) u32 { - return self.js_obj.getIdentityHash(); + return @bitCast(v8.c.v8__Object__GetIdentityHash(self.handle)); } pub const SetOpts = packed struct(u32) { @@ -51,58 +52,57 @@ pub fn setIndex(self: Object, index: u32, value: anytype, opts: SetOpts) !void { } pub fn set(self: Object, key: []const u8, value: anytype, opts: SetOpts) error{ FailedToSet, OutOfMemory }!void { - const context = self.context; + const ctx = self.ctx; - const js_key = v8.String.initUtf8(context.isolate, key); - const js_value = try context.zigValueToJs(value, .{}); + const js_key = v8.c.v8__String__NewFromUtf8(ctx.isolate.handle, key.ptr, v8.c.kNormal, @intCast(key.len)).?; + const js_value = try ctx.zigValueToJs(value, .{}); - const res = self.js_obj.defineOwnProperty(context.v8_context, js_key.toName(), js_value, @bitCast(opts)) orelse false; + var out: v8.c.MaybeBool = undefined; + v8.c.v8__Object__DefineOwnProperty(self.handle, ctx.v8_context.handle, @ptrCast(js_key), js_value.handle, @bitCast(opts), &out); + + const res = if (out.has_value) out.value else false; if (!res) { return error.FailedToSet; } } pub fn get(self: Object, key: []const u8) !js.Value { - const context = self.context; - const js_key = v8.String.initUtf8(context.isolate, key); - const js_val = try self.js_obj.getValue(context.v8_context, js_key); - return context.createValue(js_val); -} - -pub fn isTruthy(self: Object) bool { - const js_value = self.js_obj.toValue(); - return js_value.toBool(self.context.isolate); + const ctx = self.ctx; + const js_key = v8.c.v8__String__NewFromUtf8(ctx.isolate.handle, key.ptr, v8.c.kNormal, @intCast(key.len)).?; + const js_val_handle = v8.c.v8__Object__Get(self.handle, ctx.v8_context.handle, js_key) orelse return error.JsException; + const js_val = v8.Value{ .handle = js_val_handle }; + return ctx.createValue(js_val); } pub fn toString(self: Object) ![]const u8 { - const js_value = self.js_obj.toValue(); - return self.context.valueToString(js_value, .{}); + const js_value = v8.Value{ .handle = @ptrCast(self.handle) }; + return self.ctx.valueToString(js_value, .{}); } pub fn format(self: Object, writer: *std.Io.Writer) !void { if (comptime IS_DEBUG) { - return self.context.debugValue(self.js_obj.toValue(), writer); + const js_value = v8.Value{ .handle = @ptrCast(self.handle) }; + return self.ctx.debugValue(js_value, writer); } const str = self.toString() catch return error.WriteFailed; return writer.writeAll(str); } pub fn toJson(self: Object, allocator: Allocator) ![]u8 { - const json_string = try v8.Json.stringify(self.context.v8_context, self.js_obj.toValue(), null); - const str = try self.context.jsStringToZig(json_string, .{ .allocator = allocator }); - return str; + const json_str_handle = v8.c.v8__JSON__Stringify(self.ctx.v8_context.handle, @ptrCast(self.handle), null) orelse return error.JsException; + const json_string = v8.String{ .handle = json_str_handle }; + return self.ctx.jsStringToZig(json_string, .{ .allocator = allocator }); } pub fn persist(self: Object) !Object { - var context = self.context; - const js_obj = self.js_obj; + var ctx = self.ctx; - const persisted = PersistentObject.init(context.isolate, js_obj); - try context.js_object_list.append(context.arena, persisted); + const global = js.Global(Object).init(ctx.isolate.handle, self.handle); + try ctx.global_objects.append(ctx.arena, global); return .{ - .context = context, - .js_obj = persisted.castToObject(), + .ctx = ctx, + .handle = global.local(), }; } @@ -110,15 +110,16 @@ pub fn getFunction(self: Object, name: []const u8) !?js.Function { if (self.isNullOrUndefined()) { return null; } - const context = self.context; + const ctx = self.ctx; - const js_name = v8.String.initUtf8(context.isolate, name); + const js_name = v8.c.v8__String__NewFromUtf8(ctx.isolate.handle, name.ptr, v8.c.kNormal, @intCast(name.len)).?; + const js_val_handle = v8.c.v8__Object__Get(self.handle, ctx.v8_context.handle, js_name) orelse return error.JsException; + const js_value = v8.Value{ .handle = js_val_handle }; - const js_value = try self.js_obj.getValue(context.v8_context, js_name.toName()); if (!js_value.isFunction()) { return null; } - return try context.createFunction(js_value); + return try ctx.createFunction(js_value); } pub fn callMethod(self: Object, comptime T: type, method_name: []const u8, args: anytype) !T { @@ -126,41 +127,33 @@ pub fn callMethod(self: Object, comptime T: type, method_name: []const u8, args: return func.callWithThis(T, self, args); } -pub fn isNull(self: Object) bool { - return self.js_obj.toValue().isNull(); -} - -pub fn isUndefined(self: Object) bool { - return self.js_obj.toValue().isUndefined(); -} - pub fn isNullOrUndefined(self: Object) bool { - return self.js_obj.toValue().isNullOrUndefined(); + return v8.c.v8__Value__IsNullOrUndefined(@ptrCast(self.handle)); } pub fn nameIterator(self: Object) NameIterator { - const context = self.context; - const js_obj = self.js_obj; + const ctx = self.ctx; - const array = js_obj.getPropertyNames(context.v8_context); - const count = array.length(); + const handle = v8.c.v8__Object__GetPropertyNames(self.handle, ctx.v8_context.handle).?; + const count = v8.c.v8__Array__Length(handle); return .{ + .ctx = ctx, + .handle = handle, .count = count, - .context = context, - .js_obj = array.castTo(v8.Object), }; } pub fn toZig(self: Object, comptime T: type) !T { - return self.context.jsValueToZig(T, self.js_obj.toValue()); + const js_value = v8.Value{ .handle = @ptrCast(self.handle) }; + return self.ctx.jsValueToZig(T, js_value); } pub const NameIterator = struct { count: u32, idx: u32 = 0, - js_obj: v8.Object, - context: *const Context, + ctx: *const Context, + handle: *const v8.c.Array, pub fn next(self: *NameIterator) !?[]const u8 { const idx = self.idx; @@ -169,8 +162,8 @@ pub const NameIterator = struct { } self.idx += 1; - const context = self.context; - const js_val = try self.js_obj.getAtIndex(context.v8_context, idx); - return try context.valueToString(js_val, .{}); + const js_val_handle = v8.c.v8__Object__GetIndex(@ptrCast(self.handle), self.ctx.v8_context.handle, idx) orelse return error.JsException; + const js_val = v8.Value{ .handle = js_val_handle }; + return try self.ctx.valueToString(js_val, .{}); } }; diff --git a/src/browser/js/Value.zig b/src/browser/js/Value.zig index b419688d..39ca9bde 100644 --- a/src/browser/js/Value.zig +++ b/src/browser/js/Value.zig @@ -112,8 +112,8 @@ pub fn toObject(self: Value) js.Object { } return .{ - .context = self.ctx, - .js_obj = .{ .handle = self.handle }, + .ctx = self.ctx, + .handle = self.handle, }; } @@ -127,3 +127,11 @@ pub fn toArray(self: Value) js.Array { .handle = self.handle, }; } + +pub fn format(self: Value, writer: *std.Io.Writer) !void { + if (comptime IS_DEBUG) { + return self.ctx.debugValue(.{ .handle = self.handle }, writer); + } + const str = self.toString(.{}) catch return error.WriteFailed; + return writer.writeAll(str); +} diff --git a/src/browser/tests/net/response.html b/src/browser/tests/net/response.html index c632c3ff..b7c149ba 100644 --- a/src/browser/tests/net/response.html +++ b/src/browser/tests/net/response.html @@ -2,12 +2,12 @@ -