diff --git a/lib/compiler/configure_runner.zig b/lib/compiler/configure_runner.zig index 392f0a42c5..901b494713 100644 --- a/lib/compiler/configure_runner.zig +++ b/lib/compiler/configure_runner.zig @@ -239,7 +239,7 @@ const Serialize = struct { return gop.value_ptr.*; } - fn addOptionalLazyPath(s: *Serialize, lp: ?std.Build.LazyPath) !Configuration.OptionalLazyPath { + fn addOptionalLazyPathEnum(s: *Serialize, lp: ?std.Build.LazyPath) !Configuration.OptionalLazyPath { const wc = s.wc; return @enumFromInt(switch (lp orelse return .none) { .src_path => |src_path| i: { @@ -274,6 +274,18 @@ const Serialize = struct { }, }); } + + fn addOptionalLazyPath(s: *Serialize, lp: ?std.Build.LazyPath) !?Configuration.LazyPath { + return (try addOptionalLazyPathEnum(s, lp)).unwrap(); + } + + fn addOptionalSemVer(s: *Serialize, sem_ver: ?std.SemanticVersion) !?Configuration.String { + return if (sem_ver) |sv| try s.wc.addSemVer(sv) else null; + } + + fn addOptionalString(s: *Serialize, opt_slice: ?[]const u8) !?Configuration.String { + return if (opt_slice) |slice| try s.wc.addString(slice) else null; + } }; fn serialize(b: *std.Build, wc: *Configuration.Wip, writer: *Io.Writer) !void { @@ -416,9 +428,36 @@ fn serialize(b: *std.Build, wc: *Configuration.Wip, writer: *Io.Writer) !void { .error_limit = c.error_limit != null, .install_name = c.install_name != null, .entitlements = c.entitlements != null, + .expect_errors = if (c.expect_errors) |x| switch (x) { + .contains => .contains, + .exact => .exact, + .starts_with => .starts_with, + .stderr_contains => .stderr_contains, + } else .none, + .linker_script = c.linker_script != null, + .version_script = c.version_script != null, }, .root_module = try addModule(&s, c.root_module), .root_name = try wc.addString(c.name), + .linker_script = .{ .value = try s.addOptionalLazyPath(c.linker_script) }, + .version_script = .{ .value = try s.addOptionalLazyPath(c.version_script) }, + .zig_lib_dir = .{ .value = try s.addOptionalLazyPath(c.zig_lib_dir) }, + .libc_file = .{ .value = try s.addOptionalLazyPath(c.libc_file) }, + .win32_manifest = .{ .value = try s.addOptionalLazyPath(c.win32_manifest) }, + .win32_module_definition = .{ .value = try s.addOptionalLazyPath(c.win32_module_definition) }, + .entitlements = .{ .value = try s.addOptionalLazyPath(c.entitlements) }, + .version = .{ .value = try s.addOptionalSemVer(c.version) }, + .install_name = .{ .value = try s.addOptionalString(c.install_name) }, + .initial_memory = .{ .value = c.initial_memory }, + .max_memory = .{ .value = c.max_memory }, + .global_base = .{ .value = c.global_base }, + .image_base = .{ .value = c.image_base }, + .link_z_common_page_size = .{ .value = c.link_z_common_page_size }, + .link_z_max_page_size = .{ .value = c.link_z_max_page_size }, + .pagezero_size = .{ .value = c.pagezero_size }, + .stack_size = .{ .value = c.stack_size }, + .headerpad_size = .{ .value = c.headerpad_size }, + .error_limit = .{ .value = c.error_limit }, })); log.err("TODO serialize the trailing Compile step data", .{}); @@ -433,13 +472,13 @@ fn serialize(b: *std.Build, wc: *Configuration.Wip, writer: *Io.Writer) !void { }, .dest_dir = try addInstallDir(wc, ia.dest_dir), .dest_sub_path = try wc.addString(ia.dest_sub_path), - .emitted_bin = try s.addOptionalLazyPath(ia.emitted_bin), + .emitted_bin = try s.addOptionalLazyPathEnum(ia.emitted_bin), .implib_dir = try addInstallDir(wc, ia.implib_dir), - .emitted_implib = try s.addOptionalLazyPath(ia.emitted_implib), + .emitted_implib = try s.addOptionalLazyPathEnum(ia.emitted_implib), .pdb_dir = try addInstallDir(wc, ia.pdb_dir), - .emitted_pdb = try s.addOptionalLazyPath(ia.emitted_pdb), + .emitted_pdb = try s.addOptionalLazyPathEnum(ia.emitted_pdb), .h_dir = try addInstallDir(wc, ia.h_dir), - .emitted_h = try s.addOptionalLazyPath(ia.emitted_h), + .emitted_h = try s.addOptionalLazyPathEnum(ia.emitted_h), .artifact = stepIndex(&step_map, &ia.artifact.step), })); }, @@ -490,7 +529,7 @@ fn serialize(b: *std.Build, wc: *Configuration.Wip, writer: *Io.Writer) !void { }, .file_inputs_len = @intCast(run.file_inputs.items.len), .args_len = @intCast(run.argv.items.len), - .cwd = try s.addOptionalLazyPath(run.cwd), + .cwd = try s.addOptionalLazyPathEnum(run.cwd), .captured_stdout = captured_stdout, .captured_stderr = captured_stderr, })); @@ -565,8 +604,7 @@ fn addModule(s: *Serialize, m: *std.Build.Module) !Configuration.Module.Index { .frameworks = m.frameworks.entries.len != 0, .link_objects = m.link_objects.items.len != 0, .export_symbol_names = m.export_symbol_names.len != 0, - }, - .flags2 = .{ + .valgrind = .init(m.strip), .pic = .init(m.strip), .red_zone = .init(m.strip), @@ -577,7 +615,7 @@ fn addModule(s: *Serialize, m: *std.Build.Module) !Configuration.Module.Index { .no_builtin = .init(m.strip), }, .owner = try s.builderToPackage(m.owner), - .root_source_file = try s.addOptionalLazyPath(m.root_source_file), + .root_source_file = try s.addOptionalLazyPathEnum(m.root_source_file), .import_table = import_table, .resolved_target = try addOptionalResolvedTarget(wc, m.resolved_target), }))); diff --git a/lib/std/Build/Step/Compile.zig b/lib/std/Build/Step/Compile.zig index 0c1e3868f1..38c0b3d6f6 100644 --- a/lib/std/Build/Step/Compile.zig +++ b/lib/std/Build/Step/Compile.zig @@ -145,8 +145,8 @@ link_z_defs: bool = false, /// (Darwin) Install name for the dylib install_name: ?[]const u8 = null, -/// (Darwin) Path to entitlements file -entitlements: ?[]const u8 = null, +/// Must be passed in via `Options`. +entitlements: ?LazyPath = null, /// (Darwin) Size of the pagezero segment. pagezero_size: ?u64 = null, @@ -286,6 +286,8 @@ pub const Options = struct { win32_manifest: ?LazyPath = null, /// Win32 module definition file. win32_module_definition: ?LazyPath = null, + /// (Darwin) Path to entitlements file + entitlements: ?LazyPath = null, }; pub const Kind = std.Build.Configuration.Step.Compile.Kind; @@ -462,6 +464,11 @@ pub fn create(owner: *std.Build, options: Options) *Compile { } } + if (options.entitlements) |lp| { + compile.entitlements = lp.dupe(compile.step.owner); + lp.addStepDependencies(&compile.step); + } + if (compile.kind == .lib) { if (compile.linkage != null and compile.linkage.? == .static) { compile.out_lib_filename = compile.out_filename; diff --git a/lib/std/zig/Configuration.zig b/lib/std/zig/Configuration.zig index 0e40f0ce7e..6ae31958c6 100644 --- a/lib/std/zig/Configuration.zig +++ b/lib/std/zig/Configuration.zig @@ -205,9 +205,7 @@ pub const Wip = struct { null; const cpu_features_add_empty = q.cpu_features_add.isEmpty(); const cpu_features_sub_empty = q.cpu_features_sub.isEmpty(); - try wip.extra.ensureUnusedCapacity(gpa, @typeInfo(TargetQuery).@"struct".fields.len + 6 + - 2 * ((@sizeOf(std.Target.Cpu.Feature.Set) + 3) / 4)); - const result_index: TargetQuery.Index = @enumFromInt(wip.addExtraAssumeCapacity(@as(TargetQuery, .{ + const result_index: TargetQuery.Index = @enumFromInt(try wip.addExtra(@as(TargetQuery, .{ .flags = .{ .cpu_arch = .init(q.cpu_arch), .cpu_model = .init(q.cpu_model), @@ -218,19 +216,20 @@ pub const Wip = struct { .object_format = .init(q.ofmt), .os_version_min = .init(q.os_version_min), .os_version_max = .init(q.os_version_max), - .glibc_version = q.glibc_version != null, + .glibc_version = glibc_version != null, .android_api_level = q.android_api_level != null, - .dynamic_linker = q.dynamic_linker != null, + .dynamic_linker = dynamic_linker != null, }, + .cpu_features_add = .{ .value = if (cpu_features_add_empty) null else q.cpu_features_add }, + .cpu_features_sub = .{ .value = if (cpu_features_sub_empty) null else q.cpu_features_sub }, + .glibc_version = .{ .value = glibc_version }, + .android_api_level = .{ .value = q.android_api_level }, + .dynamic_linker = .{ .value = dynamic_linker }, }))); - if (!cpu_features_add_empty) wip.extra.appendSliceAssumeCapacity(@ptrCast(&q.cpu_features_add.ints)); - if (!cpu_features_sub_empty) wip.extra.appendSliceAssumeCapacity(@ptrCast(&q.cpu_features_sub.ints)); - wip.addExtraOptionalStringAssumeCapacity(cpu_name); - if (os_version_min) |v| wip.extra.appendAssumeCapacity(v); - if (os_version_max) |v| wip.extra.appendAssumeCapacity(v); - wip.addExtraOptionalStringAssumeCapacity(glibc_version); - if (q.android_api_level) |x| wip.extra.appendAssumeCapacity(x); - wip.addExtraOptionalStringAssumeCapacity(dynamic_linker); + std.log.err("TODO serialize more target query stuff", .{}); + _ = os_version_min; + _ = os_version_max; + _ = cpu_name; // Deduplicate. const gop = try wip.targets_table.getOrPutContext(gpa, result_index, @as(TargetsTableContext, .{ @@ -287,9 +286,7 @@ pub const Wip = struct { .semver, .linux, .hurd => .semver, .windows => .windows, }; - try wip.extra.ensureUnusedCapacity(gpa, @typeInfo(TargetQuery).@"struct".fields.len + 6 + - 2 * ((@sizeOf(std.Target.Cpu.Feature.Set) + 3) / 4)); - const result_index: TargetQuery.Index = @enumFromInt(wip.addExtraAssumeCapacity(@as(TargetQuery, .{ + const result_index: TargetQuery.Index = @enumFromInt(try wip.addExtra(@as(TargetQuery, .{ .flags = .{ .cpu_arch = .init(t.cpu.arch), .cpu_model = .explicit, @@ -304,14 +301,16 @@ pub const Wip = struct { .android_api_level = android_api_level != null, .dynamic_linker = dynamic_linker != null, }, + .cpu_features_add = .{ .value = if (cpu_features_add_empty) null else t.cpu.features }, + .cpu_features_sub = .{ .value = null }, + .glibc_version = .{ .value = glibc_version }, + .android_api_level = .{ .value = android_api_level }, + .dynamic_linker = .{ .value = dynamic_linker }, }))); - if (!cpu_features_add_empty) wip.extra.appendSliceAssumeCapacity(@ptrCast(&t.cpu.features.ints)); - wip.addExtraOptionalStringAssumeCapacity(cpu_name); - if (os_version_min) |v| wip.extra.appendAssumeCapacity(v); - if (os_version_max) |v| wip.extra.appendAssumeCapacity(v); - wip.addExtraOptionalStringAssumeCapacity(glibc_version); - if (android_api_level) |x| wip.extra.appendAssumeCapacity(x); - wip.addExtraOptionalStringAssumeCapacity(dynamic_linker); + std.log.err("TODO serialize more target stuff", .{}); + _ = cpu_name; + _ = os_version_min; + _ = os_version_max; // Deduplicate. const gop = try wip.targets_table.getOrPutContext(gpa, result_index, @as(TargetsTableContext, .{ @@ -345,17 +344,14 @@ pub const Wip = struct { } pub fn addExtra(wip: *Wip, extra: anytype) Allocator.Error!u32 { - const gpa = wip.gpa; - const fields = @typeInfo(@TypeOf(extra)).@"struct".fields; - try wip.extra.ensureUnusedCapacity(gpa, fields.len); + const extra_len = Storage.calculateExtraLenUpperBound(@TypeOf(extra)); + try wip.extra.ensureUnusedCapacity(wip.gpa, extra_len); return addExtraAssumeCapacity(wip, extra); } pub fn addExtraAssumeCapacity(wip: *Wip, extra: anytype) u32 { - const fields = @typeInfo(@TypeOf(extra)).@"struct".fields; const result: u32 = @intCast(wip.extra.items.len); - wip.extra.items.len += fields.len; - setExtra(wip, result, extra); + wip.extra.items.len = Storage.setExtra(wip.extra.allocatedSlice(), result, extra); return result; } @@ -363,21 +359,6 @@ pub const Wip = struct { const string = optional_string orelse return; wip.extra.appendAssumeCapacity(@intFromEnum(string)); } - - fn setExtra(wip: *Wip, index: usize, extra: anytype) void { - const fields = @typeInfo(@TypeOf(extra)).@"struct".fields; - var i = index; - inline for (fields) |field| { - comptime assert(@sizeOf(field.type) == @sizeOf(u32)); - wip.extra.items[i] = switch (@typeInfo(field.type)) { - .int => @field(extra, field.name), - .@"enum" => @intFromEnum(@field(extra, field.name)), - .@"struct" => @bitCast(@field(extra, field.name)), - else => @compileError("bad field type: " ++ @typeName(field.type)), - }; - i += 1; - } - } }; pub const SystemIntegration = extern struct { @@ -577,7 +558,7 @@ pub const Step = extern struct { }; /// Trailing: - /// * exact_match: String, // if expected_compile_errors is contains, starts_with, or stderr_contains + /// * exact_match: String, // if expect_errors is contains, starts_with, or stderr_contains /// * test_runner: LazyPath, // if test_runner_mode is not default pub const Compile = struct { flags: @This().Flags, @@ -588,36 +569,34 @@ pub const Step = extern struct { root_module: Module.Index, root_name: String, - trailing: Trailing(struct { - filters: FlagLengthPrefixedList(.flags, .filters_len, String), - exec_cmd_args: FlagLengthPrefixedList(.flags, .exec_cmd_args_len, u32), - installed_headers: FlagLengthPrefixedList(.flags, .installed_headers_len, InstalledHeader), - force_undefined_symbols: FlagLengthPrefixedList(.flags, .force_undefined_symbols_len, String), - exacts: EnumConditionalPrefixedList(.flags4, .expected_compile_errors, .exact, String), - linker_script: FlagOptional(.flags4, .linker_script, LazyPath), - version_script: FlagOptional(.flags4, .version_script, LazyPath), - zig_lib_dir: FlagOptional(.flags3, .zig_lib_dir, LazyPath), - libc_file: FlagOptional(.flags4, .libc_file, LazyPath), - win32_manifest: FlagOptional(.flags3, .win32_manifest, LazyPath), - win32_module_definition: FlagOptional(.flags3, .win32_module_definition, LazyPath), - entitlements: FlagOptional(.flags4, .entitlements, LazyPath), - version: FlagOptional(.flags3, .version, String), // semantic version string - entry: EnumOptional(.flags3, .entry, .symbol, String), - install_name: FlagOptional(.flags4, .install_name, String), - initial_memory: FlagOptional(.flags3, .initial_memory, u64), - max_memory: FlagOptional(.flags3, .max_memory, u64), - global_base: FlagOptional(.flags3, .global_base, u64), - image_base: FlagOptional(.flags3, .image_base, u64), - link_z_common_page_size: FlagOptional(.flags4, .link_z_common_page_size, u64), - link_z_max_page_size: FlagOptional(.flags4, .link_z_max_page_size, u64), - pagezero_size: FlagOptional(.flags4, .pagezero_size, u64), - stack_size: FlagOptional(.flags4, .stack_size, u64), - headerpad_size: FlagOptional(.flags4, .headerpad_size, u32), - error_limit: FlagOptional(.flags4, .error_limit, u32), - build_id: EnumOptional(.flags3, .build_id, .hexstring, Hexstring), - }), + //filters: FlagLengthPrefixedList(.flags, .filters_len, String), + //exec_cmd_args: FlagLengthPrefixedList(.flags, .exec_cmd_args_len, u32), + //installed_headers: FlagLengthPrefixedList(.flags, .installed_headers_len, InstalledHeader), + //force_undefined_symbols: FlagLengthPrefixedList(.flags, .force_undefined_symbols_len, String), + //exacts: EnumConditionalPrefixedList(.flags4, .expect_errors, .exact, String), + linker_script: Storage.FlagOptional(.flags4, .linker_script, LazyPath), + version_script: Storage.FlagOptional(.flags4, .version_script, LazyPath), + zig_lib_dir: Storage.FlagOptional(.flags3, .zig_lib_dir, LazyPath), + libc_file: Storage.FlagOptional(.flags4, .libc_file, LazyPath), + win32_manifest: Storage.FlagOptional(.flags3, .win32_manifest, LazyPath), + win32_module_definition: Storage.FlagOptional(.flags3, .win32_module_definition, LazyPath), + entitlements: Storage.FlagOptional(.flags4, .entitlements, LazyPath), + version: Storage.FlagOptional(.flags3, .version, String), // semantic version string + //entry: EnumOptional(.flags3, .entry, .symbol, String), + install_name: Storage.FlagOptional(.flags4, .install_name, String), + initial_memory: Storage.FlagOptional(.flags3, .initial_memory, u64), + max_memory: Storage.FlagOptional(.flags3, .max_memory, u64), + global_base: Storage.FlagOptional(.flags3, .global_base, u64), + image_base: Storage.FlagOptional(.flags3, .image_base, u64), + link_z_common_page_size: Storage.FlagOptional(.flags4, .link_z_common_page_size, u64), + link_z_max_page_size: Storage.FlagOptional(.flags4, .link_z_max_page_size, u64), + pagezero_size: Storage.FlagOptional(.flags4, .pagezero_size, u64), + stack_size: Storage.FlagOptional(.flags4, .stack_size, u64), + headerpad_size: Storage.FlagOptional(.flags4, .headerpad_size, u32), + error_limit: Storage.FlagOptional(.flags4, .error_limit, u32), + //build_id: EnumOptional(.flags3, .build_id, .hexstring, Hexstring), - pub const ExpectedCompileErrors = enum(u3) { contains, exact, starts_with, stderr_contains, none }; + pub const ExpectErrors = enum(u3) { contains, exact, starts_with, stderr_contains, none }; pub const TestRunnerMode = enum(u2) { default, simple, server }; pub const Entry = enum(u2) { default, disabled, enabled, symbol_name }; @@ -803,7 +782,7 @@ pub const Step = extern struct { error_limit: bool, install_name: bool, entitlements: bool, - expected_compile_errors: ExpectedCompileErrors, + expect_errors: ExpectErrors, linker_script: bool, version_script: bool, _: u18 = 0, @@ -833,6 +812,13 @@ pub const MaxRss = enum(u32) { pub const OptionalLazyPath = enum(u32) { none = maxInt(u32), _, + + pub fn unwrap(this: @This()) ?LazyPath { + return switch (this) { + .none => null, + else => @enumFromInt(@intFromEnum(this)), + }; + } }; /// An index into `extra`. @@ -909,7 +895,6 @@ pub const Package = struct { /// * link_objects: UnionList(LinkObject), // if flag is set pub const Module = struct { flags: Flags, - flags2: Flags2, owner: Package.Index, root_source_file: OptionalLazyPath, import_table: ImportTable, @@ -979,7 +964,7 @@ pub const Module = struct { _, }; - pub const Flags = packed struct(u32) { + pub const Flags = packed struct(u64) { optimize: Optimize, strip: DefaultingBool, unwind_tables: UnwindTables, @@ -998,9 +983,7 @@ pub const Module = struct { frameworks: bool, link_objects: bool, export_symbol_names: bool, - }; - pub const Flags2 = packed struct(u32) { valgrind: DefaultingBool, pic: DefaultingBool, red_zone: DefaultingBool, @@ -1257,20 +1240,20 @@ pub const ResolvedTarget = struct { }; }; -/// Trailing: -/// * cpu_features_add: std.Target.Feature.Set, // if flag set -/// * cpu_features_sub: std.Target.Feature.Set, // if flag set -/// * cpu_name: String, // if cpu_model is explicit -/// * os_version_min: WindowsVersion // if os_version_min is windows -/// * os_version_min: String // if os_version_min is semver -/// * os_version_max: WindowsVersion // if os_version_max is windows -/// * os_version_max: String // if os_version_max is semver -/// * glibc_version: String, // if flag is set -/// * android_api_level: u32, // if flag is set -/// * dynamic_linker: String, // if flag is set pub const TargetQuery = struct { flags: Flags, + cpu_features_add: Storage.FlagOptional(.flags, .cpu_features_add, std.Target.Cpu.Feature.Set), + cpu_features_sub: Storage.FlagOptional(.flags, .cpu_features_sub, std.Target.Cpu.Feature.Set), + //cpu_name: Storage.EnumOptional(.flags, .cpu_name, .explicit, String), + //os_version_min: Storage.EnumOptional(.flags, .os_version_min, .windows, WindowsVersion), + //os_version_min: Storage.EnumOptional(.flags, .os_version_min, .semver, String), + //os_version_max: Storage.EnumOptional(.flags, .os_version_max, .windows, WindowsVersion), + //os_version_max: Storage.EnumOptional(.flags, .os_version_max, .semver, String), + glibc_version: Storage.FlagOptional(.flags, .glibc_version, String), + android_api_level: Storage.FlagOptional(.flags, .android_api_level, u32), + dynamic_linker: Storage.FlagOptional(.flags, .dynamic_linker, String), + pub const Index = enum(u32) { _, @@ -1279,24 +1262,7 @@ pub const TargetQuery = struct { } pub fn length(i: Index, extra: []const u32) usize { - //const flags = getExtra(extra, @intFromEnum(i), TargetQuery).flags; - const flags: Flags = @bitCast(extra[@intFromEnum(i)]); - const feature_set_size: usize = (@sizeOf(std.Target.Cpu.Feature.Set) + 3) / 4; - return @typeInfo(TargetQuery).@"struct".fields.len + - (if (flags.cpu_features_add) feature_set_size else 0) + - (if (flags.cpu_features_sub) feature_set_size else 0) + - @intFromBool(flags.cpu_model == .explicit) + - @as(usize, switch (flags.os_version_min) { - .semver, .windows => 1, - else => 0, - }) + - @as(usize, switch (flags.os_version_max) { - .semver, .windows => 1, - else => 0, - }) + - @intFromBool(flags.glibc_version) + - @intFromBool(flags.android_api_level) + - @intFromBool(flags.dynamic_linker); + return Storage.dataLength(extra, @intFromEnum(i), TargetQuery); } }; @@ -1528,21 +1494,186 @@ pub const TargetQuery = struct { }; }; -pub fn extraData(c: *const Configuration, comptime T: type, index: usize) T { - const extra = c.extra; - var i: usize = index; - var result: T = undefined; - inline for (@typeInfo(T).@"struct".fields) |field| { - comptime assert(@sizeOf(field.type) == @sizeOf(u32)); - @field(result, field.name) = switch (@typeInfo(field.type)) { - .int => extra[i], - .@"enum" => @enumFromInt(extra[i]), - .@"struct" => @bitCast(extra[i]), +pub const Storage = enum { + flag_optional, + + pub fn FlagOptional( + comptime flags_arg: @EnumLiteral(), + comptime flag_arg: @EnumLiteral(), + comptime ValueArg: type, + ) type { + return struct { + value: ?Value, + + pub const flags = flags_arg; + pub const flag = flag_arg; + pub const storage: Storage = .flag_optional; + pub const Value = ValueArg; + }; + } + + pub fn dataLength(buffer: []const u32, i: usize, comptime S: type) usize { + var end = i; + _ = data(buffer, &end, S); + return end - i; + } + + pub fn data(buffer: []const u32, i: *usize, comptime S: type) S { + var result: S = undefined; + const fields = @typeInfo(S).@"struct".fields; + inline for (fields) |field| { + @field(result, field.name) = dataField(buffer, i, &result, field.type); + } + return result; + } + + fn dataField(buffer: []const u32, i: *usize, container: anytype, comptime Field: type) Field { + switch (@typeInfo(Field)) { + .int => |info| switch (info.bits) { + 32 => { + defer i.* += 1; + return buffer[i.*]; + }, + 64 => { + defer i.* += 2; + return buffer[i.*..][0..2].*; + }, + else => comptime unreachable, + }, + .@"enum" => { + defer i.* += 1; + return @enumFromInt(buffer[i.*]); + }, + .@"struct" => |info| switch (info.layout) { + .@"packed" => switch (info.backing_integer.?) { + u32 => { + defer i.* += 1; + return @bitCast(buffer[i.*]); + }, + u64 => { + defer i.* += 2; + return @bitCast(buffer[i.*..][0..2].*); + }, + else => comptime unreachable, + }, + .auto => switch (Field) { + std.Target.Cpu.Feature.Set => { + const u32_count = (Field.usize_count * @sizeOf(usize)) / @sizeOf(u32); + defer i.* += u32_count; + return .{ .ints = @as( + *align(@alignOf(u32)) const [Field.usize_count]usize, + @ptrCast(buffer[i.*..][0..u32_count]), + ).* }; + }, + else => switch (Field.storage) { + .flag_optional => { + const flags = @field(container, @tagName(Field.flags)); + const flag = @field(flags, @tagName(Field.flag)); + return .{ + .value = if (flag) dataField(buffer, i, container, Field.Value) else null, + }; + }, + }, + }, + .@"extern" => comptime unreachable, + }, + else => comptime unreachable, + } + } + + /// Returns new end index. + fn setExtra(buffer: []u32, index: usize, extra: anytype) usize { + const fields = @typeInfo(@TypeOf(extra)).@"struct".fields; + var i = index; + inline for (fields) |field| { + i += setExtraField(buffer, i, field.type, @field(extra, field.name)); + } + return i; + } + + fn calculateExtraLenUpperBound(comptime Extra: type) comptime_int { + var i = 0; + const fields = @typeInfo(Extra).@"struct".fields; + inline for (fields) |field| { + i += calculateExtraFieldLenUpperBound(field.type); + } + return i; + } + + inline fn setExtraField(buffer: []u32, i: usize, comptime Field: type, value: anytype) usize { + switch (@typeInfo(Field)) { + .int => |info| switch (info.bits) { + 32 => { + buffer[i] = value; + return 1; + }, + 64 => { + buffer[i..][0..2].* = @bitCast(value); + return 2; + }, + else => comptime unreachable, + }, + .@"enum" => { + buffer[i] = @intFromEnum(value); + return 1; + }, + .@"struct" => |info| switch (info.layout) { + .@"packed" => switch (info.backing_integer.?) { + u32 => { + buffer[i] = @bitCast(value); + return 1; + }, + u64 => { + buffer[i..][0..2].* = @bitCast(value); + return 2; + }, + else => comptime unreachable, + }, + .auto => switch (Field) { + std.Target.Cpu.Feature.Set => { + const casted: []const u32 = @ptrCast(&value.ints); + @memcpy(buffer[i..][0..casted.len], casted); + return casted.len; + }, + else => switch (Field.storage) { + .flag_optional => { + return if (value.value) |v| setExtraField(buffer, i, Field.Value, v) else 0; + }, + }, + }, + .@"extern" => comptime unreachable, + }, + else => @compileError("bad field type: " ++ @typeName(Field)), + } + } + + fn calculateExtraFieldLenUpperBound(comptime Field: type) comptime_int { + return switch (@typeInfo(Field)) { + .int => |info| switch (info.bits) { + 32 => 1, + 64 => 2, + else => comptime unreachable, + }, + .@"enum" => 1, + .@"struct" => |info| switch (info.layout) { + .@"packed" => switch (info.backing_integer.?) { + u32 => 1, + u64 => 2, + else => comptime unreachable, + }, + .auto => switch (Field.storage) { + .flag_optional => 1, + }, + .@"extern" => comptime unreachable, + }, else => comptime unreachable, }; - i += 1; } - return result; +}; + +pub fn extraData(c: *const Configuration, comptime T: type, index: usize) T { + var i: usize = index; + return Storage.data(c.extra, &i, T); } pub const LoadFileError = Io.File.Reader.Error || Allocator.Error || error{EndOfStream};