authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2026-02-24 19:15:30-08:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2026-05-25 18:54:34-07:00
log92803903f3e96995cc705087615bd67749757862
treef0c4353850516fa3e6fc5fd0ac370d2c23153b15
parente8e7fbf8432899d12888bcabeba17ea8e51dc62d

Configuration: implement FlagLengthPrefixedList


3 files changed, 209 insertions(+), 67 deletions(-)

lib/compiler/Maker/ScannedConfig.zig+16-5
...@@ -55,17 +55,24 @@ fn printValue(sc: *const ScannedConfig, s: *Serializer, comptime Field: type, fi...@@ -55,17 +55,24 @@ fn printValue(sc: *const ScannedConfig, s: *Serializer, comptime Field: type, fi
55 try s.value(field_value.slice(c), .{});55 try s.value(field_value.slice(c), .{});
56 },56 },
57 Configuration.Deps => {57 Configuration.Deps => {
58 var deps_field = try s.beginTuple(.{});58 try printValue(sc, s, []Configuration.Step.Index, field_value.slice(c));
59 for (field_value.slice(c)) |dep| {
60 try deps_field.field(@intFromEnum(dep), .{});
61 }
62 try deps_field.end();
63 },59 },
64 Configuration.MaxRss => {60 Configuration.MaxRss => {
65 try s.value(field_value.toBytes(), .{});61 try s.value(field_value.toBytes(), .{});
66 },62 },
67 else => switch (@typeInfo(Field)) {63 else => switch (@typeInfo(Field)) {
68 .int => try s.int(field_value),64 .int => try s.int(field_value),
65 .pointer => |info| switch (info.size) {
66 .slice => {
67 var slice_field = try s.beginTuple(.{});
68 for (field_value) |elem| {
69 try slice_field.fieldPrefix();
70 try printValue(sc, s, info.child, elem);
71 }
72 try slice_field.end();
73 },
74 else => comptime unreachable,
75 },
69 .@"enum" => {76 .@"enum" => {
70 if (@hasDecl(Field, "storage")) switch (Field.storage) {77 if (@hasDecl(Field, "storage")) switch (Field.storage) {
71 .extended => {78 .extended => {
...@@ -74,6 +81,7 @@ fn printValue(sc: *const ScannedConfig, s: *Serializer, comptime Field: type, fi...@@ -74,6 +81,7 @@ fn printValue(sc: *const ScannedConfig, s: *Serializer, comptime Field: type, fi
74 try sub_struct.end();81 try sub_struct.end();
75 },82 },
76 .flag_optional => comptime unreachable,83 .flag_optional => comptime unreachable,
84 .flag_length_prefixed_list => comptime unreachable,
77 .enum_optional => comptime unreachable,85 .enum_optional => comptime unreachable,
78 } else if (std.enums.tagName(Field, field_value)) |name| {86 } else if (std.enums.tagName(Field, field_value)) |name| {
79 try s.ident(name);87 try s.ident(name);
...@@ -93,6 +101,9 @@ fn printValue(sc: *const ScannedConfig, s: *Serializer, comptime Field: type, fi...@@ -93,6 +101,9 @@ fn printValue(sc: *const ScannedConfig, s: *Serializer, comptime Field: type, fi
93 try s.value(null, .{});101 try s.value(null, .{});
94 }102 }
95 },103 },
104 .flag_length_prefixed_list => {
105 try printValue(sc, s, @TypeOf(field_value.slice), field_value.slice);
106 },
96 .extended => @compileError("TODO"),107 .extended => @compileError("TODO"),
97 },108 },
98 else => @compileError("not implemented: " ++ @typeName(Field)),109 else => @compileError("not implemented: " ++ @typeName(Field)),
lib/compiler/configure_runner.zig+49-3
...@@ -279,6 +279,10 @@ const Serialize = struct {...@@ -279,6 +279,10 @@ const Serialize = struct {
279 return (try addOptionalLazyPathEnum(s, lp)).unwrap();279 return (try addOptionalLazyPathEnum(s, lp)).unwrap();
280 }280 }
281281
282 fn addLazyPath(s: *Serialize, lp: ?std.Build.LazyPath) !Configuration.LazyPath {
283 return @enumFromInt(@intFromEnum(try addOptionalLazyPathEnum(s, lp)));
284 }
285
282 fn addOptionalSemVer(s: *Serialize, sem_ver: ?std.SemanticVersion) !?Configuration.String {286 fn addOptionalSemVer(s: *Serialize, sem_ver: ?std.SemanticVersion) !?Configuration.String {
283 return if (sem_ver) |sv| try s.wc.addSemVer(sv) else null;287 return if (sem_ver) |sv| try s.wc.addSemVer(sv) else null;
284 }288 }
...@@ -286,6 +290,20 @@ const Serialize = struct {...@@ -286,6 +290,20 @@ const Serialize = struct {
286 fn addOptionalString(s: *Serialize, opt_slice: ?[]const u8) !?Configuration.String {290 fn addOptionalString(s: *Serialize, opt_slice: ?[]const u8) !?Configuration.String {
287 return if (opt_slice) |slice| try s.wc.addString(slice) else null;291 return if (opt_slice) |slice| try s.wc.addString(slice) else null;
288 }292 }
293
294 fn initStringList(s: *Serialize, list: []const []const u8) ![]const Configuration.String {
295 const wc = s.wc;
296 const result = try s.arena.alloc(Configuration.String, list.len);
297 for (result, list) |*dest, src| dest.* = try wc.addString(src);
298 return result;
299 }
300
301 fn initOptionalStringList(s: *Serialize, list: []const ?[]const u8) ![]const Configuration.OptionalString {
302 const wc = s.wc;
303 const result = try s.arena.alloc(Configuration.OptionalString, list.len);
304 for (result, list) |*dest, src| dest.* = try wc.addOptionalString(src);
305 return result;
306 }
289};307};
290308
291fn serialize(b: *std.Build, wc: *Configuration.Wip, writer: *Io.Writer) !void {309fn serialize(b: *std.Build, wc: *Configuration.Wip, writer: *Io.Writer) !void {
...@@ -320,7 +338,7 @@ fn serialize(b: *std.Build, wc: *Configuration.Wip, writer: *Io.Writer) !void {...@@ -320,7 +338,7 @@ fn serialize(b: *std.Build, wc: *Configuration.Wip, writer: *Io.Writer) !void {
320 // Add and then de-duplicate dependencies.338 // Add and then de-duplicate dependencies.
321 const deps = d: {339 const deps = d: {
322 const deps: Configuration.Deps = @enumFromInt(wc.extra.items.len);340 const deps: Configuration.Deps = @enumFromInt(wc.extra.items.len);
323 for (try wc.prepareDeps(step.dependencies.items.len), step.dependencies.items) |*dep, dep_step|341 for (try wc.reserveLengthPrefixed(step.dependencies.items.len), step.dependencies.items) |*dep, dep_step|
324 dep.* = @intCast(step_map.getIndex(dep_step).?);342 dep.* = @intCast(step_map.getIndex(dep_step).?);
325 break :d try wc.dedupeDeps(deps);343 break :d try wc.dedupeDeps(deps);
326 };344 };
...@@ -340,11 +358,35 @@ fn serialize(b: *std.Build, wc: *Configuration.Wip, writer: *Io.Writer) !void {...@@ -340,11 +358,35 @@ fn serialize(b: *std.Build, wc: *Configuration.Wip, writer: *Io.Writer) !void {
340 },358 },
341 .compile => e: {359 .compile => e: {
342 const c: *Step.Compile = @fieldParentPtr("step", step);360 const c: *Step.Compile = @fieldParentPtr("step", step);
361 const exec_cmd_args: []const ?[]const u8 = c.exec_cmd_args orelse &.{};
362 const installed_headers: []u32 = try arena.alloc(u32, c.installed_headers.items.len);
363 for (installed_headers, c.installed_headers.items) |*dst, src| switch (src) {
364 .file => |file| {
365 dst.* = try wc.addExtra(@as(Configuration.Step.Compile.InstalledHeader.File, .{
366 .source = try s.addLazyPath(file.source),
367 .dest_sub_path = try wc.addString(file.dest_rel_path),
368 }));
369 },
370 .directory => |directory| {
371 const include_extensions = directory.options.include_extensions orelse &.{};
372 dst.* = try wc.addExtra(@as(Configuration.Step.Compile.InstalledHeader.Directory, .{
373 .flags = .{
374 .include_extensions = include_extensions.len != 0,
375 .exclude_extensions = directory.options.exclude_extensions.len != 0,
376 },
377 .source = try s.addLazyPath(directory.source),
378 .dest_sub_path = try wc.addString(directory.dest_rel_path),
379 .exclude_extensions = .{ .slice = try s.initStringList(directory.options.exclude_extensions) },
380 .include_extensions = .{ .slice = try s.initStringList(include_extensions) },
381 }));
382 },
383 };
384
343 const extra_index = try wc.addExtra(@as(Configuration.Step.Compile, .{385 const extra_index = try wc.addExtra(@as(Configuration.Step.Compile, .{
344 .flags = .{386 .flags = .{
345 .filters_len = c.filters.len != 0,387 .filters_len = c.filters.len != 0,
346 .exec_cmd_args_len = if (c.exec_cmd_args) |a| a.len != 0 else false,388 .exec_cmd_args_len = exec_cmd_args.len != 0,
347 .installed_headers_len = c.installed_headers.items.len != 0,389 .installed_headers_len = installed_headers.len != 0,
348 .force_undefined_symbols_len = c.force_undefined_symbols.entries.len != 0,390 .force_undefined_symbols_len = c.force_undefined_symbols.entries.len != 0,
349391
350 .verbose_link = c.verbose_link,392 .verbose_link = c.verbose_link,
...@@ -466,6 +508,10 @@ fn serialize(b: *std.Build, wc: *Configuration.Wip, writer: *Io.Writer) !void {...@@ -466,6 +508,10 @@ fn serialize(b: *std.Build, wc: *Configuration.Wip, writer: *Io.Writer) !void {
466 .hexstring => |*hexstring| try wc.addString(hexstring.toSlice()),508 .hexstring => |*hexstring| try wc.addString(hexstring.toSlice()),
467 .none, .fast, .uuid, .sha1, .md5 => null,509 .none, .fast, .uuid, .sha1, .md5 => null,
468 } else null },510 } else null },
511 .filters = .{ .slice = try s.initStringList(c.filters) },
512 .exec_cmd_args = .{ .slice = try s.initOptionalStringList(exec_cmd_args) },
513 .installed_headers = .initErased(installed_headers),
514 .force_undefined_symbols = .{ .slice = try s.initStringList(c.force_undefined_symbols.keys()) },
469 }));515 }));
470516
471 log.err("TODO serialize the trailing Compile step data", .{});517 log.err("TODO serialize the trailing Compile step data", .{});
lib/std/zig/Configuration.zig+144-59
...@@ -33,7 +33,9 @@ pub const Header = extern struct {...@@ -33,7 +33,9 @@ pub const Header = extern struct {
33pub const Wip = struct {33pub const Wip = struct {
34 gpa: Allocator,34 gpa: Allocator,
35 string_table: StringTable = .empty,35 string_table: StringTable = .empty,
36 deps_table: DepsTable = .empty,36 /// De-duplicates an array inside `extra` that has first element length
37 /// followed by length elements.
38 length_prefixed_table: LengthPrefixedTable = .empty,
37 targets_table: TargetsTable = .empty,39 targets_table: TargetsTable = .empty,
3840
39 string_bytes: std.ArrayList(u8) = .empty,41 string_bytes: std.ArrayList(u8) = .empty,
...@@ -44,23 +46,23 @@ pub const Wip = struct {...@@ -44,23 +46,23 @@ pub const Wip = struct {
44 path_deps: std.MultiArrayList(Path) = .empty,46 path_deps: std.MultiArrayList(Path) = .empty,
45 extra: std.ArrayList(u32) = .empty,47 extra: std.ArrayList(u32) = .empty,
4648
47 const DepsTable = std.HashMapUnmanaged(Deps, void, DepsTableContext, std.hash_map.default_max_load_percentage);49 const LengthPrefixedTable = std.HashMapUnmanaged(u32, void, LengthPrefixedContext, std.hash_map.default_max_load_percentage);
48 const TargetsTable = std.HashMapUnmanaged(TargetQuery.Index, void, TargetsTableContext, std.hash_map.default_max_load_percentage);50 const TargetsTable = std.HashMapUnmanaged(TargetQuery.Index, void, TargetsTableContext, std.hash_map.default_max_load_percentage);
4951
50 const DepsTableContext = struct {52 const LengthPrefixedContext = struct {
51 extra: []const u32,53 extra: []const u32,
5254
53 pub fn eql(ctx: @This(), a: Deps, b: Deps) bool {55 pub fn eql(ctx: @This(), a: u32, b: u32) bool {
54 const len_a = ctx.extra[@intFromEnum(a)];56 const len_a = ctx.extra[a];
55 const len_b = ctx.extra[@intFromEnum(b)];57 const len_b = ctx.extra[b];
56 const slice_a = ctx.extra[@intFromEnum(a) + 1 ..][0..len_a];58 const slice_a = ctx.extra[a + 1 ..][0..len_a];
57 const slice_b = ctx.extra[@intFromEnum(b) + 1 ..][0..len_b];59 const slice_b = ctx.extra[b + 1 ..][0..len_b];
58 return std.mem.eql(u32, slice_a, slice_b);60 return std.mem.eql(u32, slice_a, slice_b);
59 }61 }
6062
61 pub fn hash(ctx: @This(), key: Deps) u64 {63 pub fn hash(ctx: @This(), key: u32) u64 {
62 const len = ctx.extra[@intFromEnum(key)];64 const len = ctx.extra[key];
63 const slice = ctx.extra[@intFromEnum(key) + 1 ..][0..len];65 const slice = ctx.extra[key + 1 ..][0..len];
64 return std.hash_map.hashString(@ptrCast(slice));66 return std.hash_map.hashString(@ptrCast(slice));
65 }67 }
66 };68 };
...@@ -174,6 +176,10 @@ pub const Wip = struct {...@@ -174,6 +176,10 @@ pub const Wip = struct {
174 return new_off;176 return new_off;
175 }177 }
176178
179 pub fn addOptionalString(wip: *Wip, bytes: ?[]const u8) Allocator.Error!OptionalString {
180 return .init(try addString(wip, bytes orelse return .none));
181 }
182
177 pub fn addSemVer(wip: *Wip, sv: std.SemanticVersion) Allocator.Error!String {183 pub fn addSemVer(wip: *Wip, sv: std.SemanticVersion) Allocator.Error!String {
178 var buffer: [256]u8 = undefined;184 var buffer: [256]u8 = undefined;
179 var writer: std.Io.Writer = .fixed(&buffer);185 var writer: std.Io.Writer = .fixed(&buffer);
...@@ -324,27 +330,32 @@ pub const Wip = struct {...@@ -324,27 +330,32 @@ pub const Wip = struct {
324 }330 }
325 }331 }
326332
327 pub fn prepareDeps(wip: *Wip, n: usize) Allocator.Error![]u32 {333 pub fn reserveLengthPrefixed(wip: *Wip, n: usize) Allocator.Error![]u32 {
328 const slice = try wip.extra.addManyAsSlice(wip.gpa, n + 1);334 const slice = try wip.extra.addManyAsSlice(wip.gpa, n + 1);
329 slice[0] = @intCast(n);335 slice[0] = @intCast(n);
330 return slice[1..];336 return slice[1..];
331 }337 }
332338
333 pub fn dedupeDeps(wip: *Wip, deps: Deps) Allocator.Error!Deps {339 pub fn dedupeLengthPrefixed(wip: *Wip, index: u32) Allocator.Error!u32 {
340 assert(wip.extra.items.len == index + wip.extra.items[index] + 1);
334 const gpa = wip.gpa;341 const gpa = wip.gpa;
335 const gop = try wip.deps_table.getOrPutContext(gpa, deps, @as(DepsTableContext, .{342 const gop = try wip.length_prefixed_table.getOrPutContext(gpa, index, @as(LengthPrefixedContext, .{
336 .extra = wip.extra.items,343 .extra = wip.extra.items,
337 }));344 }));
338 if (gop.found_existing) {345 if (gop.found_existing) {
339 wip.extra.items.len = @intFromEnum(deps);346 wip.extra.items.len = index;
340 return gop.key_ptr.*;347 return gop.key_ptr.*;
341 } else {348 } else {
342 return deps;349 return index;
343 }350 }
344 }351 }
345352
353 pub fn dedupeDeps(wip: *Wip, deps: Deps) Allocator.Error!Deps {
354 return @enumFromInt(try dedupeLengthPrefixed(wip, @intFromEnum(deps)));
355 }
356
346 pub fn addExtra(wip: *Wip, extra: anytype) Allocator.Error!u32 {357 pub fn addExtra(wip: *Wip, extra: anytype) Allocator.Error!u32 {
347 const extra_len = Storage.calculateExtraLenUpperBound(@TypeOf(extra));358 const extra_len = Storage.extraLen(extra);
348 try wip.extra.ensureUnusedCapacity(wip.gpa, extra_len);359 try wip.extra.ensureUnusedCapacity(wip.gpa, extra_len);
349 return addExtraAssumeCapacity(wip, extra);360 return addExtraAssumeCapacity(wip, extra);
350 }361 }
...@@ -397,7 +408,7 @@ pub const Step = extern struct {...@@ -397,7 +408,7 @@ pub const Step = extern struct {
397 owner: Package.Index,408 owner: Package.Index,
398 deps: Deps,409 deps: Deps,
399 max_rss: MaxRss,410 max_rss: MaxRss,
400 extended: Storage.ExtendedIndex(Flags, union(Tag) {411 extended: Storage.Extended(Flags, union(Tag) {
401 check_file: CheckFile,412 check_file: CheckFile,
402 check_object: CheckObject,413 check_object: CheckObject,
403 compile: Compile,414 compile: Compile,
...@@ -585,10 +596,10 @@ pub const Step = extern struct {...@@ -585,10 +596,10 @@ pub const Step = extern struct {
585 root_module: Module.Index,596 root_module: Module.Index,
586 root_name: String,597 root_name: String,
587598
588 //filters: FlagLengthPrefixedList(.flags, .filters_len, String),599 filters: Storage.FlagLengthPrefixedList(.flags, .filters_len, String),
589 //exec_cmd_args: FlagLengthPrefixedList(.flags, .exec_cmd_args_len, u32),600 exec_cmd_args: Storage.FlagLengthPrefixedList(.flags, .exec_cmd_args_len, OptionalString),
590 //installed_headers: FlagLengthPrefixedList(.flags, .installed_headers_len, InstalledHeader),601 installed_headers: Storage.FlagLengthPrefixedList(.flags, .installed_headers_len, Storage.Extended(InstalledHeader.Flags, InstalledHeader)),
591 //force_undefined_symbols: FlagLengthPrefixedList(.flags, .force_undefined_symbols_len, String),602 force_undefined_symbols: Storage.FlagLengthPrefixedList(.flags, .force_undefined_symbols_len, String),
592 //exacts: EnumConditionalPrefixedList(.flags4, .expect_errors, .exact, String),603 //exacts: EnumConditionalPrefixedList(.flags4, .expect_errors, .exact, String),
593 linker_script: Storage.FlagOptional(.flags4, .linker_script, LazyPath),604 linker_script: Storage.FlagOptional(.flags4, .linker_script, LazyPath),
594 version_script: Storage.FlagOptional(.flags4, .version_script, LazyPath),605 version_script: Storage.FlagOptional(.flags4, .version_script, LazyPath),
...@@ -612,6 +623,46 @@ pub const Step = extern struct {...@@ -612,6 +623,46 @@ pub const Step = extern struct {
612 error_limit: Storage.FlagOptional(.flags4, .error_limit, u32),623 error_limit: Storage.FlagOptional(.flags4, .error_limit, u32),
613 build_id: Storage.EnumOptional(.flags3, .build_id, .hexstring, String),624 build_id: Storage.EnumOptional(.flags3, .build_id, .hexstring, String),
614625
626 pub const InstalledHeader = union(@This().Tag) {
627 file: File,
628 directory: Directory,
629
630 pub const Flags = packed struct(u32) {
631 tag: InstalledHeader.Tag,
632 _: u24 = 0,
633 };
634
635 pub const Tag = enum(u8) {
636 file,
637 directory,
638 };
639
640 pub const File = struct {
641 flags: @This().Flags = .{},
642 source: LazyPath,
643 dest_sub_path: String,
644
645 pub const Flags = packed struct(u32) {
646 tag: InstalledHeader.Tag = .file,
647 _: u24 = 0,
648 };
649 };
650
651 pub const Directory = struct {
652 flags: @This().Flags,
653 source: LazyPath,
654 dest_sub_path: String,
655 exclude_extensions: Storage.FlagLengthPrefixedList(.flags, .exclude_extensions, String),
656 include_extensions: Storage.FlagLengthPrefixedList(.flags, .include_extensions, String),
657
658 pub const Flags = packed struct(u32) {
659 tag: InstalledHeader.Tag = .directory,
660 exclude_extensions: bool,
661 include_extensions: bool,
662 _: u22 = 0,
663 };
664 };
665 };
615 pub const ExpectErrors = enum(u3) { contains, exact, starts_with, stderr_contains, none };666 pub const ExpectErrors = enum(u3) { contains, exact, starts_with, stderr_contains, none };
616 pub const TestRunnerMode = enum(u2) { default, simple, server };667 pub const TestRunnerMode = enum(u2) { default, simple, server };
617 pub const Entry = enum(u2) { default, disabled, enabled, symbol_name };668 pub const Entry = enum(u2) { default, disabled, enabled, symbol_name };
...@@ -1636,6 +1687,7 @@ pub const Storage = enum {...@@ -1636,6 +1687,7 @@ pub const Storage = enum {
1636 flag_optional,1687 flag_optional,
1637 enum_optional,1688 enum_optional,
1638 extended,1689 extended,
1690 flag_length_prefixed_list,
16391691
1640 /// The presence of the field is determined by a boolean within a packed1692 /// The presence of the field is determined by a boolean within a packed
1641 /// struct.1693 /// struct.
...@@ -1674,16 +1726,7 @@ pub const Storage = enum {...@@ -1674,16 +1726,7 @@ pub const Storage = enum {
16741726
1675 /// The field indexes into an auxilary buffer, with the first element being1727 /// The field indexes into an auxilary buffer, with the first element being
1676 /// a packed struct that contains the tag.1728 /// a packed struct that contains the tag.
1677 pub fn Extended(comptime U: type) type {1729 pub fn Extended(comptime BaseFlags: type, comptime U: type) type {
1678 return struct {
1679 value: U,
1680
1681 pub const storage: Storage = .extended;
1682 };
1683 }
1684
1685 /// Equivalent to `Extended` but works in an `extern struct`.
1686 pub fn ExtendedIndex(comptime BaseFlags: type, comptime U: type) type {
1687 return enum(u32) {1730 return enum(u32) {
1688 _,1731 _,
16891732
...@@ -1699,6 +1742,30 @@ pub const Storage = enum {...@@ -1699,6 +1742,30 @@ pub const Storage = enum {
1699 };1742 };
1700 }1743 }
17011744
1745 /// A field in flags determines whether the length is zero or nonzero. If the length is
1746 /// nonzero, then there is a length field followed by the list.
1747 ///
1748 /// When deserializing, the slice field is set. When serializing, the index
1749 /// field must be set.
1750 pub fn FlagLengthPrefixedList(
1751 comptime flags_arg: @EnumLiteral(),
1752 comptime flag_arg: @EnumLiteral(),
1753 comptime ValueArg: type,
1754 ) type {
1755 return struct {
1756 slice: []const Value,
1757
1758 pub const storage: Storage = .flag_length_prefixed_list;
1759 pub const flags = flags_arg;
1760 pub const flag = flag_arg;
1761 pub const Value = ValueArg;
1762
1763 pub fn initErased(s: []const u32) @This() {
1764 return .{ .slice = @ptrCast(s) };
1765 }
1766 };
1767 }
1768
1702 pub fn dataLength(buffer: []const u32, i: usize, comptime S: type) usize {1769 pub fn dataLength(buffer: []const u32, i: usize, comptime S: type) usize {
1703 var end = i;1770 var end = i;
1704 _ = data(buffer, &end, S);1771 _ = data(buffer, &end, S);
...@@ -1769,6 +1836,15 @@ pub const Storage = enum {...@@ -1769,6 +1836,15 @@ pub const Storage = enum {
1769 };1836 };
1770 },1837 },
1771 .extended => @compileError("TODO"),1838 .extended => @compileError("TODO"),
1839 .flag_length_prefixed_list => {
1840 const flags = @field(container, @tagName(Field.flags));
1841 const flag = @field(flags, @tagName(Field.flag));
1842 if (!flag) return .{ .slice = &.{} };
1843 const data_start = i.* + 1;
1844 const len = buffer[data_start - 1];
1845 defer i.* = data_start + len;
1846 return .{ .slice = @ptrCast(buffer[data_start..][0..len]) };
1847 },
1772 },1848 },
1773 },1849 },
1774 .@"extern" => comptime unreachable,1850 .@"extern" => comptime unreachable,
...@@ -1787,11 +1863,36 @@ pub const Storage = enum {...@@ -1787,11 +1863,36 @@ pub const Storage = enum {
1787 return i;1863 return i;
1788 }1864 }
17891865
1790 fn calculateExtraLenUpperBound(comptime Extra: type) comptime_int {1866 fn extraFieldLen(field: anytype) usize {
1791 var i = 0;1867 const Field = @TypeOf(field);
1792 const fields = @typeInfo(Extra).@"struct".fields;1868 return switch (@typeInfo(Field)) {
1869 .int => |info| switch (info.bits) {
1870 32 => 1,
1871 64 => 2,
1872 else => comptime unreachable,
1873 },
1874 .@"enum" => 1,
1875 .@"struct" => |info| switch (info.layout) {
1876 .@"packed" => switch (info.backing_integer.?) {
1877 u32 => 1,
1878 u64 => 2,
1879 else => comptime unreachable,
1880 },
1881 .auto => switch (Field.storage) {
1882 .flag_optional, .enum_optional, .extended => 1,
1883 .flag_length_prefixed_list => field.slice.len + 1,
1884 },
1885 .@"extern" => comptime unreachable,
1886 },
1887 else => @compileError("bad type: " ++ @typeName(Field)),
1888 };
1889 }
1890
1891 fn extraLen(extra: anytype) usize {
1892 const fields = @typeInfo(@TypeOf(extra)).@"struct".fields;
1893 var i: usize = 0;
1793 inline for (fields) |field| {1894 inline for (fields) |field| {
1794 i += calculateExtraFieldLenUpperBound(field.type);1895 i += Storage.extraFieldLen(@field(extra, field.name));
1795 }1896 }
1796 return i;1897 return i;
1797 }1898 }
...@@ -1836,6 +1937,13 @@ pub const Storage = enum {...@@ -1836,6 +1937,13 @@ pub const Storage = enum {
1836 return if (value.value) |v| setExtraField(buffer, i, Field.Value, v) else 0;1937 return if (value.value) |v| setExtraField(buffer, i, Field.Value, v) else 0;
1837 },1938 },
1838 .extended => @compileError("TODO"),1939 .extended => @compileError("TODO"),
1940 .flag_length_prefixed_list => {
1941 const len: u32 = @intCast(value.slice.len);
1942 if (len == 0) return 0;
1943 buffer[i] = len;
1944 @memcpy(buffer[i + 1 ..][0..len], @as([]const u32, @ptrCast(value.slice)));
1945 return len + 1;
1946 },
1839 },1947 },
1840 },1948 },
1841 .@"extern" => comptime unreachable,1949 .@"extern" => comptime unreachable,
...@@ -1843,29 +1951,6 @@ pub const Storage = enum {...@@ -1843,29 +1951,6 @@ pub const Storage = enum {
1843 else => @compileError("bad field type: " ++ @typeName(Field)),1951 else => @compileError("bad field type: " ++ @typeName(Field)),
1844 }1952 }
1845 }1953 }
1846
1847 fn calculateExtraFieldLenUpperBound(comptime Field: type) comptime_int {
1848 return switch (@typeInfo(Field)) {
1849 .int => |info| switch (info.bits) {
1850 32 => 1,
1851 64 => 2,
1852 else => comptime unreachable,
1853 },
1854 .@"enum" => 1,
1855 .@"struct" => |info| switch (info.layout) {
1856 .@"packed" => switch (info.backing_integer.?) {
1857 u32 => 1,
1858 u64 => 2,
1859 else => comptime unreachable,
1860 },
1861 .auto => switch (Field.storage) {
1862 .flag_optional, .enum_optional, .extended => 1,
1863 },
1864 .@"extern" => comptime unreachable,
1865 },
1866 else => comptime unreachable,
1867 };
1868 }
1869};1954};
18701955
1871pub fn extraData(c: *const Configuration, comptime T: type, index: usize) T {1956pub fn extraData(c: *const Configuration, comptime T: type, index: usize) T {