mirror of
https://github.com/lightpanda-io/browser.git
synced 2026-02-04 06:23:45 +00:00
Make js.Array and js.Value directly contain their v8 handles.
This commit is contained in:
@@ -21,18 +21,24 @@ const js = @import("js.zig");
|
||||
const v8 = js.v8;
|
||||
|
||||
const Array = @This();
|
||||
js_arr: v8.Array,
|
||||
context: *js.Context,
|
||||
|
||||
ctx: *js.Context,
|
||||
handle: *const v8.c.Array,
|
||||
|
||||
pub fn len(self: Array) usize {
|
||||
return @intCast(self.js_arr.length());
|
||||
return v8.c.v8__Array__Length(self.handle);
|
||||
}
|
||||
|
||||
pub fn get(self: Array, index: usize) !js.Value {
|
||||
const idx_key = v8.Integer.initU32(self.context.isolate, @intCast(index));
|
||||
const js_obj = self.js_arr.castTo(v8.Object);
|
||||
pub fn get(self: Array, index: u32) !js.Value {
|
||||
const ctx = self.ctx;
|
||||
|
||||
const idx = js.Integer.init(ctx.isolate.handle, index);
|
||||
const handle = v8.c.v8__Object__Get(@ptrCast(self.handle), ctx.v8_context.handle, idx.handle) orelse {
|
||||
return error.JsException;
|
||||
};
|
||||
|
||||
return .{
|
||||
.context = self.context,
|
||||
.js_val = try js_obj.getValue(self.context.v8_context, idx_key.toValue()),
|
||||
.ctx = self.ctx,
|
||||
.handle = handle,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -86,8 +86,8 @@ identity_map: std.AutoHashMapUnmanaged(usize, PersistentObject) = .empty,
|
||||
// we now simply persist every time persist() is called.
|
||||
js_object_list: std.ArrayListUnmanaged(PersistentObject) = .empty,
|
||||
|
||||
// js_value_list tracks persisted js values.
|
||||
js_value_list: std.ArrayListUnmanaged(PersistentValue) = .empty,
|
||||
// tracks Global(v8.c.Value).
|
||||
global_values: std.ArrayList(js.Global(js.Value)) = .empty,
|
||||
|
||||
// Various web APIs depend on having a persistent promise resolver. They
|
||||
// require for this PromiseResolver to be valid for a lifetime longer than
|
||||
@@ -165,8 +165,8 @@ pub fn deinit(self: *Context) void {
|
||||
p.deinit();
|
||||
}
|
||||
|
||||
for (self.js_value_list.items) |*p| {
|
||||
p.deinit();
|
||||
for (self.global_values.items) |*global| {
|
||||
global.deinit();
|
||||
}
|
||||
|
||||
for (self.persisted_promise_resolvers.items) |*p| {
|
||||
@@ -374,12 +374,10 @@ pub fn createException(self: *const Context, e: v8.Value) js.Exception {
|
||||
};
|
||||
}
|
||||
|
||||
// Wrap a v8.Value, largely so that we can provide a convenient
|
||||
// toString function
|
||||
pub fn createValue(self: *Context, value: v8.Value) js.Value {
|
||||
return .{
|
||||
.js_val = value,
|
||||
.context = self,
|
||||
.ctx = self,
|
||||
.handle = value.handle,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -499,7 +497,7 @@ pub fn zigValueToJs(self: *Context, value: anytype, comptime opts: Caller.CallOp
|
||||
}
|
||||
|
||||
if (T == js.Value) {
|
||||
return value.js_val;
|
||||
return .{ .handle = value.handle };
|
||||
}
|
||||
|
||||
if (T == js.Promise) {
|
||||
@@ -837,8 +835,8 @@ fn jsValueToStruct(self: *Context, comptime T: type, js_value: v8.Value) !?T {
|
||||
// Caller wants an opaque js.Object. Probably a parameter
|
||||
// that it needs to pass back into a callback.
|
||||
js.Value => js.Value{
|
||||
.js_val = js_value,
|
||||
.context = self,
|
||||
.ctx = self,
|
||||
.handle = js_value.handle,
|
||||
},
|
||||
// Caller wants an opaque js.Object. Probably a parameter
|
||||
// that it needs to pass back into a callback.
|
||||
|
||||
35
src/browser/js/Integer.zig
Normal file
35
src/browser/js/Integer.zig
Normal file
@@ -0,0 +1,35 @@
|
||||
// Copyright (C) 2023-2025 Lightpanda (Selecy SAS)
|
||||
//
|
||||
// Francis Bouvier <francis@lightpanda.io>
|
||||
// Pierre Tachoire <pierre@lightpanda.io>
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License as
|
||||
// published by the Free Software Foundation, either version 3 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Affero General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
const std = @import("std");
|
||||
const js = @import("js.zig");
|
||||
|
||||
const v8 = js.v8;
|
||||
|
||||
const Integer = @This();
|
||||
|
||||
handle: *const v8.c.Integer,
|
||||
|
||||
pub fn init(isolate: *v8.c.Isolate, value: anytype) Integer {
|
||||
const handle = switch (@TypeOf(value)) {
|
||||
i8, i16, i32 => v8.c.v8__Integer__New(isolate, value).?,
|
||||
u8, u16, u32 => v8.c.v8__Integer__NewFromUnsigned(isolate, value).?,
|
||||
else => |T| @compileError("cannot create v8::Integer from: " ++ @typeName(T)),
|
||||
};
|
||||
return .{ .handle = handle };
|
||||
}
|
||||
@@ -21,24 +21,25 @@ const js = @import("js.zig");
|
||||
|
||||
const v8 = js.v8;
|
||||
|
||||
const IS_DEBUG = @import("builtin").mode == .Debug;
|
||||
|
||||
const Allocator = std.mem.Allocator;
|
||||
|
||||
const PersistentValue = v8.Persistent(v8.Value);
|
||||
|
||||
const Value = @This();
|
||||
js_val: v8.Value,
|
||||
context: *js.Context,
|
||||
|
||||
ctx: *js.Context,
|
||||
handle: *const v8.c.Value,
|
||||
|
||||
pub fn isObject(self: Value) bool {
|
||||
return self.js_val.isObject();
|
||||
return v8.c.v8__Value__IsObject(self.handle);
|
||||
}
|
||||
|
||||
pub fn isString(self: Value) bool {
|
||||
return self.js_val.isString();
|
||||
return v8.c.v8__Value__IsString(self.handle);
|
||||
}
|
||||
|
||||
pub fn isArray(self: Value) bool {
|
||||
return self.js_val.isArray();
|
||||
return v8.c.v8__Value__IsArray(self.handle);
|
||||
}
|
||||
|
||||
pub fn isNull(self: Value) bool {
|
||||
@@ -50,7 +51,7 @@ pub fn isUndefined(self: Value) bool {
|
||||
}
|
||||
|
||||
pub fn toString(self: Value, allocator: Allocator) ![]const u8 {
|
||||
return self.context.valueToString(self.js_val, .{ .allocator = allocator });
|
||||
return self.ctx.valueToString(.{ .handle = self.handle }, .{ .allocator = allocator });
|
||||
}
|
||||
|
||||
pub fn toBool(self: Value) bool {
|
||||
@@ -60,17 +61,19 @@ pub fn toBool(self: Value) bool {
|
||||
pub fn fromJson(ctx: *js.Context, json: []const u8) !Value {
|
||||
const json_string = v8.String.initUtf8(ctx.isolate, json);
|
||||
const value = try v8.Json.parse(ctx.v8_context, json_string);
|
||||
return Value{ .context = ctx, .js_val = value };
|
||||
return .{ .ctx = ctx, .handle = value.handle };
|
||||
}
|
||||
|
||||
pub fn persist(self: Value) !Value {
|
||||
const js_val = self.js_val;
|
||||
var context = self.context;
|
||||
var ctx = self.ctx;
|
||||
|
||||
const persisted = PersistentValue.init(context.isolate, js_val);
|
||||
try context.js_value_list.append(context.arena, persisted);
|
||||
const global = js.Global(Value).init(ctx.isolate.handle, self);
|
||||
try ctx.global_values.append(ctx.arena, global);
|
||||
|
||||
return Value{ .context = context, .js_val = persisted.toValue() };
|
||||
return .{
|
||||
.ctx = ctx,
|
||||
.handle = global.local(),
|
||||
};
|
||||
}
|
||||
|
||||
pub fn toZig(self: Value, comptime T: type) !T {
|
||||
@@ -78,15 +81,23 @@ pub fn toZig(self: Value, comptime T: type) !T {
|
||||
}
|
||||
|
||||
pub fn toObject(self: Value) js.Object {
|
||||
if (comptime IS_DEBUG) {
|
||||
std.debug.assert(self.isObject());
|
||||
}
|
||||
|
||||
return .{
|
||||
.context = self.context,
|
||||
.js_obj = self.js_val.castTo(v8.Object),
|
||||
.context = self.ctx,
|
||||
.js_obj = .{ .handle = self.handle },
|
||||
};
|
||||
}
|
||||
|
||||
pub fn toArray(self: Value) js.Array {
|
||||
if (comptime IS_DEBUG) {
|
||||
std.debug.assert(self.isArray());
|
||||
}
|
||||
|
||||
return .{
|
||||
.context = self.context,
|
||||
.js_arr = self.js_val.castTo(v8.Array),
|
||||
.ctx = self.ctx,
|
||||
.handle = self.handle,
|
||||
};
|
||||
}
|
||||
|
||||
48
src/browser/js/global.zig
Normal file
48
src/browser/js/global.zig
Normal file
@@ -0,0 +1,48 @@
|
||||
// Copyright (C) 2023-2025 Lightpanda (Selecy SAS)
|
||||
//
|
||||
// Francis Bouvier <francis@lightpanda.io>
|
||||
// Pierre Tachoire <pierre@lightpanda.io>
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License as
|
||||
// published by the Free Software Foundation, either version 3 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Affero General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
const std = @import("std");
|
||||
const js = @import("js.zig");
|
||||
|
||||
const v8 = js.v8;
|
||||
|
||||
pub fn Global(comptime T: type) type {
|
||||
const H = @FieldType(T, "handle");
|
||||
|
||||
return struct {
|
||||
global: v8.c.Global,
|
||||
|
||||
const Self = @This();
|
||||
|
||||
pub fn init(isolate: *v8.c.Isolate, data: T) Self {
|
||||
var global: v8.c.Global = undefined;
|
||||
v8.c.v8__Global__New(isolate, data.handle, &global);
|
||||
return .{
|
||||
.global = global,
|
||||
};
|
||||
}
|
||||
|
||||
pub fn deinit(self: *Self) void {
|
||||
v8.c.v8__Global__Reset(&self.global);
|
||||
}
|
||||
|
||||
pub fn local(self: *const Self) H {
|
||||
return @ptrCast(@alignCast(@as(*const anyopaque, @ptrFromInt(self.global.data_ptr))));
|
||||
}
|
||||
};
|
||||
}
|
||||
@@ -37,6 +37,9 @@ pub const Object = @import("Object.zig");
|
||||
pub const TryCatch = @import("TryCatch.zig");
|
||||
pub const Function = @import("Function.zig");
|
||||
|
||||
pub const Integer = @import("Integer.zig");
|
||||
pub const Global = @import("global.zig").Global;
|
||||
|
||||
const Allocator = std.mem.Allocator;
|
||||
|
||||
pub fn Bridge(comptime T: type) type {
|
||||
|
||||
@@ -72,7 +72,7 @@ pub fn define(self: *CustomElementRegistry, name: []const u8, constructor: js.Fu
|
||||
if (observed_attrs.isArray()) {
|
||||
var js_arr = observed_attrs.toArray();
|
||||
for (0..js_arr.len()) |i| {
|
||||
const attr_val = js_arr.get(i) catch continue;
|
||||
const attr_val = js_arr.get(@intCast(i)) catch continue;
|
||||
const attr_name = attr_val.toString(page.arena) catch continue;
|
||||
const owned_attr = page.dupeString(attr_name) catch continue;
|
||||
definition.observed_attributes.put(page.arena, owned_attr, {}) catch continue;
|
||||
|
||||
Reference in New Issue
Block a user