mirror of
https://github.com/lightpanda-io/browser.git
synced 2026-07-31 09:46:05 -04:00
webapi: Improve storage WebAPI
Largely about improving the named indexer storage["blah"] to support setting and deletion. Also adds support for numeric indexes storage[4] by adding an indexer (not named) and converting the integer -> string. A number of other files had minor changes because namedIndexed now takes a deleter, enumerator and query functions (or null) so all the other namedIndexed now need to pass 3 other nulls. I assume these should be set on at least some of the other consumers.
This commit is contained in:
@@ -209,6 +209,59 @@ fn _getIndex(comptime T: type, local: *const Local, func: anytype, idx: u32, inf
|
||||
return handleIndexedReturn(T, F, true, local, ret, info, opts);
|
||||
}
|
||||
|
||||
pub fn setIndex(self: *Caller, comptime T: type, func: anytype, idx: u32, js_value: *const v8.Value, handle: *const v8.PropertyCallbackInfo, comptime opts: CallOpts) u32 {
|
||||
const local = &self.local;
|
||||
|
||||
var hs: js.HandleScope = undefined;
|
||||
hs.init(local.isolate);
|
||||
defer hs.deinit();
|
||||
|
||||
const info = PropertyCallbackInfo{ .handle = handle };
|
||||
return _setIndex(T, local, func, idx, .{ .local = &self.local, .handle = js_value }, info, opts) catch |err| {
|
||||
handleError(T, @TypeOf(func), local, err, info);
|
||||
return js.Intercepted.no;
|
||||
};
|
||||
}
|
||||
|
||||
fn _setIndex(comptime T: type, local: *const Local, func: anytype, idx: u32, js_value: js.Value, info: PropertyCallbackInfo, comptime opts: CallOpts) !u32 {
|
||||
const F = @TypeOf(func);
|
||||
var args: ParameterTypes(F) = undefined;
|
||||
@field(args, "0") = try TaggedOpaque.fromJS(*T, info.getThis());
|
||||
@field(args, "1") = idx;
|
||||
@field(args, "2") = try local.jsValueToZig(@TypeOf(@field(args, "2")), js_value);
|
||||
if (@typeInfo(F).@"fn".params.len == 4) {
|
||||
@field(args, "3") = getGlobalArg(@TypeOf(args.@"3"), local.ctx);
|
||||
}
|
||||
const ret = @call(.auto, func, args);
|
||||
return handleIndexedReturn(T, F, false, local, ret, info, opts);
|
||||
}
|
||||
|
||||
pub fn deleteIndex(self: *Caller, comptime T: type, func: anytype, idx: u32, handle: *const v8.PropertyCallbackInfo, comptime opts: CallOpts) u32 {
|
||||
const local = &self.local;
|
||||
|
||||
var hs: js.HandleScope = undefined;
|
||||
hs.init(local.isolate);
|
||||
defer hs.deinit();
|
||||
|
||||
const info = PropertyCallbackInfo{ .handle = handle };
|
||||
return _deleteIndex(T, local, func, idx, info, opts) catch |err| {
|
||||
handleError(T, @TypeOf(func), local, err, info);
|
||||
return js.Intercepted.no;
|
||||
};
|
||||
}
|
||||
|
||||
fn _deleteIndex(comptime T: type, local: *const Local, func: anytype, idx: u32, info: PropertyCallbackInfo, comptime opts: CallOpts) !u32 {
|
||||
const F = @TypeOf(func);
|
||||
var args: ParameterTypes(F) = undefined;
|
||||
@field(args, "0") = try TaggedOpaque.fromJS(*T, info.getThis());
|
||||
@field(args, "1") = idx;
|
||||
if (@typeInfo(F).@"fn".params.len == 3) {
|
||||
@field(args, "2") = getGlobalArg(@TypeOf(args.@"2"), local.ctx);
|
||||
}
|
||||
const ret = @call(.auto, func, args);
|
||||
return handleIndexedReturn(T, F, false, local, ret, info, opts);
|
||||
}
|
||||
|
||||
pub fn getNamedIndex(self: *Caller, comptime T: type, func: anytype, name: *const v8.Name, handle: *const v8.PropertyCallbackInfo, comptime opts: CallOpts) u32 {
|
||||
const local = &self.local;
|
||||
|
||||
@@ -313,6 +366,66 @@ fn _getEnumerator(comptime T: type, local: *const Local, func: anytype, info: Pr
|
||||
return handleIndexedReturn(T, F, true, local, ret, info, opts);
|
||||
}
|
||||
|
||||
pub fn getIndexQuery(self: *Caller, comptime T: type, func: anytype, idx: u32, handle: *const v8.PropertyCallbackInfo) u32 {
|
||||
const local = &self.local;
|
||||
|
||||
var hs: js.HandleScope = undefined;
|
||||
hs.init(local.isolate);
|
||||
defer hs.deinit();
|
||||
|
||||
const info = PropertyCallbackInfo{ .handle = handle };
|
||||
return _getIndexQuery(T, local, func, idx, info) catch |err| {
|
||||
handleError(T, @TypeOf(func), local, err, info);
|
||||
return js.Intercepted.no;
|
||||
};
|
||||
}
|
||||
|
||||
fn _getIndexQuery(comptime T: type, local: *const Local, func: anytype, idx: u32, info: PropertyCallbackInfo) !u32 {
|
||||
const F = @TypeOf(func);
|
||||
var args: ParameterTypes(F) = undefined;
|
||||
@field(args, "0") = try TaggedOpaque.fromJS(*T, info.getThis());
|
||||
@field(args, "1") = idx;
|
||||
if (@typeInfo(F).@"fn".params.len == 3) {
|
||||
@field(args, "2") = getGlobalArg(@TypeOf(args.@"2"), local.ctx);
|
||||
}
|
||||
if (@call(.auto, func, args) == false) {
|
||||
return js.Intercepted.no;
|
||||
}
|
||||
info.getReturnValue().set(try local.zigValueToJs(@as(u32, v8.None), .{}));
|
||||
return js.Intercepted.yes;
|
||||
}
|
||||
|
||||
pub fn getNamedQuery(self: *Caller, comptime T: type, func: anytype, name: *const v8.Name, handle: *const v8.PropertyCallbackInfo) u32 {
|
||||
const local = &self.local;
|
||||
|
||||
var hs: js.HandleScope = undefined;
|
||||
hs.init(local.isolate);
|
||||
defer hs.deinit();
|
||||
|
||||
const info = PropertyCallbackInfo{ .handle = handle };
|
||||
return _getNamedQuery(T, local, func, name, info) catch |err| {
|
||||
handleError(T, @TypeOf(func), local, err, info);
|
||||
return js.Intercepted.no;
|
||||
};
|
||||
}
|
||||
|
||||
fn _getNamedQuery(comptime T: type, local: *const Local, func: anytype, name: *const v8.Name, info: PropertyCallbackInfo) !u32 {
|
||||
const F = @TypeOf(func);
|
||||
var args: ParameterTypes(F) = undefined;
|
||||
@field(args, "0") = try TaggedOpaque.fromJS(*T, info.getThis());
|
||||
@field(args, "1") = try nameToString(local, @TypeOf(args.@"1"), name);
|
||||
if (@typeInfo(F).@"fn".params.len == 3) {
|
||||
@field(args, "2") = getGlobalArg(@TypeOf(args.@"2"), local.ctx);
|
||||
}
|
||||
if (@call(.auto, func, args) == false) {
|
||||
return js.Intercepted.no;
|
||||
}
|
||||
// The property exists as a supported property name; report it as an
|
||||
// enumerable, writable, configurable data property (PropertyAttribute.None).
|
||||
info.getReturnValue().set(try local.zigValueToJs(@as(u32, v8.None), .{}));
|
||||
return js.Intercepted.yes;
|
||||
}
|
||||
|
||||
fn handleIndexedReturn(comptime T: type, comptime F: type, comptime with_value: bool, local: *const Local, ret: anytype, info: PropertyCallbackInfo, comptime opts: CallOpts) !u32 {
|
||||
// need to unwrap this error immediately for when opts.null_as_undefined == true
|
||||
// and we need to compare it to null;
|
||||
|
||||
@@ -443,10 +443,15 @@ fn countExternalReferences() comptime_int {
|
||||
if (value.enumerator != null) {
|
||||
count += 1;
|
||||
}
|
||||
if (value.setter != null) count += 1;
|
||||
if (value.deleter != null) count += 1;
|
||||
if (value.query != null) count += 1;
|
||||
} else if (T == bridge.NamedIndexed) {
|
||||
count += 1;
|
||||
if (value.setter != null) count += 1;
|
||||
if (value.deleter != null) count += 1;
|
||||
if (value.enumerator != null) count += 1;
|
||||
if (value.query != null) count += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -519,6 +524,18 @@ fn collectExternalReferences() [countExternalReferences()]isize {
|
||||
references[idx] = @bitCast(@intFromPtr(enumerator));
|
||||
idx += 1;
|
||||
}
|
||||
if (value.setter) |setter| {
|
||||
references[idx] = @bitCast(@intFromPtr(setter));
|
||||
idx += 1;
|
||||
}
|
||||
if (value.deleter) |deleter| {
|
||||
references[idx] = @bitCast(@intFromPtr(deleter));
|
||||
idx += 1;
|
||||
}
|
||||
if (value.query) |query| {
|
||||
references[idx] = @bitCast(@intFromPtr(query));
|
||||
idx += 1;
|
||||
}
|
||||
} else if (T == bridge.NamedIndexed) {
|
||||
references[idx] = @bitCast(@intFromPtr(value.getter));
|
||||
idx += 1;
|
||||
@@ -530,6 +547,14 @@ fn collectExternalReferences() [countExternalReferences()]isize {
|
||||
references[idx] = @bitCast(@intFromPtr(deleter));
|
||||
idx += 1;
|
||||
}
|
||||
if (value.enumerator) |enumerator| {
|
||||
references[idx] = @bitCast(@intFromPtr(enumerator));
|
||||
idx += 1;
|
||||
}
|
||||
if (value.query) |query| {
|
||||
references[idx] = @bitCast(@intFromPtr(query));
|
||||
idx += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -792,9 +817,9 @@ fn attachClass(comptime JsApi: type, comptime flatten: bool, isolate: *v8.Isolat
|
||||
var configuration: v8.IndexedPropertyHandlerConfiguration = .{
|
||||
.getter = value.getter,
|
||||
.enumerator = value.enumerator,
|
||||
.setter = null,
|
||||
.query = null,
|
||||
.deleter = null,
|
||||
.setter = value.setter,
|
||||
.query = value.query,
|
||||
.deleter = value.deleter,
|
||||
.definer = null,
|
||||
.descriptor = null,
|
||||
.index_of = null,
|
||||
@@ -807,9 +832,9 @@ fn attachClass(comptime JsApi: type, comptime flatten: bool, isolate: *v8.Isolat
|
||||
var configuration: v8.NamedPropertyHandlerConfiguration = .{
|
||||
.getter = value.getter,
|
||||
.setter = value.setter,
|
||||
.query = null,
|
||||
.query = value.query,
|
||||
.deleter = value.deleter,
|
||||
.enumerator = null,
|
||||
.enumerator = value.enumerator,
|
||||
.definer = null,
|
||||
.descriptor = null,
|
||||
.data = null,
|
||||
|
||||
@@ -46,11 +46,15 @@ pub fn Builder(comptime T: type) type {
|
||||
}
|
||||
|
||||
pub fn indexed(comptime getter_func: anytype, comptime enumerator_func: anytype, comptime opts: Indexed.Opts) Indexed {
|
||||
return Indexed.init(T, getter_func, enumerator_func, opts);
|
||||
return Indexed.init(T, getter_func, null, null, null, enumerator_func, opts);
|
||||
}
|
||||
|
||||
pub fn namedIndexed(comptime getter_func: anytype, setter_func: anytype, deleter_func: anytype, comptime opts: NamedIndexed.Opts) NamedIndexed {
|
||||
return NamedIndexed.init(T, getter_func, setter_func, deleter_func, opts);
|
||||
pub fn indexedReadWrite(comptime getter_func: anytype, setter_func: anytype, deleter_func: anytype, query_func: anytype, comptime enumerator_func: anytype, comptime opts: Indexed.Opts) Indexed {
|
||||
return Indexed.init(T, getter_func, setter_func, deleter_func, query_func, enumerator_func, opts);
|
||||
}
|
||||
|
||||
pub fn namedIndexed(comptime getter_func: anytype, setter_func: anytype, deleter_func: anytype, enumerator_func: anytype, query_func: anytype, comptime opts: NamedIndexed.Opts) NamedIndexed {
|
||||
return NamedIndexed.init(T, getter_func, setter_func, deleter_func, enumerator_func, query_func, opts);
|
||||
}
|
||||
|
||||
pub fn iterator(comptime func: anytype, comptime opts: Iterator.Opts) Iterator {
|
||||
@@ -261,13 +265,16 @@ pub const Accessor = struct {
|
||||
pub const Indexed = struct {
|
||||
getter: *const fn (idx: u32, handle: ?*const v8.PropertyCallbackInfo) callconv(.c) u32,
|
||||
enumerator: ?*const fn (handle: ?*const v8.PropertyCallbackInfo) callconv(.c) u32,
|
||||
setter: ?*const fn (idx: u32, c_value: ?*const v8.Value, handle: ?*const v8.PropertyCallbackInfo) callconv(.c) u32 = null,
|
||||
deleter: ?*const fn (idx: u32, handle: ?*const v8.PropertyCallbackInfo) callconv(.c) u32 = null,
|
||||
query: ?*const fn (idx: u32, handle: ?*const v8.PropertyCallbackInfo) callconv(.c) u32 = null,
|
||||
|
||||
const Opts = struct {
|
||||
as_typed_array: bool = false,
|
||||
null_as_undefined: bool = false,
|
||||
};
|
||||
|
||||
fn init(comptime T: type, comptime getter: anytype, comptime enumerator: anytype, comptime opts: Opts) Indexed {
|
||||
fn init(comptime T: type, comptime getter: anytype, setter: anytype, deleter: anytype, query: anytype, comptime enumerator: anytype, comptime opts: Opts) Indexed {
|
||||
var indexed = Indexed{
|
||||
.enumerator = null,
|
||||
.getter = struct {
|
||||
@@ -301,6 +308,57 @@ pub const Indexed = struct {
|
||||
}.wrap;
|
||||
}
|
||||
|
||||
if (@typeInfo(@TypeOf(setter)) != .null) {
|
||||
indexed.setter = struct {
|
||||
fn wrap(idx: u32, c_value: ?*const v8.Value, handle: ?*const v8.PropertyCallbackInfo) callconv(.c) u32 {
|
||||
const v8_isolate = v8.v8__PropertyCallbackInfo__GetIsolate(handle).?;
|
||||
var caller: Caller = undefined;
|
||||
if (!caller.init(v8_isolate)) {
|
||||
return js.Intercepted.no;
|
||||
}
|
||||
defer caller.deinit();
|
||||
|
||||
return caller.setIndex(T, setter, idx, c_value.?, handle.?, .{
|
||||
.as_typed_array = opts.as_typed_array,
|
||||
.null_as_undefined = opts.null_as_undefined,
|
||||
});
|
||||
}
|
||||
}.wrap;
|
||||
}
|
||||
|
||||
if (@typeInfo(@TypeOf(deleter)) != .null) {
|
||||
indexed.deleter = struct {
|
||||
fn wrap(idx: u32, handle: ?*const v8.PropertyCallbackInfo) callconv(.c) u32 {
|
||||
const v8_isolate = v8.v8__PropertyCallbackInfo__GetIsolate(handle).?;
|
||||
var caller: Caller = undefined;
|
||||
if (!caller.init(v8_isolate)) {
|
||||
return js.Intercepted.no;
|
||||
}
|
||||
defer caller.deinit();
|
||||
|
||||
return caller.deleteIndex(T, deleter, idx, handle.?, .{
|
||||
.as_typed_array = opts.as_typed_array,
|
||||
.null_as_undefined = opts.null_as_undefined,
|
||||
});
|
||||
}
|
||||
}.wrap;
|
||||
}
|
||||
|
||||
if (@typeInfo(@TypeOf(query)) != .null) {
|
||||
indexed.query = struct {
|
||||
fn wrap(idx: u32, handle: ?*const v8.PropertyCallbackInfo) callconv(.c) u32 {
|
||||
const v8_isolate = v8.v8__PropertyCallbackInfo__GetIsolate(handle).?;
|
||||
var caller: Caller = undefined;
|
||||
if (!caller.init(v8_isolate)) {
|
||||
return js.Intercepted.no;
|
||||
}
|
||||
defer caller.deinit();
|
||||
|
||||
return caller.getIndexQuery(T, query, idx, handle.?);
|
||||
}
|
||||
}.wrap;
|
||||
}
|
||||
|
||||
return indexed;
|
||||
}
|
||||
};
|
||||
@@ -309,6 +367,8 @@ pub const NamedIndexed = struct {
|
||||
getter: *const fn (c_name: ?*const v8.Name, handle: ?*const v8.PropertyCallbackInfo) callconv(.c) u32,
|
||||
setter: ?*const fn (c_name: ?*const v8.Name, c_value: ?*const v8.Value, handle: ?*const v8.PropertyCallbackInfo) callconv(.c) u32 = null,
|
||||
deleter: ?*const fn (c_name: ?*const v8.Name, handle: ?*const v8.PropertyCallbackInfo) callconv(.c) u32 = null,
|
||||
enumerator: ?*const fn (handle: ?*const v8.PropertyCallbackInfo) callconv(.c) u32 = null,
|
||||
query: ?*const fn (c_name: ?*const v8.Name, handle: ?*const v8.PropertyCallbackInfo) callconv(.c) u32 = null,
|
||||
|
||||
const Opts = struct {
|
||||
as_typed_array: bool = false,
|
||||
@@ -319,7 +379,7 @@ pub const NamedIndexed = struct {
|
||||
ce_reactions: bool = false,
|
||||
};
|
||||
|
||||
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, enumerator: anytype, query: anytype, comptime opts: Opts) NamedIndexed {
|
||||
const getter_fn = struct {
|
||||
fn wrap(c_name: ?*const v8.Name, handle: ?*const v8.PropertyCallbackInfo) callconv(.c) u32 {
|
||||
const v8_isolate = v8.v8__PropertyCallbackInfo__GetIsolate(handle).?;
|
||||
@@ -392,10 +452,38 @@ pub const NamedIndexed = struct {
|
||||
}
|
||||
}.wrap;
|
||||
|
||||
const enumerator_fn = if (@typeInfo(@TypeOf(enumerator)) == .null) null else struct {
|
||||
fn wrap(handle: ?*const v8.PropertyCallbackInfo) callconv(.c) u32 {
|
||||
const v8_isolate = v8.v8__PropertyCallbackInfo__GetIsolate(handle).?;
|
||||
var caller: Caller = undefined;
|
||||
if (!caller.init(v8_isolate)) {
|
||||
return js.Intercepted.no;
|
||||
}
|
||||
defer caller.deinit();
|
||||
|
||||
return caller.getEnumerator(T, enumerator, handle.?, .{});
|
||||
}
|
||||
}.wrap;
|
||||
|
||||
const query_fn = if (@typeInfo(@TypeOf(query)) == .null) null else struct {
|
||||
fn wrap(c_name: ?*const v8.Name, handle: ?*const v8.PropertyCallbackInfo) callconv(.c) u32 {
|
||||
const v8_isolate = v8.v8__PropertyCallbackInfo__GetIsolate(handle).?;
|
||||
var caller: Caller = undefined;
|
||||
if (!caller.init(v8_isolate)) {
|
||||
return js.Intercepted.no;
|
||||
}
|
||||
defer caller.deinit();
|
||||
|
||||
return caller.getNamedQuery(T, query, c_name.?, handle.?);
|
||||
}
|
||||
}.wrap;
|
||||
|
||||
return .{
|
||||
.getter = getter_fn,
|
||||
.setter = setter_fn,
|
||||
.deleter = deleter_fn,
|
||||
.enumerator = enumerator_fn,
|
||||
.query = query_fn,
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
@@ -51,11 +51,14 @@
|
||||
localStorage.setItem('number', '123');
|
||||
testing.expectEqual('123', localStorage.getItem('number'));
|
||||
|
||||
// null/undefined keys are stringified per WebIDL (DOMString coercion).
|
||||
localStorage.setItem(null, 'null_key_value');
|
||||
testing.expectEqual(null, localStorage.getItem(null));
|
||||
testing.expectEqual('null_key_value', localStorage.getItem(null));
|
||||
testing.expectEqual('null_key_value', localStorage.getItem('null'));
|
||||
|
||||
localStorage.setItem(undefined, 'undefined_key_value');
|
||||
testing.expectEqual(null, localStorage.getItem(undefined));
|
||||
testing.expectEqual('undefined_key_value', localStorage.getItem(undefined));
|
||||
testing.expectEqual('undefined_key_value', localStorage.getItem('undefined'));
|
||||
|
||||
localStorage.clear();
|
||||
testing.expectEqual(0, localStorage.length);
|
||||
|
||||
@@ -64,7 +64,7 @@ pub const JsApi = struct {
|
||||
pub const length = bridge.property(0, .{ .template = false });
|
||||
pub const refresh = bridge.function(PluginArray.refresh, .{});
|
||||
pub const @"[int]" = bridge.indexed(PluginArray.getAtIndex, null, .{ .null_as_undefined = true });
|
||||
pub const @"[str]" = bridge.namedIndexed(PluginArray.getByName, null, null, .{ .null_as_undefined = true });
|
||||
pub const @"[str]" = bridge.namedIndexed(PluginArray.getByName, null, null, null, null, .{ .null_as_undefined = true });
|
||||
pub const item = bridge.function(_item, .{});
|
||||
fn _item(self: *const PluginArray, index: i32) ?*Plugin {
|
||||
if (index < 0) {
|
||||
|
||||
@@ -172,7 +172,7 @@ pub const JsApi = struct {
|
||||
|
||||
pub const length = bridge.accessor(HTMLAllCollection.length, null, .{});
|
||||
pub const @"[int]" = bridge.indexed(HTMLAllCollection.getAtIndex, null, .{ .null_as_undefined = true });
|
||||
pub const @"[str]" = bridge.namedIndexed(HTMLAllCollection.getByName, null, null, .{ .null_as_undefined = true });
|
||||
pub const @"[str]" = bridge.namedIndexed(HTMLAllCollection.getByName, null, null, null, null, .{ .null_as_undefined = true });
|
||||
|
||||
pub const item = bridge.function(_item, .{});
|
||||
fn _item(self: *HTMLAllCollection, index: i32, frame: *Frame) ?*Element {
|
||||
|
||||
@@ -155,7 +155,7 @@ pub const JsApi = struct {
|
||||
|
||||
return self.getByName(name, frame) orelse error.NotHandled;
|
||||
}
|
||||
}.wrap, null, null, .{ .null_as_undefined = true });
|
||||
}.wrap, null, null, null, null, .{ .null_as_undefined = true });
|
||||
|
||||
pub const item = bridge.function(_item, .{});
|
||||
fn _item(self: *HTMLCollection, index: i32, frame: *Frame) ?*Element {
|
||||
|
||||
@@ -139,6 +139,6 @@ pub const JsApi = struct {
|
||||
|
||||
pub const length = bridge.accessor(HTMLFormControlsCollection.length, null, .{});
|
||||
pub const @"[int]" = bridge.indexed(HTMLFormControlsCollection.getAtIndex, null, .{ .null_as_undefined = true });
|
||||
pub const @"[str]" = bridge.namedIndexed(HTMLFormControlsCollection.namedItem, null, null, .{ .null_as_undefined = true });
|
||||
pub const @"[str]" = bridge.namedIndexed(HTMLFormControlsCollection.namedItem, null, null, null, null, .{ .null_as_undefined = true });
|
||||
pub const namedItem = bridge.function(HTMLFormControlsCollection.namedItem, .{});
|
||||
};
|
||||
|
||||
@@ -101,7 +101,7 @@ pub const JsApi = struct {
|
||||
|
||||
// Indexed access
|
||||
pub const @"[int]" = bridge.indexed(HTMLOptionsCollection.getAtIndex, null, .{ .null_as_undefined = true });
|
||||
pub const @"[str]" = bridge.namedIndexed(HTMLOptionsCollection.getByName, null, null, .{ .null_as_undefined = true });
|
||||
pub const @"[str]" = bridge.namedIndexed(HTMLOptionsCollection.getByName, null, null, null, null, .{ .null_as_undefined = true });
|
||||
|
||||
pub const selectedIndex = bridge.accessor(HTMLOptionsCollection.getSelectedIndex, HTMLOptionsCollection.setSelectedIndex, .{});
|
||||
pub const add = bridge.function(HTMLOptionsCollection.add, .{ .ce_reactions = true });
|
||||
|
||||
@@ -397,5 +397,5 @@ pub const JsApi = struct {
|
||||
pub var class_id: bridge.ClassId = undefined;
|
||||
};
|
||||
|
||||
pub const @"[]" = bridge.namedIndexed(CSSStyleProperties.getNamed, CSSStyleProperties.setNamed, null, .{});
|
||||
pub const @"[]" = bridge.namedIndexed(CSSStyleProperties.getNamed, CSSStyleProperties.setNamed, null, null, null, .{});
|
||||
};
|
||||
|
||||
@@ -540,7 +540,7 @@ pub const NamedNodeMap = struct {
|
||||
|
||||
pub const length = bridge.accessor(NamedNodeMap.length, null, .{});
|
||||
pub const @"[int]" = bridge.indexed(NamedNodeMap.getAtIndex, null, .{ .null_as_undefined = true });
|
||||
pub const @"[str]" = bridge.namedIndexed(NamedNodeMap.getByName, null, null, .{ .null_as_undefined = true });
|
||||
pub const @"[str]" = bridge.namedIndexed(NamedNodeMap.getByName, null, null, null, null, .{ .null_as_undefined = true });
|
||||
pub const getNamedItem = bridge.function(NamedNodeMap.getByName, .{});
|
||||
pub const setNamedItem = bridge.function(NamedNodeMap.set, .{ .ce_reactions = true });
|
||||
pub const removeNamedItem = bridge.function(NamedNodeMap.removeByName, .{ .ce_reactions = true });
|
||||
|
||||
@@ -136,5 +136,5 @@ pub const JsApi = struct {
|
||||
pub var class_id: bridge.ClassId = undefined;
|
||||
};
|
||||
|
||||
pub const @"[]" = bridge.namedIndexed(getProperty, setProperty, deleteProperty, .{ .null_as_undefined = true, .ce_reactions = true });
|
||||
pub const @"[]" = bridge.namedIndexed(getProperty, setProperty, deleteProperty, null, null, .{ .null_as_undefined = true, .ce_reactions = true });
|
||||
};
|
||||
|
||||
@@ -89,14 +89,11 @@ pub const Lookup = struct {
|
||||
self._size = 0;
|
||||
}
|
||||
|
||||
pub fn getItem(self: *const Lookup, key_: ?[]const u8) ?[]const u8 {
|
||||
const k = key_ orelse return null;
|
||||
pub fn getItem(self: *const Lookup, k: []const u8) ?[]const u8 {
|
||||
return self._data.get(k);
|
||||
}
|
||||
|
||||
pub fn setItem(self: *Lookup, key_: ?[]const u8, value: []const u8) !void {
|
||||
const k = key_ orelse return;
|
||||
|
||||
pub fn setItem(self: *Lookup, k: []const u8, value: []const u8) !void {
|
||||
const old_len = if (self._data.get(k)) |old| old.len else 0;
|
||||
std.debug.assert(old_len <= self._size);
|
||||
if (self._size - old_len + value.len > max_size) {
|
||||
@@ -120,8 +117,7 @@ pub const Lookup = struct {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn removeItem(self: *Lookup, key_: ?[]const u8) void {
|
||||
const k = key_ orelse return;
|
||||
pub fn removeItem(self: *Lookup, k: []const u8) void {
|
||||
const kv = self._data.fetchRemove(k) orelse return;
|
||||
self._size -= kv.value.len;
|
||||
self._allocator.free(kv.key);
|
||||
@@ -154,6 +150,21 @@ pub const Lookup = struct {
|
||||
return @intCast(self._data.count());
|
||||
}
|
||||
|
||||
pub fn hasItem(self: *const Lookup, k: []const u8) bool {
|
||||
return self._data.contains(k);
|
||||
}
|
||||
|
||||
pub fn keys(self: *const Lookup, exec: *const js.Execution) !js.Array {
|
||||
const local = exec.js.local.?;
|
||||
var arr = local.newArray(self.getLength());
|
||||
var it = self._data.keyIterator();
|
||||
var i: u32 = 0;
|
||||
while (it.next()) |k| : (i += 1) {
|
||||
_ = try arr.set(i, k.*, .{});
|
||||
}
|
||||
return arr;
|
||||
}
|
||||
|
||||
pub const JsApi = struct {
|
||||
pub const bridge = js.Bridge(Lookup);
|
||||
|
||||
@@ -169,7 +180,30 @@ pub const Lookup = struct {
|
||||
pub const removeItem = bridge.function(Lookup.removeItem, .{});
|
||||
pub const clear = bridge.function(Lookup.clear, .{});
|
||||
pub const key = bridge.function(Lookup.key, .{});
|
||||
pub const @"[str]" = bridge.namedIndexed(Lookup.getItem, Lookup.setItem, null, .{ .null_as_undefined = true });
|
||||
pub const @"[str]" = bridge.namedIndexed(Lookup.getItem, Lookup.setItem, Lookup.removeItem, Lookup.keys, Lookup.hasItem, .{ .null_as_undefined = true });
|
||||
pub const @"[int]" = bridge.indexedReadWrite(_getByIndex, _setByIndex, _removeByIndex, _indexHas, null, .{ .null_as_undefined = true });
|
||||
|
||||
// v8 routes storage[9] to the indexed interceptor, so we need to do the
|
||||
// int -> string conversion
|
||||
fn _getByIndex(self: *const Lookup, idx: u32) ?[]const u8 {
|
||||
var buf: [10]u8 = undefined;
|
||||
return self._data.get(std.fmt.bufPrint(&buf, "{d}", .{idx}) catch unreachable);
|
||||
}
|
||||
|
||||
fn _setByIndex(self: *Lookup, idx: u32, value: []const u8) !void {
|
||||
var buf: [10]u8 = undefined;
|
||||
return self.setItem(std.fmt.bufPrint(&buf, "{d}", .{idx}) catch unreachable, value);
|
||||
}
|
||||
|
||||
fn _removeByIndex(self: *Lookup, idx: u32) void {
|
||||
var buf: [10]u8 = undefined;
|
||||
return self.removeItem(std.fmt.bufPrint(&buf, "{d}", .{idx}) catch unreachable);
|
||||
}
|
||||
|
||||
fn _indexHas(self: *const Lookup, idx: u32) bool {
|
||||
var buf: [10]u8 = undefined;
|
||||
return self._data.contains(std.fmt.bufPrint(&buf, "{d}", .{idx}) catch unreachable);
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user