mirror of
https://github.com/lightpanda-io/browser.git
synced 2026-02-04 14:33:47 +00:00
Make Promise, PromiseResolver and Module have explicit globals.
See bb06900b6f84abaccc7ecfd386af1a9dc0029c50 for an explanation.
This commit is contained in:
@@ -79,10 +79,10 @@ identity_map: std.AutoHashMapUnmanaged(usize, js.Global(js.Object)) = .empty,
|
|||||||
// we now simply persist every time persist() is called.
|
// we now simply persist every time persist() is called.
|
||||||
global_values: std.ArrayList(v8.Global) = .empty,
|
global_values: std.ArrayList(v8.Global) = .empty,
|
||||||
global_objects: std.ArrayList(v8.Global) = .empty,
|
global_objects: std.ArrayList(v8.Global) = .empty,
|
||||||
global_modules: std.ArrayList(js.Global(js.Module)) = .empty,
|
global_modules: std.ArrayList(v8.Global) = .empty,
|
||||||
global_promises: std.ArrayList(js.Global(js.Promise)) = .empty,
|
global_promises: std.ArrayList(v8.Global) = .empty,
|
||||||
global_functions: std.ArrayList(v8.Global) = .empty,
|
global_functions: std.ArrayList(v8.Global) = .empty,
|
||||||
global_promise_resolvers: std.ArrayList(js.Global(js.PromiseResolver)) = .empty,
|
global_promise_resolvers: std.ArrayList(v8.Global) = .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,
|
||||||
@@ -100,19 +100,19 @@ script_manager: ?*ScriptManager,
|
|||||||
const ModuleEntry = struct {
|
const ModuleEntry = struct {
|
||||||
// Can be null if we're asynchrously loading the module, in
|
// Can be null if we're asynchrously loading the module, in
|
||||||
// which case resolver_promise cannot be null.
|
// which case resolver_promise cannot be null.
|
||||||
module: ?js.Module = null,
|
module: ?js.Module.Global = null,
|
||||||
|
|
||||||
// The promise of the evaluating module. The resolved value is
|
// The promise of the evaluating module. The resolved value is
|
||||||
// meaningless to us, but the resolver promise needs to chain
|
// meaningless to us, but the resolver promise needs to chain
|
||||||
// to this, since we need to know when it's complete.
|
// to this, since we need to know when it's complete.
|
||||||
module_promise: ?js.Promise = null,
|
module_promise: ?js.Promise.Global = null,
|
||||||
|
|
||||||
// The promise for the resolver which is loading the module.
|
// The promise for the resolver which is loading the module.
|
||||||
// (AKA, the first time we try to load it). This resolver will
|
// (AKA, the first time we try to load it). This resolver will
|
||||||
// chain to the module_promise and, when it's done evaluating
|
// chain to the module_promise and, when it's done evaluating
|
||||||
// will resolve its namespace. Any other attempt to load the
|
// will resolve its namespace. Any other attempt to load the
|
||||||
// module willchain to this.
|
// module willchain to this.
|
||||||
resolver_promise: ?js.Promise = null,
|
resolver_promise: ?js.Promise.Global = null,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub fn fromC(c_context: *const v8.Context) *Context {
|
pub fn fromC(c_context: *const v8.Context) *Context {
|
||||||
@@ -150,7 +150,7 @@ pub fn deinit(self: *Context) void {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for (self.global_modules.items) |*global| {
|
for (self.global_modules.items) |*global| {
|
||||||
global.deinit();
|
v8.v8__Global__Reset(global);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (self.global_functions.items) |*global| {
|
for (self.global_functions.items) |*global| {
|
||||||
@@ -158,11 +158,11 @@ pub fn deinit(self: *Context) void {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for (self.global_promises.items) |*global| {
|
for (self.global_promises.items) |*global| {
|
||||||
global.deinit();
|
v8.v8__Global__Reset(global);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (self.global_promise_resolvers.items) |*global| {
|
for (self.global_promise_resolvers.items) |*global| {
|
||||||
global.deinit();
|
v8.v8__Global__Reset(global);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (self.handle_scope) |*scope| {
|
if (self.handle_scope) |*scope| {
|
||||||
@@ -472,6 +472,21 @@ pub fn zigValueToJs(self: *Context, value: anytype, comptime opts: Caller.CallOp
|
|||||||
return .{ .ctx = self, .handle = @ptrCast(value.local().handle) };
|
return .{ .ctx = self, .handle = @ptrCast(value.local().handle) };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (T == js.Promise.Global) {
|
||||||
|
// Auto-convert Global to local for bridge
|
||||||
|
return .{ .ctx = self, .handle = @ptrCast(value.local().handle) };
|
||||||
|
}
|
||||||
|
|
||||||
|
if (T == js.PromiseResolver.Global) {
|
||||||
|
// Auto-convert Global to local for bridge
|
||||||
|
return .{ .ctx = self, .handle = @ptrCast(value.local().handle) };
|
||||||
|
}
|
||||||
|
|
||||||
|
if (T == js.Module.Global) {
|
||||||
|
// Auto-convert Global to local for bridge
|
||||||
|
return .{ .ctx = self, .handle = @ptrCast(value.local().handle) };
|
||||||
|
}
|
||||||
|
|
||||||
if (T == js.Value) {
|
if (T == js.Value) {
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
@@ -841,6 +856,16 @@ fn jsValueToStruct(self: *Context, comptime T: type, js_value: js.Value) !?T {
|
|||||||
js.Value.Global => {
|
js.Value.Global => {
|
||||||
return try js_value.persist();
|
return try js_value.persist();
|
||||||
},
|
},
|
||||||
|
js.Promise.Global => {
|
||||||
|
if (!js_value.isPromise()) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
const promise = js.Promise{
|
||||||
|
.ctx = self,
|
||||||
|
.handle = @ptrCast(js_value.handle),
|
||||||
|
};
|
||||||
|
return try promise.persist();
|
||||||
|
},
|
||||||
else => {
|
else => {
|
||||||
if (!js_value.isObject()) {
|
if (!js_value.isObject()) {
|
||||||
return null;
|
return null;
|
||||||
@@ -1286,7 +1311,7 @@ fn _resolveModuleCallback(self: *Context, referrer: js.Module, specifier: [:0]co
|
|||||||
|
|
||||||
const entry = self.module_cache.getPtr(normalized_specifier).?;
|
const entry = self.module_cache.getPtr(normalized_specifier).?;
|
||||||
if (entry.module) |m| {
|
if (entry.module) |m| {
|
||||||
return m.handle;
|
return m.local().handle;
|
||||||
}
|
}
|
||||||
|
|
||||||
var source = try self.script_manager.?.waitForImport(normalized_specifier);
|
var source = try self.script_manager.?.waitForImport(normalized_specifier);
|
||||||
@@ -1299,7 +1324,7 @@ fn _resolveModuleCallback(self: *Context, referrer: js.Module, specifier: [:0]co
|
|||||||
const mod = try self.compileModule(source.src(), normalized_specifier);
|
const mod = try self.compileModule(source.src(), normalized_specifier);
|
||||||
try self.postCompileModule(mod, normalized_specifier);
|
try self.postCompileModule(mod, normalized_specifier);
|
||||||
entry.module = try mod.persist();
|
entry.module = try mod.persist();
|
||||||
return entry.module.?.handle;
|
return entry.module.?.local().handle;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Will get passed to ScriptManager and then passed back to us when
|
// Will get passed to ScriptManager and then passed back to us when
|
||||||
@@ -1307,11 +1332,11 @@ fn _resolveModuleCallback(self: *Context, referrer: js.Module, specifier: [:0]co
|
|||||||
const DynamicModuleResolveState = struct {
|
const DynamicModuleResolveState = struct {
|
||||||
// The module that we're resolving (we'll actually resolve its
|
// The module that we're resolving (we'll actually resolve its
|
||||||
// namespace)
|
// namespace)
|
||||||
module: ?js.Module,
|
module: ?js.Module.Global,
|
||||||
context_id: usize,
|
context_id: usize,
|
||||||
context: *Context,
|
context: *Context,
|
||||||
specifier: [:0]const u8,
|
specifier: [:0]const u8,
|
||||||
resolver: js.PromiseResolver,
|
resolver: js.PromiseResolver.Global,
|
||||||
};
|
};
|
||||||
|
|
||||||
fn _dynamicModuleCallback(self: *Context, specifier: [:0]const u8, referrer: []const u8) !js.Promise {
|
fn _dynamicModuleCallback(self: *Context, specifier: [:0]const u8, referrer: []const u8) !js.Promise {
|
||||||
@@ -1320,7 +1345,7 @@ fn _dynamicModuleCallback(self: *Context, specifier: [:0]const u8, referrer: []c
|
|||||||
// This is easy, there's already something responsible
|
// This is easy, there's already something responsible
|
||||||
// for loading the module. Maybe it's still loading, maybe
|
// for loading the module. Maybe it's still loading, maybe
|
||||||
// it's complete. Whatever, we can just return that promise.
|
// it's complete. Whatever, we can just return that promise.
|
||||||
return gop.value_ptr.resolver_promise.?;
|
return gop.value_ptr.resolver_promise.?.local();
|
||||||
}
|
}
|
||||||
|
|
||||||
const resolver = try self.createPromiseResolver().persist();
|
const resolver = try self.createPromiseResolver().persist();
|
||||||
@@ -1334,7 +1359,7 @@ fn _dynamicModuleCallback(self: *Context, specifier: [:0]const u8, referrer: []c
|
|||||||
.resolver = resolver,
|
.resolver = resolver,
|
||||||
};
|
};
|
||||||
|
|
||||||
const promise = try resolver.promise().persist();
|
const promise = try resolver.local().promise().persist();
|
||||||
|
|
||||||
if (!gop.found_existing) {
|
if (!gop.found_existing) {
|
||||||
// this module hasn't been seen before. This is the most
|
// this module hasn't been seen before. This is the most
|
||||||
@@ -1352,13 +1377,13 @@ 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 = self.newString(@errorName(err));
|
const error_msg = self.newString(@errorName(err));
|
||||||
_ = resolver.reject("dynamic module get async", error_msg);
|
_ = resolver.local().reject("dynamic module get async", error_msg);
|
||||||
};
|
};
|
||||||
|
|
||||||
// For now, we're done. but this will be continued in
|
// For now, we're done. but this will be continued in
|
||||||
// `dynamicModuleSourceCallback`, once the source for the
|
// `dynamicModuleSourceCallback`, once the source for the
|
||||||
// moduel is loaded.
|
// moduel is loaded.
|
||||||
return promise;
|
return promise.local();
|
||||||
}
|
}
|
||||||
|
|
||||||
// So we have a module, but no async resolver. This can only
|
// So we have a module, but no async resolver. This can only
|
||||||
@@ -1374,20 +1399,21 @@ fn _dynamicModuleCallback(self: *Context, specifier: [:0]const u8, referrer: []c
|
|||||||
// If the module hasn't been evaluated yet (it was only instantiated
|
// If the module hasn't been evaluated yet (it was only instantiated
|
||||||
// as a static import dependency), we need to evaluate it now.
|
// as a static import dependency), we need to evaluate it now.
|
||||||
if (gop.value_ptr.module_promise == null) {
|
if (gop.value_ptr.module_promise == null) {
|
||||||
const mod = gop.value_ptr.module.?;
|
const mod_global = gop.value_ptr.module.?;
|
||||||
|
const mod = mod_global.local();
|
||||||
const status = mod.getStatus();
|
const status = mod.getStatus();
|
||||||
if (status == .kEvaluated or status == .kEvaluating) {
|
if (status == .kEvaluated or status == .kEvaluating) {
|
||||||
// Module was already evaluated (shouldn't normally happen, but handle it).
|
// Module was already evaluated (shouldn't normally happen, but handle it).
|
||||||
// Create a pre-resolved promise with the module namespace.
|
// Create a pre-resolved promise with the module namespace.
|
||||||
const module_resolver = try self.createPromiseResolver().persist();
|
const module_resolver = try self.createPromiseResolver().persist();
|
||||||
_ = module_resolver.resolve("resolve module", mod.getModuleNamespace());
|
_ = module_resolver.local().resolve("resolve module", mod.getModuleNamespace());
|
||||||
gop.value_ptr.module_promise = try module_resolver.promise().persist();
|
gop.value_ptr.module_promise = try module_resolver.local().promise().persist();
|
||||||
} else {
|
} else {
|
||||||
// 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() catch {
|
const evaluated = mod.evaluate() catch {
|
||||||
std.debug.assert(status == .kErrored);
|
std.debug.assert(status == .kErrored);
|
||||||
_ = resolver.reject("module evaluation", self.newString("Module evaluation failed"));
|
_ = resolver.local().reject("module evaluation", self.newString("Module evaluation failed"));
|
||||||
return promise;
|
return promise.local();
|
||||||
};
|
};
|
||||||
std.debug.assert(evaluated.isPromise());
|
std.debug.assert(evaluated.isPromise());
|
||||||
gop.value_ptr.module_promise = try evaluated.toPromise().persist();
|
gop.value_ptr.module_promise = try evaluated.toPromise().persist();
|
||||||
@@ -1402,7 +1428,7 @@ fn _dynamicModuleCallback(self: *Context, specifier: [:0]const u8, referrer: []c
|
|||||||
// But we can skip direclty to `resolveDynamicModule` which is
|
// But we can skip direclty to `resolveDynamicModule` which is
|
||||||
// what the above callback will eventually do.
|
// what the above callback will eventually do.
|
||||||
self.resolveDynamicModule(state, gop.value_ptr.*);
|
self.resolveDynamicModule(state, gop.value_ptr.*);
|
||||||
return promise;
|
return promise.local();
|
||||||
}
|
}
|
||||||
|
|
||||||
fn dynamicModuleSourceCallback(ctx: *anyopaque, module_source_: anyerror!ScriptManager.ModuleSource) void {
|
fn dynamicModuleSourceCallback(ctx: *anyopaque, module_source_: anyerror!ScriptManager.ModuleSource) void {
|
||||||
@@ -1410,7 +1436,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| {
|
||||||
_ = state.resolver.reject("dynamic module source", self.newString(@errorName(err)));
|
_ = state.resolver.local().reject("dynamic module source", self.newString(@errorName(err)));
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -1427,7 +1453,7 @@ fn dynamicModuleSourceCallback(ctx: *anyopaque, module_source_: anyerror!ScriptM
|
|||||||
.caught = caught,
|
.caught = caught,
|
||||||
.specifier = state.specifier,
|
.specifier = state.specifier,
|
||||||
});
|
});
|
||||||
_ = state.resolver.reject("dynamic compilation failure", self.newString(caught.exception orelse ""));
|
_ = state.resolver.local().reject("dynamic compilation failure", self.newString(caught.exception orelse ""));
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
@@ -1471,8 +1497,8 @@ fn resolveDynamicModule(self: *Context, state: *DynamicModuleResolveState, modul
|
|||||||
}
|
}
|
||||||
|
|
||||||
defer caller.context.runMicrotasks();
|
defer caller.context.runMicrotasks();
|
||||||
const namespace = s.module.?.getModuleNamespace();
|
const namespace = s.module.?.local().getModuleNamespace();
|
||||||
_ = s.resolver.resolve("resolve namespace", namespace);
|
_ = s.resolver.local().resolve("resolve namespace", namespace);
|
||||||
}
|
}
|
||||||
}.callback, @ptrCast(state));
|
}.callback, @ptrCast(state));
|
||||||
|
|
||||||
@@ -1491,19 +1517,19 @@ fn resolveDynamicModule(self: *Context, state: *DynamicModuleResolveState, modul
|
|||||||
}
|
}
|
||||||
|
|
||||||
defer ctx.runMicrotasks();
|
defer ctx.runMicrotasks();
|
||||||
_ = s.resolver.reject("catch callback", js.Value{
|
_ = s.resolver.local().reject("catch callback", js.Value{
|
||||||
.ctx = ctx,
|
.ctx = ctx,
|
||||||
.handle = v8.v8__FunctionCallbackInfo__Data(callback_handle).?,
|
.handle = v8.v8__FunctionCallbackInfo__Data(callback_handle).?,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}.callback, @ptrCast(state));
|
}.callback, @ptrCast(state));
|
||||||
|
|
||||||
_ = module_entry.module_promise.?.thenAndCatch(then_callback, catch_callback) catch |err| {
|
_ = module_entry.module_promise.?.local().thenAndCatch(then_callback, catch_callback) catch |err| {
|
||||||
log.err(.js, "module evaluation is promise", .{
|
log.err(.js, "module evaluation is promise", .{
|
||||||
.err = err,
|
.err = err,
|
||||||
.specifier = state.specifier,
|
.specifier = state.specifier,
|
||||||
});
|
});
|
||||||
_ = state.resolver.reject("module promise", self.newString("Failed to evaluate promise"));
|
_ = state.resolver.local().reject("module promise", self.newString("Failed to evaluate promise"));
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -89,18 +89,37 @@ pub fn getScriptId(self: Module) u32 {
|
|||||||
return @intCast(v8.v8__Module__ScriptId(self.handle));
|
return @intCast(v8.v8__Module__ScriptId(self.handle));
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn persist(self: Module) !Module {
|
pub fn persist(self: Module) !Global {
|
||||||
var ctx = self.ctx;
|
var ctx = self.ctx;
|
||||||
|
var global: v8.Global = undefined;
|
||||||
const global = js.Global(Module).init(ctx.isolate.handle, self.handle);
|
v8.v8__Global__New(ctx.isolate.handle, self.handle, &global);
|
||||||
try ctx.global_modules.append(ctx.arena, global);
|
try ctx.global_modules.append(ctx.arena, global);
|
||||||
|
|
||||||
return .{
|
return .{
|
||||||
|
.handle = global,
|
||||||
.ctx = ctx,
|
.ctx = ctx,
|
||||||
.handle = global.local(),
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub const Global = struct {
|
||||||
|
handle: v8.Global,
|
||||||
|
ctx: *js.Context,
|
||||||
|
|
||||||
|
pub fn deinit(self: *Global) void {
|
||||||
|
v8.v8__Global__Reset(&self.handle);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn local(self: *const Global) Module {
|
||||||
|
return .{
|
||||||
|
.ctx = self.ctx,
|
||||||
|
.handle = @ptrCast(v8.v8__Global__Get(&self.handle, self.ctx.isolate.handle)),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn isEqual(self: *const Global, other: Module) bool {
|
||||||
|
return v8.v8__Global__IsEqual(&self.handle, other.handle);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
const Requests = struct {
|
const Requests = struct {
|
||||||
ctx: *const v8.Context,
|
ctx: *const v8.Context,
|
||||||
handle: *const v8.FixedArray,
|
handle: *const v8.FixedArray,
|
||||||
|
|||||||
@@ -47,14 +47,37 @@ pub fn thenAndCatch(self: Promise, on_fulfilled: js.Function, on_rejected: js.Fu
|
|||||||
}
|
}
|
||||||
return error.PromiseChainFailed;
|
return error.PromiseChainFailed;
|
||||||
}
|
}
|
||||||
pub fn persist(self: Promise) !Promise {
|
pub fn persist(self: Promise) !Global {
|
||||||
var ctx = self.ctx;
|
var ctx = self.ctx;
|
||||||
|
var global: v8.Global = undefined;
|
||||||
const global = js.Global(Promise).init(ctx.isolate.handle, self.handle);
|
v8.v8__Global__New(ctx.isolate.handle, self.handle, &global);
|
||||||
try ctx.global_promises.append(ctx.arena, global);
|
try ctx.global_promises.append(ctx.arena, global);
|
||||||
|
|
||||||
return .{
|
return .{
|
||||||
|
.handle = global,
|
||||||
.ctx = ctx,
|
.ctx = ctx,
|
||||||
.handle = global.local(),
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub const Global = struct {
|
||||||
|
handle: v8.Global,
|
||||||
|
ctx: *js.Context,
|
||||||
|
|
||||||
|
pub fn deinit(self: *Global) void {
|
||||||
|
v8.v8__Global__Reset(&self.handle);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn local(self: *const Global) Promise {
|
||||||
|
return .{
|
||||||
|
.ctx = self.ctx,
|
||||||
|
.handle = @ptrCast(v8.v8__Global__Get(&self.handle, self.ctx.isolate.handle)),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn isEqual(self: *const Global, other: Promise) bool {
|
||||||
|
return v8.v8__Global__IsEqual(&self.handle, other.handle);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn promise(self: *const Global) Promise {
|
||||||
|
return self.local();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|||||||
@@ -75,14 +75,33 @@ fn _reject(self: PromiseResolver, value: anytype) !void {
|
|||||||
ctx.runMicrotasks();
|
ctx.runMicrotasks();
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn persist(self: PromiseResolver) !PromiseResolver {
|
pub fn persist(self: PromiseResolver) !Global {
|
||||||
var ctx = self.ctx;
|
var ctx = self.ctx;
|
||||||
|
var global: v8.Global = undefined;
|
||||||
const global = js.Global(PromiseResolver).init(ctx.isolate.handle, self.handle);
|
v8.v8__Global__New(ctx.isolate.handle, self.handle, &global);
|
||||||
try ctx.global_promise_resolvers.append(ctx.arena, global);
|
try ctx.global_promise_resolvers.append(ctx.arena, global);
|
||||||
|
|
||||||
return .{
|
return .{
|
||||||
|
.handle = global,
|
||||||
.ctx = ctx,
|
.ctx = ctx,
|
||||||
.handle = global.local(),
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub const Global = struct {
|
||||||
|
handle: v8.Global,
|
||||||
|
ctx: *js.Context,
|
||||||
|
|
||||||
|
pub fn deinit(self: *Global) void {
|
||||||
|
v8.v8__Global__Reset(&self.handle);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn local(self: *const Global) PromiseResolver {
|
||||||
|
return .{
|
||||||
|
.ctx = self.ctx,
|
||||||
|
.handle = @ptrCast(v8.v8__Global__Get(&self.handle, self.ctx.isolate.handle)),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn isEqual(self: *const Global, other: PromiseResolver) bool {
|
||||||
|
return v8.v8__Global__IsEqual(&self.handle, other.handle);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ const CustomElementDefinition = @import("CustomElementDefinition.zig");
|
|||||||
const CustomElementRegistry = @This();
|
const CustomElementRegistry = @This();
|
||||||
|
|
||||||
_definitions: std.StringHashMapUnmanaged(*CustomElementDefinition) = .{},
|
_definitions: std.StringHashMapUnmanaged(*CustomElementDefinition) = .{},
|
||||||
_when_defined: std.StringHashMapUnmanaged(js.PromiseResolver) = .{},
|
_when_defined: std.StringHashMapUnmanaged(js.PromiseResolver.Global) = .{},
|
||||||
|
|
||||||
const DefineOptions = struct {
|
const DefineOptions = struct {
|
||||||
extends: ?[]const u8 = null,
|
extends: ?[]const u8 = null,
|
||||||
@@ -106,7 +106,7 @@ pub fn define(self: *CustomElementRegistry, name: []const u8, constructor: js.Fu
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (self._when_defined.fetchRemove(name)) |entry| {
|
if (self._when_defined.fetchRemove(name)) |entry| {
|
||||||
entry.value.resolve("whenDefined", constructor);
|
entry.value.local().resolve("whenDefined", constructor);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -126,7 +126,7 @@ pub fn whenDefined(self: *CustomElementRegistry, name: []const u8, page: *Page)
|
|||||||
|
|
||||||
const gop = try self._when_defined.getOrPut(page.arena, name);
|
const gop = try self._when_defined.getOrPut(page.arena, name);
|
||||||
if (gop.found_existing) {
|
if (gop.found_existing) {
|
||||||
return gop.value_ptr.promise();
|
return gop.value_ptr.local().promise();
|
||||||
}
|
}
|
||||||
errdefer _ = self._when_defined.remove(name);
|
errdefer _ = self._when_defined.remove(name);
|
||||||
const owned_name = try page.dupeString(name);
|
const owned_name = try page.dupeString(name);
|
||||||
@@ -135,7 +135,7 @@ pub fn whenDefined(self: *CustomElementRegistry, name: []const u8, page: *Page)
|
|||||||
gop.key_ptr.* = owned_name;
|
gop.key_ptr.* = owned_name;
|
||||||
gop.value_ptr.* = resolver;
|
gop.value_ptr.* = resolver;
|
||||||
|
|
||||||
return resolver.promise();
|
return resolver.local().promise();
|
||||||
}
|
}
|
||||||
|
|
||||||
fn upgradeNode(self: *CustomElementRegistry, node: *Node, page: *Page) !void {
|
fn upgradeNode(self: *CustomElementRegistry, node: *Node, page: *Page) !void {
|
||||||
|
|||||||
@@ -23,8 +23,8 @@ const Animation = @This();
|
|||||||
|
|
||||||
_effect: ?js.Object.Global = null,
|
_effect: ?js.Object.Global = null,
|
||||||
_timeline: ?js.Object.Global = null,
|
_timeline: ?js.Object.Global = null,
|
||||||
_ready_resolver: ?js.PromiseResolver = null,
|
_ready_resolver: ?js.PromiseResolver.Global = null,
|
||||||
_finished_resolver: ?js.PromiseResolver = null,
|
_finished_resolver: ?js.PromiseResolver.Global = null,
|
||||||
|
|
||||||
pub fn init(page: *Page) !*Animation {
|
pub fn init(page: *Page) !*Animation {
|
||||||
return page._factory.create(Animation{});
|
return page._factory.create(Animation{});
|
||||||
@@ -47,10 +47,10 @@ pub fn getPending(_: *const Animation) bool {
|
|||||||
pub fn getFinished(self: *Animation, page: *Page) !js.Promise {
|
pub fn getFinished(self: *Animation, page: *Page) !js.Promise {
|
||||||
if (self._finished_resolver == null) {
|
if (self._finished_resolver == null) {
|
||||||
const resolver = try page.js.createPromiseResolver().persist();
|
const resolver = try page.js.createPromiseResolver().persist();
|
||||||
resolver.resolve("Animation.getFinished", self);
|
resolver.local().resolve("Animation.getFinished", self);
|
||||||
self._finished_resolver = resolver;
|
self._finished_resolver = resolver;
|
||||||
}
|
}
|
||||||
return self._finished_resolver.?.promise();
|
return self._finished_resolver.?.local().promise();
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn getReady(self: *Animation, page: *Page) !js.Promise {
|
pub fn getReady(self: *Animation, page: *Page) !js.Promise {
|
||||||
@@ -59,7 +59,7 @@ pub fn getReady(self: *Animation, page: *Page) !js.Promise {
|
|||||||
const resolver = try page.js.createPromiseResolver().persist();
|
const resolver = try page.js.createPromiseResolver().persist();
|
||||||
self._ready_resolver = resolver;
|
self._ready_resolver = resolver;
|
||||||
}
|
}
|
||||||
return self._ready_resolver.?.promise();
|
return self._ready_resolver.?.local().promise();
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn getEffect(self: *const Animation) ?js.Object.Global {
|
pub fn getEffect(self: *const Animation) ?js.Object.Global {
|
||||||
|
|||||||
@@ -92,8 +92,8 @@ pub fn getTransition(_: *const Navigation) ?NavigationTransition {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const NavigationReturn = struct {
|
const NavigationReturn = struct {
|
||||||
committed: js.Promise,
|
committed: js.Promise.Global,
|
||||||
finished: js.Promise,
|
finished: js.Promise.Global,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub fn back(self: *Navigation, page: *Page) !NavigationReturn {
|
pub fn back(self: *Navigation, page: *Page) !NavigationReturn {
|
||||||
@@ -278,9 +278,9 @@ pub fn navigateInner(
|
|||||||
if (is_same_document) {
|
if (is_same_document) {
|
||||||
page.url = new_url;
|
page.url = new_url;
|
||||||
|
|
||||||
committed.resolve("navigation push", {});
|
committed.local().resolve("navigation push", {});
|
||||||
// todo: Fire navigate event
|
// todo: Fire navigate event
|
||||||
finished.resolve("navigation push", {});
|
finished.local().resolve("navigation push", {});
|
||||||
|
|
||||||
_ = try self.pushEntry(url, .{ .source = .navigation, .value = state }, page, true);
|
_ = try self.pushEntry(url, .{ .source = .navigation, .value = state }, page, true);
|
||||||
} else {
|
} else {
|
||||||
@@ -291,9 +291,9 @@ pub fn navigateInner(
|
|||||||
if (is_same_document) {
|
if (is_same_document) {
|
||||||
page.url = new_url;
|
page.url = new_url;
|
||||||
|
|
||||||
committed.resolve("navigation replace", {});
|
committed.local().resolve("navigation replace", {});
|
||||||
// todo: Fire navigate event
|
// todo: Fire navigate event
|
||||||
finished.resolve("navigation replace", {});
|
finished.local().resolve("navigation replace", {});
|
||||||
|
|
||||||
_ = try self.replaceEntry(url, .{ .source = .navigation, .value = state }, page, true);
|
_ = try self.replaceEntry(url, .{ .source = .navigation, .value = state }, page, true);
|
||||||
} else {
|
} else {
|
||||||
@@ -306,9 +306,9 @@ pub fn navigateInner(
|
|||||||
if (is_same_document) {
|
if (is_same_document) {
|
||||||
page.url = new_url;
|
page.url = new_url;
|
||||||
|
|
||||||
committed.resolve("navigation traverse", {});
|
committed.local().resolve("navigation traverse", {});
|
||||||
// todo: Fire navigate event
|
// todo: Fire navigate event
|
||||||
finished.resolve("navigation traverse", {});
|
finished.local().resolve("navigation traverse", {});
|
||||||
} else {
|
} else {
|
||||||
try page.scheduleNavigation(url, .{ .reason = .navigation, .kind = kind }, .script);
|
try page.scheduleNavigation(url, .{ .reason = .navigation, .kind = kind }, .script);
|
||||||
}
|
}
|
||||||
@@ -327,8 +327,8 @@ pub fn navigateInner(
|
|||||||
try self._proto.dispatch(.{ .currententrychange = event }, page);
|
try self._proto.dispatch(.{ .currententrychange = event }, page);
|
||||||
|
|
||||||
return .{
|
return .{
|
||||||
.committed = committed.promise(),
|
.committed = try committed.local().promise().persist(),
|
||||||
.finished = finished.promise(),
|
.finished = try finished.local().promise().persist(),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -47,7 +47,7 @@ pub const NavigationState = struct {
|
|||||||
|
|
||||||
// https://developer.mozilla.org/en-US/docs/Web/API/NavigationTransition
|
// https://developer.mozilla.org/en-US/docs/Web/API/NavigationTransition
|
||||||
pub const NavigationTransition = struct {
|
pub const NavigationTransition = struct {
|
||||||
finished: js.Promise,
|
finished: js.Promise.Global,
|
||||||
from: NavigationHistoryEntry,
|
from: NavigationHistoryEntry,
|
||||||
navigation_type: NavigationType,
|
navigation_type: NavigationType,
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -36,7 +36,7 @@ _page: *Page,
|
|||||||
_url: []const u8,
|
_url: []const u8,
|
||||||
_buf: std.ArrayList(u8),
|
_buf: std.ArrayList(u8),
|
||||||
_response: *Response,
|
_response: *Response,
|
||||||
_resolver: js.PromiseResolver,
|
_resolver: js.PromiseResolver.Global,
|
||||||
|
|
||||||
pub const Input = Request.Input;
|
pub const Input = Request.Input;
|
||||||
pub const InitOpts = Request.InitOpts;
|
pub const InitOpts = Request.InitOpts;
|
||||||
@@ -77,7 +77,7 @@ pub fn init(input: Input, options: ?InitOpts, page: *Page) !js.Promise {
|
|||||||
.done_callback = httpDoneCallback,
|
.done_callback = httpDoneCallback,
|
||||||
.error_callback = httpErrorCallback,
|
.error_callback = httpErrorCallback,
|
||||||
});
|
});
|
||||||
return fetch._resolver.promise();
|
return fetch._resolver.local().promise();
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn deinit(self: *Fetch) void {
|
pub fn deinit(self: *Fetch) void {
|
||||||
@@ -149,13 +149,13 @@ fn httpDoneCallback(ctx: *anyopaque) !void {
|
|||||||
.len = self._buf.items.len,
|
.len = self._buf.items.len,
|
||||||
});
|
});
|
||||||
|
|
||||||
return self._resolver.resolve("fetch done", self._response);
|
return self._resolver.local().resolve("fetch done", self._response);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn httpErrorCallback(ctx: *anyopaque, err: anyerror) void {
|
fn httpErrorCallback(ctx: *anyopaque, err: anyerror) void {
|
||||||
const self: *Fetch = @ptrCast(@alignCast(ctx));
|
const self: *Fetch = @ptrCast(@alignCast(ctx));
|
||||||
self._response._type = .@"error"; // Set type to error for network failures
|
self._response._type = .@"error"; // Set type to error for network failures
|
||||||
self._resolver.reject("fetch error", @errorName(err));
|
self._resolver.local().reject("fetch error", @errorName(err));
|
||||||
}
|
}
|
||||||
|
|
||||||
const testing = @import("../../../testing.zig");
|
const testing = @import("../../../testing.zig");
|
||||||
|
|||||||
@@ -170,7 +170,7 @@ pub fn cancel(self: *ReadableStream, reason: ?[]const u8, page: *Page) !js.Promi
|
|||||||
if (self._state != .readable) {
|
if (self._state != .readable) {
|
||||||
if (self._cancel) |c| {
|
if (self._cancel) |c| {
|
||||||
if (c.resolver) |r| {
|
if (c.resolver) |r| {
|
||||||
return r.promise();
|
return r.local().promise();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return page.js.resolvePromise(.{});
|
return page.js.resolvePromise(.{});
|
||||||
@@ -201,19 +201,19 @@ pub fn cancel(self: *ReadableStream, reason: ?[]const u8, page: *Page) !js.Promi
|
|||||||
.done = true,
|
.done = true,
|
||||||
.value = .empty,
|
.value = .empty,
|
||||||
};
|
};
|
||||||
for (self._controller._pending_reads.items) |resolver| {
|
for (self._controller._pending_reads.items) |*resolver| {
|
||||||
resolver.resolve("stream cancelled", result);
|
resolver.local().resolve("stream cancelled", result);
|
||||||
}
|
}
|
||||||
self._controller._pending_reads.clearRetainingCapacity();
|
self._controller._pending_reads.clearRetainingCapacity();
|
||||||
|
|
||||||
c.resolver.?.resolve("ReadableStream.cancel", {});
|
c.resolver.?.local().resolve("ReadableStream.cancel", {});
|
||||||
return c.resolver.?.promise();
|
return c.resolver.?.local().promise();
|
||||||
}
|
}
|
||||||
|
|
||||||
const Cancel = struct {
|
const Cancel = struct {
|
||||||
callback: ?js.Function.Global = null,
|
callback: ?js.Function.Global = null,
|
||||||
reason: ?[]const u8 = null,
|
reason: ?[]const u8 = null,
|
||||||
resolver: ?js.PromiseResolver = null,
|
resolver: ?js.PromiseResolver.Global = null,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub const JsApi = struct {
|
pub const JsApi = struct {
|
||||||
|
|||||||
@@ -42,7 +42,7 @@ _page: *Page,
|
|||||||
_stream: *ReadableStream,
|
_stream: *ReadableStream,
|
||||||
_arena: std.mem.Allocator,
|
_arena: std.mem.Allocator,
|
||||||
_queue: std.ArrayList(Chunk),
|
_queue: std.ArrayList(Chunk),
|
||||||
_pending_reads: std.ArrayList(js.PromiseResolver),
|
_pending_reads: std.ArrayList(js.PromiseResolver.Global),
|
||||||
_high_water_mark: u32,
|
_high_water_mark: u32,
|
||||||
|
|
||||||
pub fn init(stream: *ReadableStream, high_water_mark: u32, page: *Page) !*ReadableStreamDefaultController {
|
pub fn init(stream: *ReadableStream, high_water_mark: u32, page: *Page) !*ReadableStreamDefaultController {
|
||||||
@@ -59,7 +59,7 @@ pub fn init(stream: *ReadableStream, high_water_mark: u32, page: *Page) !*Readab
|
|||||||
pub fn addPendingRead(self: *ReadableStreamDefaultController, page: *Page) !js.Promise {
|
pub fn addPendingRead(self: *ReadableStreamDefaultController, page: *Page) !js.Promise {
|
||||||
const resolver = try page.js.createPromiseResolver().persist();
|
const resolver = try page.js.createPromiseResolver().persist();
|
||||||
try self._pending_reads.append(self._arena, resolver);
|
try self._pending_reads.append(self._arena, resolver);
|
||||||
return resolver.promise();
|
return resolver.local().promise();
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn enqueue(self: *ReadableStreamDefaultController, chunk: Chunk) !void {
|
pub fn enqueue(self: *ReadableStreamDefaultController, chunk: Chunk) !void {
|
||||||
@@ -79,7 +79,7 @@ pub fn enqueue(self: *ReadableStreamDefaultController, chunk: Chunk) !void {
|
|||||||
.done = false,
|
.done = false,
|
||||||
.value = .fromChunk(chunk),
|
.value = .fromChunk(chunk),
|
||||||
};
|
};
|
||||||
resolver.resolve("stream enqueue", result);
|
resolver.local().resolve("stream enqueue", result);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn close(self: *ReadableStreamDefaultController) !void {
|
pub fn close(self: *ReadableStreamDefaultController) !void {
|
||||||
@@ -94,8 +94,8 @@ pub fn close(self: *ReadableStreamDefaultController) !void {
|
|||||||
.done = true,
|
.done = true,
|
||||||
.value = .empty,
|
.value = .empty,
|
||||||
};
|
};
|
||||||
for (self._pending_reads.items) |resolver| {
|
for (self._pending_reads.items) |*resolver| {
|
||||||
resolver.resolve("stream close", result);
|
resolver.local().resolve("stream close", result);
|
||||||
}
|
}
|
||||||
self._pending_reads.clearRetainingCapacity();
|
self._pending_reads.clearRetainingCapacity();
|
||||||
}
|
}
|
||||||
@@ -109,8 +109,8 @@ pub fn doError(self: *ReadableStreamDefaultController, err: []const u8) !void {
|
|||||||
self._stream._stored_error = try self._page.arena.dupe(u8, err);
|
self._stream._stored_error = try self._page.arena.dupe(u8, err);
|
||||||
|
|
||||||
// Reject all pending reads
|
// Reject all pending reads
|
||||||
for (self._pending_reads.items) |resolver| {
|
for (self._pending_reads.items) |*resolver| {
|
||||||
resolver.reject("stream errror", err);
|
resolver.local().reject("stream errror", err);
|
||||||
}
|
}
|
||||||
self._pending_reads.clearRetainingCapacity();
|
self._pending_reads.clearRetainingCapacity();
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user