mirror of
https://github.com/lightpanda-io/browser.git
synced 2025-10-28 22:53:28 +00:00
Add generate function for Tuple
Signed-off-by: Francis Bouvier <francis.bouvier@gmail.com>
This commit is contained in:
69
src/dom.zig
69
src/dom.zig
@@ -1,3 +1,5 @@
|
|||||||
|
const generate = @import("generate.zig");
|
||||||
|
|
||||||
const Console = @import("jsruntime").Console;
|
const Console = @import("jsruntime").Console;
|
||||||
|
|
||||||
// DOM
|
// DOM
|
||||||
@@ -12,7 +14,7 @@ pub const HTMLDocument = @import("html/document.zig").HTMLDocument;
|
|||||||
const E = @import("html/elements.zig");
|
const E = @import("html/elements.zig");
|
||||||
|
|
||||||
// Interfaces
|
// Interfaces
|
||||||
pub const Interfaces = .{
|
const interfaces = .{
|
||||||
Console,
|
Console,
|
||||||
|
|
||||||
// DOM
|
// DOM
|
||||||
@@ -23,69 +25,8 @@ pub const Interfaces = .{
|
|||||||
|
|
||||||
// HTML
|
// HTML
|
||||||
HTMLDocument,
|
HTMLDocument,
|
||||||
|
|
||||||
E.HTMLElement,
|
E.HTMLElement,
|
||||||
E.HTMLMediaElement,
|
E.HTMLMediaElement,
|
||||||
|
E.HTMLElementsTypes,
|
||||||
// TODO: generate HTMLElements comptime
|
|
||||||
E.HTMLUnknownElement,
|
|
||||||
E.HTMLAnchorElement,
|
|
||||||
E.HTMLAreaElement,
|
|
||||||
E.HTMLAudioElement,
|
|
||||||
E.HTMLBRElement,
|
|
||||||
E.HTMLBaseElement,
|
|
||||||
E.HTMLBodyElement,
|
|
||||||
E.HTMLButtonElement,
|
|
||||||
E.HTMLCanvasElement,
|
|
||||||
E.HTMLDListElement,
|
|
||||||
E.HTMLDialogElement,
|
|
||||||
E.HTMLDataElement,
|
|
||||||
E.HTMLDivElement,
|
|
||||||
E.HTMLEmbedElement,
|
|
||||||
E.HTMLFieldSetElement,
|
|
||||||
E.HTMLFormElement,
|
|
||||||
E.HTMLFrameSetElement,
|
|
||||||
E.HTMLHRElement,
|
|
||||||
E.HTMLHeadElement,
|
|
||||||
E.HTMLHeadingElement,
|
|
||||||
E.HTMLHtmlElement,
|
|
||||||
E.HTMLIFrameElement,
|
|
||||||
E.HTMLImageElement,
|
|
||||||
E.HTMLInputElement,
|
|
||||||
E.HTMLLIElement,
|
|
||||||
E.HTMLLabelElement,
|
|
||||||
E.HTMLLegendElement,
|
|
||||||
E.HTMLLinkElement,
|
|
||||||
E.HTMLMapElement,
|
|
||||||
E.HTMLMetaElement,
|
|
||||||
E.HTMLMeterElement,
|
|
||||||
E.HTMLModElement,
|
|
||||||
E.HTMLOListElement,
|
|
||||||
E.HTMLObjectElement,
|
|
||||||
E.HTMLOptGroupElement,
|
|
||||||
E.HTMLOptionElement,
|
|
||||||
E.HTMLOutputElement,
|
|
||||||
E.HTMLParagraphElement,
|
|
||||||
E.HTMLPictureElement,
|
|
||||||
E.HTMLPreElement,
|
|
||||||
E.HTMLProgressElement,
|
|
||||||
E.HTMLQuoteElement,
|
|
||||||
E.HTMLScriptElement,
|
|
||||||
E.HTMLSelectElement,
|
|
||||||
E.HTMLSourceElement,
|
|
||||||
E.HTMLSpanElement,
|
|
||||||
E.HTMLStyleElement,
|
|
||||||
E.HTMLTableElement,
|
|
||||||
E.HTMLTableCaptionElement,
|
|
||||||
E.HTMLTableCellElement,
|
|
||||||
E.HTMLTableColElement,
|
|
||||||
E.HTMLTableRowElement,
|
|
||||||
E.HTMLTableSectionElement,
|
|
||||||
E.HTMLTemplateElement,
|
|
||||||
E.HTMLTextAreaElement,
|
|
||||||
E.HTMLTimeElement,
|
|
||||||
E.HTMLTitleElement,
|
|
||||||
E.HTMLTrackElement,
|
|
||||||
E.HTMLUListElement,
|
|
||||||
E.HTMLVideoElement,
|
|
||||||
};
|
};
|
||||||
|
pub const Interfaces = generate.TupleInst(generate.TupleT(interfaces), interfaces);
|
||||||
|
|||||||
149
src/generate.zig
149
src/generate.zig
@@ -6,6 +6,8 @@ fn fmtName(comptime T: type) []const u8 {
|
|||||||
return it.first();
|
return it.first();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Generate a flatten tagged Union from various structs and union of structs
|
||||||
|
// TODO: make this function more generic
|
||||||
pub const Union = struct {
|
pub const Union = struct {
|
||||||
_enum: type,
|
_enum: type,
|
||||||
_union: type,
|
_union: type,
|
||||||
@@ -23,7 +25,7 @@ pub const Union = struct {
|
|||||||
const tuple_T = @TypeOf(tuple);
|
const tuple_T = @TypeOf(tuple);
|
||||||
const tuple_info = @typeInfo(tuple_T);
|
const tuple_info = @typeInfo(tuple_T);
|
||||||
if (tuple_info != .Struct or !tuple_info.Struct.is_tuple) {
|
if (tuple_info != .Struct or !tuple_info.Struct.is_tuple) {
|
||||||
return error.GenerateUnionArgNotTuple;
|
return error.GenerateArgNotTuple;
|
||||||
}
|
}
|
||||||
|
|
||||||
const tuple_members = tuple_info.Struct.fields;
|
const tuple_members = tuple_info.Struct.fields;
|
||||||
@@ -39,7 +41,7 @@ pub const Union = struct {
|
|||||||
} else if (member_info == .Struct) {
|
} else if (member_info == .Struct) {
|
||||||
members_nb += 1;
|
members_nb += 1;
|
||||||
} else {
|
} else {
|
||||||
return error.GenerateUnionMemberNotUnionOrStruct;
|
return error.GenerateMemberNotUnionOrStruct;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -64,7 +66,7 @@ pub const Union = struct {
|
|||||||
} else if (members_nb < 65536) {
|
} else if (members_nb < 65536) {
|
||||||
tag_type = u16;
|
tag_type = u16;
|
||||||
} else {
|
} else {
|
||||||
return error.GenerateUnionTooMuchMembers;
|
return error.GenerateTooMuchMembers;
|
||||||
}
|
}
|
||||||
|
|
||||||
// second iteration to generate tags
|
// second iteration to generate tags
|
||||||
@@ -100,7 +102,7 @@ pub const Union = struct {
|
|||||||
};
|
};
|
||||||
const enum_T = @Type(std.builtin.Type{ .Enum = enum_info });
|
const enum_T = @Type(std.builtin.Type{ .Enum = enum_info });
|
||||||
|
|
||||||
// third iteration to generate union
|
// third iteration to generate union type
|
||||||
comptime var union_fields: [members_nb]std.builtin.Type.UnionField = undefined;
|
comptime var union_fields: [members_nb]std.builtin.Type.UnionField = undefined;
|
||||||
done = 0;
|
done = 0;
|
||||||
inline for (tuple_members) |member, i| {
|
inline for (tuple_members) |member, i| {
|
||||||
@@ -141,13 +143,123 @@ pub const Union = struct {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
fn itoa(comptime i: u8) ![]u8 {
|
||||||
|
comptime {
|
||||||
|
var len: usize = undefined;
|
||||||
|
if (i < 10) {
|
||||||
|
len = 1;
|
||||||
|
} else if (i < 100) {
|
||||||
|
len = 2;
|
||||||
|
} else {
|
||||||
|
return error.GenerateTooMuchMembers;
|
||||||
|
}
|
||||||
|
var buf: [len]u8 = undefined;
|
||||||
|
return try std.fmt.bufPrint(buf[0..], "{d}", .{i});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Generate a flatten tuple type from various structs and tuple of structs.
|
||||||
|
// TODO: make this function more generic
|
||||||
|
pub fn TupleT(comptime tuple: anytype) type {
|
||||||
|
|
||||||
|
// 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");
|
||||||
|
}
|
||||||
|
|
||||||
|
const tuple_members = tuple_info.Struct.fields;
|
||||||
|
|
||||||
|
// first iteration to get the total number of members
|
||||||
|
comptime var members_nb = 0;
|
||||||
|
for (tuple_members) |member| {
|
||||||
|
const member_T = @field(tuple, member.name);
|
||||||
|
if (@TypeOf(member_T) == type) {
|
||||||
|
members_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");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
members_nb += member_info.Struct.fields.len;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// second iteration to generate the tuple type
|
||||||
|
var fields: [members_nb]std.builtin.Type.StructField = undefined;
|
||||||
|
var done = 0;
|
||||||
|
while (done < members_nb) {
|
||||||
|
fields[done] = .{
|
||||||
|
.name = try itoa(done),
|
||||||
|
.field_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,
|
||||||
|
};
|
||||||
|
return @Type(std.builtin.Type{ .Struct = info });
|
||||||
|
}
|
||||||
|
|
||||||
|
// Instantiate a flatten tuple from various structs and tuple of structs
|
||||||
|
// You need to call first TupleT to generate the according type
|
||||||
|
// TODO: make this function more generic
|
||||||
|
pub fn TupleInst(comptime T: type, comptime tuple: anytype) T {
|
||||||
|
|
||||||
|
// check types provided
|
||||||
|
const tuple_T = @TypeOf(tuple);
|
||||||
|
const tuple_info = @typeInfo(tuple_T);
|
||||||
|
const tuple_members = tuple_info.Struct.fields;
|
||||||
|
|
||||||
|
// instantiate the tuple
|
||||||
|
var t: T = undefined;
|
||||||
|
var done = 0;
|
||||||
|
for (tuple_members) |member| {
|
||||||
|
const member_T = @field(tuple, member.name);
|
||||||
|
var member_info: std.builtin.Type = undefined;
|
||||||
|
if (@TypeOf(member_T) == type) {
|
||||||
|
member_info = @typeInfo(member_T);
|
||||||
|
} else {
|
||||||
|
member_info = @typeInfo(@TypeOf(member_T));
|
||||||
|
}
|
||||||
|
var member_detail = member_info.Struct;
|
||||||
|
if (member_detail.is_tuple) {
|
||||||
|
for (member_detail.fields) |field| {
|
||||||
|
const name = try itoa(done);
|
||||||
|
@field(t, name) = @field(member_T, field.name);
|
||||||
|
done += 1;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
const name = try itoa(done);
|
||||||
|
@field(t, name) = @field(tuple, member.name);
|
||||||
|
done += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return t;
|
||||||
|
}
|
||||||
|
|
||||||
// Tests
|
// Tests
|
||||||
// -----
|
// -----
|
||||||
|
|
||||||
const Error = error{
|
const Error = error{
|
||||||
UnionArgNotTuple,
|
GenerateArgNotTuple,
|
||||||
UnionMemberNotUnionOrStruct,
|
GenerateMemberNotUnionOrStruct,
|
||||||
UnionTooMuchMembers,
|
GenerateMemberNotTupleOrStruct,
|
||||||
|
GenerateMemberTupleNotStruct,
|
||||||
|
GenerateTooMuchMembers,
|
||||||
};
|
};
|
||||||
|
|
||||||
const Astruct = struct {
|
const Astruct = struct {
|
||||||
@@ -200,4 +312,27 @@ pub fn tests() !void {
|
|||||||
try std.testing.expectEqualStrings(from_mix_union.Union.fields[3].name, "Dstruct");
|
try std.testing.expectEqualStrings(from_mix_union.Union.fields[3].name, "Dstruct");
|
||||||
|
|
||||||
std.debug.print("Generate Union: OK\n", .{});
|
std.debug.print("Generate Union: OK\n", .{});
|
||||||
|
|
||||||
|
// Tuple from structs
|
||||||
|
const tuple_structs = .{ Astruct, Bstruct };
|
||||||
|
const tFromStructs = TupleInst(TupleT(tuple_structs), 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);
|
||||||
|
|
||||||
|
// Tuple from tuple and structs
|
||||||
|
const tuple_mix = .{ tFromStructs, Cstruct };
|
||||||
|
const tFromMix = TupleInst(TupleT(tuple_mix), 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);
|
||||||
|
|
||||||
|
std.debug.print("Generate Tuple: OK\n", .{});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ pub const HTMLElement = struct {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const HTMLElementsTypes = .{
|
pub const HTMLElementsTypes = .{
|
||||||
HTMLUnknownElement,
|
HTMLUnknownElement,
|
||||||
HTMLAnchorElement,
|
HTMLAnchorElement,
|
||||||
HTMLAreaElement,
|
HTMLAreaElement,
|
||||||
@@ -78,10 +78,7 @@ const HTMLElementsTypes = .{
|
|||||||
HTMLUListElement,
|
HTMLUListElement,
|
||||||
HTMLVideoElement,
|
HTMLVideoElement,
|
||||||
};
|
};
|
||||||
fn generateElements() generate.Union {
|
const HTMLElementsGenerated = generate.Union.compile(HTMLElementsTypes);
|
||||||
return generate.Union.compile(HTMLElementsTypes);
|
|
||||||
}
|
|
||||||
const HTMLElementsGenerated = generateElements();
|
|
||||||
pub const HTMLElements = HTMLElementsGenerated._union;
|
pub const HTMLElements = HTMLElementsGenerated._union;
|
||||||
pub const HTMLElementsTags = HTMLElementsGenerated._enum;
|
pub const HTMLElementsTags = HTMLElementsGenerated._enum;
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user