diff --git a/src/apiweb.zig b/src/apiweb.zig
index ad825044..8df1bd6d 100644
--- a/src/apiweb.zig
+++ b/src/apiweb.zig
@@ -42,6 +42,6 @@ pub const Interfaces = generate.Tuple(.{
URL.Interfaces,
Iterators.Interfaces,
XMLSerializer.Interfaces,
-});
+}){};
pub const UserContext = @import("user_context.zig").UserContext;
diff --git a/src/dom/character_data.zig b/src/dom/character_data.zig
index b195b921..372395c2 100644
--- a/src/dom/character_data.zig
+++ b/src/dom/character_data.zig
@@ -21,7 +21,6 @@ const std = @import("std");
const jsruntime = @import("jsruntime");
const Case = jsruntime.test_utils.Case;
const checkCases = jsruntime.test_utils.checkCases;
-const generate = @import("../generate.zig");
const parser = @import("netsurf");
@@ -32,12 +31,12 @@ const ProcessingInstruction = @import("processing_instruction.zig").ProcessingIn
const HTMLElem = @import("../html/elements.zig");
// CharacterData interfaces
-pub const Interfaces = generate.Tuple(.{
+pub const Interfaces = .{
Comment,
Text.Text,
Text.Interfaces,
ProcessingInstruction,
-});
+};
// CharacterData implementation
pub const CharacterData = struct {
diff --git a/src/dom/dom.zig b/src/dom/dom.zig
index dc521bb6..76a4a185 100644
--- a/src/dom/dom.zig
+++ b/src/dom/dom.zig
@@ -16,8 +16,6 @@
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see .
-const generate = @import("../generate.zig");
-
const DOMException = @import("exceptions.zig").DOMException;
const EventTarget = @import("event_target.zig").EventTarget;
const DOMImplementation = @import("implementation.zig").DOMImplementation;
@@ -27,7 +25,7 @@ const NodeList = @import("nodelist.zig");
const Nod = @import("node.zig");
const MutationObserver = @import("mutation_observer.zig");
-pub const Interfaces = generate.Tuple(.{
+pub const Interfaces = .{
DOMException,
EventTarget,
DOMImplementation,
@@ -37,4 +35,4 @@ pub const Interfaces = generate.Tuple(.{
Nod.Node,
Nod.Interfaces,
MutationObserver.Interfaces,
-});
+};
diff --git a/src/dom/mutation_observer.zig b/src/dom/mutation_observer.zig
index 9219ccc9..f5003686 100644
--- a/src/dom/mutation_observer.zig
+++ b/src/dom/mutation_observer.zig
@@ -26,15 +26,13 @@ const CallbackResult = jsruntime.CallbackResult;
const Case = jsruntime.test_utils.Case;
const checkCases = jsruntime.test_utils.checkCases;
-const generate = @import("../generate.zig");
-
const NodeList = @import("nodelist.zig").NodeList;
-pub const Interfaces = generate.Tuple(.{
+pub const Interfaces = .{
MutationObserver,
MutationRecord,
MutationRecords,
-});
+};
const Walker = @import("../dom/walker.zig").WalkerChildren;
diff --git a/src/dom/node.zig b/src/dom/node.zig
index 05c47d74..3e0a7561 100644
--- a/src/dom/node.zig
+++ b/src/dom/node.zig
@@ -47,7 +47,7 @@ const HTML = @import("../html/html.zig");
const HTMLElem = @import("../html/elements.zig");
// Node interfaces
-pub const Interfaces = generate.Tuple(.{
+pub const Interfaces = .{
Attr,
CData.CharacterData,
CData.Interfaces,
@@ -57,12 +57,10 @@ pub const Interfaces = generate.Tuple(.{
DocumentFragment,
HTMLCollection,
HTMLCollectionIterator,
-
HTML.Interfaces,
-});
-const Generated = generate.Union.compile(Interfaces);
-pub const Union = Generated._union;
-pub const Tags = Generated._enum;
+};
+
+pub const Union = generate.Union(Interfaces);
// Node implementation
pub const Node = struct {
diff --git a/src/dom/nodelist.zig b/src/dom/nodelist.zig
index 6dfb5cc6..5dfc7031 100644
--- a/src/dom/nodelist.zig
+++ b/src/dom/nodelist.zig
@@ -25,7 +25,6 @@ const Callback = jsruntime.Callback;
const CallbackResult = jsruntime.CallbackResult;
const Case = jsruntime.test_utils.Case;
const checkCases = jsruntime.test_utils.checkCases;
-const generate = @import("../generate.zig");
const NodeUnion = @import("node.zig").Union;
const Node = @import("node.zig").Node;
@@ -36,10 +35,10 @@ const log = std.log.scoped(.nodelist);
const DOMException = @import("exceptions.zig").DOMException;
-pub const Interfaces = generate.Tuple(.{
+pub const Interfaces = .{
NodeListIterator,
NodeList,
-});
+};
pub const NodeListIterator = struct {
pub const mem_guarantied = true;
diff --git a/src/dom/text.zig b/src/dom/text.zig
index 39c22c47..a2d3f9cf 100644
--- a/src/dom/text.zig
+++ b/src/dom/text.zig
@@ -21,7 +21,6 @@ const std = @import("std");
const jsruntime = @import("jsruntime");
const Case = jsruntime.test_utils.Case;
const checkCases = jsruntime.test_utils.checkCases;
-const generate = @import("../generate.zig");
const parser = @import("netsurf");
@@ -31,9 +30,9 @@ const CDATASection = @import("cdata_section.zig").CDATASection;
const UserContext = @import("../user_context.zig").UserContext;
// Text interfaces
-pub const Interfaces = generate.Tuple(.{
+pub const Interfaces = .{
CDATASection,
-});
+};
pub const Text = struct {
pub const Self = parser.Text;
diff --git a/src/events/event.zig b/src/events/event.zig
index be92ba30..35069ceb 100644
--- a/src/events/event.zig
+++ b/src/events/event.zig
@@ -37,12 +37,12 @@ const ProgressEvent = @import("../xhr/progress_event.zig").ProgressEvent;
const log = std.log.scoped(.events);
// Event interfaces
-pub const Interfaces = generate.Tuple(.{
+pub const Interfaces = .{
Event,
ProgressEvent,
-});
-const Generated = generate.Union.compile(Interfaces);
-pub const Union = Generated._union;
+};
+
+pub const Union = generate.Union(Interfaces);
// https://dom.spec.whatwg.org/#event
pub const Event = struct {
diff --git a/src/generate.zig b/src/generate.zig
index e1ae7d0e..62be7edb 100644
--- a/src/generate.zig
+++ b/src/generate.zig
@@ -17,430 +17,202 @@
// along with this program. If not, see .
const std = @import("std");
-const builtin = @import("builtin");
-
-// Utils
-// -----
+const Type = std.builtin.Type;
+
+pub fn Union(interfaces: anytype) type {
+ // @setEvalBranchQuota(10000);
+ const tuple = Tuple(interfaces){};
+ const fields = std.meta.fields(@TypeOf(tuple));
+
+ const tag_type = switch (fields.len) {
+ 0 => unreachable,
+ 1 => u0,
+ 2 => u1,
+ 3...4 => u2,
+ 5...8 => u3,
+ 9...16 => u4,
+ 17...32 => u5,
+ 33...64 => u6,
+ 65...128 => u7,
+ 129...256 => u8,
+ else => @compileError("Too many interfaces to generate union"),
+ };
-fn itoa(comptime i: u8) ![]const u8 {
- var len: usize = undefined;
- if (i < 10) {
- len = 1;
- } else if (i < 100) {
- len = 2;
- } else if (i < 1000) {
- len = 3;
- } else {
- return error.GenerateTooMuchMembers;
+ // second iteration to generate tags
+ var enum_fields: [fields.len]Type.EnumField = undefined;
+ for (fields, 0..) |field, index| {
+ const member = @field(tuple, field.name);
+ const full_name = @typeName(member);
+ const separator = std.mem.lastIndexOfScalar(u8, full_name, '.') orelse unreachable;
+ const name = full_name[separator + 1 ..];
+ enum_fields[index] = .{
+ .name = name ++ "",
+ .value = index,
+ };
}
- var buf: [len]u8 = undefined;
- return try std.fmt.bufPrint(buf[0..], "{d}", .{i});
-}
-
-fn fmtName(comptime T: type) [:0]const u8 {
- var it = std.mem.splitBackwards(u8, @typeName(T), ".");
- return it.first() ++ "";
-}
-// Union
-// -----
-
-// Generate a flatten tagged Union from various structs and union of structs
-// TODO: make this function more generic
-// TODO: dedup
-pub const Union = struct {
- _enum: type,
- _union: type,
-
- pub fn compile(comptime tuple: anytype) Union {
- return private_compile(tuple) catch |err| @compileError(@errorName(err));
+ const enum_info = Type.Enum{
+ .tag_type = tag_type,
+ .fields = &enum_fields,
+ .decls = &.{},
+ .is_exhaustive = true,
+ };
+ const enum_T = @Type(std.builtin.Type{ .Enum = enum_info });
+
+ // third iteration to generate union type
+ var union_fields: [fields.len]Type.UnionField = undefined;
+ for (fields, enum_fields, 0..) |field, e, index| {
+ var FT = @field(tuple, field.name);
+ if (@hasDecl(FT, "Self")) {
+ FT = *(@field(FT, "Self"));
+ }
+ union_fields[index] = .{
+ .type = FT,
+ .name = e.name,
+ .alignment = @alignOf(FT),
+ };
}
- fn private_compile(comptime tuple: anytype) !Union {
- @setEvalBranchQuota(10000);
+ return @Type(.{ .Union = .{
+ .layout = .auto,
+ .tag_type = enum_T,
+ .fields = &union_fields,
+ .decls = &.{},
+ } });
+}
- // check types provided
- const tuple_T = @TypeOf(tuple);
- const tuple_info = @typeInfo(tuple_T);
- if (tuple_info != .Struct or !tuple_info.Struct.is_tuple) {
- return error.GenerateArgNotTuple;
- }
+pub fn Tuple(args: anytype) type {
+ @setEvalBranchQuota(100000);
- const tuple_members = tuple_info.Struct.fields;
+ const count = countInterfaces(args, 0);
+ var interfaces: [count]type = undefined;
+ _ = flattenInterfaces(args, &interfaces, 0);
- // first iteration to get the total number of members
- var members_nb = 0;
- for (tuple_members) |member| {
- const member_T = @field(tuple, member.name);
- const member_info = @typeInfo(member_T);
- if (member_info == .Union) {
- const member_union = member_info.Union;
- members_nb += member_union.fields.len;
- } else if (member_info == .Struct) {
- members_nb += 1;
- } else {
- return error.GenerateMemberNotUnionOrStruct;
- }
- }
+ const unfiltered_count, const filter_set = filterMap(count, interfaces);
- // define the tag type regarding the members nb
- var tag_type: type = undefined;
- if (members_nb < 3) {
- tag_type = u1;
- } else if (members_nb < 4) {
- tag_type = u2;
- } else if (members_nb < 8) {
- tag_type = u3;
- } else if (members_nb < 16) {
- tag_type = u4;
- } else if (members_nb < 32) {
- tag_type = u5;
- } else if (members_nb < 64) {
- tag_type = u6;
- } else if (members_nb < 128) {
- tag_type = u7;
- } else if (members_nb < 256) {
- tag_type = u8;
- } else if (members_nb < 65536) {
- tag_type = u16;
- } else {
- return error.GenerateTooMuchMembers;
- }
+ var field_index: usize = 0;
+ var fields: [unfiltered_count]Type.StructField = undefined;
- // second iteration to generate tags
- var enum_fields: [members_nb]std.builtin.Type.EnumField = undefined;
- var done = 0;
- for (tuple_members) |member| {
- const member_T = @field(tuple, member.name);
- const member_info = @typeInfo(member_T);
- if (member_info == .Union) {
- const member_union = member_info.Union;
- for (member_union.fields) |field| {
- enum_fields[done] = .{
- .name = fmtName(field.type),
- .value = done,
- };
- done += 1;
- }
- } else if (member_info == .Struct) {
- enum_fields[done] = .{
- .name = fmtName(member_T),
- .value = done,
- };
- done += 1;
- }
- }
- const decls: [0]std.builtin.Type.Declaration = undefined;
- const enum_info = std.builtin.Type.Enum{
- .tag_type = tag_type,
- .fields = &enum_fields,
- .decls = &decls,
- .is_exhaustive = true,
- };
- const enum_T = @Type(std.builtin.Type{ .Enum = enum_info });
-
- // third iteration to generate union type
- var union_fields: [members_nb]std.builtin.Type.UnionField = undefined;
- done = 0;
- for (tuple_members, 0..) |member, i| {
- const member_T = @field(tuple, member.name);
- const member_info = @typeInfo(member_T);
- if (member_info == .Union) {
- const member_union = member_info.Union;
- for (member_union.fields) |field| {
- var T: type = undefined;
- if (@hasDecl(field.type, "Self")) {
- T = @field(field.type, "Self");
- T = *T;
- } else {
- T = field.type;
- }
- union_fields[done] = .{
- .name = fmtName(field.type),
- .type = T,
- .alignment = @alignOf(T),
- };
- done += 1;
- }
- } else if (member_info == .Struct) {
- const member_name = try itoa(i);
- var T = @field(tuple, member_name);
- if (@hasDecl(T, "Self")) {
- T = @field(T, "Self");
- T = *T;
- }
- union_fields[done] = .{
- // UnionField.name expect a null terminated string.
- // concatenate the `[]const u8` string with an empty string
- // literal (`name ++ ""`) to explicitly coerce it to `[:0]const
- // u8`.
- .name = fmtName(member_T) ++ "",
- .type = T,
- .alignment = @alignOf(T),
- };
- done += 1;
- }
+ for (filter_set, 0..) |filter, i| {
+ if (filter) {
+ continue;
}
- const union_info = std.builtin.Type.Union{
- .layout = .auto,
- .tag_type = enum_T,
- .fields = &union_fields,
- .decls = &decls,
- };
- const union_T = @Type(std.builtin.Type{ .Union = union_info });
-
- return .{
- ._enum = enum_T,
- ._union = union_T,
+ fields[field_index] = .{
+ .name = std.fmt.comptimePrint("{d}", .{field_index}),
+ .type = type,
+ // has to be true in order to properly capture the default value
+ .is_comptime = true,
+ .alignment = @alignOf(type),
+ .default_value = @ptrCast(&interfaces[i]),
};
+ field_index += 1;
}
-};
-// Tuple
-// -----
-
-fn tupleNb(comptime tuple: anytype) usize {
- var nb = 0;
- for (@typeInfo(@TypeOf(tuple)).Struct.fields) |member| {
- const member_T = @field(tuple, member.name);
- if (@TypeOf(member_T) == type) {
- nb += 1;
- } else {
- const member_info = @typeInfo(@TypeOf(member_T));
- if (member_info != .Struct and !member_info.Struct.is_tuple) {
- @compileError("GenerateMemberNotTypeOrTuple");
- }
- for (member_info.Struct.fields) |field| {
- if (@TypeOf(@field(member_T, field.name)) != type) {
- @compileError("GenerateMemberTupleChildNotType");
- }
- }
- nb += member_info.Struct.fields.len;
- }
- }
- return nb;
+ return @Type(.{ .Struct = .{
+ .layout = .auto,
+ .fields = &fields,
+ .decls = &.{},
+ .is_tuple = true,
+ } });
}
-fn tupleTypes(comptime nb: usize, comptime tuple: anytype) [nb]type {
- var types: [nb]type = undefined;
- var done = 0;
- for (@typeInfo(@TypeOf(tuple)).Struct.fields) |member| {
- const T = @field(tuple, member.name);
- if (@TypeOf(T) == type) {
- types[done] = T;
- done += 1;
+fn countInterfaces(args: anytype, count: usize) usize {
+ var new_count = count;
+ for (@typeInfo(@TypeOf(args)).Struct.fields) |f| {
+ const member = @field(args, f.name);
+ if (@TypeOf(member) == type) {
+ new_count += 1;
} else {
- const info = @typeInfo(@TypeOf(T));
- for (info.Struct.fields) |field| {
- types[done] = @field(T, field.name);
- done += 1;
- }
- }
- }
- return types;
-}
-
-fn isDup(comptime nb: usize, comptime list: [nb]type, comptime T: type, comptime i: usize) bool {
- for (list, 0..) |item, index| {
- if (i >= index) {
- // check sequentially
- continue;
- }
- if (T == item) {
- return true;
+ new_count = countInterfaces(member, new_count);
}
}
- return false;
+ return new_count;
}
-fn dedupIndexes(comptime nb: usize, comptime types: [nb]type) [nb]i32 {
- var dedup_indexes: [nb]i32 = undefined;
- for (types, 0..) |T, i| {
- if (isDup(nb, types, T, i)) {
- dedup_indexes[i] = -1;
+fn flattenInterfaces(args: anytype, interfaces: []type, index: usize) usize {
+ var new_index = index;
+ for (@typeInfo(@TypeOf(args)).Struct.fields) |f| {
+ const member = @field(args, f.name);
+ if (@TypeOf(member) == type) {
+ interfaces[new_index] = member;
+ new_index += 1;
} else {
- dedup_indexes[i] = i;
+ new_index = flattenInterfaces(member, interfaces, new_index);
}
}
- return dedup_indexes;
+ return new_index;
}
-fn dedupNb(comptime nb: usize, comptime dedup_indexes: [nb]i32) usize {
- var dedup_nb = 0;
- for (dedup_indexes) |index| {
- if (index != -1) {
- dedup_nb += 1;
+fn filterMap(comptime count: usize, interfaces: [count]type) struct { usize, [count]bool } {
+ var map: [count]bool = undefined;
+ var unfiltered_count: usize = 0;
+ outer: for (interfaces, 0..) |iface, i| {
+ for (interfaces[i + 1 ..]) |check| {
+ if (iface == check) {
+ map[i] = true;
+ continue :outer;
+ }
}
+ map[i] = false;
+ unfiltered_count += 1;
}
- return dedup_nb;
+ return .{ unfiltered_count, map };
}
-fn TupleT(comptime tuple: anytype) type {
- @setEvalBranchQuota(100000);
-
- // logic
- const nb = tupleNb(tuple);
- const types = tupleTypes(nb, tuple);
- const dedup_indexes = dedupIndexes(nb, types);
- const dedup_nb = dedupNb(nb, dedup_indexes);
-
- // generate the tuple type
- var fields: [dedup_nb]std.builtin.Type.StructField = undefined;
- var done = 0;
- for (dedup_indexes) |index| {
- if (index == -1) {
- continue;
- }
- fields[done] = .{
- // StructField.name expect a null terminated string.
- // concatenate the `[]const u8` string with an empty string
- // literal (`name ++ ""`) to explicitly coerce it to `[:0]const
- // u8`.
- .name = try itoa(done) ++ "",
- .type = type,
- .default_value = null,
- .is_comptime = false,
- .alignment = @alignOf(type),
- };
- done += 1;
- }
- const decls: [0]std.builtin.Type.Declaration = undefined;
- const info = std.builtin.Type.Struct{
- .layout = .auto,
- .fields = &fields,
- .decls = &decls,
- .is_tuple = true,
+test "generate.Union" {
+ const Astruct = struct {
+ pub const Self = Other;
+ const Other = struct {};
};
- return @Type(std.builtin.Type{ .Struct = info });
-}
-
-// Create a flatten tuple from various structs and tuple of structs
-// Duplicates will be removed.
-// TODO: make this function more generic
-pub fn Tuple(comptime tuple: anytype) TupleT(tuple) {
-
- // check types provided
- const tuple_T = @TypeOf(tuple);
- const tuple_info = @typeInfo(tuple_T);
- if (tuple_info != .Struct or !tuple_info.Struct.is_tuple) {
- @compileError("GenerateArgNotTuple");
- }
- // generate the type
- const T = TupleT(tuple);
+ const Bstruct = struct {
+ value: u8 = 0,
+ };
- // logic
- const nb = tupleNb(tuple);
- const types = tupleTypes(nb, tuple);
- const dedup_indexes = dedupIndexes(nb, types);
+ const Cstruct = struct {
+ value: u8 = 0,
+ };
- // instantiate the tuple
- var t: T = undefined;
- var done = 0;
- for (dedup_indexes) |index| {
- if (index == -1) {
- continue;
- }
- const name = try itoa(done);
- @field(t, name) = types[index];
- done += 1;
- }
- return t;
+ const value = Union(.{ Astruct, Bstruct, .{ Cstruct } });
+ const ti = @typeInfo(value).Union;
+ try std.testing.expectEqual(3, ti.fields.len);
+ try std.testing.expectEqualStrings("*generate.test.generate.Union.Astruct.Other", @typeName(ti.fields[0].type));
+ try std.testing.expectEqualStrings(ti.fields[0].name, "Astruct");
+ try std.testing.expectEqual(Bstruct, ti.fields[1].type);
+ try std.testing.expectEqualStrings(ti.fields[1].name, "Bstruct");
+ try std.testing.expectEqual(Cstruct, ti.fields[2].type);
+ try std.testing.expectEqualStrings(ti.fields[2].name, "Cstruct");
}
-// Tests
-// -----
-
-const Error = error{
- GenerateArgNotTuple,
- GenerateMemberNotUnionOrStruct,
- GenerateMemberNotTupleOrStruct,
- GenerateMemberTupleNotStruct,
- GenerateTooMuchMembers,
-};
-
-const Astruct = struct {
- value: u8 = 0,
-};
-const Bstruct = struct {
- value: u8 = 0,
-};
-const Cstruct = struct {
- value: u8 = 0,
-};
-const Dstruct = struct {
- value: u8 = 0,
-};
-
-pub fn tests() !void {
-
- // Union from structs
- const FromStructs = try Union.private_compile(.{ Astruct, Bstruct, Cstruct });
-
- const from_structs_enum = @typeInfo(FromStructs._enum);
- try std.testing.expect(from_structs_enum == .Enum);
- try std.testing.expect(from_structs_enum.Enum.fields.len == 3);
- try std.testing.expect(from_structs_enum.Enum.tag_type == u2);
- try std.testing.expect(from_structs_enum.Enum.fields[0].value == 0);
- try std.testing.expectEqualStrings(from_structs_enum.Enum.fields[0].name, "Astruct");
-
- const from_structs_union = @typeInfo(FromStructs._union);
- try std.testing.expect(from_structs_union == .Union);
- try std.testing.expect(from_structs_union.Union.tag_type == FromStructs._enum);
- try std.testing.expect(from_structs_union.Union.fields.len == 3);
- try std.testing.expect(from_structs_union.Union.fields[0].type == Astruct);
- try std.testing.expectEqualStrings(from_structs_union.Union.fields[0].name, "Astruct");
-
- // Union from union and structs
- const FromMix = try Union.private_compile(.{ FromStructs._union, Dstruct });
-
- const from_mix_enum = @typeInfo(FromMix._enum);
- try std.testing.expect(from_mix_enum == .Enum);
- try std.testing.expect(from_mix_enum.Enum.fields.len == 4);
- try std.testing.expect(from_mix_enum.Enum.tag_type == u3);
- try std.testing.expect(from_mix_enum.Enum.fields[0].value == 0);
- try std.testing.expectEqualStrings(from_mix_enum.Enum.fields[3].name, "Dstruct");
-
- const from_mix_union = @typeInfo(FromMix._union);
- try std.testing.expect(from_mix_union == .Union);
- try std.testing.expect(from_mix_union.Union.tag_type == FromMix._enum);
- try std.testing.expect(from_mix_union.Union.fields.len == 4);
- try std.testing.expect(from_mix_union.Union.fields[3].type == Dstruct);
- try std.testing.expectEqualStrings(from_mix_union.Union.fields[3].name, "Dstruct");
-
- std.debug.print("Generate Union: OK\n", .{});
+test "generate.Tuple" {
+ const Astruct = struct {
+ };
- // Tuple from structs
- const tuple_structs = .{ Astruct, Bstruct };
- const tFromStructs = Tuple(tuple_structs);
- const t_from_structs = @typeInfo(@TypeOf(tFromStructs));
- try std.testing.expect(t_from_structs == .Struct);
- try std.testing.expect(t_from_structs.Struct.is_tuple);
- try std.testing.expect(t_from_structs.Struct.fields.len == 2);
- try std.testing.expect(@field(tFromStructs, "0") == Astruct);
- try std.testing.expect(@field(tFromStructs, "1") == Bstruct);
+ const Bstruct = struct {
+ value: u8 = 0,
+ };
- // Tuple from tuple and structs
- const tuple_mix = .{ tFromStructs, Cstruct };
- const tFromMix = Tuple(tuple_mix);
- const t_from_mix = @typeInfo(@TypeOf(tFromMix));
- try std.testing.expect(t_from_mix == .Struct);
- try std.testing.expect(t_from_mix.Struct.is_tuple);
- try std.testing.expect(t_from_mix.Struct.fields.len == 3);
- try std.testing.expect(@field(tFromMix, "0") == Astruct);
- try std.testing.expect(@field(tFromMix, "1") == Bstruct);
- try std.testing.expect(@field(tFromMix, "2") == Cstruct);
+ const Cstruct = struct {
+ value: u8 = 0,
+ };
- // Tuple with dedup
- const tuple_dedup = .{ Cstruct, Astruct, tFromStructs, Bstruct };
- const tFromDedup = Tuple(tuple_dedup);
- const t_from_dedup = @typeInfo(@TypeOf(tFromDedup));
- try std.testing.expect(t_from_dedup == .Struct);
- try std.testing.expect(t_from_dedup.Struct.is_tuple);
- try std.testing.expect(t_from_dedup.Struct.fields.len == 3);
- try std.testing.expect(@field(tFromDedup, "0") == Cstruct);
- try std.testing.expect(@field(tFromDedup, "1") == Astruct);
- try std.testing.expect(@field(tFromDedup, "2") == Bstruct);
+ {
+ const tuple = Tuple(.{ Astruct, Bstruct }){};
+ const ti = @typeInfo(@TypeOf(tuple)).Struct;
+ try std.testing.expectEqual(true, ti.is_tuple);
+ try std.testing.expectEqual(2, ti.fields.len);
+ try std.testing.expectEqual(Astruct, tuple.@"0");
+ try std.testing.expectEqual(Bstruct, tuple.@"1");
+ }
- std.debug.print("Generate Tuple: OK\n", .{});
+ {
+ // dedupe
+ const tuple = Tuple(.{ Cstruct, Astruct, .{ Astruct }, Bstruct, .{ Astruct, .{ Astruct, Bstruct } } }){};
+ const ti = @typeInfo(@TypeOf(tuple)).Struct;
+ try std.testing.expectEqual(true, ti.is_tuple);
+ try std.testing.expectEqual(3, ti.fields.len);
+ try std.testing.expectEqual(Cstruct, tuple.@"0");
+ try std.testing.expectEqual(Astruct, tuple.@"1");
+ try std.testing.expectEqual(Bstruct, tuple.@"2");
+ }
}
diff --git a/src/html/elements.zig b/src/html/elements.zig
index c632b63c..d0ff13a4 100644
--- a/src/html/elements.zig
+++ b/src/html/elements.zig
@@ -99,9 +99,8 @@ pub const Interfaces = .{
HTMLVideoElement,
CSSProperties,
};
-const Generated = generate.Union.compile(Interfaces);
-pub const Union = Generated._union;
-pub const Tags = Generated._enum;
+
+pub const Union = generate.Union(Interfaces);
// Abstract class
// --------------
diff --git a/src/html/html.zig b/src/html/html.zig
index 43535e17..9aae1de2 100644
--- a/src/html/html.zig
+++ b/src/html/html.zig
@@ -25,7 +25,7 @@ const Navigator = @import("navigator.zig").Navigator;
const History = @import("history.zig").History;
const Location = @import("location.zig").Location;
-pub const Interfaces = generate.Tuple(.{
+pub const Interfaces = .{
HTMLDocument,
HTMLElem.HTMLElement,
HTMLElem.HTMLMediaElement,
@@ -34,4 +34,4 @@ pub const Interfaces = generate.Tuple(.{
Navigator,
History,
Location,
-});
+};
diff --git a/src/iterator/iterator.zig b/src/iterator/iterator.zig
index e1dc9d3e..803cd978 100644
--- a/src/iterator/iterator.zig
+++ b/src/iterator/iterator.zig
@@ -1,10 +1,8 @@
const std = @import("std");
-const generate = @import("../generate.zig");
-
-pub const Interfaces = generate.Tuple(.{
+pub const Interfaces = .{
U32Iterator,
-});
+};
pub const U32Iterator = struct {
pub const mem_guarantied = true;
diff --git a/src/run_tests.zig b/src/run_tests.zig
index 5e569f26..9c0c98b9 100644
--- a/src/run_tests.zig
+++ b/src/run_tests.zig
@@ -332,13 +332,11 @@ test {
const queryTest = @import("url/query.zig");
std.testing.refAllDecls(queryTest);
+ std.testing.refAllDecls(@import("generate.zig"));
std.testing.refAllDecls(@import("cdp/msg.zig"));
}
fn testJSRuntime(alloc: std.mem.Allocator) !void {
- // generate tests
- try generate.tests();
-
// create JS vm
const vm = jsruntime.VM.init();
defer vm.deinit();
diff --git a/src/storage/storage.zig b/src/storage/storage.zig
index 6937594d..205a3895 100644
--- a/src/storage/storage.zig
+++ b/src/storage/storage.zig
@@ -21,15 +21,13 @@ const std = @import("std");
const jsruntime = @import("jsruntime");
const Case = jsruntime.test_utils.Case;
const checkCases = jsruntime.test_utils.checkCases;
-const generate = @import("../generate.zig");
-
const DOMError = @import("netsurf").DOMError;
const log = std.log.scoped(.storage);
-pub const Interfaces = generate.Tuple(.{
+pub const Interfaces = .{
Bottle,
-});
+};
// See https://storage.spec.whatwg.org/#model for storage hierarchy.
// A Shed contains map of Shelves. The key is the document's origin.
diff --git a/src/url/url.zig b/src/url/url.zig
index bea44839..683186c2 100644
--- a/src/url/url.zig
+++ b/src/url/url.zig
@@ -21,14 +21,13 @@ const std = @import("std");
const jsruntime = @import("jsruntime");
const Case = jsruntime.test_utils.Case;
const checkCases = jsruntime.test_utils.checkCases;
-const generate = @import("../generate.zig");
const query = @import("query.zig");
-pub const Interfaces = generate.Tuple(.{
+pub const Interfaces = .{
URL,
URLSearchParams,
-});
+};
// https://url.spec.whatwg.org/#url
//
diff --git a/src/xhr/xhr.zig b/src/xhr/xhr.zig
index 91243150..77131577 100644
--- a/src/xhr/xhr.zig
+++ b/src/xhr/xhr.zig
@@ -21,7 +21,6 @@ const std = @import("std");
const jsruntime = @import("jsruntime");
const Case = jsruntime.test_utils.Case;
const checkCases = jsruntime.test_utils.checkCases;
-const generate = @import("../generate.zig");
const DOMError = @import("netsurf").DOMError;
const DOMException = @import("../dom/exceptions.zig").DOMException;
@@ -42,11 +41,11 @@ const log = std.log.scoped(.xhr);
// XHR interfaces
// https://xhr.spec.whatwg.org/#interface-xmlhttprequest
-pub const Interfaces = generate.Tuple(.{
+pub const Interfaces = .{
XMLHttpRequestEventTarget,
XMLHttpRequestUpload,
XMLHttpRequest,
-});
+};
pub const XMLHttpRequestUpload = struct {
pub const prototype = *XMLHttpRequestEventTarget;
diff --git a/src/xmlserializer/xmlserializer.zig b/src/xmlserializer/xmlserializer.zig
index f39745f1..a0153558 100644
--- a/src/xmlserializer/xmlserializer.zig
+++ b/src/xmlserializer/xmlserializer.zig
@@ -21,16 +21,15 @@ const std = @import("std");
const jsruntime = @import("jsruntime");
const Case = jsruntime.test_utils.Case;
const checkCases = jsruntime.test_utils.checkCases;
-const generate = @import("../generate.zig");
const DOMError = @import("netsurf").DOMError;
const parser = @import("netsurf");
const dump = @import("../browser/dump.zig");
-pub const Interfaces = generate.Tuple(.{
+pub const Interfaces = .{
XMLSerializer,
-});
+};
// https://w3c.github.io/DOM-Parsing/#dom-xmlserializer-constructor
pub const XMLSerializer = struct {