mirror of
https://github.com/lightpanda-io/browser.git
synced 2026-02-04 14:33:47 +00:00
migrate most cases, merge Caller into bridge
This commit is contained in:
@@ -25,7 +25,7 @@ const js = @import("js.zig");
|
|||||||
const v8 = js.v8;
|
const v8 = js.v8;
|
||||||
|
|
||||||
const bridge = @import("bridge.zig");
|
const bridge = @import("bridge.zig");
|
||||||
const Caller = @import("Caller.zig");
|
const Caller = bridge.Caller;
|
||||||
|
|
||||||
const Page = @import("../Page.zig");
|
const Page = @import("../Page.zig");
|
||||||
const ScriptManager = @import("../ScriptManager.zig");
|
const ScriptManager = @import("../ScriptManager.zig");
|
||||||
@@ -52,7 +52,7 @@ handle_scope: ?js.HandleScope,
|
|||||||
cpu_profiler: ?v8.CpuProfiler = null,
|
cpu_profiler: ?v8.CpuProfiler = null,
|
||||||
|
|
||||||
// references Env.templates
|
// references Env.templates
|
||||||
templates: []v8.FunctionTemplate,
|
templates: []*const v8.c.FunctionTemplate,
|
||||||
|
|
||||||
// Arena for the lifetime of the context
|
// Arena for the lifetime of the context
|
||||||
arena: Allocator,
|
arena: Allocator,
|
||||||
@@ -88,9 +88,6 @@ global_objects: std.ArrayList(js.Global(js.Object)) = .empty,
|
|||||||
global_functions: std.ArrayList(js.Global(js.Function)) = .empty,
|
global_functions: std.ArrayList(js.Global(js.Function)) = .empty,
|
||||||
global_promise_resolvers: std.ArrayList(js.Global(js.PromiseResolver)) = .empty,
|
global_promise_resolvers: std.ArrayList(js.Global(js.PromiseResolver)) = .empty,
|
||||||
|
|
||||||
// Some Zig types have code to execute to cleanup
|
|
||||||
destructor_callbacks: std.ArrayListUnmanaged(DestructorCallback) = .empty,
|
|
||||||
|
|
||||||
// Our module cache: normalized module specifier => module.
|
// Our module cache: normalized module specifier => module.
|
||||||
module_cache: std.StringHashMapUnmanaged(ModuleEntry) = .empty,
|
module_cache: std.StringHashMapUnmanaged(ModuleEntry) = .empty,
|
||||||
|
|
||||||
@@ -138,21 +135,10 @@ pub fn fromIsolate(isolate: js.Isolate) *Context {
|
|||||||
pub fn setupGlobal(self: *Context) !void {
|
pub fn setupGlobal(self: *Context) !void {
|
||||||
const global = v8.c.v8__Context__Global(self.handle).?;
|
const global = v8.c.v8__Context__Global(self.handle).?;
|
||||||
const v8_obj = v8.Object{ .handle = global };
|
const v8_obj = v8.Object{ .handle = global };
|
||||||
_ = try self.mapZigInstanceToJs(v8_obj, self.page.window);
|
_ = try self.mapZigInstanceToJs(v8_obj.handle, self.page.window);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn deinit(self: *Context) void {
|
pub fn deinit(self: *Context) void {
|
||||||
{
|
|
||||||
// reverse order, as this has more chance of respecting any
|
|
||||||
// dependencies objects might have with each other.
|
|
||||||
const items = self.destructor_callbacks.items;
|
|
||||||
var i = items.len;
|
|
||||||
while (i > 0) {
|
|
||||||
i -= 1;
|
|
||||||
items[i].destructor();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
{
|
||||||
var it = self.identity_map.valueIterator();
|
var it = self.identity_map.valueIterator();
|
||||||
while (it.next()) |p| {
|
while (it.next()) |p| {
|
||||||
@@ -233,7 +219,7 @@ pub fn module(self: *Context, comptime want_result: bool, src: []const u8, url:
|
|||||||
}
|
}
|
||||||
|
|
||||||
const owned_url = try arena.dupeZ(u8, url);
|
const owned_url = try arena.dupeZ(u8, url);
|
||||||
const m = try compileModule(v8_isolate, src, owned_url);
|
const m = try compileModule(self.isolate, src, owned_url);
|
||||||
|
|
||||||
if (cacheable) {
|
if (cacheable) {
|
||||||
// compileModule is synchronous - nothing can modify the cache during compilation
|
// compileModule is synchronous - nothing can modify the cache during compilation
|
||||||
@@ -261,9 +247,10 @@ pub fn module(self: *Context, comptime want_result: bool, src: []const u8, url:
|
|||||||
|
|
||||||
// Some module-loading errors aren't handled by TryCatch. We need to
|
// Some module-loading errors aren't handled by TryCatch. We need to
|
||||||
// get the error from the module itself.
|
// get the error from the module itself.
|
||||||
|
const v8_exception = mod.getException();
|
||||||
log.warn(.js, "evaluate module", .{
|
log.warn(.js, "evaluate module", .{
|
||||||
.specifier = owned_url,
|
.specifier = owned_url,
|
||||||
.message = self.valueToString(mod.getException(), .{}) catch "???",
|
.message = self.valueToString(js.Value{ .ctx = self, .handle = v8_exception.handle }, .{}) catch "???",
|
||||||
});
|
});
|
||||||
return error.EvaluationError;
|
return error.EvaluationError;
|
||||||
};
|
};
|
||||||
@@ -315,7 +302,7 @@ pub fn stringToFunction(self: *Context, str: []const u8) !js.Function {
|
|||||||
if (!js_value.isFunction()) {
|
if (!js_value.isFunction()) {
|
||||||
return error.StringFunctionError;
|
return error.StringFunctionError;
|
||||||
}
|
}
|
||||||
return self.createFunction(.{ .handle = js_value.handle });
|
return self.createFunction(js_value);
|
||||||
}
|
}
|
||||||
|
|
||||||
// After we compile a module, whether it's a top-level one, or a nested one,
|
// After we compile a module, whether it's a top-level one, or a nested one,
|
||||||
@@ -358,28 +345,14 @@ pub fn createArray(self: *Context, len: u32) js.Array {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn createException(self: *const Context, e: v8.Value) js.Exception {
|
pub fn createObject(self: *Context, js_value: js.Value) js.Object {
|
||||||
return .{
|
|
||||||
.inner = e,
|
|
||||||
.context = self,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn createValue(self: *Context, value: v8.Value) js.Value {
|
|
||||||
return .{
|
|
||||||
.ctx = self,
|
|
||||||
.handle = value.handle,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn createObject(self: *Context, js_value: v8.Value) js.Object {
|
|
||||||
return .{
|
return .{
|
||||||
.ctx = self,
|
.ctx = self,
|
||||||
.handle = @ptrCast(js_value.handle),
|
.handle = @ptrCast(js_value.handle),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn createFunction(self: *Context, js_value: v8.Value) !js.Function {
|
pub fn createFunction(self: *Context, js_value: js.Value) !js.Function {
|
||||||
// caller should have made sure this was a function
|
// caller should have made sure this was a function
|
||||||
if (comptime IS_DEBUG) {
|
if (comptime IS_DEBUG) {
|
||||||
std.debug.assert(js_value.isFunction());
|
std.debug.assert(js_value.isFunction());
|
||||||
@@ -394,25 +367,27 @@ pub fn createFunction(self: *Context, js_value: v8.Value) !js.Function {
|
|||||||
pub fn newString(self: *Context, str: []const u8) js.String {
|
pub fn newString(self: *Context, str: []const u8) js.String {
|
||||||
return .{
|
return .{
|
||||||
.ctx = self,
|
.ctx = self,
|
||||||
.handle = self.isolate.newStringHandle(str),
|
.handle = self.isolate.createStringHandle(str),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn throw(self: *Context, err: []const u8) js.Exception {
|
pub fn throw(self: *Context, err: []const u8) js.Exception {
|
||||||
const v8_isolate = v8.Isolate{ .handle = self.isolate.handle };
|
const handle = self.isolate.createError(err);
|
||||||
const js_value = js._createException(v8_isolate, err);
|
return .{
|
||||||
return self.createException(js_value);
|
.ctx = self,
|
||||||
|
.handle = handle,
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn zigValueToJs(self: *Context, value: anytype, comptime opts: Caller.CallOpts) !v8.Value {
|
pub fn zigValueToJs(self: *Context, value: anytype, comptime opts: Caller.CallOpts) !js.Value {
|
||||||
const isolate = self.isolate;
|
const isolate = self.isolate;
|
||||||
const v8_isolate = v8.Isolate{ .handle = isolate.handle };
|
const v8_isolate = v8.Isolate{ .handle = isolate.handle };
|
||||||
|
|
||||||
// Check if it's a "simple" type. This is extracted so that it can be
|
// Check if it's a "simple" type. This is extracted so that it can be
|
||||||
// reused by other parts of the code. "simple" types only require an
|
// reused by other parts of the code. "simple" types only require an
|
||||||
// isolate to create (specifically, they don't our templates array)
|
// isolate to create (specifically, they don't our templates array)
|
||||||
if (js.simpleZigValueToJs(v8_isolate, value, false, opts.null_as_undefined)) |js_value| {
|
if (js.simpleZigValueToJs(v8_isolate, value, false, opts.null_as_undefined)) |js_value_handle| {
|
||||||
return js_value;
|
return .{ .ctx = self, .handle = js_value_handle };
|
||||||
}
|
}
|
||||||
|
|
||||||
const v8_context = v8.Context{ .handle = self.handle };
|
const v8_context = v8.Context{ .handle = self.handle };
|
||||||
@@ -424,7 +399,7 @@ pub fn zigValueToJs(self: *Context, value: anytype, comptime opts: Caller.CallOp
|
|||||||
unreachable;
|
unreachable;
|
||||||
},
|
},
|
||||||
.array => {
|
.array => {
|
||||||
var js_arr = v8.Array.init(v8_isolate, value.len);
|
var js_arr = isolate.initArray(value.len);
|
||||||
var js_obj = js_arr.castTo(v8.Object);
|
var js_obj = js_arr.castTo(v8.Object);
|
||||||
for (value, 0..) |v, i| {
|
for (value, 0..) |v, i| {
|
||||||
const js_val = try self.zigValueToJs(v, opts);
|
const js_val = try self.zigValueToJs(v, opts);
|
||||||
@@ -432,14 +407,14 @@ pub fn zigValueToJs(self: *Context, value: anytype, comptime opts: Caller.CallOp
|
|||||||
return error.FailedToCreateArray;
|
return error.FailedToCreateArray;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return js_obj.toValue();
|
return .{ .ctx = self, .handle = @ptrCast(js_obj.handle) };
|
||||||
},
|
},
|
||||||
.pointer => |ptr| switch (ptr.size) {
|
.pointer => |ptr| switch (ptr.size) {
|
||||||
.one => {
|
.one => {
|
||||||
if (@typeInfo(ptr.child) == .@"struct" and @hasDecl(ptr.child, "JsApi")) {
|
if (@typeInfo(ptr.child) == .@"struct" and @hasDecl(ptr.child, "JsApi")) {
|
||||||
if (bridge.JsApiLookup.has(ptr.child.JsApi)) {
|
if (bridge.JsApiLookup.has(ptr.child.JsApi)) {
|
||||||
const js_obj = try self.mapZigInstanceToJs(null, value);
|
const js_obj = try self.mapZigInstanceToJs(null, value);
|
||||||
return js_obj.toValue();
|
return .{ .ctx = self, .handle = @ptrCast(js_obj.handle) };
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -463,16 +438,16 @@ pub fn zigValueToJs(self: *Context, value: anytype, comptime opts: Caller.CallOp
|
|||||||
// have handled it
|
// have handled it
|
||||||
unreachable;
|
unreachable;
|
||||||
}
|
}
|
||||||
var js_arr = v8.Array.init(v8_isolate, @intCast(value.len));
|
var js_arr = isolate.initArray(@intCast(value.len));
|
||||||
var js_obj = js_arr.castTo(v8.Object);
|
var js_obj = js_arr.castTo(v8.Object);
|
||||||
|
|
||||||
for (value, 0..) |v, i| {
|
for (value, 0..) |v, i| {
|
||||||
const js_val = try self.zigValueToJs(v, opts);
|
const js_val = try self.zigValueToJs(v, opts);
|
||||||
if (js_obj.setValueAtIndex(v8_context, @intCast(i), js_val) == false) {
|
if (js_obj.setValueAtIndex(v8_context, @intCast(i), .{ .handle = js_val.handle }) == false) {
|
||||||
return error.FailedToCreateArray;
|
return error.FailedToCreateArray;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return js_obj.toValue();
|
return .{ .ctx = self, .handle = @ptrCast(js_obj.handle) };
|
||||||
},
|
},
|
||||||
else => {},
|
else => {},
|
||||||
},
|
},
|
||||||
@@ -480,31 +455,31 @@ pub fn zigValueToJs(self: *Context, value: anytype, comptime opts: Caller.CallOp
|
|||||||
if (@hasDecl(T, "JsApi")) {
|
if (@hasDecl(T, "JsApi")) {
|
||||||
if (bridge.JsApiLookup.has(T.JsApi)) {
|
if (bridge.JsApiLookup.has(T.JsApi)) {
|
||||||
const js_obj = try self.mapZigInstanceToJs(null, value);
|
const js_obj = try self.mapZigInstanceToJs(null, value);
|
||||||
return js_obj.toValue();
|
return .{ .ctx = self, .handle = @ptrCast(js_obj.handle) };
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (T == js.Function) {
|
if (T == js.Function) {
|
||||||
// we're returning a callback
|
// we're returning a callback
|
||||||
return .{ .handle = @ptrCast(value.handle) };
|
return .{ .ctx = self, .handle = @ptrCast(value.handle) };
|
||||||
}
|
}
|
||||||
|
|
||||||
if (T == js.Object) {
|
if (T == js.Object) {
|
||||||
// we're returning a v8.Object
|
// we're returning a v8.Object
|
||||||
return .{ .handle = @ptrCast(value.handle) };
|
return .{ .ctx = self, .handle = @ptrCast(value.handle) };
|
||||||
}
|
}
|
||||||
|
|
||||||
if (T == js.Value) {
|
if (T == js.Value) {
|
||||||
return .{ .handle = value.handle };
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (T == js.Promise) {
|
if (T == js.Promise) {
|
||||||
// we're returning a js.Promise
|
// we're returning a js.Promise
|
||||||
return .{ .handle = @ptrCast(value.handle) };
|
return .{ .ctx = self, .handle = @ptrCast(value.handle) };
|
||||||
}
|
}
|
||||||
|
|
||||||
if (T == js.Exception) {
|
if (T == js.Exception) {
|
||||||
return isolate.throwException(value.inner);
|
return .{ .ctx = self, .handle = isolate.throwException(value.handle) };
|
||||||
}
|
}
|
||||||
|
|
||||||
if (@hasDecl(T, "runtimeGenericWrap")) {
|
if (@hasDecl(T, "runtimeGenericWrap")) {
|
||||||
@@ -514,31 +489,31 @@ pub fn zigValueToJs(self: *Context, value: anytype, comptime opts: Caller.CallOp
|
|||||||
|
|
||||||
if (s.is_tuple) {
|
if (s.is_tuple) {
|
||||||
// return the tuple struct as an array
|
// return the tuple struct as an array
|
||||||
var js_arr = v8.Array.init(v8_isolate, @intCast(s.fields.len));
|
var js_arr = isolate.initArray(@intCast(s.fields.len));
|
||||||
var js_obj = js_arr.castTo(v8.Object);
|
var js_obj = js_arr.castTo(v8.Object);
|
||||||
inline for (s.fields, 0..) |f, i| {
|
inline for (s.fields, 0..) |f, i| {
|
||||||
const js_val = try self.zigValueToJs(@field(value, f.name), opts);
|
const js_val = try self.zigValueToJs(@field(value, f.name), opts);
|
||||||
if (js_obj.setValueAtIndex(v8_context, @intCast(i), js_val) == false) {
|
if (js_obj.setValueAtIndex(v8_context, @intCast(i), .{ .handle = js_val.handle }) == false) {
|
||||||
return error.FailedToCreateArray;
|
return error.FailedToCreateArray;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return js_obj.toValue();
|
return .{ .ctx = self, .handle = @ptrCast(js_obj.handle) };
|
||||||
}
|
}
|
||||||
|
|
||||||
// return the struct as a JS object
|
// return the struct as a JS object
|
||||||
const js_obj = v8.Object.init(v8_isolate);
|
const js_obj = isolate.initObject();
|
||||||
inline for (s.fields) |f| {
|
inline for (s.fields) |f| {
|
||||||
const js_val = try self.zigValueToJs(@field(value, f.name), opts);
|
const js_val = try self.zigValueToJs(@field(value, f.name), opts);
|
||||||
const key = v8.String.initUtf8(v8_isolate, f.name);
|
const key = isolate.initString(f.name);
|
||||||
if (!js_obj.setValue(v8_context, key, js_val)) {
|
if (!js_obj.setValue(v8_context, key, .{ .handle = js_val.handle })) {
|
||||||
return error.CreateObjectFailure;
|
return error.CreateObjectFailure;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return js_obj.toValue();
|
return .{ .ctx = self, .handle = @ptrCast(js_obj.handle) };
|
||||||
},
|
},
|
||||||
.@"union" => |un| {
|
.@"union" => |un| {
|
||||||
if (T == std.json.Value) {
|
if (T == std.json.Value) {
|
||||||
return zigJsonToJs(isolate, v8_context, value);
|
return zigJsonToJs(self, value);
|
||||||
}
|
}
|
||||||
if (un.tag_type) |UnionTagType| {
|
if (un.tag_type) |UnionTagType| {
|
||||||
inline for (un.fields) |field| {
|
inline for (un.fields) |field| {
|
||||||
@@ -577,7 +552,7 @@ pub fn zigValueToJs(self: *Context, value: anytype, comptime opts: Caller.CallOp
|
|||||||
// 4 - Store our TaggedAnyOpaque into the persistent object
|
// 4 - Store our TaggedAnyOpaque into the persistent object
|
||||||
// 5 - Update our identity_map (so that, if we return this same instance again,
|
// 5 - Update our identity_map (so that, if we return this same instance again,
|
||||||
// we can just grab it from the identity_map)
|
// we can just grab it from the identity_map)
|
||||||
pub fn mapZigInstanceToJs(self: *Context, js_obj_: ?v8.Object, value: anytype) !PersistentObject {
|
pub fn mapZigInstanceToJs(self: *Context, js_obj_handle: ?*const v8.c.Object, value: anytype) !PersistentObject {
|
||||||
const v8_context = v8.Context{ .handle = self.handle };
|
const v8_context = v8.Context{ .handle = self.handle };
|
||||||
const arena = self.arena;
|
const arena = self.arena;
|
||||||
|
|
||||||
@@ -587,7 +562,7 @@ pub fn mapZigInstanceToJs(self: *Context, js_obj_: ?v8.Object, value: anytype) !
|
|||||||
// Struct, has to be placed on the heap
|
// Struct, has to be placed on the heap
|
||||||
const heap = try arena.create(T);
|
const heap = try arena.create(T);
|
||||||
heap.* = value;
|
heap.* = value;
|
||||||
return self.mapZigInstanceToJs(js_obj_, heap);
|
return self.mapZigInstanceToJs(js_obj_handle, heap);
|
||||||
},
|
},
|
||||||
.pointer => |ptr| {
|
.pointer => |ptr| {
|
||||||
const resolved = resolveValue(value);
|
const resolved = resolveValue(value);
|
||||||
@@ -610,9 +585,13 @@ pub fn mapZigInstanceToJs(self: *Context, js_obj_: ?v8.Object, value: anytype) !
|
|||||||
// Sometimes though we already have the v8.Objct to bind to
|
// Sometimes though we already have the v8.Objct to bind to
|
||||||
// for example, when we're executing a constructor, v8 has
|
// for example, when we're executing a constructor, v8 has
|
||||||
// already created the "this" object.
|
// already created the "this" object.
|
||||||
const js_obj = js_obj_ orelse blk: {
|
const js_obj = if (js_obj_handle) |handle|
|
||||||
const template = self.templates[resolved.class_id];
|
v8.Object{ .handle = handle }
|
||||||
break :blk template.getInstanceTemplate().initInstance(v8_context);
|
else blk: {
|
||||||
|
const function_template_handle = self.templates[resolved.class_id];
|
||||||
|
const object_template_handle = v8.c.v8__FunctionTemplate__InstanceTemplate(function_template_handle).?;
|
||||||
|
const object_handle = v8.c.v8__ObjectTemplate__NewInstance(object_template_handle, v8_context.handle).?;
|
||||||
|
break :blk v8.Object{ .handle = object_handle };
|
||||||
};
|
};
|
||||||
|
|
||||||
if (!@hasDecl(JsApi.Meta, "empty_with_no_proto")) {
|
if (!@hasDecl(JsApi.Meta, "empty_with_no_proto")) {
|
||||||
@@ -648,8 +627,7 @@ pub fn mapZigInstanceToJs(self: *Context, js_obj_: ?v8.Object, value: anytype) !
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn jsValueToZig(self: *Context, comptime T: type, js_value: v8.Value) !T {
|
pub fn jsValueToZig(self: *Context, comptime T: type, js_value: js.Value) !T {
|
||||||
const v8_isolate = v8.Isolate{ .handle = self.isolate.handle };
|
|
||||||
const v8_context = v8.Context{ .handle = self.handle };
|
const v8_context = v8.Context{ .handle = self.handle };
|
||||||
switch (@typeInfo(T)) {
|
switch (@typeInfo(T)) {
|
||||||
.optional => |o| {
|
.optional => |o| {
|
||||||
@@ -688,12 +666,12 @@ pub fn jsValueToZig(self: *Context, comptime T: type, js_value: v8.Value) !T {
|
|||||||
return try self.jsValueToZig(o.child, js_value);
|
return try self.jsValueToZig(o.child, js_value);
|
||||||
},
|
},
|
||||||
.float => |f| switch (f.bits) {
|
.float => |f| switch (f.bits) {
|
||||||
0...32 => return js_value.toF32(v8_context),
|
0...32 => return js_value.toF32(),
|
||||||
33...64 => return js_value.toF64(v8_context),
|
33...64 => return js_value.toF64(),
|
||||||
else => {},
|
else => {},
|
||||||
},
|
},
|
||||||
.int => return jsIntToZig(T, js_value, v8_context),
|
.int => return jsIntToZig(T, js_value),
|
||||||
.bool => return js_value.toBool(v8_isolate),
|
.bool => return js_value.toBool(),
|
||||||
.pointer => |ptr| switch (ptr.size) {
|
.pointer => |ptr| switch (ptr.size) {
|
||||||
.one => {
|
.one => {
|
||||||
if (!js_value.isObject()) {
|
if (!js_value.isObject()) {
|
||||||
@@ -702,7 +680,7 @@ pub fn jsValueToZig(self: *Context, comptime T: type, js_value: v8.Value) !T {
|
|||||||
if (@hasDecl(ptr.child, "JsApi")) {
|
if (@hasDecl(ptr.child, "JsApi")) {
|
||||||
std.debug.assert(bridge.JsApiLookup.has(ptr.child.JsApi));
|
std.debug.assert(bridge.JsApiLookup.has(ptr.child.JsApi));
|
||||||
const js_obj = js_value.castTo(v8.Object);
|
const js_obj = js_value.castTo(v8.Object);
|
||||||
return typeTaggedAnyOpaque(*ptr.child, js_obj);
|
return typeTaggedAnyOpaque(*ptr.child, js_obj.handle);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
.slice => {
|
.slice => {
|
||||||
@@ -732,7 +710,8 @@ pub fn jsValueToZig(self: *Context, comptime T: type, js_value: v8.Value) !T {
|
|||||||
// to do this (V8::Array has an iterate method on it)
|
// to do this (V8::Array has an iterate method on it)
|
||||||
const arr = try self.call_arena.alloc(ptr.child, js_arr.length());
|
const arr = try self.call_arena.alloc(ptr.child, js_arr.length());
|
||||||
for (arr, 0..) |*a, i| {
|
for (arr, 0..) |*a, i| {
|
||||||
a.* = try self.jsValueToZig(ptr.child, try js_obj.getAtIndex(v8_context, @intCast(i)));
|
const v8_val = try js_obj.getAtIndex(v8_context, @intCast(i));
|
||||||
|
a.* = try self.jsValueToZig(ptr.child, js.Value{ .ctx = self, .handle = v8_val.handle });
|
||||||
}
|
}
|
||||||
return arr;
|
return arr;
|
||||||
},
|
},
|
||||||
@@ -812,7 +791,7 @@ pub fn jsValueToZig(self: *Context, comptime T: type, js_value: v8.Value) !T {
|
|||||||
|
|
||||||
// Extracted so that it can be used in both jsValueToZig and in
|
// Extracted so that it can be used in both jsValueToZig and in
|
||||||
// probeJsValueToZig. Avoids having to duplicate this logic when probing.
|
// probeJsValueToZig. Avoids having to duplicate this logic when probing.
|
||||||
fn jsValueToStruct(self: *Context, comptime T: type, js_value: v8.Value) !?T {
|
fn jsValueToStruct(self: *Context, comptime T: type, js_value: js.Value) !?T {
|
||||||
return switch (T) {
|
return switch (T) {
|
||||||
js.Function => {
|
js.Function => {
|
||||||
if (!js_value.isFunction()) {
|
if (!js_value.isFunction()) {
|
||||||
@@ -856,14 +835,14 @@ fn jsValueToStruct(self: *Context, comptime T: type, js_value: v8.Value) !?T {
|
|||||||
const js_obj = js_value.castTo(v8.Object);
|
const js_obj = js_value.castTo(v8.Object);
|
||||||
const v8_context = v8.Context{ .handle = self.handle };
|
const v8_context = v8.Context{ .handle = self.handle };
|
||||||
const isolate = self.isolate;
|
const isolate = self.isolate;
|
||||||
const v8_isolate = v8.Isolate{ .handle = isolate.handle };
|
|
||||||
|
|
||||||
var value: T = undefined;
|
var value: T = undefined;
|
||||||
inline for (@typeInfo(T).@"struct".fields) |field| {
|
inline for (@typeInfo(T).@"struct".fields) |field| {
|
||||||
const name = field.name;
|
const name = field.name;
|
||||||
const key = v8.String.initUtf8(v8_isolate, name);
|
const key = isolate.initString(name);
|
||||||
if (js_obj.has(v8_context, key.toValue())) {
|
if (js_obj.has(v8_context, key.toValue())) {
|
||||||
@field(value, name) = try self.jsValueToZig(field.type, try js_obj.getValue(v8_context, key));
|
const v8_val = try js_obj.getValue(v8_context, key);
|
||||||
|
@field(value, name) = try self.jsValueToZig(field.type, js.Value{ .ctx = self, .handle = v8_val.handle });
|
||||||
} else if (@typeInfo(field.type) == .optional) {
|
} else if (@typeInfo(field.type) == .optional) {
|
||||||
@field(value, name) = null;
|
@field(value, name) = null;
|
||||||
} else {
|
} else {
|
||||||
@@ -877,7 +856,7 @@ fn jsValueToStruct(self: *Context, comptime T: type, js_value: v8.Value) !?T {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
fn jsValueToTypedArray(_: *Context, comptime T: type, js_value: v8.Value) !?[]T {
|
fn jsValueToTypedArray(_: *Context, comptime T: type, js_value: js.Value) !?[]T {
|
||||||
var force_u8 = false;
|
var force_u8 = false;
|
||||||
var array_buffer: ?v8.ArrayBuffer = null;
|
var array_buffer: ?v8.ArrayBuffer = null;
|
||||||
var byte_len: usize = undefined;
|
var byte_len: usize = undefined;
|
||||||
@@ -1017,61 +996,73 @@ fn resolveT(comptime T: type, value: *anyopaque) Resolved {
|
|||||||
const valueToStringOpts = struct {
|
const valueToStringOpts = struct {
|
||||||
allocator: ?Allocator = null,
|
allocator: ?Allocator = null,
|
||||||
};
|
};
|
||||||
pub fn valueToString(self: *const Context, js_val: v8.Value, opts: valueToStringOpts) ![]u8 {
|
pub fn valueToString(self: *const Context, js_val: js.Value, opts: valueToStringOpts) ![]u8 {
|
||||||
const allocator = opts.allocator orelse self.call_arena;
|
const allocator = opts.allocator orelse self.call_arena;
|
||||||
if (js_val.isSymbol()) {
|
if (js_val.isSymbol()) {
|
||||||
const js_sym = v8.Symbol{ .handle = js_val.handle };
|
const js_sym = v8.Symbol{ .handle = js_val.handle };
|
||||||
const v8_isolate = v8.Isolate{ .handle = self.isolate.handle };
|
const v8_isolate = v8.Isolate{ .handle = self.isolate.handle };
|
||||||
const js_sym_desc = js_sym.getDescription(v8_isolate);
|
const js_sym_desc = js_sym.getDescription(v8_isolate);
|
||||||
return self.valueToString(js_sym_desc, .{});
|
return self.valueToString(js.Value{ .ctx = self, .handle = js_sym_desc.handle }, .{});
|
||||||
}
|
}
|
||||||
const v8_context = v8.Context{ .handle = self.handle };
|
const str_handle = v8.c.v8__Value__ToString(js_val.handle, self.handle) orelse {
|
||||||
const str = try js_val.toString(v8_context);
|
return error.JsException;
|
||||||
|
};
|
||||||
|
const str = v8.String{ .handle = str_handle };
|
||||||
return self.jsStringToZig(str, .{ .allocator = allocator });
|
return self.jsStringToZig(str, .{ .allocator = allocator });
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn valueToStringZ(self: *const Context, js_val: v8.Value, opts: valueToStringOpts) ![:0]u8 {
|
pub fn valueToStringZ(self: *const Context, js_val: js.Value, opts: valueToStringOpts) ![:0]u8 {
|
||||||
const allocator = opts.allocator orelse self.call_arena;
|
const allocator = opts.allocator orelse self.call_arena;
|
||||||
if (js_val.isSymbol()) {
|
if (js_val.isSymbol()) {
|
||||||
const js_sym = v8.Symbol{ .handle = js_val.handle };
|
const js_sym = v8.Symbol{ .handle = js_val.handle };
|
||||||
const v8_isolate = v8.Isolate{ .handle = self.isolate.handle };
|
const v8_isolate = v8.Isolate{ .handle = self.isolate.handle };
|
||||||
const js_sym_desc = js_sym.getDescription(v8_isolate);
|
const js_sym_desc = js_sym.getDescription(v8_isolate);
|
||||||
return self.valueToStringZ(js_sym_desc, .{});
|
return self.valueToStringZ(js.Value{ .ctx = self, .handle = js_sym_desc.handle }, .{});
|
||||||
}
|
}
|
||||||
const v8_context = v8.Context{ .handle = self.handle };
|
const str_handle = v8.c.v8__Value__ToString(js_val.handle, self.handle) orelse {
|
||||||
const str = try js_val.toString(v8_context);
|
return error.JsException;
|
||||||
|
};
|
||||||
|
const str = v8.String{ .handle = str_handle };
|
||||||
return self.jsStringToZigZ(str, .{ .allocator = allocator });
|
return self.jsStringToZigZ(str, .{ .allocator = allocator });
|
||||||
}
|
}
|
||||||
|
|
||||||
const JsStringToZigOpts = struct {
|
const JsStringToZigOpts = struct {
|
||||||
allocator: ?Allocator = null,
|
allocator: ?Allocator = null,
|
||||||
};
|
};
|
||||||
pub fn jsStringToZig(self: *const Context, str: v8.String, opts: JsStringToZigOpts) ![]u8 {
|
pub fn jsStringToZig(self: *const Context, str: anytype, opts: JsStringToZigOpts) ![]u8 {
|
||||||
const allocator = opts.allocator orelse self.call_arena;
|
const allocator = opts.allocator orelse self.call_arena;
|
||||||
|
const T = @TypeOf(str);
|
||||||
|
const handle = if (T == js.String or T == v8.String) str.handle else str;
|
||||||
|
|
||||||
const v8_isolate = v8.Isolate{ .handle = self.isolate.handle };
|
const v8_isolate = v8.Isolate{ .handle = self.isolate.handle };
|
||||||
const len = str.lenUtf8(v8_isolate);
|
const v8_str = v8.String{ .handle = handle };
|
||||||
|
const len = v8_str.lenUtf8(v8_isolate);
|
||||||
const buf = try allocator.alloc(u8, len);
|
const buf = try allocator.alloc(u8, len);
|
||||||
const n = str.writeUtf8(v8_isolate, buf);
|
const n = v8_str.writeUtf8(v8_isolate, buf);
|
||||||
std.debug.assert(n == len);
|
std.debug.assert(n == len);
|
||||||
return buf;
|
return buf;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn jsStringToZigZ(self: *const Context, str: v8.String, opts: JsStringToZigOpts) ![:0]u8 {
|
pub fn jsStringToZigZ(self: *const Context, str: anytype, opts: JsStringToZigOpts) ![:0]u8 {
|
||||||
const allocator = opts.allocator orelse self.call_arena;
|
const allocator = opts.allocator orelse self.call_arena;
|
||||||
|
const T = @TypeOf(str);
|
||||||
|
const handle = if (T == js.String or T == v8.String) str.handle else str;
|
||||||
|
|
||||||
const v8_isolate = v8.Isolate{ .handle = self.isolate.handle };
|
const v8_isolate = v8.Isolate{ .handle = self.isolate.handle };
|
||||||
const len = str.lenUtf8(v8_isolate);
|
const v8_str = v8.String{ .handle = handle };
|
||||||
|
const len = v8_str.lenUtf8(v8_isolate);
|
||||||
const buf = try allocator.allocSentinel(u8, len, 0);
|
const buf = try allocator.allocSentinel(u8, len, 0);
|
||||||
const n = str.writeUtf8(v8_isolate, buf);
|
const n = v8_str.writeUtf8(v8_isolate, buf);
|
||||||
std.debug.assert(n == len);
|
std.debug.assert(n == len);
|
||||||
return buf;
|
return buf;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn debugValue(self: *const Context, js_val: v8.Value, writer: *std.Io.Writer) !void {
|
pub fn debugValue(self: *const Context, js_val: js.Value, writer: *std.Io.Writer) !void {
|
||||||
var seen: std.AutoHashMapUnmanaged(u32, void) = .empty;
|
var seen: std.AutoHashMapUnmanaged(u32, void) = .empty;
|
||||||
return _debugValue(self, js_val, &seen, 0, writer) catch error.WriteFailed;
|
return _debugValue(self, js_val, &seen, 0, writer) catch error.WriteFailed;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn _debugValue(self: *const Context, js_val: v8.Value, seen: *std.AutoHashMapUnmanaged(u32, void), depth: usize, writer: *std.Io.Writer) !void {
|
fn _debugValue(self: *const Context, js_val: js.Value, seen: *std.AutoHashMapUnmanaged(u32, void), depth: usize, writer: *std.Io.Writer) !void {
|
||||||
if (js_val.isNull()) {
|
if (js_val.isNull()) {
|
||||||
// I think null can sometimes appear as an object, so check this and
|
// I think null can sometimes appear as an object, so check this and
|
||||||
// handle it first.
|
// handle it first.
|
||||||
@@ -1095,10 +1086,10 @@ fn _debugValue(self: *const Context, js_val: v8.Value, seen: *std.AutoHashMapUnm
|
|||||||
if (js_val.isSymbol()) {
|
if (js_val.isSymbol()) {
|
||||||
const js_sym = v8.Symbol{ .handle = js_val.handle };
|
const js_sym = v8.Symbol{ .handle = js_val.handle };
|
||||||
const js_sym_desc = js_sym.getDescription(v8_isolate);
|
const js_sym_desc = js_sym.getDescription(v8_isolate);
|
||||||
const js_sym_str = try self.valueToString(js_sym_desc, .{});
|
const js_sym_str = try self.valueToString(js.Value{ .ctx = self, .handle = js_sym_desc.handle }, .{});
|
||||||
return writer.print("{s} (symbol)", .{js_sym_str});
|
return writer.print("{s} (symbol)", .{js_sym_str});
|
||||||
}
|
}
|
||||||
const js_type = try self.jsStringToZig(try js_val.typeOf(v8_isolate), .{});
|
const js_type = try self.jsStringToZig(js_val.typeOf(), .{});
|
||||||
const js_val_str = try self.valueToString(js_val, .{});
|
const js_val_str = try self.valueToString(js_val, .{});
|
||||||
if (js_val_str.len > 2000) {
|
if (js_val_str.len > 2000) {
|
||||||
try writer.writeAll(js_val_str[0..2000]);
|
try writer.writeAll(js_val_str[0..2000]);
|
||||||
@@ -1144,11 +1135,12 @@ fn _debugValue(self: *const Context, js_val: v8.Value, seen: *std.AutoHashMapUnm
|
|||||||
try writer.writeByte('\n');
|
try writer.writeByte('\n');
|
||||||
}
|
}
|
||||||
const field_name = try names_obj.getAtIndex(v8_context, @intCast(i));
|
const field_name = try names_obj.getAtIndex(v8_context, @intCast(i));
|
||||||
const name = try self.valueToString(field_name, .{});
|
const name = try self.valueToString(js.Value{ .ctx = self, .handle = field_name.handle }, .{});
|
||||||
try writer.splatByteAll(' ', depth);
|
try writer.splatByteAll(' ', depth);
|
||||||
try writer.writeAll(name);
|
try writer.writeAll(name);
|
||||||
try writer.writeAll(": ");
|
try writer.writeAll(": ");
|
||||||
try self._debugValue(try js_obj.getValue(v8_context, field_name), seen, depth + 1, writer);
|
const field_val = try js_obj.getValue(v8_context, field_name);
|
||||||
|
try self._debugValue(js.Value{ .ctx = self, .handle = field_val.handle }, seen, depth + 1, writer);
|
||||||
if (i != len - 1) {
|
if (i != len - 1) {
|
||||||
try writer.writeByte('\n');
|
try writer.writeByte('\n');
|
||||||
}
|
}
|
||||||
@@ -1220,7 +1212,7 @@ fn resolveModuleCallback(
|
|||||||
|
|
||||||
const self = fromC(c_context.?);
|
const self = fromC(c_context.?);
|
||||||
|
|
||||||
const specifier = self.jsStringToZigZ(.{ .handle = c_specifier.? }, .{}) catch |err| {
|
const specifier = self.jsStringToZigZ(c_specifier.?, .{}) catch |err| {
|
||||||
log.err(.js, "resolve module", .{ .err = err });
|
log.err(.js, "resolve module", .{ .err = err });
|
||||||
return null;
|
return null;
|
||||||
};
|
};
|
||||||
@@ -1247,12 +1239,12 @@ pub fn dynamicModuleCallback(
|
|||||||
|
|
||||||
const self = fromC(c_context.?);
|
const self = fromC(c_context.?);
|
||||||
|
|
||||||
const resource = self.jsStringToZigZ(.{ .handle = resource_name.? }, .{}) catch |err| {
|
const resource = self.jsStringToZigZ(resource_name.?, .{}) catch |err| {
|
||||||
log.err(.app, "OOM", .{ .err = err, .src = "dynamicModuleCallback1" });
|
log.err(.app, "OOM", .{ .err = err, .src = "dynamicModuleCallback1" });
|
||||||
return @constCast((self.rejectPromise("Out of memory") catch return null).handle);
|
return @constCast((self.rejectPromise("Out of memory") catch return null).handle);
|
||||||
};
|
};
|
||||||
|
|
||||||
const specifier = self.jsStringToZigZ(.{ .handle = v8_specifier.? }, .{}) catch |err| {
|
const specifier = self.jsStringToZigZ(v8_specifier.?, .{}) catch |err| {
|
||||||
log.err(.app, "OOM", .{ .err = err, .src = "dynamicModuleCallback2" });
|
log.err(.app, "OOM", .{ .err = err, .src = "dynamicModuleCallback2" });
|
||||||
return @constCast((self.rejectPromise("Out of memory") catch return null).handle);
|
return @constCast((self.rejectPromise("Out of memory") catch return null).handle);
|
||||||
};
|
};
|
||||||
@@ -1278,7 +1270,7 @@ pub fn dynamicModuleCallback(
|
|||||||
pub fn metaObjectCallback(c_context: ?*v8.C_Context, c_module: ?*v8.C_Module, c_meta: ?*v8.C_Value) callconv(.c) void {
|
pub fn metaObjectCallback(c_context: ?*v8.C_Context, c_module: ?*v8.C_Module, c_meta: ?*v8.C_Value) callconv(.c) void {
|
||||||
const self = fromC(c_context.?);
|
const self = fromC(c_context.?);
|
||||||
const m = js.Module{ .handle = c_module.? };
|
const m = js.Module{ .handle = c_module.? };
|
||||||
const meta = v8.Object{ .handle = c_meta.? };
|
const meta = js.Object{ .ctx = self, .handle = @ptrCast(c_meta.?) };
|
||||||
|
|
||||||
const url = self.module_identifier.get(m.getIdentityHash()) orelse {
|
const url = self.module_identifier.get(m.getIdentityHash()) orelse {
|
||||||
// Shouldn't be possible.
|
// Shouldn't be possible.
|
||||||
@@ -1286,11 +1278,11 @@ pub fn metaObjectCallback(c_context: ?*v8.C_Context, c_module: ?*v8.C_Module, c_
|
|||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
|
|
||||||
const v8_isolate = v8.Isolate{ .handle = self.isolate.handle };
|
const js_value = self.zigValueToJs(url, .{}) catch {
|
||||||
const js_key = v8.String.initUtf8(v8_isolate, "url");
|
log.err(.js, "import meta", .{ .err = error.FailedToConvertUrl });
|
||||||
const js_value = try self.zigValueToJs(url, .{});
|
return;
|
||||||
const v8_context = v8.Context{ .handle = self.handle };
|
};
|
||||||
const res = meta.defineOwnProperty(v8_context, js_key.toName(), js_value, 0) orelse false;
|
const res = meta.defineOwnProperty("url", js_value, 0) orelse false;
|
||||||
if (!res) {
|
if (!res) {
|
||||||
log.err(.js, "import meta", .{ .err = error.FailedToSet });
|
log.err(.js, "import meta", .{ .err = error.FailedToSet });
|
||||||
}
|
}
|
||||||
@@ -1321,7 +1313,7 @@ fn _resolveModuleCallback(self: *Context, referrer: js.Module, specifier: [:0]co
|
|||||||
defer try_catch.deinit();
|
defer try_catch.deinit();
|
||||||
|
|
||||||
const v8_isolate = v8.Isolate{ .handle = self.isolate.handle };
|
const v8_isolate = v8.Isolate{ .handle = self.isolate.handle };
|
||||||
const mod = try compileModule(v8_isolate, source.src(), normalized_specifier);
|
const mod = try compileModule(self.isolate, source.src(), normalized_specifier);
|
||||||
try self.postCompileModule(mod, normalized_specifier);
|
try self.postCompileModule(mod, normalized_specifier);
|
||||||
const v8_module = v8.Module{ .handle = mod.handle };
|
const v8_module = v8.Module{ .handle = mod.handle };
|
||||||
entry.module = PersistentModule.init(v8_isolate, v8_module);
|
entry.module = PersistentModule.init(v8_isolate, v8_module);
|
||||||
@@ -1385,7 +1377,7 @@ fn _dynamicModuleCallback(self: *Context, specifier: [:0]const u8, referrer: []c
|
|||||||
|
|
||||||
// Next, we need to actually load it.
|
// Next, we need to actually load it.
|
||||||
self.script_manager.?.getAsyncImport(specifier, dynamicModuleSourceCallback, state, referrer) catch |err| {
|
self.script_manager.?.getAsyncImport(specifier, dynamicModuleSourceCallback, state, referrer) catch |err| {
|
||||||
const error_msg = v8.String.initUtf8(v8_isolate, @errorName(err));
|
const error_msg = isolate.initString(@errorName(err));
|
||||||
_ = resolver.reject(v8_context, error_msg.toValue());
|
_ = resolver.reject(v8_context, error_msg.toValue());
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -1423,7 +1415,7 @@ fn _dynamicModuleCallback(self: *Context, specifier: [:0]const u8, referrer: []c
|
|||||||
// the module was loaded, but not evaluated, we _have_ to evaluate it now
|
// the module was loaded, but not evaluated, we _have_ to evaluate it now
|
||||||
const evaluated = mod.evaluate(v8_context) catch {
|
const evaluated = mod.evaluate(v8_context) catch {
|
||||||
std.debug.assert(status == .kErrored);
|
std.debug.assert(status == .kErrored);
|
||||||
const error_msg = v8.String.initUtf8(v8_isolate, "Module evaluation failed");
|
const error_msg = isolate.initString("Module evaluation failed");
|
||||||
_ = resolver.reject(v8_context, error_msg.toValue());
|
_ = resolver.reject(v8_context, error_msg.toValue());
|
||||||
const v8_promise = promise;
|
const v8_promise = promise;
|
||||||
return .{ .handle = v8_promise.handle };
|
return .{ .handle = v8_promise.handle };
|
||||||
@@ -1450,8 +1442,7 @@ fn dynamicModuleSourceCallback(ctx: *anyopaque, module_source_: anyerror!ScriptM
|
|||||||
var self = state.context;
|
var self = state.context;
|
||||||
|
|
||||||
var ms = module_source_ catch |err| {
|
var ms = module_source_ catch |err| {
|
||||||
const v8_isolate = v8.Isolate{ .handle = self.isolate.handle };
|
const error_msg = self.isolate.initString(@errorName(err));
|
||||||
const error_msg = v8.String.initUtf8(v8_isolate, @errorName(err));
|
|
||||||
const v8_context = v8.Context{ .handle = self.handle };
|
const v8_context = v8.Context{ .handle = self.handle };
|
||||||
_ = state.resolver.castToPromiseResolver().reject(v8_context, error_msg.toValue());
|
_ = state.resolver.castToPromiseResolver().reject(v8_context, error_msg.toValue());
|
||||||
return;
|
return;
|
||||||
@@ -1472,9 +1463,8 @@ fn dynamicModuleSourceCallback(ctx: *anyopaque, module_source_: anyerror!ScriptM
|
|||||||
.stack = try_catch.stack(self.call_arena) catch null,
|
.stack = try_catch.stack(self.call_arena) catch null,
|
||||||
.line = try_catch.sourceLineNumber() orelse 0,
|
.line = try_catch.sourceLineNumber() orelse 0,
|
||||||
});
|
});
|
||||||
const v8_isolate = v8.Isolate{ .handle = self.isolate.handle };
|
|
||||||
const v8_context = v8.Context{ .handle = self.handle };
|
const v8_context = v8.Context{ .handle = self.handle };
|
||||||
const error_msg = v8.String.initUtf8(v8_isolate, ex);
|
const error_msg = self.isolate.initString(ex);
|
||||||
_ = state.resolver.castToPromiseResolver().reject(v8_context, error_msg.toValue());
|
_ = state.resolver.castToPromiseResolver().reject(v8_context, error_msg.toValue());
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
@@ -1506,10 +1496,12 @@ fn resolveDynamicModule(self: *Context, state: *DynamicModuleResolveState, modul
|
|||||||
|
|
||||||
const then_callback = v8.Function.initWithData(ctx, struct {
|
const then_callback = v8.Function.initWithData(ctx, struct {
|
||||||
pub fn callback(raw_info: ?*const v8.c.FunctionCallbackInfo) callconv(.c) void {
|
pub fn callback(raw_info: ?*const v8.c.FunctionCallbackInfo) callconv(.c) void {
|
||||||
var info = v8.FunctionCallbackInfo.initFromV8(raw_info);
|
const callback_v8_isolate = v8.c.v8__FunctionCallbackInfo__GetIsolate(raw_info).?;
|
||||||
var caller = Caller.init(info);
|
var caller = Caller.init(callback_v8_isolate);
|
||||||
defer caller.deinit();
|
defer caller.deinit();
|
||||||
|
|
||||||
|
var info = v8.FunctionCallbackInfo.initFromV8(raw_info);
|
||||||
|
|
||||||
const s: *DynamicModuleResolveState = @ptrCast(@alignCast(info.getExternalValue()));
|
const s: *DynamicModuleResolveState = @ptrCast(@alignCast(info.getExternalValue()));
|
||||||
|
|
||||||
if (s.context_id != caller.context.id) {
|
if (s.context_id != caller.context.id) {
|
||||||
@@ -1530,10 +1522,12 @@ fn resolveDynamicModule(self: *Context, state: *DynamicModuleResolveState, modul
|
|||||||
|
|
||||||
const catch_callback = v8.Function.initWithData(ctx, struct {
|
const catch_callback = v8.Function.initWithData(ctx, struct {
|
||||||
pub fn callback(raw_info: ?*const v8.c.FunctionCallbackInfo) callconv(.c) void {
|
pub fn callback(raw_info: ?*const v8.c.FunctionCallbackInfo) callconv(.c) void {
|
||||||
var info = v8.FunctionCallbackInfo.initFromV8(raw_info);
|
const callback_v8_isolate = v8.c.v8__FunctionCallbackInfo__GetIsolate(raw_info).?;
|
||||||
var caller = Caller.init(info);
|
var caller = Caller.init(callback_v8_isolate);
|
||||||
defer caller.deinit();
|
defer caller.deinit();
|
||||||
|
|
||||||
|
var info = v8.FunctionCallbackInfo.initFromV8(raw_info);
|
||||||
|
|
||||||
const s: *DynamicModuleResolveState = @ptrCast(@alignCast(info.getExternalValue()));
|
const s: *DynamicModuleResolveState = @ptrCast(@alignCast(info.getExternalValue()));
|
||||||
if (s.context_id != caller.context.id) {
|
if (s.context_id != caller.context.id) {
|
||||||
return;
|
return;
|
||||||
@@ -1549,7 +1543,7 @@ fn resolveDynamicModule(self: *Context, state: *DynamicModuleResolveState, modul
|
|||||||
.err = err,
|
.err = err,
|
||||||
.specifier = state.specifier,
|
.specifier = state.specifier,
|
||||||
});
|
});
|
||||||
const error_msg = v8.String.initUtf8(v8_isolate, "Failed to evaluate promise");
|
const error_msg = isolate.initString("Failed to evaluate promise");
|
||||||
_ = state.resolver.castToPromiseResolver().reject(ctx, error_msg.toValue());
|
_ = state.resolver.castToPromiseResolver().reject(ctx, error_msg.toValue());
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@@ -1558,7 +1552,9 @@ fn resolveDynamicModule(self: *Context, state: *DynamicModuleResolveState, modul
|
|||||||
|
|
||||||
// Reverses the mapZigInstanceToJs, making sure that our TaggedAnyOpaque
|
// Reverses the mapZigInstanceToJs, making sure that our TaggedAnyOpaque
|
||||||
// contains a ptr to the correct type.
|
// contains a ptr to the correct type.
|
||||||
pub fn typeTaggedAnyOpaque(comptime R: type, js_obj: v8.Object) !R {
|
pub fn typeTaggedAnyOpaque(comptime R: type, js_obj_handle: *const v8.c.Object) !R {
|
||||||
|
const js_obj = v8.Object{ .handle = js_obj_handle };
|
||||||
|
|
||||||
const ti = @typeInfo(R);
|
const ti = @typeInfo(R);
|
||||||
if (ti != .pointer) {
|
if (ti != .pointer) {
|
||||||
@compileError("non-pointer Zig parameter type: " ++ @typeName(R));
|
@compileError("non-pointer Zig parameter type: " ++ @typeName(R));
|
||||||
@@ -1671,7 +1667,7 @@ fn ProbeResult(comptime T: type) type {
|
|||||||
invalid: void,
|
invalid: void,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
fn probeJsValueToZig(self: *Context, comptime T: type, js_value: v8.Value) !ProbeResult(T) {
|
fn probeJsValueToZig(self: *Context, comptime T: type, js_value: js.Value) !ProbeResult(T) {
|
||||||
switch (@typeInfo(T)) {
|
switch (@typeInfo(T)) {
|
||||||
.optional => |o| {
|
.optional => |o| {
|
||||||
if (js_value.isNullOrUndefined()) {
|
if (js_value.isNullOrUndefined()) {
|
||||||
@@ -1720,7 +1716,7 @@ fn probeJsValueToZig(self: *Context, comptime T: type, js_value: v8.Value) !Prob
|
|||||||
// of having a version of typeTaggedAnyOpaque which
|
// of having a version of typeTaggedAnyOpaque which
|
||||||
// returns a boolean or an optional, we rely on the
|
// returns a boolean or an optional, we rely on the
|
||||||
// main implementation and just handle the error.
|
// main implementation and just handle the error.
|
||||||
const attempt = typeTaggedAnyOpaque(*ptr.child, js_obj);
|
const attempt = typeTaggedAnyOpaque(*ptr.child, js_obj.handle);
|
||||||
if (attempt) |value| {
|
if (attempt) |value| {
|
||||||
return .{ .value = value };
|
return .{ .value = value };
|
||||||
} else |_| {
|
} else |_| {
|
||||||
@@ -1788,7 +1784,8 @@ fn probeJsValueToZig(self: *Context, comptime T: type, js_value: v8.Value) !Prob
|
|||||||
// not tricky in this case either.
|
// not tricky in this case either.
|
||||||
const v8_context = v8.Context{ .handle = self.handle };
|
const v8_context = v8.Context{ .handle = self.handle };
|
||||||
const js_obj = js_arr.castTo(v8.Object);
|
const js_obj = js_arr.castTo(v8.Object);
|
||||||
switch (try self.probeJsValueToZig(ptr.child, try js_obj.getAtIndex(v8_context, 0))) {
|
const v8_val = try js_obj.getAtIndex(v8_context, 0);
|
||||||
|
switch (try self.probeJsValueToZig(ptr.child, js.Value{ .ctx = self, .handle = v8_val.handle })) {
|
||||||
.value, .ok => return .{ .ok = {} },
|
.value, .ok => return .{ .ok = {} },
|
||||||
.compatible => return .{ .compatible = {} },
|
.compatible => return .{ .compatible = {} },
|
||||||
.coerce => return .{ .coerce = {} },
|
.coerce => return .{ .coerce = {} },
|
||||||
@@ -1841,25 +1838,25 @@ fn probeJsValueToZig(self: *Context, comptime T: type, js_value: v8.Value) !Prob
|
|||||||
return .{ .invalid = {} };
|
return .{ .invalid = {} };
|
||||||
}
|
}
|
||||||
|
|
||||||
fn jsIntToZig(comptime T: type, js_value: v8.Value, v8_context: v8.Context) !T {
|
fn jsIntToZig(comptime T: type, js_value: js.Value) !T {
|
||||||
const n = @typeInfo(T).int;
|
const n = @typeInfo(T).int;
|
||||||
switch (n.signedness) {
|
switch (n.signedness) {
|
||||||
.signed => switch (n.bits) {
|
.signed => switch (n.bits) {
|
||||||
8 => return jsSignedIntToZig(i8, -128, 127, try js_value.toI32(v8_context)),
|
8 => return jsSignedIntToZig(i8, -128, 127, try js_value.toI32()),
|
||||||
16 => return jsSignedIntToZig(i16, -32_768, 32_767, try js_value.toI32(v8_context)),
|
16 => return jsSignedIntToZig(i16, -32_768, 32_767, try js_value.toI32()),
|
||||||
32 => return jsSignedIntToZig(i32, -2_147_483_648, 2_147_483_647, try js_value.toI32(v8_context)),
|
32 => return jsSignedIntToZig(i32, -2_147_483_648, 2_147_483_647, try js_value.toI32()),
|
||||||
64 => {
|
64 => {
|
||||||
if (js_value.isBigInt()) {
|
if (js_value.isBigInt()) {
|
||||||
const v = js_value.castTo(v8.BigInt);
|
const v = js_value.castTo(v8.BigInt);
|
||||||
return v.getInt64();
|
return v.getInt64();
|
||||||
}
|
}
|
||||||
return jsSignedIntToZig(i64, -2_147_483_648, 2_147_483_647, try js_value.toI32(v8_context));
|
return jsSignedIntToZig(i64, -2_147_483_648, 2_147_483_647, try js_value.toI32());
|
||||||
},
|
},
|
||||||
else => {},
|
else => {},
|
||||||
},
|
},
|
||||||
.unsigned => switch (n.bits) {
|
.unsigned => switch (n.bits) {
|
||||||
8 => return jsUnsignedIntToZig(u8, 255, try js_value.toU32(v8_context)),
|
8 => return jsUnsignedIntToZig(u8, 255, try js_value.toU32()),
|
||||||
16 => return jsUnsignedIntToZig(u16, 65_535, try js_value.toU32(v8_context)),
|
16 => return jsUnsignedIntToZig(u16, 65_535, try js_value.toU32()),
|
||||||
32 => {
|
32 => {
|
||||||
if (js_value.isBigInt()) {
|
if (js_value.isBigInt()) {
|
||||||
const v = js_value.castTo(v8.BigInt);
|
const v = js_value.castTo(v8.BigInt);
|
||||||
@@ -1869,14 +1866,14 @@ fn jsIntToZig(comptime T: type, js_value: v8.Value, v8_context: v8.Context) !T {
|
|||||||
}
|
}
|
||||||
return error.InvalidArgument;
|
return error.InvalidArgument;
|
||||||
}
|
}
|
||||||
return jsUnsignedIntToZig(u32, 4_294_967_295, try js_value.toU32(v8_context));
|
return jsUnsignedIntToZig(u32, 4_294_967_295, try js_value.toU32());
|
||||||
},
|
},
|
||||||
64 => {
|
64 => {
|
||||||
if (js_value.isBigInt()) {
|
if (js_value.isBigInt()) {
|
||||||
const v = js_value.castTo(v8.BigInt);
|
const v = js_value.castTo(v8.BigInt);
|
||||||
return v.getUint64();
|
return v.getUint64();
|
||||||
}
|
}
|
||||||
return jsUnsignedIntToZig(u64, 4_294_967_295, try js_value.toU32(v8_context));
|
return jsUnsignedIntToZig(u64, 4_294_967_295, try js_value.toU32());
|
||||||
},
|
},
|
||||||
else => {},
|
else => {},
|
||||||
},
|
},
|
||||||
@@ -1899,8 +1896,8 @@ fn jsUnsignedIntToZig(comptime T: type, max: comptime_int, maybe: u32) !T {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn compileAndRun(self: *Context, src: []const u8, name: ?[]const u8) !js.Value {
|
fn compileAndRun(self: *Context, src: []const u8, name: ?[]const u8) !js.Value {
|
||||||
const script_name = self.isolate.newStringHandle(name orelse "anonymous");
|
const script_name = self.isolate.createStringHandle(name orelse "anonymous");
|
||||||
const script_source = self.isolate.newStringHandle(src);
|
const script_source = self.isolate.createStringHandle(src);
|
||||||
|
|
||||||
// Create ScriptOrigin
|
// Create ScriptOrigin
|
||||||
var origin: v8.c.ScriptOrigin = undefined;
|
var origin: v8.c.ScriptOrigin = undefined;
|
||||||
@@ -1924,10 +1921,11 @@ fn compileAndRun(self: *Context, src: []const u8, name: ?[]const u8) !js.Value {
|
|||||||
return .{ .ctx = self, .handle = result };
|
return .{ .ctx = self, .handle = result };
|
||||||
}
|
}
|
||||||
|
|
||||||
fn compileModule(isolate: v8.Isolate, src: []const u8, name: []const u8) !js.Module {
|
fn compileModule(isolate: js.Isolate, src: []const u8, name: []const u8) !js.Module {
|
||||||
// compile
|
// compile
|
||||||
const script_name = v8.String.initUtf8(isolate, name);
|
const v8_isolate = v8.Isolate{ .handle = isolate.handle };
|
||||||
const script_source = v8.String.initUtf8(isolate, src);
|
const script_name = isolate.initString(name);
|
||||||
|
const script_source = isolate.initString(src);
|
||||||
|
|
||||||
const origin = v8.ScriptOrigin.init(
|
const origin = v8.ScriptOrigin.init(
|
||||||
script_name.toValue(),
|
script_name.toValue(),
|
||||||
@@ -1947,7 +1945,7 @@ fn compileModule(isolate: v8.Isolate, src: []const u8, name: []const u8) !js.Mod
|
|||||||
defer script_comp_source.deinit();
|
defer script_comp_source.deinit();
|
||||||
|
|
||||||
const v8_module = v8.ScriptCompiler.compileModule(
|
const v8_module = v8.ScriptCompiler.compileModule(
|
||||||
isolate,
|
v8_isolate,
|
||||||
&script_comp_source,
|
&script_comp_source,
|
||||||
.kNoCompileOptions,
|
.kNoCompileOptions,
|
||||||
.kNoCacheNoReason,
|
.kNoCacheNoReason,
|
||||||
@@ -1955,40 +1953,44 @@ fn compileModule(isolate: v8.Isolate, src: []const u8, name: []const u8) !js.Mod
|
|||||||
return .{ .handle = v8_module.handle };
|
return .{ .handle = v8_module.handle };
|
||||||
}
|
}
|
||||||
|
|
||||||
fn zigJsonToJs(isolate: v8.Isolate, v8_context: v8.Context, value: std.json.Value) !v8.Value {
|
fn zigJsonToJs(self: *Context, value: std.json.Value) !js.Value {
|
||||||
|
const isolate = self.isolate;
|
||||||
|
const v8_isolate = v8.Isolate{ .handle = isolate.handle };
|
||||||
|
const v8_context = v8.Context{ .handle = self.handle };
|
||||||
|
|
||||||
switch (value) {
|
switch (value) {
|
||||||
.bool => |v| return js.simpleZigValueToJs(isolate, v, true, false),
|
.bool => |v| return .{ .ctx = self, .handle = js.simpleZigValueToJs(v8_isolate, v, true, false) },
|
||||||
.float => |v| return js.simpleZigValueToJs(isolate, v, true, false),
|
.float => |v| return .{ .ctx = self, .handle = js.simpleZigValueToJs(v8_isolate, v, true, false) },
|
||||||
.integer => |v| return js.simpleZigValueToJs(isolate, v, true, false),
|
.integer => |v| return .{ .ctx = self, .handle = js.simpleZigValueToJs(v8_isolate, v, true, false) },
|
||||||
.string => |v| return js.simpleZigValueToJs(isolate, v, true, false),
|
.string => |v| return .{ .ctx = self, .handle = js.simpleZigValueToJs(v8_isolate, v, true, false) },
|
||||||
.null => return isolate.initNull().toValue(),
|
.null => return .{ .ctx = self, .handle = isolate.initNull() },
|
||||||
|
|
||||||
// TODO handle number_string.
|
// TODO handle number_string.
|
||||||
// It is used to represent too big numbers.
|
// It is used to represent too big numbers.
|
||||||
.number_string => return error.TODO,
|
.number_string => return error.TODO,
|
||||||
|
|
||||||
.array => |v| {
|
.array => |v| {
|
||||||
const a = v8.Array.init(isolate, @intCast(v.items.len));
|
const a = isolate.initArray(@intCast(v.items.len));
|
||||||
const obj = a.castTo(v8.Object);
|
const obj = a.castTo(v8.Object);
|
||||||
for (v.items, 0..) |array_value, i| {
|
for (v.items, 0..) |array_value, i| {
|
||||||
const js_val = try zigJsonToJs(isolate, v8_context, array_value);
|
const js_val = try zigJsonToJs(self, array_value);
|
||||||
if (!obj.setValueAtIndex(v8_context, @intCast(i), js_val)) {
|
if (!obj.setValueAtIndex(v8_context, @intCast(i), .{ .handle = js_val.handle })) {
|
||||||
return error.JSObjectSetValue;
|
return error.JSObjectSetValue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return obj.toValue();
|
return .{ .ctx = self, .handle = @ptrCast(obj.handle) };
|
||||||
},
|
},
|
||||||
.object => |v| {
|
.object => |v| {
|
||||||
var obj = v8.Object.init(isolate);
|
var obj = isolate.initObject();
|
||||||
var it = v.iterator();
|
var it = v.iterator();
|
||||||
while (it.next()) |kv| {
|
while (it.next()) |kv| {
|
||||||
const js_key = v8.String.initUtf8(isolate, kv.key_ptr.*);
|
const js_key = isolate.initString(kv.key_ptr.*);
|
||||||
const js_val = try zigJsonToJs(isolate, v8_context, kv.value_ptr.*);
|
const js_val = try zigJsonToJs(self, kv.value_ptr.*);
|
||||||
if (!obj.setValue(v8_context, js_key, js_val)) {
|
if (!obj.setValue(v8_context, js_key, .{ .handle = js_val.handle })) {
|
||||||
return error.JSObjectSetValue;
|
return error.JSObjectSetValue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return obj.toValue();
|
return .{ .ctx = self, .handle = @ptrCast(obj.handle) };
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -49,15 +49,18 @@ platform: *const Platform,
|
|||||||
isolate: js.Isolate,
|
isolate: js.Isolate,
|
||||||
|
|
||||||
// just kept around because we need to free it on deinit
|
// just kept around because we need to free it on deinit
|
||||||
isolate_params: *v8.CreateParams,
|
isolate_params: *v8.c.CreateParams,
|
||||||
|
|
||||||
context_id: usize,
|
context_id: usize,
|
||||||
|
|
||||||
|
// Global handles that need to be freed on deinit
|
||||||
|
globals: []v8.c.Global,
|
||||||
|
|
||||||
// Dynamic slice to avoid circular dependency on JsApis.len at comptime
|
// Dynamic slice to avoid circular dependency on JsApis.len at comptime
|
||||||
templates: []v8.FunctionTemplate,
|
templates: []*const v8.c.FunctionTemplate,
|
||||||
|
|
||||||
pub fn init(allocator: Allocator, platform: *const Platform, snapshot: *Snapshot) !Env {
|
pub fn init(allocator: Allocator, platform: *const Platform, snapshot: *Snapshot) !Env {
|
||||||
var params = try allocator.create(v8.CreateParams);
|
var params = try allocator.create(v8.c.CreateParams);
|
||||||
errdefer allocator.destroy(params);
|
errdefer allocator.destroy(params);
|
||||||
v8.c.v8__Isolate__CreateParams__CONSTRUCT(params);
|
v8.c.v8__Isolate__CreateParams__CONSTRUCT(params);
|
||||||
params.snapshot_blob = @ptrCast(&snapshot.startup_data);
|
params.snapshot_blob = @ptrCast(&snapshot.startup_data);
|
||||||
@@ -67,39 +70,42 @@ pub fn init(allocator: Allocator, platform: *const Platform, snapshot: *Snapshot
|
|||||||
|
|
||||||
params.external_references = &snapshot.external_references;
|
params.external_references = &snapshot.external_references;
|
||||||
|
|
||||||
var v8_isolate = v8.Isolate.init(params);
|
var isolate = js.Isolate.init(params);
|
||||||
errdefer v8_isolate.deinit();
|
errdefer isolate.deinit();
|
||||||
|
|
||||||
// This is the callback that runs whenever a module is dynamically imported.
|
v8.c.v8__Isolate__SetHostImportModuleDynamicallyCallback(isolate.handle, Context.dynamicModuleCallback);
|
||||||
v8_isolate.setHostImportModuleDynamicallyCallback(Context.dynamicModuleCallback);
|
v8.c.v8__Isolate__SetPromiseRejectCallback(isolate.handle, promiseRejectCallback);
|
||||||
v8_isolate.setPromiseRejectCallback(promiseRejectCallback);
|
v8.c.v8__Isolate__SetMicrotasksPolicy(isolate.handle, v8.c.kExplicit);
|
||||||
v8_isolate.setMicrotasksPolicy(v8.c.kExplicit);
|
|
||||||
|
|
||||||
v8_isolate.enter();
|
isolate.enter();
|
||||||
errdefer v8_isolate.exit();
|
errdefer isolate.exit();
|
||||||
|
|
||||||
v8_isolate.setHostInitializeImportMetaObjectCallback(Context.metaObjectCallback);
|
v8.c.v8__Isolate__SetHostInitializeImportMetaObjectCallback(isolate.handle, Context.metaObjectCallback);
|
||||||
|
|
||||||
const isolate = js.Isolate{ .handle = v8_isolate.handle };
|
// Allocate arrays dynamically to avoid comptime dependency on JsApis.len
|
||||||
|
const globals = try allocator.alloc(v8.c.Global, JsApis.len);
|
||||||
|
errdefer allocator.free(globals);
|
||||||
|
|
||||||
// Allocate templates array dynamically to avoid comptime dependency on JsApis.len
|
const templates = try allocator.alloc(*const v8.c.FunctionTemplate, JsApis.len);
|
||||||
const templates = try allocator.alloc(v8.FunctionTemplate, JsApis.len);
|
|
||||||
errdefer allocator.free(templates);
|
errdefer allocator.free(templates);
|
||||||
|
|
||||||
{
|
{
|
||||||
var temp_scope: js.HandleScope = undefined;
|
var temp_scope: js.HandleScope = undefined;
|
||||||
temp_scope.init(isolate);
|
temp_scope.init(isolate);
|
||||||
defer temp_scope.deinit();
|
defer temp_scope.deinit();
|
||||||
const context = v8.Context.init(v8_isolate, null, null);
|
const context_handle = isolate.createContextHandle(null, null);
|
||||||
|
|
||||||
context.enter();
|
v8.c.v8__Context__Enter(context_handle);
|
||||||
defer context.exit();
|
defer v8.c.v8__Context__Exit(context_handle);
|
||||||
|
|
||||||
inline for (JsApis, 0..) |JsApi, i| {
|
inline for (JsApis, 0..) |JsApi, i| {
|
||||||
JsApi.Meta.class_id = i;
|
JsApi.Meta.class_id = i;
|
||||||
const data = context.getDataFromSnapshotOnce(snapshot.data_start + i);
|
const data = v8.c.v8__Context__GetDataFromSnapshotOnce(context_handle, snapshot.data_start + i);
|
||||||
const function = v8.FunctionTemplate{ .handle = @ptrCast(data) };
|
const function_handle: *const v8.c.FunctionTemplate = @ptrCast(data);
|
||||||
templates[i] = v8.Persistent(v8.FunctionTemplate).init(v8_isolate, function).castToFunctionTemplate();
|
// Make function template global/persistent
|
||||||
|
v8.c.v8__Global__New(isolate.handle, @ptrCast(function_handle), &globals[i]);
|
||||||
|
// Extract the local handle from the global for easy access
|
||||||
|
templates[i] = @ptrCast(@alignCast(@as(*const anyopaque, @ptrFromInt(globals[i].data_ptr))));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -108,17 +114,24 @@ pub fn init(allocator: Allocator, platform: *const Platform, snapshot: *Snapshot
|
|||||||
.isolate = isolate,
|
.isolate = isolate,
|
||||||
.platform = platform,
|
.platform = platform,
|
||||||
.allocator = allocator,
|
.allocator = allocator,
|
||||||
|
.globals = globals,
|
||||||
.templates = templates,
|
.templates = templates,
|
||||||
.isolate_params = params,
|
.isolate_params = params,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn deinit(self: *Env) void {
|
pub fn deinit(self: *Env) void {
|
||||||
|
// Free global handles before destroying the isolate
|
||||||
|
for (self.globals) |*global| {
|
||||||
|
v8.c.v8__Global__Reset(global);
|
||||||
|
}
|
||||||
|
self.allocator.free(self.globals);
|
||||||
|
self.allocator.free(self.templates);
|
||||||
|
|
||||||
self.isolate.exit();
|
self.isolate.exit();
|
||||||
self.isolate.deinit();
|
self.isolate.deinit();
|
||||||
v8.destroyArrayBufferAllocator(self.isolate_params.array_buffer_allocator.?);
|
v8.destroyArrayBufferAllocator(self.isolate_params.array_buffer_allocator.?);
|
||||||
self.allocator.destroy(self.isolate_params);
|
self.allocator.destroy(self.isolate_params);
|
||||||
self.allocator.free(self.templates);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn newInspector(self: *Env, arena: Allocator, ctx: anytype) !*Inspector {
|
pub fn newInspector(self: *Env, arena: Allocator, ctx: anytype) !*Inspector {
|
||||||
@@ -180,13 +193,13 @@ pub fn dumpMemoryStats(self: *Env) void {
|
|||||||
|
|
||||||
fn promiseRejectCallback(v8_msg: v8.C_PromiseRejectMessage) callconv(.c) void {
|
fn promiseRejectCallback(v8_msg: v8.C_PromiseRejectMessage) callconv(.c) void {
|
||||||
const msg = v8.PromiseRejectMessage.initFromC(v8_msg);
|
const msg = v8.PromiseRejectMessage.initFromC(v8_msg);
|
||||||
const v8_isolate = msg.getPromise().toObject().getIsolate();
|
const isolate_handle = v8.c.v8__Object__GetIsolate(@ptrCast(msg.getPromise().handle)).?;
|
||||||
const js_isolate = js.Isolate{ .handle = v8_isolate.handle };
|
const js_isolate = js.Isolate{ .handle = isolate_handle };
|
||||||
const context = Context.fromIsolate(js_isolate);
|
const context = Context.fromIsolate(js_isolate);
|
||||||
|
|
||||||
const value =
|
const value =
|
||||||
if (msg.getValue()) |v8_value|
|
if (msg.getValue()) |v8_value|
|
||||||
context.valueToString(v8_value, .{}) catch |err| @errorName(err)
|
context.valueToString(js.Value{ .ctx = context, .handle = v8_value.handle }, .{}) catch |err| @errorName(err)
|
||||||
else
|
else
|
||||||
"no value";
|
"no value";
|
||||||
|
|
||||||
|
|||||||
@@ -76,24 +76,33 @@ pub fn createContext(self: *ExecutionWorld, page: *Page, enter: bool) !*Context
|
|||||||
const isolate = env.isolate;
|
const isolate = env.isolate;
|
||||||
const arena = self.context_arena.allocator();
|
const arena = self.context_arena.allocator();
|
||||||
|
|
||||||
var v8_context: v8.Context = blk: {
|
const context_handle: *const v8.c.Context = blk: {
|
||||||
const v8_isolate = v8.Isolate{ .handle = isolate.handle };
|
|
||||||
var temp_scope: js.HandleScope = undefined;
|
var temp_scope: js.HandleScope = undefined;
|
||||||
temp_scope.init(isolate);
|
temp_scope.init(isolate);
|
||||||
defer temp_scope.deinit();
|
defer temp_scope.deinit();
|
||||||
|
|
||||||
// Creates a global template that inherits from Window.
|
// Getting this into the snapshot is tricky (anything involving the
|
||||||
const global_template = @import("Snapshot.zig").createGlobalTemplate(isolate, env.templates);
|
// global is tricky). Easier to do here.
|
||||||
// Add the named property handler
|
const func_tmpl_handle = isolate.createFunctionTemplateHandle();
|
||||||
global_template.setNamedProperty(v8.NamedPropertyHandlerConfiguration{
|
const global_template = v8.c.v8__FunctionTemplate__InstanceTemplate(func_tmpl_handle).?;
|
||||||
|
var configuration: v8.c.NamedPropertyHandlerConfiguration = .{
|
||||||
.getter = unknownPropertyCallback,
|
.getter = unknownPropertyCallback,
|
||||||
.flags = v8.PropertyHandlerFlags.NonMasking | v8.PropertyHandlerFlags.OnlyInterceptStrings,
|
.setter = null,
|
||||||
}, null);
|
.query = null,
|
||||||
|
.deleter = null,
|
||||||
|
.enumerator = null,
|
||||||
|
.definer = null,
|
||||||
|
.descriptor = null,
|
||||||
|
.data = null,
|
||||||
|
.flags = v8.c.kOnlyInterceptStrings | v8.c.kNonMasking,
|
||||||
|
};
|
||||||
|
v8.c.v8__ObjectTemplate__SetNamedHandler(global_template, &configuration);
|
||||||
|
|
||||||
|
const context_local = isolate.createContextHandle(null, null);
|
||||||
const context_local = v8.Context.init(isolate, global_template, null);
|
// Make the context persistent so it survives beyond this handle scope
|
||||||
const v8_context = v8.Persistent(v8.Context).init(isolate, context_local).castToContext();
|
var persistent_handle: *v8.c.Data = undefined;
|
||||||
break :blk v8_context;
|
v8.c.v8__Persistent__New(isolate.handle, @ptrCast(context_local), @ptrCast(&persistent_handle));
|
||||||
|
break :blk @ptrCast(persistent_handle);
|
||||||
};
|
};
|
||||||
|
|
||||||
// For a Page we only create one HandleScope, it is stored in the main World (enter==true). A page can have multple contexts, 1 for each World.
|
// For a Page we only create one HandleScope, it is stored in the main World (enter==true). A page can have multple contexts, 1 for each World.
|
||||||
@@ -103,10 +112,10 @@ pub fn createContext(self: *ExecutionWorld, page: *Page, enter: bool) !*Context
|
|||||||
if (enter) {
|
if (enter) {
|
||||||
handle_scope = @as(js.HandleScope, undefined);
|
handle_scope = @as(js.HandleScope, undefined);
|
||||||
handle_scope.?.init(isolate);
|
handle_scope.?.init(isolate);
|
||||||
v8_context.enter();
|
v8.c.v8__Context__Enter(context_handle);
|
||||||
}
|
}
|
||||||
errdefer if (enter) {
|
errdefer if (enter) {
|
||||||
v8_context.exit();
|
v8.c.v8__Context__Exit(context_handle);
|
||||||
handle_scope.?.deinit();
|
handle_scope.?.deinit();
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -117,7 +126,7 @@ pub fn createContext(self: *ExecutionWorld, page: *Page, enter: bool) !*Context
|
|||||||
.page = page,
|
.page = page,
|
||||||
.id = context_id,
|
.id = context_id,
|
||||||
.isolate = isolate,
|
.isolate = isolate,
|
||||||
.handle = v8_context.handle,
|
.handle = context_handle,
|
||||||
.templates = env.templates,
|
.templates = env.templates,
|
||||||
.handle_scope = handle_scope,
|
.handle_scope = handle_scope,
|
||||||
.script_manager = &page._script_manager,
|
.script_manager = &page._script_manager,
|
||||||
@@ -128,9 +137,8 @@ pub fn createContext(self: *ExecutionWorld, page: *Page, enter: bool) !*Context
|
|||||||
var context = &self.context.?;
|
var context = &self.context.?;
|
||||||
// Store a pointer to our context inside the v8 context so that, given
|
// Store a pointer to our context inside the v8 context so that, given
|
||||||
// a v8 context, we can get our context out
|
// a v8 context, we can get our context out
|
||||||
const v8_isolate = v8.Isolate{ .handle = isolate.handle };
|
const data = isolate.initBigIntU64(@intCast(@intFromPtr(context)));
|
||||||
const data = v8_isolate.initBigIntU64(@intCast(@intFromPtr(context)));
|
v8.c.v8__Context__SetEmbedderData(context_handle, 1, @ptrCast(data.handle));
|
||||||
v8_context.setEmbedderData(1, data);
|
|
||||||
|
|
||||||
try context.setupGlobal();
|
try context.setupGlobal();
|
||||||
return context;
|
return context;
|
||||||
@@ -157,10 +165,12 @@ pub fn resumeExecution(self: *const ExecutionWorld) void {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn unknownPropertyCallback(c_name: ?*const v8.C_Name, raw_info: ?*const v8.C_PropertyCallbackInfo) callconv(.c) u8 {
|
pub fn unknownPropertyCallback(c_name: ?*const v8.C_Name, raw_info: ?*const v8.C_PropertyCallbackInfo) callconv(.c) u8 {
|
||||||
const info = v8.PropertyCallbackInfo.initFromV8(raw_info);
|
const isolate_handle = v8.c.v8__PropertyCallbackInfo__GetIsolate(raw_info).?;
|
||||||
const context = Context.fromIsolate(info.getIsolate());
|
const context = Context.fromIsolate(.{ .handle = isolate_handle });
|
||||||
|
|
||||||
const maybe_property: ?[]u8 = context.valueToString(.{ .handle = c_name.? }, .{}) catch null;
|
const property: ?[]u8 = context.valueToString(.{ .ctx = context, .handle = c_name.? }, .{}) catch {
|
||||||
|
return v8.Intercepted.No;
|
||||||
|
};
|
||||||
|
|
||||||
const ignored = std.StaticStringMap(void).initComptime(.{
|
const ignored = std.StaticStringMap(void).initComptime(.{
|
||||||
.{ "process", {} },
|
.{ "process", {} },
|
||||||
@@ -184,12 +194,11 @@ pub fn unknownPropertyCallback(c_name: ?*const v8.C_Name, raw_info: ?*const v8.C
|
|||||||
.{ "CLOSURE_FLAGS", {} },
|
.{ "CLOSURE_FLAGS", {} },
|
||||||
});
|
});
|
||||||
|
|
||||||
if (maybe_property) |prop| {
|
if (!ignored.has(property)) {
|
||||||
if (!ignored.has(prop)) {
|
|
||||||
const page = context.page;
|
const page = context.page;
|
||||||
const document = page.document;
|
const document = page.document;
|
||||||
|
|
||||||
if (document.getElementById(prop, page)) |el| {
|
if (document.getElementById(property, page)) |el| {
|
||||||
const js_value = context.zigValueToJs(el, .{}) catch {
|
const js_value = context.zigValueToJs(el, .{}) catch {
|
||||||
return v8.Intercepted.No;
|
return v8.Intercepted.No;
|
||||||
};
|
};
|
||||||
@@ -202,11 +211,10 @@ pub fn unknownPropertyCallback(c_name: ?*const v8.C_Name, raw_info: ?*const v8.C
|
|||||||
log.debug(.unknown_prop, "unknown global property", .{
|
log.debug(.unknown_prop, "unknown global property", .{
|
||||||
.info = "but the property can exist in pure JS",
|
.info = "but the property can exist in pure JS",
|
||||||
.stack = context.stackTrace() catch "???",
|
.stack = context.stackTrace() catch "???",
|
||||||
.property = prop,
|
.property = property,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
return v8.Intercepted.No;
|
return v8.Intercepted.No;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -134,20 +134,20 @@ pub fn callWithThis(self: *const Function, comptime T: type, this: anytype, args
|
|||||||
|
|
||||||
const aargs = if (comptime @typeInfo(@TypeOf(args)) == .null) struct {}{} else args;
|
const aargs = if (comptime @typeInfo(@TypeOf(args)) == .null) struct {}{} else args;
|
||||||
|
|
||||||
const js_args: []const v8.Value = switch (@typeInfo(@TypeOf(aargs))) {
|
const js_args: []const *const v8.c.Value = switch (@typeInfo(@TypeOf(aargs))) {
|
||||||
.@"struct" => |s| blk: {
|
.@"struct" => |s| blk: {
|
||||||
const fields = s.fields;
|
const fields = s.fields;
|
||||||
var js_args: [fields.len]v8.Value = undefined;
|
var js_args: [fields.len]*const v8.c.Value = undefined;
|
||||||
inline for (fields, 0..) |f, i| {
|
inline for (fields, 0..) |f, i| {
|
||||||
js_args[i] = try ctx.zigValueToJs(@field(aargs, f.name), .{});
|
js_args[i] = (try ctx.zigValueToJs(@field(aargs, f.name), .{})).handle;
|
||||||
}
|
}
|
||||||
const cargs: [fields.len]v8.Value = js_args;
|
const cargs: [fields.len]*const v8.c.Value = js_args;
|
||||||
break :blk &cargs;
|
break :blk &cargs;
|
||||||
},
|
},
|
||||||
.pointer => blk: {
|
.pointer => blk: {
|
||||||
var values = try ctx.call_arena.alloc(v8.Value, args.len);
|
var values = try ctx.call_arena.alloc(*const v8.c.Value, args.len);
|
||||||
for (args, 0..) |a, i| {
|
for (args, 0..) |a, i| {
|
||||||
values[i] = try ctx.zigValueToJs(a, .{});
|
values[i] = (try ctx.zigValueToJs(a, .{})).handle;
|
||||||
}
|
}
|
||||||
break :blk values;
|
break :blk values;
|
||||||
},
|
},
|
||||||
@@ -163,7 +163,7 @@ pub fn callWithThis(self: *const Function, comptime T: type, this: anytype, args
|
|||||||
if (@typeInfo(T) == .void) {
|
if (@typeInfo(T) == .void) {
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
return ctx.jsValueToZig(T, .{ .handle = handle });
|
return ctx.jsValueToZig(T, .{ .ctx = ctx, .handle = handle });
|
||||||
}
|
}
|
||||||
|
|
||||||
fn getThis(self: *const Function) js.Object {
|
fn getThis(self: *const Function) js.Object {
|
||||||
|
|||||||
@@ -195,9 +195,8 @@ pub fn getNodePtr(self: *const Inspector, allocator: Allocator, object_id: []con
|
|||||||
return error.ObjectIdIsNotANode;
|
return error.ObjectIdIsNotANode;
|
||||||
}
|
}
|
||||||
const Node = @import("../webapi/Node.zig");
|
const Node = @import("../webapi/Node.zig");
|
||||||
// Wrap the C handle in a v8.Object for typeTaggedAnyOpaque
|
// Cast to *const v8.c.Object for typeTaggedAnyOpaque
|
||||||
const js_obj = v8.Object{ .handle = js_val };
|
return Context.typeTaggedAnyOpaque(*Node, @ptrCast(js_val)) catch {
|
||||||
return Context.typeTaggedAnyOpaque(*Node, js_obj) catch {
|
|
||||||
return error.ObjectIdIsNotANode;
|
return error.ObjectIdIsNotANode;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -23,10 +23,20 @@ const Isolate = @This();
|
|||||||
|
|
||||||
handle: *v8.c.Isolate,
|
handle: *v8.c.Isolate,
|
||||||
|
|
||||||
|
pub fn init(params: *v8.c.CreateParams) Isolate {
|
||||||
|
return .{
|
||||||
|
.handle = v8.c.v8__Isolate__New(params).?,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
pub fn deinit(self: Isolate) void {
|
pub fn deinit(self: Isolate) void {
|
||||||
v8.c.v8__Isolate__Dispose(self.handle);
|
v8.c.v8__Isolate__Dispose(self.handle);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn enter(self: Isolate) void {
|
||||||
|
v8.c.v8__Isolate__Enter(self.handle);
|
||||||
|
}
|
||||||
|
|
||||||
pub fn exit(self: Isolate) void {
|
pub fn exit(self: Isolate) void {
|
||||||
v8.c.v8__Isolate__Exit(self.handle);
|
v8.c.v8__Isolate__Exit(self.handle);
|
||||||
}
|
}
|
||||||
@@ -54,16 +64,50 @@ pub fn getHeapStatistics(self: Isolate) v8.c.HeapStatistics {
|
|||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn throwException(self: Isolate, value: anytype) v8.Value {
|
pub fn throwException(self: Isolate, value: *const v8.c.Value) *const v8.c.Value {
|
||||||
const handle = switch (@TypeOf(value)) {
|
return v8.c.v8__Isolate__ThrowException(self.handle, value).?;
|
||||||
v8.Value => value.handle,
|
|
||||||
else => @compileError("Unsupported type for throwException"),
|
|
||||||
};
|
|
||||||
return .{
|
|
||||||
.handle = v8.c.v8__Isolate__ThrowException(self.handle, handle).?,
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn newStringHandle(self: Isolate, str: []const u8) *const v8.c.String {
|
pub fn createStringHandle(self: Isolate, str: []const u8) *const v8.c.String {
|
||||||
return v8.c.v8__String__NewFromUtf8(self.handle, str.ptr, v8.c.kNormal, @as(c_int, @intCast(str.len))).?;
|
return v8.c.v8__String__NewFromUtf8(self.handle, str.ptr, v8.c.kNormal, @as(c_int, @intCast(str.len))).?;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn createError(self: Isolate, msg: []const u8) *const v8.c.Value {
|
||||||
|
const message = self.createStringHandle(msg);
|
||||||
|
return v8.c.v8__Exception__Error(message).?;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn createTypeError(self: Isolate, msg: []const u8) *const v8.c.Value {
|
||||||
|
const message = self.createStringHandle(msg);
|
||||||
|
return v8.c.v8__Exception__TypeError(message).?;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn initArray(self: Isolate, len: u32) v8.Array {
|
||||||
|
const handle = v8.c.v8__Array__New(self.handle, @intCast(len)).?;
|
||||||
|
return .{ .handle = handle };
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn initObject(self: Isolate) v8.Object {
|
||||||
|
const handle = v8.c.v8__Object__New(self.handle).?;
|
||||||
|
return .{ .handle = handle };
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn initString(self: Isolate, str: []const u8) v8.String {
|
||||||
|
return .{ .handle = self.createStringHandle(str) };
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn initNull(self: Isolate) *const v8.c.Value {
|
||||||
|
return v8.c.v8__Null(self.handle).?;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn initBigIntU64(self: Isolate, val: u64) js.BigInt {
|
||||||
|
return js.BigInt.initU64(self.handle, val);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn createContextHandle(self: Isolate, global_tmpl: ?*const v8.c.ObjectTemplate, global_obj: ?*const v8.c.Value) *const v8.c.Context {
|
||||||
|
return v8.c.v8__Context__New(self.handle, global_tmpl, global_obj).?;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn createFunctionTemplateHandle(self: Isolate) *const v8.c.FunctionTemplate {
|
||||||
|
return v8.c.v8__FunctionTemplate__New__DEFAULT(self.handle).?;
|
||||||
|
}
|
||||||
|
|||||||
@@ -36,47 +36,32 @@ pub fn getId(self: Object) u32 {
|
|||||||
return @bitCast(v8.c.v8__Object__GetIdentityHash(self.handle));
|
return @bitCast(v8.c.v8__Object__GetIdentityHash(self.handle));
|
||||||
}
|
}
|
||||||
|
|
||||||
pub const SetOpts = packed struct(u32) {
|
|
||||||
READ_ONLY: bool = false,
|
|
||||||
DONT_ENUM: bool = false,
|
|
||||||
DONT_DELETE: bool = false,
|
|
||||||
_: u29 = 0,
|
|
||||||
};
|
|
||||||
pub fn setIndex(self: Object, index: u32, value: anytype, opts: SetOpts) !void {
|
|
||||||
@setEvalBranchQuota(10000);
|
|
||||||
const key = switch (index) {
|
|
||||||
inline 0...20 => |i| std.fmt.comptimePrint("{d}", .{i}),
|
|
||||||
else => try std.fmt.allocPrint(self.context.arena, "{d}", .{index}),
|
|
||||||
};
|
|
||||||
return self.set(key, value, opts);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn set(self: Object, key: []const u8, value: anytype, opts: SetOpts) error{ FailedToSet, OutOfMemory }!void {
|
|
||||||
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_value = try ctx.zigValueToJs(value, .{});
|
|
||||||
|
|
||||||
var out: v8.c.MaybeBool = undefined;
|
|
||||||
v8.c.v8__Object__DefineOwnProperty(self.handle, ctx.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 {
|
pub fn get(self: Object, key: []const u8) !js.Value {
|
||||||
const ctx = self.ctx;
|
const ctx = self.ctx;
|
||||||
const js_key = ctx.isolate.newStringHandle(key);
|
const js_key = ctx.isolate.createStringHandle(key);
|
||||||
const js_val_handle = v8.c.v8__Object__Get(self.handle, ctx.handle, js_key) orelse return error.JsException;
|
const js_val_handle = v8.c.v8__Object__Get(self.handle, ctx.handle, js_key) orelse return error.JsException;
|
||||||
const js_val = v8.Value{ .handle = js_val_handle };
|
return .{
|
||||||
return ctx.createValue(js_val);
|
.ctx = ctx,
|
||||||
|
.handle = js_val_handle,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn defineOwnProperty(self: Object, name: []const u8, value: js.Value, attr: v8.c.PropertyAttribute) ?bool {
|
||||||
|
const ctx = self.ctx;
|
||||||
|
|
||||||
|
const name_handle = ctx.isolate.createStringHandle(name);
|
||||||
|
|
||||||
|
var out: v8.c.MaybeBool = undefined;
|
||||||
|
v8.c.v8__Object__DefineOwnProperty(self.handle, ctx.handle, @ptrCast(name_handle), value.handle, attr, &out);
|
||||||
|
if (out.has_value) {
|
||||||
|
return out.value;
|
||||||
|
} else {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn toString(self: Object) ![]const u8 {
|
pub fn toString(self: Object) ![]const u8 {
|
||||||
const js_value = v8.Value{ .handle = @ptrCast(self.handle) };
|
return self.ctx.valueToString(self.toValue(), .{});
|
||||||
return self.ctx.valueToString(js_value, .{});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn toValue(self: Object) js.Value {
|
pub fn toValue(self: Object) js.Value {
|
||||||
@@ -88,8 +73,7 @@ pub fn toValue(self: Object) js.Value {
|
|||||||
|
|
||||||
pub fn format(self: Object, writer: *std.Io.Writer) !void {
|
pub fn format(self: Object, writer: *std.Io.Writer) !void {
|
||||||
if (comptime IS_DEBUG) {
|
if (comptime IS_DEBUG) {
|
||||||
const js_value = v8.Value{ .handle = @ptrCast(self.handle) };
|
return self.ctx.debugValue(self.toValue(), writer);
|
||||||
return self.ctx.debugValue(js_value, writer);
|
|
||||||
}
|
}
|
||||||
const str = self.toString() catch return error.WriteFailed;
|
const str = self.toString() catch return error.WriteFailed;
|
||||||
return writer.writeAll(str);
|
return writer.writeAll(str);
|
||||||
@@ -119,9 +103,9 @@ pub fn getFunction(self: Object, name: []const u8) !?js.Function {
|
|||||||
}
|
}
|
||||||
const ctx = self.ctx;
|
const ctx = self.ctx;
|
||||||
|
|
||||||
const js_name = ctx.isolate.newStringHandle(name);
|
const js_name = ctx.isolate.createStringHandle(name);
|
||||||
const js_val_handle = v8.c.v8__Object__Get(self.handle, ctx.handle, js_name) orelse return error.JsException;
|
const js_val_handle = v8.c.v8__Object__Get(self.handle, ctx.handle, js_name) orelse return error.JsException;
|
||||||
const js_value = v8.Value{ .handle = js_val_handle };
|
const js_value = js.Value{ .ctx = ctx, .handle = js_val_handle };
|
||||||
|
|
||||||
if (!js_value.isFunction()) {
|
if (!js_value.isFunction()) {
|
||||||
return null;
|
return null;
|
||||||
@@ -152,7 +136,7 @@ pub fn nameIterator(self: Object) NameIterator {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn toZig(self: Object, comptime T: type) !T {
|
pub fn toZig(self: Object, comptime T: type) !T {
|
||||||
const js_value = v8.Value{ .handle = @ptrCast(self.handle) };
|
const js_value = js.Value{ .ctx = self.ctx, .handle = @ptrCast(self.handle) };
|
||||||
return self.ctx.jsValueToZig(T, js_value);
|
return self.ctx.jsValueToZig(T, js_value);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -170,7 +154,7 @@ pub const NameIterator = struct {
|
|||||||
self.idx += 1;
|
self.idx += 1;
|
||||||
|
|
||||||
const js_val_handle = v8.c.v8__Object__GetIndex(@ptrCast(self.handle), self.ctx.handle, idx) orelse return error.JsException;
|
const js_val_handle = v8.c.v8__Object__GetIndex(@ptrCast(self.handle), self.ctx.handle, idx) orelse return error.JsException;
|
||||||
const js_val = v8.Value{ .handle = js_val_handle };
|
const js_val = js.Value{ .ctx = self.ctx, .handle = js_val_handle };
|
||||||
return try self.ctx.valueToString(js_val, .{});
|
return try self.ctx.valueToString(js_val, .{});
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -479,12 +479,11 @@ fn attachClass(comptime JsApi: type, isolate: *v8.Isolate, template: *v8.Functio
|
|||||||
v8.c.v8__Template__Set(@ptrCast(target), js_name, @ptrCast(function_template), v8.c.None);
|
v8.c.v8__Template__Set(@ptrCast(target), js_name, @ptrCast(function_template), v8.c.None);
|
||||||
},
|
},
|
||||||
bridge.Property => {
|
bridge.Property => {
|
||||||
// simpleZigValueToJs still uses old v8.Isolate wrapper, so create a temp wrapper
|
// simpleZigValueToJs now returns raw handle directly
|
||||||
const iso_wrapper = v8.Isolate{ .handle = isolate };
|
const iso_wrapper = v8.Isolate{ .handle = isolate };
|
||||||
const js_value_wrapper = switch (value) {
|
const js_value = switch (value) {
|
||||||
.int => |v| js.simpleZigValueToJs(iso_wrapper, v, true, false),
|
.int => |v| js.simpleZigValueToJs(iso_wrapper, v, true, false),
|
||||||
};
|
};
|
||||||
const js_value = js_value_wrapper.handle;
|
|
||||||
|
|
||||||
const js_name = v8.c.v8__String__NewFromUtf8(isolate, name.ptr, v8.c.kNormal, @intCast(name.len));
|
const js_name = v8.c.v8__String__NewFromUtf8(isolate, name.ptr, v8.c.kNormal, @intCast(name.len));
|
||||||
// apply it both to the type itself
|
// apply it both to the type itself
|
||||||
|
|||||||
@@ -39,7 +39,7 @@ pub fn hasCaught(self: TryCatch) bool {
|
|||||||
// the caller needs to deinit the string returned
|
// the caller needs to deinit the string returned
|
||||||
pub fn exception(self: TryCatch, allocator: Allocator) !?[]const u8 {
|
pub fn exception(self: TryCatch, allocator: Allocator) !?[]const u8 {
|
||||||
const msg_value = v8.c.v8__TryCatch__Exception(&self.handle) orelse return null;
|
const msg_value = v8.c.v8__TryCatch__Exception(&self.handle) orelse return null;
|
||||||
const msg = v8.Value{ .handle = msg_value };
|
const msg = js.Value{ .ctx = self.ctx, .handle = msg_value };
|
||||||
return try self.ctx.valueToString(msg, .{ .allocator = allocator });
|
return try self.ctx.valueToString(msg, .{ .allocator = allocator });
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -47,7 +47,7 @@ pub fn exception(self: TryCatch, allocator: Allocator) !?[]const u8 {
|
|||||||
pub fn stack(self: TryCatch, allocator: Allocator) !?[]const u8 {
|
pub fn stack(self: TryCatch, allocator: Allocator) !?[]const u8 {
|
||||||
const ctx = self.ctx;
|
const ctx = self.ctx;
|
||||||
const s_value = v8.c.v8__TryCatch__StackTrace(&self.handle, ctx.handle) orelse return null;
|
const s_value = v8.c.v8__TryCatch__StackTrace(&self.handle, ctx.handle) orelse return null;
|
||||||
const s = v8.Value{ .handle = s_value };
|
const s = js.Value{ .ctx = ctx, .handle = s_value };
|
||||||
return try ctx.valueToString(s, .{ .allocator = allocator });
|
return try ctx.valueToString(s, .{ .allocator = allocator });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ const Allocator = std.mem.Allocator;
|
|||||||
|
|
||||||
const Value = @This();
|
const Value = @This();
|
||||||
|
|
||||||
ctx: *js.Context,
|
ctx: *const js.Context,
|
||||||
handle: *const v8.c.Value,
|
handle: *const v8.c.Value,
|
||||||
|
|
||||||
pub fn isObject(self: Value) bool {
|
pub fn isObject(self: Value) bool {
|
||||||
@@ -58,6 +58,146 @@ pub fn isFunction(self: Value) bool {
|
|||||||
return v8.c.v8__Value__IsFunction(self.handle);
|
return v8.c.v8__Value__IsFunction(self.handle);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn isNull(self: Value) bool {
|
||||||
|
return v8.c.v8__Value__IsNull(self.handle);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn isUndefined(self: Value) bool {
|
||||||
|
return v8.c.v8__Value__IsUndefined(self.handle);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn isNullOrUndefined(self: Value) bool {
|
||||||
|
return v8.c.v8__Value__IsNullOrUndefined(self.handle);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn isNumber(self: Value) bool {
|
||||||
|
return v8.c.v8__Value__IsNumber(self.handle);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn isNumberObject(self: Value) bool {
|
||||||
|
return v8.c.v8__Value__IsNumberObject(self.handle);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn isInt32(self: Value) bool {
|
||||||
|
return v8.c.v8__Value__IsInt32(self.handle);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn isUint32(self: Value) bool {
|
||||||
|
return v8.c.v8__Value__IsUint32(self.handle);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn isBigInt(self: Value) bool {
|
||||||
|
return v8.c.v8__Value__IsBigInt(self.handle);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn isBigIntObject(self: Value) bool {
|
||||||
|
return v8.c.v8__Value__IsBigIntObject(self.handle);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn isBoolean(self: Value) bool {
|
||||||
|
return v8.c.v8__Value__IsBoolean(self.handle);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn isBooleanObject(self: Value) bool {
|
||||||
|
return v8.c.v8__Value__IsBooleanObject(self.handle);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn isTrue(self: Value) bool {
|
||||||
|
return v8.c.v8__Value__IsTrue(self.handle);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn isFalse(self: Value) bool {
|
||||||
|
return v8.c.v8__Value__IsFalse(self.handle);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn isTypedArray(self: Value) bool {
|
||||||
|
return v8.c.v8__Value__IsTypedArray(self.handle);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn isArrayBufferView(self: Value) bool {
|
||||||
|
return v8.c.v8__Value__IsArrayBufferView(self.handle);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn isArrayBuffer(self: Value) bool {
|
||||||
|
return v8.c.v8__Value__IsArrayBuffer(self.handle);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn isUint8Array(self: Value) bool {
|
||||||
|
return v8.c.v8__Value__IsUint8Array(self.handle);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn isUint8ClampedArray(self: Value) bool {
|
||||||
|
return v8.c.v8__Value__IsUint8ClampedArray(self.handle);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn isInt8Array(self: Value) bool {
|
||||||
|
return v8.c.v8__Value__IsInt8Array(self.handle);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn isUint16Array(self: Value) bool {
|
||||||
|
return v8.c.v8__Value__IsUint16Array(self.handle);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn isInt16Array(self: Value) bool {
|
||||||
|
return v8.c.v8__Value__IsInt16Array(self.handle);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn isUint32Array(self: Value) bool {
|
||||||
|
return v8.c.v8__Value__IsUint32Array(self.handle);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn isInt32Array(self: Value) bool {
|
||||||
|
return v8.c.v8__Value__IsInt32Array(self.handle);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn isBigUint64Array(self: Value) bool {
|
||||||
|
return v8.c.v8__Value__IsBigUint64Array(self.handle);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn isBigInt64Array(self: Value) bool {
|
||||||
|
return v8.c.v8__Value__IsBigInt64Array(self.handle);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn toBool(self: Value) bool {
|
||||||
|
return v8.c.v8__Value__BooleanValue(self.handle, self.ctx.isolate.handle);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn typeOf(self: Value) js.String {
|
||||||
|
const str_handle = v8.c.v8__Value__TypeOf(self.handle, self.ctx.isolate.handle).?;
|
||||||
|
return js.String{ .ctx = @constCast(self.ctx), .handle = str_handle };
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn toF32(self: Value) !f32 {
|
||||||
|
return @floatCast(try self.toF64());
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn toF64(self: Value) !f64 {
|
||||||
|
var maybe: v8.c.MaybeF64 = undefined;
|
||||||
|
v8.c.v8__Value__NumberValue(self.handle, self.ctx.handle, &maybe);
|
||||||
|
if (!maybe.has_value) {
|
||||||
|
return error.JsException;
|
||||||
|
}
|
||||||
|
return maybe.value;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn toI32(self: Value) !i32 {
|
||||||
|
var maybe: v8.c.MaybeI32 = undefined;
|
||||||
|
v8.c.v8__Value__Int32Value(self.handle, self.ctx.handle, &maybe);
|
||||||
|
if (!maybe.has_value) {
|
||||||
|
return error.JsException;
|
||||||
|
}
|
||||||
|
return maybe.value;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn toU32(self: Value) !u32 {
|
||||||
|
var maybe: v8.c.MaybeU32 = undefined;
|
||||||
|
v8.c.v8__Value__Uint32Value(self.handle, self.ctx.handle, &maybe);
|
||||||
|
if (!maybe.has_value) {
|
||||||
|
return error.JsException;
|
||||||
|
}
|
||||||
|
return maybe.value;
|
||||||
|
}
|
||||||
|
|
||||||
pub fn toString(self: Value, opts: js.String.ToZigOpts) ![]u8 {
|
pub fn toString(self: Value, opts: js.String.ToZigOpts) ![]u8 {
|
||||||
return self._toString(false, opts);
|
return self._toString(false, opts);
|
||||||
}
|
}
|
||||||
@@ -66,7 +206,7 @@ pub fn toStringZ(self: Value, opts: js.String.ToZigOpts) ![:0]u8 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn _toString(self: Value, comptime null_terminate: bool, opts: js.String.ToZigOpts) !(if (null_terminate) [:0]u8 else []u8) {
|
fn _toString(self: Value, comptime null_terminate: bool, opts: js.String.ToZigOpts) !(if (null_terminate) [:0]u8 else []u8) {
|
||||||
const ctx = self.ctx;
|
const ctx: *js.Context = @constCast(self.ctx);
|
||||||
|
|
||||||
if (self.isSymbol()) {
|
if (self.isSymbol()) {
|
||||||
const sym_handle = v8.c.v8__Symbol__Description(@ptrCast(self.handle), ctx.isolate.handle).?;
|
const sym_handle = v8.c.v8__Symbol__Description(@ptrCast(self.handle), ctx.isolate.handle).?;
|
||||||
@@ -97,7 +237,7 @@ pub fn fromJson(ctx: *js.Context, json: []const u8) !Value {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn persist(self: Value) !Value {
|
pub fn persist(self: Value) !Value {
|
||||||
var ctx = self.ctx;
|
var ctx: *js.Context = @constCast(self.ctx);
|
||||||
|
|
||||||
const global = js.Global(Value).init(ctx.isolate.handle, self.handle);
|
const global = js.Global(Value).init(ctx.isolate.handle, self.handle);
|
||||||
try ctx.global_values.append(ctx.arena, global);
|
try ctx.global_values.append(ctx.arena, global);
|
||||||
@@ -118,7 +258,7 @@ pub fn toObject(self: Value) js.Object {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return .{
|
return .{
|
||||||
.ctx = self.ctx,
|
.ctx = @constCast(self.ctx),
|
||||||
.handle = self.handle,
|
.handle = self.handle,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@@ -129,14 +269,20 @@ pub fn toArray(self: Value) js.Array {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return .{
|
return .{
|
||||||
.ctx = self.ctx,
|
.ctx = @constCast(self.ctx),
|
||||||
.handle = self.handle,
|
.handle = self.handle,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn castTo(self: Value, comptime T: type) T {
|
||||||
|
return .{
|
||||||
|
.handle = @ptrCast(self.handle),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
pub fn format(self: Value, writer: *std.Io.Writer) !void {
|
pub fn format(self: Value, writer: *std.Io.Writer) !void {
|
||||||
if (comptime IS_DEBUG) {
|
if (comptime IS_DEBUG) {
|
||||||
return self.ctx.debugValue(.{ .handle = self.handle }, writer);
|
return self.ctx.debugValue(self, writer);
|
||||||
}
|
}
|
||||||
const str = self.toString(.{}) catch return error.WriteFailed;
|
const str = self.toString(.{}) catch return error.WriteFailed;
|
||||||
return writer.writeAll(str);
|
return writer.writeAll(str);
|
||||||
|
|||||||
@@ -22,7 +22,533 @@ const log = @import("../../log.zig");
|
|||||||
|
|
||||||
const v8 = js.v8;
|
const v8 = js.v8;
|
||||||
|
|
||||||
const Caller = @import("Caller.zig");
|
const Context = @import("Context.zig");
|
||||||
|
const Page = @import("../Page.zig");
|
||||||
|
|
||||||
|
const Allocator = std.mem.Allocator;
|
||||||
|
const ArenaAllocator = std.heap.ArenaAllocator;
|
||||||
|
|
||||||
|
const CALL_ARENA_RETAIN = 1024 * 16;
|
||||||
|
|
||||||
|
// ============================================================================
|
||||||
|
// Internal Callback Info Wrappers
|
||||||
|
// ============================================================================
|
||||||
|
// These wrap the raw v8 C API to provide a cleaner interface.
|
||||||
|
// They are not exported - internal to this module only.
|
||||||
|
|
||||||
|
const Value = struct {
|
||||||
|
handle: *const v8.c.Value,
|
||||||
|
|
||||||
|
fn isArray(self: Value) bool {
|
||||||
|
return v8.c.v8__Value__IsArray(self.handle);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn isTypedArray(self: Value) bool {
|
||||||
|
return v8.c.v8__Value__IsTypedArray(self.handle);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn isFunction(self: Value) bool {
|
||||||
|
return v8.c.v8__Value__IsFunction(self.handle);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const Name = struct {
|
||||||
|
handle: *const v8.c.Name,
|
||||||
|
};
|
||||||
|
|
||||||
|
const CallbackInfo = struct {
|
||||||
|
raw: *const v8.c.FunctionCallbackInfo,
|
||||||
|
|
||||||
|
fn length(self: CallbackInfo) u32 {
|
||||||
|
return @intCast(v8.c.v8__FunctionCallbackInfo__Length(self.raw));
|
||||||
|
}
|
||||||
|
|
||||||
|
fn getArg(self: CallbackInfo, index: u32) Value {
|
||||||
|
return .{ .handle = v8.c.v8__FunctionCallbackInfo__INDEX(self.raw, @intCast(index)).? };
|
||||||
|
}
|
||||||
|
|
||||||
|
fn getThis(self: CallbackInfo) *const v8.c.Object {
|
||||||
|
return v8.c.v8__FunctionCallbackInfo__This(self.raw).?;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn getReturnValue(self: CallbackInfo) ReturnValue {
|
||||||
|
var rv: v8.c.ReturnValue = undefined;
|
||||||
|
v8.c.v8__FunctionCallbackInfo__GetReturnValue(self.raw, &rv);
|
||||||
|
return .{ .raw = rv };
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const PropertyCallbackInfo = struct {
|
||||||
|
raw: *const v8.c.PropertyCallbackInfo,
|
||||||
|
|
||||||
|
fn getThis(self: PropertyCallbackInfo) *const v8.c.Object {
|
||||||
|
return v8.c.v8__PropertyCallbackInfo__This(self.raw).?;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn getReturnValue(self: PropertyCallbackInfo) ReturnValue {
|
||||||
|
var rv: v8.c.ReturnValue = undefined;
|
||||||
|
v8.c.v8__PropertyCallbackInfo__GetReturnValue(self.raw, &rv);
|
||||||
|
return .{ .raw = rv };
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const ReturnValue = struct {
|
||||||
|
raw: v8.c.ReturnValue,
|
||||||
|
|
||||||
|
fn set(self: ReturnValue, value: anytype) void {
|
||||||
|
const T = @TypeOf(value);
|
||||||
|
if (T == Value) {
|
||||||
|
self.setValueHandle(value.handle);
|
||||||
|
} else if (T == *const v8.c.Object) {
|
||||||
|
self.setValueHandle(@ptrCast(value));
|
||||||
|
} else if (T == *const v8.c.Value) {
|
||||||
|
self.setValueHandle(value);
|
||||||
|
} else if (T == js.Value) {
|
||||||
|
self.setValueHandle(value.handle);
|
||||||
|
} else {
|
||||||
|
@compileError("Unsupported type for ReturnValue.set: " ++ @typeName(T));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn setValueHandle(self: ReturnValue, handle: *const v8.c.Value) void {
|
||||||
|
v8.c.v8__ReturnValue__Set(self.raw, handle);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// ============================================================================
|
||||||
|
// Caller - Responsible for calling Zig functions from JS invocations
|
||||||
|
// ============================================================================
|
||||||
|
|
||||||
|
pub const Caller = struct {
|
||||||
|
context: *Context,
|
||||||
|
isolate: js.Isolate,
|
||||||
|
call_arena: Allocator,
|
||||||
|
|
||||||
|
// Takes the raw v8 isolate and extracts the context from it.
|
||||||
|
pub fn init(v8_isolate: *v8.c.Isolate) Caller {
|
||||||
|
const isolate = js.Isolate{ .handle = v8_isolate };
|
||||||
|
const v8_context_handle = v8.c.v8__Isolate__GetCurrentContext(v8_isolate);
|
||||||
|
const embedder_data = v8.c.v8__Context__GetEmbedderData(v8_context_handle, 1);
|
||||||
|
var lossless: bool = undefined;
|
||||||
|
const context: *Context = @ptrFromInt(v8.c.v8__BigInt__Uint64Value(embedder_data, &lossless));
|
||||||
|
|
||||||
|
context.call_depth += 1;
|
||||||
|
return .{
|
||||||
|
.context = context,
|
||||||
|
.isolate = isolate,
|
||||||
|
.call_arena = context.call_arena,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn deinit(self: *Caller) void {
|
||||||
|
const context = self.context;
|
||||||
|
const call_depth = context.call_depth - 1;
|
||||||
|
|
||||||
|
// Because of callbacks, calls can be nested. Because of this, we
|
||||||
|
// can't clear the call_arena after _every_ call. Imagine we have
|
||||||
|
// arr.forEach((i) => { console.log(i); }
|
||||||
|
//
|
||||||
|
// First we call forEach. Inside of our forEach call,
|
||||||
|
// we call console.log. If we reset the call_arena after this call,
|
||||||
|
// it'll reset it for the `forEach` call after, which might still
|
||||||
|
// need the data.
|
||||||
|
//
|
||||||
|
// Therefore, we keep a call_depth, and only reset the call_arena
|
||||||
|
// when a top-level (call_depth == 0) function ends.
|
||||||
|
if (call_depth == 0) {
|
||||||
|
const arena: *ArenaAllocator = @ptrCast(@alignCast(context.call_arena.ptr));
|
||||||
|
_ = arena.reset(.{ .retain_with_limit = CALL_ARENA_RETAIN });
|
||||||
|
}
|
||||||
|
|
||||||
|
context.call_depth = call_depth;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub const CallOpts = struct {
|
||||||
|
dom_exception: bool = false,
|
||||||
|
null_as_undefined: bool = false,
|
||||||
|
as_typed_array: bool = false,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub fn constructor(self: *Caller, comptime T: type, func: anytype, info: CallbackInfo, comptime opts: CallOpts) void {
|
||||||
|
self._constructor(func, info) catch |err| {
|
||||||
|
self.handleError(T, @TypeOf(func), err, info, opts);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
fn _constructor(self: *Caller, func: anytype, info: CallbackInfo) !void {
|
||||||
|
const F = @TypeOf(func);
|
||||||
|
const args = try self.getArgs(F, 0, info);
|
||||||
|
const res = @call(.auto, func, args);
|
||||||
|
|
||||||
|
const ReturnType = @typeInfo(F).@"fn".return_type orelse {
|
||||||
|
@compileError(@typeName(F) ++ " has a constructor without a return type");
|
||||||
|
};
|
||||||
|
|
||||||
|
const new_this_handle = info.getThis();
|
||||||
|
const new_this = v8.Object{ .handle = new_this_handle };
|
||||||
|
var this = new_this;
|
||||||
|
if (@typeInfo(ReturnType) == .error_union) {
|
||||||
|
const non_error_res = res catch |err| return err;
|
||||||
|
this = (try self.context.mapZigInstanceToJs(new_this_handle, non_error_res)).castToObject();
|
||||||
|
} else {
|
||||||
|
this = (try self.context.mapZigInstanceToJs(new_this_handle, res)).castToObject();
|
||||||
|
}
|
||||||
|
|
||||||
|
// If we got back a different object (existing wrapper), copy the prototype
|
||||||
|
// from new object. (this happens when we're upgrading an CustomElement)
|
||||||
|
if (this.handle != new_this.handle) {
|
||||||
|
const new_prototype = new_this.getPrototype();
|
||||||
|
const v8_context = v8.Context{ .handle = self.context.handle };
|
||||||
|
_ = this.setPrototype(v8_context, new_prototype.castTo(v8.Object));
|
||||||
|
}
|
||||||
|
|
||||||
|
info.getReturnValue().set(this.handle);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn method(self: *Caller, comptime T: type, func: anytype, info: CallbackInfo, comptime opts: CallOpts) void {
|
||||||
|
self._method(T, func, info, opts) catch |err| {
|
||||||
|
self.handleError(T, @TypeOf(func), err, info, opts);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
fn _method(self: *Caller, comptime T: type, func: anytype, info: CallbackInfo, comptime opts: CallOpts) !void {
|
||||||
|
const F = @TypeOf(func);
|
||||||
|
var handle_scope: js.HandleScope = undefined;
|
||||||
|
handle_scope.init(self.isolate);
|
||||||
|
defer handle_scope.deinit();
|
||||||
|
|
||||||
|
var args = try self.getArgs(F, 1, info);
|
||||||
|
@field(args, "0") = try Context.typeTaggedAnyOpaque(*T, info.getThis());
|
||||||
|
const res = @call(.auto, func, args);
|
||||||
|
info.getReturnValue().set(try self.context.zigValueToJs(res, opts));
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn function(self: *Caller, comptime T: type, func: anytype, info: CallbackInfo, comptime opts: CallOpts) void {
|
||||||
|
self._function(func, info, opts) catch |err| {
|
||||||
|
self.handleError(T, @TypeOf(func), err, info, opts);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
fn _function(self: *Caller, func: anytype, info: CallbackInfo, comptime opts: CallOpts) !void {
|
||||||
|
const F = @TypeOf(func);
|
||||||
|
const context = self.context;
|
||||||
|
const args = try self.getArgs(F, 0, info);
|
||||||
|
const res = @call(.auto, func, args);
|
||||||
|
info.getReturnValue().set(try context.zigValueToJs(res, opts));
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn getIndex(self: *Caller, comptime T: type, func: anytype, idx: u32, info: PropertyCallbackInfo, comptime opts: CallOpts) u8 {
|
||||||
|
return self._getIndex(T, func, idx, info, opts) catch |err| {
|
||||||
|
self.handleError(T, @TypeOf(func), err, info, opts);
|
||||||
|
return v8.Intercepted.No;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
fn _getIndex(self: *Caller, comptime T: type, func: anytype, idx: u32, info: PropertyCallbackInfo, comptime opts: CallOpts) !u8 {
|
||||||
|
const F = @TypeOf(func);
|
||||||
|
var args = try self.getArgs(F, 2, info);
|
||||||
|
@field(args, "0") = try Context.typeTaggedAnyOpaque(*T, info.getThis());
|
||||||
|
@field(args, "1") = idx;
|
||||||
|
const ret = @call(.auto, func, args);
|
||||||
|
return self.handleIndexedReturn(T, F, true, ret, info, opts);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn getNamedIndex(self: *Caller, comptime T: type, func: anytype, name: Name, info: PropertyCallbackInfo, comptime opts: CallOpts) u8 {
|
||||||
|
return self._getNamedIndex(T, func, name, info, opts) catch |err| {
|
||||||
|
self.handleError(T, @TypeOf(func), err, info, opts);
|
||||||
|
return v8.Intercepted.No;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
fn _getNamedIndex(self: *Caller, comptime T: type, func: anytype, name: Name, info: PropertyCallbackInfo, comptime opts: CallOpts) !u8 {
|
||||||
|
const F = @TypeOf(func);
|
||||||
|
var args = try self.getArgs(F, 2, info);
|
||||||
|
@field(args, "0") = try Context.typeTaggedAnyOpaque(*T, info.getThis());
|
||||||
|
@field(args, "1") = try self.nameToString(name);
|
||||||
|
const ret = @call(.auto, func, args);
|
||||||
|
return self.handleIndexedReturn(T, F, true, ret, info, opts);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn setNamedIndex(self: *Caller, comptime T: type, func: anytype, name: Name, js_value: Value, info: PropertyCallbackInfo, comptime opts: CallOpts) u8 {
|
||||||
|
return self._setNamedIndex(T, func, name, js_value, info, opts) catch |err| {
|
||||||
|
self.handleError(T, @TypeOf(func), err, info, opts);
|
||||||
|
return v8.Intercepted.No;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
fn _setNamedIndex(self: *Caller, comptime T: type, func: anytype, name: Name, js_value: Value, info: PropertyCallbackInfo, comptime opts: CallOpts) !u8 {
|
||||||
|
const F = @TypeOf(func);
|
||||||
|
var args: ParameterTypes(F) = undefined;
|
||||||
|
@field(args, "0") = try Context.typeTaggedAnyOpaque(*T, info.getThis());
|
||||||
|
@field(args, "1") = try self.nameToString(name);
|
||||||
|
@field(args, "2") = try self.context.jsValueToZig(@TypeOf(@field(args, "2")), js.Value{ .ctx = self.context, .handle = js_value.handle });
|
||||||
|
if (@typeInfo(F).@"fn".params.len == 4) {
|
||||||
|
@field(args, "3") = self.context.page;
|
||||||
|
}
|
||||||
|
const ret = @call(.auto, func, args);
|
||||||
|
return self.handleIndexedReturn(T, F, false, ret, info, opts);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn deleteNamedIndex(self: *Caller, comptime T: type, func: anytype, name: Name, info: PropertyCallbackInfo, comptime opts: CallOpts) u8 {
|
||||||
|
return self._deleteNamedIndex(T, func, name, info, opts) catch |err| {
|
||||||
|
self.handleError(T, @TypeOf(func), err, info, opts);
|
||||||
|
return v8.Intercepted.No;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
fn _deleteNamedIndex(self: *Caller, comptime T: type, func: anytype, name: Name, info: PropertyCallbackInfo, comptime opts: CallOpts) !u8 {
|
||||||
|
const F = @TypeOf(func);
|
||||||
|
var args: ParameterTypes(F) = undefined;
|
||||||
|
@field(args, "0") = try Context.typeTaggedAnyOpaque(*T, info.getThis());
|
||||||
|
@field(args, "1") = try self.nameToString(name);
|
||||||
|
if (@typeInfo(F).@"fn".params.len == 3) {
|
||||||
|
@field(args, "2") = self.context.page;
|
||||||
|
}
|
||||||
|
const ret = @call(.auto, func, args);
|
||||||
|
return self.handleIndexedReturn(T, F, false, ret, info, opts);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn handleIndexedReturn(self: *Caller, comptime T: type, comptime F: type, comptime getter: bool, ret: anytype, info: PropertyCallbackInfo, comptime opts: CallOpts) !u8 {
|
||||||
|
// need to unwrap this error immediately for when opts.null_as_undefined == true
|
||||||
|
// and we need to compare it to null;
|
||||||
|
const non_error_ret = switch (@typeInfo(@TypeOf(ret))) {
|
||||||
|
.error_union => |eu| blk: {
|
||||||
|
break :blk ret catch |err| {
|
||||||
|
// We can't compare err == error.NotHandled if error.NotHandled
|
||||||
|
// isn't part of the possible error set. So we first need to check
|
||||||
|
// if error.NotHandled is part of the error set.
|
||||||
|
if (isInErrorSet(error.NotHandled, eu.error_set)) {
|
||||||
|
if (err == error.NotHandled) {
|
||||||
|
return v8.Intercepted.No;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
self.handleError(T, F, err, info, opts);
|
||||||
|
return v8.Intercepted.No;
|
||||||
|
};
|
||||||
|
},
|
||||||
|
else => ret,
|
||||||
|
};
|
||||||
|
|
||||||
|
if (comptime getter) {
|
||||||
|
info.getReturnValue().set(try self.context.zigValueToJs(non_error_ret, opts));
|
||||||
|
}
|
||||||
|
return v8.Intercepted.Yes;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn isInErrorSet(err: anyerror, comptime T: type) bool {
|
||||||
|
inline for (@typeInfo(T).error_set.?) |e| {
|
||||||
|
if (err == @field(anyerror, e.name)) return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn nameToString(self: *Caller, name: Name) ![]const u8 {
|
||||||
|
return self.context.valueToString(js.Value{ .ctx = self.context, .handle = @ptrCast(name.handle) }, .{});
|
||||||
|
}
|
||||||
|
|
||||||
|
fn handleError(self: *Caller, comptime T: type, comptime F: type, err: anyerror, info: anytype, comptime opts: CallOpts) void {
|
||||||
|
const isolate = self.isolate;
|
||||||
|
|
||||||
|
if (comptime @import("builtin").mode == .Debug and @TypeOf(info) == CallbackInfo) {
|
||||||
|
if (log.enabled(.js, .warn)) {
|
||||||
|
self.logFunctionCallError(@typeName(T), @typeName(F), err, info);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const js_err: *const v8.c.Value = switch (err) {
|
||||||
|
error.InvalidArgument => isolate.createTypeError("invalid argument"),
|
||||||
|
error.OutOfMemory => isolate.createError("out of memory"),
|
||||||
|
error.IllegalConstructor => isolate.createError("Illegal Contructor"),
|
||||||
|
else => blk: {
|
||||||
|
if (comptime opts.dom_exception) {
|
||||||
|
const DOMException = @import("../webapi/DOMException.zig");
|
||||||
|
if (DOMException.fromError(err)) |ex| {
|
||||||
|
const value = self.context.zigValueToJs(ex, .{}) catch break :blk isolate.createError("internal error");
|
||||||
|
break :blk value.handle;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break :blk isolate.createError(@errorName(err));
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const js_exception = isolate.throwException(js_err);
|
||||||
|
info.getReturnValue().setValueHandle(js_exception);
|
||||||
|
}
|
||||||
|
|
||||||
|
// If we call a method in javascript: cat.lives('nine');
|
||||||
|
//
|
||||||
|
// Then we'd expect a Zig function with 2 parameters: a self and the string.
|
||||||
|
// In this case, offset == 1. Offset is always 1 for setters or methods.
|
||||||
|
//
|
||||||
|
// Offset is always 0 for constructors.
|
||||||
|
//
|
||||||
|
// For constructors, setters and methods, we can further increase offset + 1
|
||||||
|
// if the first parameter is an instance of Page.
|
||||||
|
//
|
||||||
|
// Finally, if the JS function is called with _more_ parameters and
|
||||||
|
// the last parameter in Zig is an array, we'll try to slurp the additional
|
||||||
|
// parameters into the array.
|
||||||
|
fn getArgs(self: *const Caller, comptime F: type, comptime offset: usize, info: anytype) !ParameterTypes(F) {
|
||||||
|
const context = self.context;
|
||||||
|
var args: ParameterTypes(F) = undefined;
|
||||||
|
|
||||||
|
const params = @typeInfo(F).@"fn".params[offset..];
|
||||||
|
// Except for the constructor, the first parameter is always `self`
|
||||||
|
// This isn't something we'll bind from JS, so skip it.
|
||||||
|
const params_to_map = blk: {
|
||||||
|
if (params.len == 0) {
|
||||||
|
return args;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If the last parameter is the Page, set it, and exclude it
|
||||||
|
// from our params slice, because we don't want to bind it to
|
||||||
|
// a JS argument
|
||||||
|
if (comptime isPage(params[params.len - 1].type.?)) {
|
||||||
|
@field(args, tupleFieldName(params.len - 1 + offset)) = self.context.page;
|
||||||
|
break :blk params[0 .. params.len - 1];
|
||||||
|
}
|
||||||
|
|
||||||
|
// we have neither a Page nor a JsObject. All params must be
|
||||||
|
// bound to a JavaScript value.
|
||||||
|
break :blk params;
|
||||||
|
};
|
||||||
|
|
||||||
|
if (params_to_map.len == 0) {
|
||||||
|
return args;
|
||||||
|
}
|
||||||
|
|
||||||
|
const js_parameter_count = info.length();
|
||||||
|
const last_js_parameter = params_to_map.len - 1;
|
||||||
|
var is_variadic = false;
|
||||||
|
|
||||||
|
{
|
||||||
|
// This is going to get complicated. If the last Zig parameter
|
||||||
|
// is a slice AND the corresponding javascript parameter is
|
||||||
|
// NOT an an array, then we'll treat it as a variadic.
|
||||||
|
|
||||||
|
const last_parameter_type = params_to_map[params_to_map.len - 1].type.?;
|
||||||
|
const last_parameter_type_info = @typeInfo(last_parameter_type);
|
||||||
|
if (last_parameter_type_info == .pointer and last_parameter_type_info.pointer.size == .slice) {
|
||||||
|
const slice_type = last_parameter_type_info.pointer.child;
|
||||||
|
const corresponding_js_value = info.getArg(@as(u32, @intCast(last_js_parameter)));
|
||||||
|
if (corresponding_js_value.isArray() == false and corresponding_js_value.isTypedArray() == false and slice_type != u8) {
|
||||||
|
is_variadic = true;
|
||||||
|
if (js_parameter_count == 0) {
|
||||||
|
@field(args, tupleFieldName(params_to_map.len + offset - 1)) = &.{};
|
||||||
|
} else if (js_parameter_count >= params_to_map.len) {
|
||||||
|
const arr = try self.call_arena.alloc(last_parameter_type_info.pointer.child, js_parameter_count - params_to_map.len + 1);
|
||||||
|
for (arr, last_js_parameter..) |*a, i| {
|
||||||
|
const js_value = info.getArg(@as(u32, @intCast(i)));
|
||||||
|
a.* = try context.jsValueToZig(slice_type, js.Value{ .ctx = context, .handle = js_value.handle });
|
||||||
|
}
|
||||||
|
@field(args, tupleFieldName(params_to_map.len + offset - 1)) = arr;
|
||||||
|
} else {
|
||||||
|
@field(args, tupleFieldName(params_to_map.len + offset - 1)) = &.{};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
inline for (params_to_map, 0..) |param, i| {
|
||||||
|
const field_index = comptime i + offset;
|
||||||
|
if (comptime i == params_to_map.len - 1) {
|
||||||
|
if (is_variadic) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (comptime isPage(param.type.?)) {
|
||||||
|
@compileError("Page must be the last parameter (or 2nd last if there's a JsThis): " ++ @typeName(F));
|
||||||
|
} else if (i >= js_parameter_count) {
|
||||||
|
if (@typeInfo(param.type.?) != .optional) {
|
||||||
|
return error.InvalidArgument;
|
||||||
|
}
|
||||||
|
@field(args, tupleFieldName(field_index)) = null;
|
||||||
|
} else {
|
||||||
|
const js_value = info.getArg(@as(u32, @intCast(i)));
|
||||||
|
@field(args, tupleFieldName(field_index)) = context.jsValueToZig(param.type.?, js.Value{ .ctx = context, .handle = js_value.handle }) catch {
|
||||||
|
return error.InvalidArgument;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return args;
|
||||||
|
}
|
||||||
|
|
||||||
|
// This is extracted to speed up compilation. When left inlined in handleError,
|
||||||
|
// this can add as much as 10 seconds of compilation time.
|
||||||
|
fn logFunctionCallError(self: *Caller, type_name: []const u8, func: []const u8, err: anyerror, info: CallbackInfo) void {
|
||||||
|
const args_dump = self.serializeFunctionArgs(info) catch "failed to serialize args";
|
||||||
|
log.info(.js, "function call error", .{
|
||||||
|
.type = type_name,
|
||||||
|
.func = func,
|
||||||
|
.err = err,
|
||||||
|
.args = args_dump,
|
||||||
|
.stack = self.context.stackTrace() catch |err1| @errorName(err1),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
fn serializeFunctionArgs(self: *Caller, info: CallbackInfo) ![]const u8 {
|
||||||
|
const context = self.context;
|
||||||
|
var buf = std.Io.Writer.Allocating.init(context.call_arena);
|
||||||
|
|
||||||
|
const separator = log.separator();
|
||||||
|
for (0..info.length()) |i| {
|
||||||
|
try buf.writer.print("{s}{d} - ", .{ separator, i + 1 });
|
||||||
|
const val = info.getArg(@intCast(i));
|
||||||
|
try context.debugValue(js.Value{ .ctx = context, .handle = val.handle }, &buf.writer);
|
||||||
|
}
|
||||||
|
return buf.written();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Takes a function, and returns a tuple for its argument. Used when we
|
||||||
|
// @call a function
|
||||||
|
fn ParameterTypes(comptime F: type) type {
|
||||||
|
const params = @typeInfo(F).@"fn".params;
|
||||||
|
var fields: [params.len]std.builtin.Type.StructField = undefined;
|
||||||
|
|
||||||
|
inline for (params, 0..) |param, i| {
|
||||||
|
fields[i] = .{
|
||||||
|
.name = tupleFieldName(i),
|
||||||
|
.type = param.type.?,
|
||||||
|
.default_value_ptr = null,
|
||||||
|
.is_comptime = false,
|
||||||
|
.alignment = @alignOf(param.type.?),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
return @Type(.{ .@"struct" = .{
|
||||||
|
.layout = .auto,
|
||||||
|
.decls = &.{},
|
||||||
|
.fields = &fields,
|
||||||
|
.is_tuple = true,
|
||||||
|
} });
|
||||||
|
}
|
||||||
|
|
||||||
|
fn tupleFieldName(comptime i: usize) [:0]const u8 {
|
||||||
|
return switch (i) {
|
||||||
|
0 => "0",
|
||||||
|
1 => "1",
|
||||||
|
2 => "2",
|
||||||
|
3 => "3",
|
||||||
|
4 => "4",
|
||||||
|
5 => "5",
|
||||||
|
6 => "6",
|
||||||
|
7 => "7",
|
||||||
|
8 => "8",
|
||||||
|
9 => "9",
|
||||||
|
else => std.fmt.comptimePrint("{d}", .{i}),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
fn isPage(comptime T: type) bool {
|
||||||
|
return T == *Page or T == *const Page;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// ============================================================================
|
||||||
|
// Bridge Builder Functions
|
||||||
|
// ============================================================================
|
||||||
|
|
||||||
pub fn Builder(comptime T: type) type {
|
pub fn Builder(comptime T: type) type {
|
||||||
return struct {
|
return struct {
|
||||||
@@ -98,10 +624,11 @@ pub const Constructor = struct {
|
|||||||
fn init(comptime T: type, comptime func: anytype, comptime opts: Opts) Constructor {
|
fn init(comptime T: type, comptime func: anytype, comptime opts: Opts) Constructor {
|
||||||
return .{ .func = struct {
|
return .{ .func = struct {
|
||||||
fn wrap(raw_info: ?*const v8.C_FunctionCallbackInfo) callconv(.c) void {
|
fn wrap(raw_info: ?*const v8.C_FunctionCallbackInfo) callconv(.c) void {
|
||||||
const info = v8.FunctionCallbackInfo.initFromV8(raw_info);
|
const v8_isolate = v8.c.v8__FunctionCallbackInfo__GetIsolate(raw_info).?;
|
||||||
var caller = Caller.init(info);
|
var caller = Caller.init(v8_isolate);
|
||||||
defer caller.deinit();
|
defer caller.deinit();
|
||||||
|
|
||||||
|
const info = CallbackInfo{ .raw = raw_info.? };
|
||||||
caller.constructor(T, func, info, .{
|
caller.constructor(T, func, info, .{
|
||||||
.dom_exception = opts.dom_exception,
|
.dom_exception = opts.dom_exception,
|
||||||
});
|
});
|
||||||
@@ -126,10 +653,11 @@ pub const Function = struct {
|
|||||||
.static = opts.static,
|
.static = opts.static,
|
||||||
.func = struct {
|
.func = struct {
|
||||||
fn wrap(raw_info: ?*const v8.C_FunctionCallbackInfo) callconv(.c) void {
|
fn wrap(raw_info: ?*const v8.C_FunctionCallbackInfo) callconv(.c) void {
|
||||||
const info = v8.FunctionCallbackInfo.initFromV8(raw_info);
|
const v8_isolate = v8.c.v8__FunctionCallbackInfo__GetIsolate(raw_info).?;
|
||||||
var caller = Caller.init(info);
|
var caller = Caller.init(v8_isolate);
|
||||||
defer caller.deinit();
|
defer caller.deinit();
|
||||||
|
|
||||||
|
const info = CallbackInfo{ .raw = raw_info.? };
|
||||||
if (comptime opts.static) {
|
if (comptime opts.static) {
|
||||||
caller.function(T, func, info, .{
|
caller.function(T, func, info, .{
|
||||||
.dom_exception = opts.dom_exception,
|
.dom_exception = opts.dom_exception,
|
||||||
@@ -169,10 +697,11 @@ pub const Accessor = struct {
|
|||||||
if (@typeInfo(@TypeOf(getter)) != .null) {
|
if (@typeInfo(@TypeOf(getter)) != .null) {
|
||||||
accessor.getter = struct {
|
accessor.getter = struct {
|
||||||
fn wrap(raw_info: ?*const v8.C_FunctionCallbackInfo) callconv(.c) void {
|
fn wrap(raw_info: ?*const v8.C_FunctionCallbackInfo) callconv(.c) void {
|
||||||
const info = v8.FunctionCallbackInfo.initFromV8(raw_info);
|
const v8_isolate = v8.c.v8__FunctionCallbackInfo__GetIsolate(raw_info).?;
|
||||||
var caller = Caller.init(info);
|
var caller = Caller.init(v8_isolate);
|
||||||
defer caller.deinit();
|
defer caller.deinit();
|
||||||
|
|
||||||
|
const info = CallbackInfo{ .raw = raw_info.? };
|
||||||
caller.method(T, getter, info, .{
|
caller.method(T, getter, info, .{
|
||||||
.as_typed_array = opts.as_typed_array,
|
.as_typed_array = opts.as_typed_array,
|
||||||
.null_as_undefined = opts.null_as_undefined,
|
.null_as_undefined = opts.null_as_undefined,
|
||||||
@@ -184,12 +713,13 @@ pub const Accessor = struct {
|
|||||||
if (@typeInfo(@TypeOf(setter)) != .null) {
|
if (@typeInfo(@TypeOf(setter)) != .null) {
|
||||||
accessor.setter = struct {
|
accessor.setter = struct {
|
||||||
fn wrap(raw_info: ?*const v8.C_FunctionCallbackInfo) callconv(.c) void {
|
fn wrap(raw_info: ?*const v8.C_FunctionCallbackInfo) callconv(.c) void {
|
||||||
const info = v8.FunctionCallbackInfo.initFromV8(raw_info);
|
const v8_isolate = v8.c.v8__FunctionCallbackInfo__GetIsolate(raw_info).?;
|
||||||
std.debug.assert(info.length() == 1);
|
var caller = Caller.init(v8_isolate);
|
||||||
|
|
||||||
var caller = Caller.init(info);
|
|
||||||
defer caller.deinit();
|
defer caller.deinit();
|
||||||
|
|
||||||
|
const info = CallbackInfo{ .raw = raw_info.? };
|
||||||
|
std.debug.assert(info.length() == 1);
|
||||||
|
|
||||||
caller.method(T, setter, info, .{
|
caller.method(T, setter, info, .{
|
||||||
.as_typed_array = opts.as_typed_array,
|
.as_typed_array = opts.as_typed_array,
|
||||||
.null_as_undefined = opts.null_as_undefined,
|
.null_as_undefined = opts.null_as_undefined,
|
||||||
@@ -213,9 +743,11 @@ pub const Indexed = struct {
|
|||||||
fn init(comptime T: type, comptime getter: anytype, comptime opts: Opts) Indexed {
|
fn init(comptime T: type, comptime getter: anytype, comptime opts: Opts) Indexed {
|
||||||
return .{ .getter = struct {
|
return .{ .getter = struct {
|
||||||
fn wrap(idx: u32, raw_info: ?*const v8.C_PropertyCallbackInfo) callconv(.c) u8 {
|
fn wrap(idx: u32, raw_info: ?*const v8.C_PropertyCallbackInfo) callconv(.c) u8 {
|
||||||
const info = v8.PropertyCallbackInfo.initFromV8(raw_info);
|
const v8_isolate = v8.c.v8__PropertyCallbackInfo__GetIsolate(raw_info).?;
|
||||||
var caller = Caller.init(info);
|
var caller = Caller.init(v8_isolate);
|
||||||
defer caller.deinit();
|
defer caller.deinit();
|
||||||
|
|
||||||
|
const info = PropertyCallbackInfo{ .raw = raw_info.? };
|
||||||
return caller.getIndex(T, getter, idx, info, .{
|
return caller.getIndex(T, getter, idx, info, .{
|
||||||
.as_typed_array = opts.as_typed_array,
|
.as_typed_array = opts.as_typed_array,
|
||||||
.null_as_undefined = opts.null_as_undefined,
|
.null_as_undefined = opts.null_as_undefined,
|
||||||
@@ -238,9 +770,11 @@ pub const NamedIndexed = struct {
|
|||||||
fn init(comptime T: type, comptime getter: anytype, setter: anytype, deleter: anytype, comptime opts: Opts) NamedIndexed {
|
fn init(comptime T: type, comptime getter: anytype, setter: anytype, deleter: anytype, comptime opts: Opts) NamedIndexed {
|
||||||
const getter_fn = struct {
|
const getter_fn = struct {
|
||||||
fn wrap(c_name: ?*const v8.C_Name, raw_info: ?*const v8.C_PropertyCallbackInfo) callconv(.c) u8 {
|
fn wrap(c_name: ?*const v8.C_Name, raw_info: ?*const v8.C_PropertyCallbackInfo) callconv(.c) u8 {
|
||||||
const info = v8.PropertyCallbackInfo.initFromV8(raw_info);
|
const v8_isolate = v8.c.v8__PropertyCallbackInfo__GetIsolate(raw_info).?;
|
||||||
var caller = Caller.init(info);
|
var caller = Caller.init(v8_isolate);
|
||||||
defer caller.deinit();
|
defer caller.deinit();
|
||||||
|
|
||||||
|
const info = PropertyCallbackInfo{ .raw = raw_info.? };
|
||||||
return caller.getNamedIndex(T, getter, .{ .handle = c_name.? }, info, .{
|
return caller.getNamedIndex(T, getter, .{ .handle = c_name.? }, info, .{
|
||||||
.as_typed_array = opts.as_typed_array,
|
.as_typed_array = opts.as_typed_array,
|
||||||
.null_as_undefined = opts.null_as_undefined,
|
.null_as_undefined = opts.null_as_undefined,
|
||||||
@@ -250,10 +784,11 @@ pub const NamedIndexed = struct {
|
|||||||
|
|
||||||
const setter_fn = if (@typeInfo(@TypeOf(setter)) == .null) null else struct {
|
const setter_fn = if (@typeInfo(@TypeOf(setter)) == .null) null else struct {
|
||||||
fn wrap(c_name: ?*const v8.C_Name, c_value: ?*const v8.C_Value, raw_info: ?*const v8.C_PropertyCallbackInfo) callconv(.c) u8 {
|
fn wrap(c_name: ?*const v8.C_Name, c_value: ?*const v8.C_Value, raw_info: ?*const v8.C_PropertyCallbackInfo) callconv(.c) u8 {
|
||||||
const info = v8.PropertyCallbackInfo.initFromV8(raw_info);
|
const v8_isolate = v8.c.v8__PropertyCallbackInfo__GetIsolate(raw_info).?;
|
||||||
var caller = Caller.init(info);
|
var caller = Caller.init(v8_isolate);
|
||||||
defer caller.deinit();
|
defer caller.deinit();
|
||||||
|
|
||||||
|
const info = PropertyCallbackInfo{ .raw = raw_info.? };
|
||||||
return caller.setNamedIndex(T, setter, .{ .handle = c_name.? }, .{ .handle = c_value.? }, info, .{
|
return caller.setNamedIndex(T, setter, .{ .handle = c_name.? }, .{ .handle = c_value.? }, info, .{
|
||||||
.as_typed_array = opts.as_typed_array,
|
.as_typed_array = opts.as_typed_array,
|
||||||
.null_as_undefined = opts.null_as_undefined,
|
.null_as_undefined = opts.null_as_undefined,
|
||||||
@@ -263,10 +798,11 @@ pub const NamedIndexed = struct {
|
|||||||
|
|
||||||
const deleter_fn = if (@typeInfo(@TypeOf(deleter)) == .null) null else struct {
|
const deleter_fn = if (@typeInfo(@TypeOf(deleter)) == .null) null else struct {
|
||||||
fn wrap(c_name: ?*const v8.C_Name, raw_info: ?*const v8.C_PropertyCallbackInfo) callconv(.c) u8 {
|
fn wrap(c_name: ?*const v8.C_Name, raw_info: ?*const v8.C_PropertyCallbackInfo) callconv(.c) u8 {
|
||||||
const info = v8.PropertyCallbackInfo.initFromV8(raw_info);
|
const v8_isolate = v8.c.v8__PropertyCallbackInfo__GetIsolate(raw_info).?;
|
||||||
var caller = Caller.init(info);
|
var caller = Caller.init(v8_isolate);
|
||||||
defer caller.deinit();
|
defer caller.deinit();
|
||||||
|
|
||||||
|
const info = PropertyCallbackInfo{ .raw = raw_info.? };
|
||||||
return caller.deleteNamedIndex(T, deleter, .{ .handle = c_name.? }, info, .{
|
return caller.deleteNamedIndex(T, deleter, .{ .handle = c_name.? }, info, .{
|
||||||
.as_typed_array = opts.as_typed_array,
|
.as_typed_array = opts.as_typed_array,
|
||||||
.null_as_undefined = opts.null_as_undefined,
|
.null_as_undefined = opts.null_as_undefined,
|
||||||
@@ -308,9 +844,11 @@ pub const Iterator = struct {
|
|||||||
.async = opts.async,
|
.async = opts.async,
|
||||||
.func = struct {
|
.func = struct {
|
||||||
fn wrap(raw_info: ?*const v8.C_FunctionCallbackInfo) callconv(.c) void {
|
fn wrap(raw_info: ?*const v8.C_FunctionCallbackInfo) callconv(.c) void {
|
||||||
const info = v8.FunctionCallbackInfo.initFromV8(raw_info);
|
const v8_isolate = v8.c.v8__FunctionCallbackInfo__GetIsolate(raw_info).?;
|
||||||
var caller = Caller.init(info);
|
var caller = Caller.init(v8_isolate);
|
||||||
defer caller.deinit();
|
defer caller.deinit();
|
||||||
|
|
||||||
|
const info = CallbackInfo{ .raw = raw_info.? };
|
||||||
caller.method(T, struct_or_func, info, .{});
|
caller.method(T, struct_or_func, info, .{});
|
||||||
}
|
}
|
||||||
}.wrap,
|
}.wrap,
|
||||||
@@ -328,9 +866,11 @@ pub const Callable = struct {
|
|||||||
fn init(comptime T: type, comptime func: anytype, comptime opts: Opts) Callable {
|
fn init(comptime T: type, comptime func: anytype, comptime opts: Opts) Callable {
|
||||||
return .{ .func = struct {
|
return .{ .func = struct {
|
||||||
fn wrap(raw_info: ?*const v8.C_FunctionCallbackInfo) callconv(.c) void {
|
fn wrap(raw_info: ?*const v8.C_FunctionCallbackInfo) callconv(.c) void {
|
||||||
const info = v8.FunctionCallbackInfo.initFromV8(raw_info);
|
const v8_isolate = v8.c.v8__FunctionCallbackInfo__GetIsolate(raw_info).?;
|
||||||
var caller = Caller.init(info);
|
var caller = Caller.init(v8_isolate);
|
||||||
defer caller.deinit();
|
defer caller.deinit();
|
||||||
|
|
||||||
|
const info = CallbackInfo{ .raw = raw_info.? };
|
||||||
caller.method(T, func, info, .{
|
caller.method(T, func, info, .{
|
||||||
.null_as_undefined = opts.null_as_undefined,
|
.null_as_undefined = opts.null_as_undefined,
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -101,7 +101,7 @@ pub const PersistentPromiseResolver = struct {
|
|||||||
defer context.runMicrotasks();
|
defer context.runMicrotasks();
|
||||||
|
|
||||||
const v8_context = v8.Context{ .handle = context.handle };
|
const v8_context = v8.Context{ .handle = context.handle };
|
||||||
if (self.resolver.castToPromiseResolver().resolve(v8_context, js_value) == null) {
|
if (self.resolver.castToPromiseResolver().resolve(v8_context, js_value.handle) == null) {
|
||||||
return error.FailedToResolvePromise;
|
return error.FailedToResolvePromise;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -119,17 +119,16 @@ pub const PersistentPromiseResolver = struct {
|
|||||||
defer context.runMicrotasks();
|
defer context.runMicrotasks();
|
||||||
|
|
||||||
// resolver.reject will return null if the promise isn't pending
|
// resolver.reject will return null if the promise isn't pending
|
||||||
if (self.resolver.castToPromiseResolver().reject(v8_context, js_value) == null) {
|
if (self.resolver.castToPromiseResolver().reject(v8_context, js_value.handle) == null) {
|
||||||
return error.FailedToRejectPromise;
|
return error.FailedToRejectPromise;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
pub const Exception = struct {
|
pub const Exception = struct {
|
||||||
inner: v8.Value,
|
ctx: *const Context,
|
||||||
context: *const Context,
|
handle: *const v8.c.Value,
|
||||||
|
|
||||||
// the caller needs to deinit the string returned
|
|
||||||
pub fn exception(self: Exception, allocator: Allocator) ![]const u8 {
|
pub fn exception(self: Exception, allocator: Allocator) ![]const u8 {
|
||||||
return self.context.valueToString(self.inner, .{ .allocator = allocator });
|
return self.context.valueToString(self.inner, .{ .allocator = allocator });
|
||||||
}
|
}
|
||||||
@@ -216,30 +215,30 @@ pub fn isComplexAttributeType(ti: std.builtin.Type) bool {
|
|||||||
// These are simple types that we can convert to JS with only an isolate. This
|
// These are simple types that we can convert to JS with only an isolate. This
|
||||||
// is separated from the Caller's zigValueToJs to make it available when we
|
// is separated from the Caller's zigValueToJs to make it available when we
|
||||||
// don't have a caller (i.e., when setting static attributes on types)
|
// don't have a caller (i.e., when setting static attributes on types)
|
||||||
pub fn simpleZigValueToJs(isolate: v8.Isolate, value: anytype, comptime fail: bool, comptime null_as_undefined: bool) if (fail) v8.Value else ?v8.Value {
|
pub fn simpleZigValueToJs(isolate: v8.Isolate, value: anytype, comptime fail: bool, comptime null_as_undefined: bool) if (fail) *const v8.c.Value else ?*const v8.c.Value {
|
||||||
switch (@typeInfo(@TypeOf(value))) {
|
switch (@typeInfo(@TypeOf(value))) {
|
||||||
.void => return v8.initUndefined(isolate).toValue(),
|
.void => return @ptrCast(v8.initUndefined(isolate).handle),
|
||||||
.null => if (comptime null_as_undefined) return v8.initUndefined(isolate).toValue() else return v8.initNull(isolate).toValue(),
|
.null => if (comptime null_as_undefined) return @ptrCast(v8.initUndefined(isolate).handle) else return @ptrCast(v8.initNull(isolate).handle),
|
||||||
.bool => return v8.getValue(if (value) v8.initTrue(isolate) else v8.initFalse(isolate)),
|
.bool => return if (value) v8.initTrue(isolate).handle else v8.initFalse(isolate).handle,
|
||||||
.int => |n| switch (n.signedness) {
|
.int => |n| switch (n.signedness) {
|
||||||
.signed => {
|
.signed => {
|
||||||
if (value > 0 and value <= 4_294_967_295) {
|
if (value > 0 and value <= 4_294_967_295) {
|
||||||
return v8.Integer.initU32(isolate, @intCast(value)).toValue();
|
return @ptrCast(v8.Integer.initU32(isolate, @intCast(value)).handle);
|
||||||
}
|
}
|
||||||
if (value >= -2_147_483_648 and value <= 2_147_483_647) {
|
if (value >= -2_147_483_648 and value <= 2_147_483_647) {
|
||||||
return v8.Integer.initI32(isolate, @intCast(value)).toValue();
|
return @ptrCast(v8.Integer.initI32(isolate, @intCast(value)).handle);
|
||||||
}
|
}
|
||||||
if (comptime n.bits <= 64) {
|
if (comptime n.bits <= 64) {
|
||||||
return v8.getValue(v8.BigInt.initI64(isolate, @intCast(value)));
|
return @ptrCast(v8.BigInt.initI64(isolate, @intCast(value)).handle);
|
||||||
}
|
}
|
||||||
@compileError(@typeName(value) ++ " is not supported");
|
@compileError(@typeName(value) ++ " is not supported");
|
||||||
},
|
},
|
||||||
.unsigned => {
|
.unsigned => {
|
||||||
if (value <= 4_294_967_295) {
|
if (value <= 4_294_967_295) {
|
||||||
return v8.Integer.initU32(isolate, @intCast(value)).toValue();
|
return @ptrCast(v8.Integer.initU32(isolate, @intCast(value)).handle);
|
||||||
}
|
}
|
||||||
if (comptime n.bits <= 64) {
|
if (comptime n.bits <= 64) {
|
||||||
return v8.getValue(v8.BigInt.initU64(isolate, @intCast(value)));
|
return @ptrCast(v8.BigInt.initU64(isolate, @intCast(value)).handle);
|
||||||
}
|
}
|
||||||
@compileError(@typeName(value) ++ " is not supported");
|
@compileError(@typeName(value) ++ " is not supported");
|
||||||
},
|
},
|
||||||
@@ -247,29 +246,29 @@ pub fn simpleZigValueToJs(isolate: v8.Isolate, value: anytype, comptime fail: bo
|
|||||||
.comptime_int => {
|
.comptime_int => {
|
||||||
if (value >= 0) {
|
if (value >= 0) {
|
||||||
if (value <= 4_294_967_295) {
|
if (value <= 4_294_967_295) {
|
||||||
return v8.Integer.initU32(isolate, @intCast(value)).toValue();
|
return @ptrCast(v8.Integer.initU32(isolate, @intCast(value)).handle);
|
||||||
}
|
}
|
||||||
return v8.BigInt.initU64(isolate, @intCast(value)).toValue();
|
return @ptrCast(v8.BigInt.initU64(isolate, @intCast(value)).handle);
|
||||||
}
|
}
|
||||||
if (value >= -2_147_483_648) {
|
if (value >= -2_147_483_648) {
|
||||||
return v8.Integer.initI32(isolate, @intCast(value)).toValue();
|
return @ptrCast(v8.Integer.initI32(isolate, @intCast(value)).handle);
|
||||||
}
|
}
|
||||||
return v8.BigInt.initI64(isolate, @intCast(value)).toValue();
|
return @ptrCast(v8.BigInt.initI64(isolate, @intCast(value)).handle);
|
||||||
},
|
},
|
||||||
.comptime_float => return v8.Number.init(isolate, value).toValue(),
|
.comptime_float => return @ptrCast(v8.Number.init(isolate, value).handle),
|
||||||
.float => |f| switch (f.bits) {
|
.float => |f| switch (f.bits) {
|
||||||
64 => return v8.Number.init(isolate, value).toValue(),
|
64 => return @ptrCast(v8.Number.init(isolate, value).handle),
|
||||||
32 => return v8.Number.init(isolate, @floatCast(value)).toValue(),
|
32 => return @ptrCast(v8.Number.init(isolate, @floatCast(value)).handle),
|
||||||
else => @compileError(@typeName(value) ++ " is not supported"),
|
else => @compileError(@typeName(value) ++ " is not supported"),
|
||||||
},
|
},
|
||||||
.pointer => |ptr| {
|
.pointer => |ptr| {
|
||||||
if (ptr.size == .slice and ptr.child == u8) {
|
if (ptr.size == .slice and ptr.child == u8) {
|
||||||
return v8.String.initUtf8(isolate, value).toValue();
|
return @ptrCast(v8.String.initUtf8(isolate, value).handle);
|
||||||
}
|
}
|
||||||
if (ptr.size == .one) {
|
if (ptr.size == .one) {
|
||||||
const one_info = @typeInfo(ptr.child);
|
const one_info = @typeInfo(ptr.child);
|
||||||
if (one_info == .array and one_info.array.child == u8) {
|
if (one_info == .array and one_info.array.child == u8) {
|
||||||
return v8.String.initUtf8(isolate, value).toValue();
|
return @ptrCast(v8.String.initUtf8(isolate, value).handle);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -279,9 +278,9 @@ pub fn simpleZigValueToJs(isolate: v8.Isolate, value: anytype, comptime fail: bo
|
|||||||
return simpleZigValueToJs(isolate, v, fail, null_as_undefined);
|
return simpleZigValueToJs(isolate, v, fail, null_as_undefined);
|
||||||
}
|
}
|
||||||
if (comptime null_as_undefined) {
|
if (comptime null_as_undefined) {
|
||||||
return v8.initUndefined(isolate).toValue();
|
return @ptrCast(v8.initUndefined(isolate).handle);
|
||||||
}
|
}
|
||||||
return v8.initNull(isolate).toValue();
|
return @ptrCast(v8.initNull(isolate).handle);
|
||||||
},
|
},
|
||||||
.@"struct" => {
|
.@"struct" => {
|
||||||
switch (@TypeOf(value)) {
|
switch (@TypeOf(value)) {
|
||||||
@@ -294,7 +293,7 @@ pub fn simpleZigValueToJs(isolate: v8.Isolate, value: anytype, comptime fail: bo
|
|||||||
@memcpy(data[0..len], @as([]const u8, @ptrCast(values))[0..len]);
|
@memcpy(data[0..len], @as([]const u8, @ptrCast(values))[0..len]);
|
||||||
array_buffer = v8.ArrayBuffer.initWithBackingStore(isolate, &backing_store.toSharedPtr());
|
array_buffer = v8.ArrayBuffer.initWithBackingStore(isolate, &backing_store.toSharedPtr());
|
||||||
|
|
||||||
return .{ .handle = array_buffer.handle };
|
return @ptrCast(array_buffer.handle);
|
||||||
},
|
},
|
||||||
// zig fmt: off
|
// zig fmt: off
|
||||||
TypedArray(u8), TypedArray(u16), TypedArray(u32), TypedArray(u64),
|
TypedArray(u8), TypedArray(u16), TypedArray(u32), TypedArray(u64),
|
||||||
@@ -325,23 +324,23 @@ pub fn simpleZigValueToJs(isolate: v8.Isolate, value: anytype, comptime fail: bo
|
|||||||
switch (@typeInfo(value_type)) {
|
switch (@typeInfo(value_type)) {
|
||||||
.int => |n| switch (n.signedness) {
|
.int => |n| switch (n.signedness) {
|
||||||
.unsigned => switch (n.bits) {
|
.unsigned => switch (n.bits) {
|
||||||
8 => return v8.Uint8Array.init(array_buffer, 0, len).toValue(),
|
8 => return @ptrCast(v8.Uint8Array.init(array_buffer, 0, len).handle),
|
||||||
16 => return v8.Uint16Array.init(array_buffer, 0, len).toValue(),
|
16 => return @ptrCast(v8.Uint16Array.init(array_buffer, 0, len).handle),
|
||||||
32 => return v8.Uint32Array.init(array_buffer, 0, len).toValue(),
|
32 => return @ptrCast(v8.Uint32Array.init(array_buffer, 0, len).handle),
|
||||||
64 => return v8.BigUint64Array.init(array_buffer, 0, len).toValue(),
|
64 => return @ptrCast(v8.BigUint64Array.init(array_buffer, 0, len).handle),
|
||||||
else => {},
|
else => {},
|
||||||
},
|
},
|
||||||
.signed => switch (n.bits) {
|
.signed => switch (n.bits) {
|
||||||
8 => return v8.Int8Array.init(array_buffer, 0, len).toValue(),
|
8 => return @ptrCast(v8.Int8Array.init(array_buffer, 0, len).handle),
|
||||||
16 => return v8.Int16Array.init(array_buffer, 0, len).toValue(),
|
16 => return @ptrCast(v8.Int16Array.init(array_buffer, 0, len).handle),
|
||||||
32 => return v8.Int32Array.init(array_buffer, 0, len).toValue(),
|
32 => return @ptrCast(v8.Int32Array.init(array_buffer, 0, len).handle),
|
||||||
64 => return v8.BigInt64Array.init(array_buffer, 0, len).toValue(),
|
64 => return @ptrCast(v8.BigInt64Array.init(array_buffer, 0, len).handle),
|
||||||
else => {},
|
else => {},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
.float => |f| switch (f.bits) {
|
.float => |f| switch (f.bits) {
|
||||||
32 => return v8.Float32Array.init(array_buffer, 0, len).toValue(),
|
32 => return @ptrCast(v8.Float32Array.init(array_buffer, 0, len).handle),
|
||||||
64 => return v8.Float64Array.init(array_buffer, 0, len).toValue(),
|
64 => return @ptrCast(v8.Float64Array.init(array_buffer, 0, len).handle),
|
||||||
else => {},
|
else => {},
|
||||||
},
|
},
|
||||||
else => {},
|
else => {},
|
||||||
@@ -368,10 +367,6 @@ pub fn simpleZigValueToJs(isolate: v8.Isolate, value: anytype, comptime fail: bo
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn _createException(isolate: v8.Isolate, msg: []const u8) v8.Value {
|
|
||||||
return v8.Exception.initError(v8.String.initUtf8(isolate, msg));
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn classNameForStruct(comptime Struct: type) []const u8 {
|
pub fn classNameForStruct(comptime Struct: type) []const u8 {
|
||||||
if (@hasDecl(Struct, "js_name")) {
|
if (@hasDecl(Struct, "js_name")) {
|
||||||
return Struct.js_name;
|
return Struct.js_name;
|
||||||
|
|||||||
Reference in New Issue
Block a user