Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

std.Build: support passing optionals to dependency args #21928

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
43 changes: 23 additions & 20 deletions lib/std/Build.zig
Original file line number Diff line number Diff line change
Expand Up @@ -409,45 +409,48 @@ fn createChildOnly(
}

fn userInputOptionsFromArgs(allocator: Allocator, args: anytype) UserInputOptionsMap {
var user_input_options = UserInputOptionsMap.init(allocator);
var user_input_options: UserInputOptionsMap = .init(allocator);
inline for (@typeInfo(@TypeOf(args)).@"struct".fields) |field| {
const v = @field(args, field.name);
const T = @TypeOf(v);
switch (T) {
const maybe_value = @field(args, field.name);
const given, const value = switch (@typeInfo(@TypeOf(maybe_value))) {
.optional => if (maybe_value) |v| .{ true, v } else .{ false, undefined },
else => .{ true, maybe_value },
};
if (given) switch (@TypeOf(value)) {
Comment on lines 413 to +419

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I feel like this is an odd pattern to assign a seperate boolean for the sole purpose of determining whether or not to skip this iteration of the inline loop on the next line.

Could it be replaced with this:

inline for (@typeInfo(@TypeOf(args)).@"struct".fields) |field| blk: {
    const maybe_value = @field(args, field.name);
    const value = switch (@typeInfo(@TypeOf(maybe_value))) {
        .optional => maybe_value orelse break :blk,
        else => maybe_value,
    };
    switch (@TypeOf(value)) {
        ...

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also, what should the behavior be when just specifying null instead of something like @as(?std.builtin.OptimizeMode, null) as in your example? With both my suggested change and your current code, I believe this would just be a compile error (null has it's own type; it's not covered by the .optional case). I think it may be better to just treat plain null as not specified to be consistent with optionals.

Example fix:

inline for (@typeInfo(@TypeOf(args)).@"struct".fields) |field| blk: {
    const maybe_value = @field(args, field.name);
    const value = switch (@typeInfo(@TypeOf(maybe_value))) {
        .optional => maybe_value orelse break :blk,
        .null => break :blk,    // <-- Note this added case
        else => maybe_value,
    };
    switch (@TypeOf(value)) {
        ...

Target.Query => {
user_input_options.put(field.name, .{
.name = field.name,
.value = .{ .scalar = v.zigTriple(allocator) catch @panic("OOM") },
.value = .{ .scalar = value.zigTriple(allocator) catch @panic("OOM") },
.used = false,
}) catch @panic("OOM");
user_input_options.put("cpu", .{
.name = "cpu",
.value = .{ .scalar = v.serializeCpuAlloc(allocator) catch @panic("OOM") },
.value = .{ .scalar = value.serializeCpuAlloc(allocator) catch @panic("OOM") },
.used = false,
}) catch @panic("OOM");
},
ResolvedTarget => {
user_input_options.put(field.name, .{
.name = field.name,
.value = .{ .scalar = v.query.zigTriple(allocator) catch @panic("OOM") },
.value = .{ .scalar = value.query.zigTriple(allocator) catch @panic("OOM") },
.used = false,
}) catch @panic("OOM");
user_input_options.put("cpu", .{
.name = "cpu",
.value = .{ .scalar = v.query.serializeCpuAlloc(allocator) catch @panic("OOM") },
.value = .{ .scalar = value.query.serializeCpuAlloc(allocator) catch @panic("OOM") },
.used = false,
}) catch @panic("OOM");
},
LazyPath => {
user_input_options.put(field.name, .{
.name = field.name,
.value = .{ .lazy_path = v.dupeInner(allocator) },
.value = .{ .lazy_path = value.dupeInner(allocator) },
.used = false,
}) catch @panic("OOM");
},
[]const LazyPath => {
var list = ArrayList(LazyPath).initCapacity(allocator, v.len) catch @panic("OOM");
for (v) |lp| list.appendAssumeCapacity(lp.dupeInner(allocator));
var list = ArrayList(LazyPath).initCapacity(allocator, value.len) catch @panic("OOM");
for (value) |lp| list.appendAssumeCapacity(lp.dupeInner(allocator));
user_input_options.put(field.name, .{
.name = field.name,
.value = .{ .lazy_path_list = list },
Expand All @@ -457,52 +460,52 @@ fn userInputOptionsFromArgs(allocator: Allocator, args: anytype) UserInputOption
[]const u8 => {
user_input_options.put(field.name, .{
.name = field.name,
.value = .{ .scalar = v },
.value = .{ .scalar = value },
.used = false,
}) catch @panic("OOM");
},
[]const []const u8 => {
var list = ArrayList([]const u8).initCapacity(allocator, v.len) catch @panic("OOM");
list.appendSliceAssumeCapacity(v);
var list = ArrayList([]const u8).initCapacity(allocator, value.len) catch @panic("OOM");
list.appendSliceAssumeCapacity(value);

user_input_options.put(field.name, .{
.name = field.name,
.value = .{ .list = list },
.used = false,
}) catch @panic("OOM");
},
else => switch (@typeInfo(T)) {
else => |T| switch (@typeInfo(T)) {
.bool => {
user_input_options.put(field.name, .{
.name = field.name,
.value = .{ .scalar = if (v) "true" else "false" },
.value = .{ .scalar = if (value) "true" else "false" },
.used = false,
}) catch @panic("OOM");
},
.@"enum", .enum_literal => {
user_input_options.put(field.name, .{
.name = field.name,
.value = .{ .scalar = @tagName(v) },
.value = .{ .scalar = @tagName(value) },
.used = false,
}) catch @panic("OOM");
},
.comptime_int, .int => {
user_input_options.put(field.name, .{
.name = field.name,
.value = .{ .scalar = std.fmt.allocPrint(allocator, "{d}", .{v}) catch @panic("OOM") },
.value = .{ .scalar = std.fmt.allocPrint(allocator, "{d}", .{value}) catch @panic("OOM") },
.used = false,
}) catch @panic("OOM");
},
.comptime_float, .float => {
user_input_options.put(field.name, .{
.name = field.name,
.value = .{ .scalar = std.fmt.allocPrint(allocator, "{e}", .{v}) catch @panic("OOM") },
.value = .{ .scalar = std.fmt.allocPrint(allocator, "{e}", .{value}) catch @panic("OOM") },
.used = false,
}) catch @panic("OOM");
},
else => @compileError("option '" ++ field.name ++ "' has unsupported type: " ++ @typeName(T)),
},
}
};
}

return user_input_options;
Expand Down
Loading