| ... | @@ -199,7 +199,7 @@ const AvailableOption = struct { | ... | @@ -199,7 +199,7 @@ const AvailableOption = struct { |
| 199 | name: []const u8, | 199 | name: []const u8, |
| 200 | type_id: TypeId, | 200 | type_id: TypeId, |
| 201 | description: []const u8, | 201 | description: []const u8, |
| 202 | /// If the `type_id` is `enum` this provides the list of enum options | 202 | /// If the `type_id` is `enum` or `enum_list` this provides the list of enum options |
| 203 | enum_options: ?[]const []const u8, | 203 | enum_options: ?[]const []const u8, |
| 204 | }; | 204 | }; |
| 205 | | 205 | |
| ... | @@ -221,6 +221,7 @@ const TypeId = enum { | ... | @@ -221,6 +221,7 @@ const TypeId = enum { |
| 221 | int, | 221 | int, |
| 222 | float, | 222 | float, |
| 223 | @"enum", | 223 | @"enum", |
| | 224 | enum_list, |
| 224 | string, | 225 | string, |
| 225 | list, | 226 | list, |
| 226 | build_id, | 227 | build_id, |
| ... | @@ -1084,8 +1085,9 @@ pub fn option(b: *Build, comptime T: type, name_raw: []const u8, description_raw | ... | @@ -1084,8 +1085,9 @@ pub fn option(b: *Build, comptime T: type, name_raw: []const u8, description_raw |
| 1084 | const name = b.dupe(name_raw); | 1085 | const name = b.dupe(name_raw); |
| 1085 | const description = b.dupe(description_raw); | 1086 | const description = b.dupe(description_raw); |
| 1086 | const type_id = comptime typeToEnum(T); | 1087 | const type_id = comptime typeToEnum(T); |
| 1087 | const enum_options = if (type_id == .@"enum") blk: { | 1088 | const enum_options = if (type_id == .@"enum" or type_id == .enum_list) blk: { |
| 1088 | const fields = comptime std.meta.fields(T); | 1089 | const EnumType = if (type_id == .enum_list) @typeInfo(T).Pointer.child else T; |
| | 1090 | const fields = comptime std.meta.fields(EnumType); |
| 1089 | var options = ArrayList([]const u8).initCapacity(b.allocator, fields.len) catch @panic("OOM"); | 1091 | var options = ArrayList([]const u8).initCapacity(b.allocator, fields.len) catch @panic("OOM"); |
| 1090 | | 1092 | |
| 1091 | inline for (fields) |field| { | 1093 | inline for (fields) |field| { |
| ... | @@ -1229,6 +1231,38 @@ pub fn option(b: *Build, comptime T: type, name_raw: []const u8, description_raw | ... | @@ -1229,6 +1231,38 @@ pub fn option(b: *Build, comptime T: type, name_raw: []const u8, description_raw |
| 1229 | }, | 1231 | }, |
| 1230 | .list => |lst| return lst.items, | 1232 | .list => |lst| return lst.items, |
| 1231 | }, | 1233 | }, |
| | 1234 | .enum_list => switch (option_ptr.value) { |
| | 1235 | .flag, .map => { |
| | 1236 | log.err("Expected -D{s} to be a list, but received a {s}.", .{ |
| | 1237 | name, @tagName(option_ptr.value), |
| | 1238 | }); |
| | 1239 | b.markInvalidUserInput(); |
| | 1240 | return null; |
| | 1241 | }, |
| | 1242 | .scalar => |s| { |
| | 1243 | const Child = @typeInfo(T).Pointer.child; |
| | 1244 | const value = std.meta.stringToEnum(Child, s) orelse { |
| | 1245 | log.err("Expected -D{s} to be of type {s}.", .{ name, @typeName(Child) }); |
| | 1246 | b.markInvalidUserInput(); |
| | 1247 | return null; |
| | 1248 | }; |
| | 1249 | return b.allocator.dupe(Child, &[_]Child{value}) catch @panic("OOM"); |
| | 1250 | }, |
| | 1251 | .list => |lst| { |
| | 1252 | const Child = @typeInfo(T).Pointer.child; |
| | 1253 | var new_list = b.allocator.alloc(Child, lst.items.len) catch @panic("OOM"); |
| | 1254 | for (lst.items, 0..) |str, i| { |
| | 1255 | const value = std.meta.stringToEnum(Child, str) orelse { |
| | 1256 | log.err("Expected -D{s} to be of type {s}.", .{ name, @typeName(Child) }); |
| | 1257 | b.markInvalidUserInput(); |
| | 1258 | b.allocator.free(new_list); |
| | 1259 | return null; |
| | 1260 | }; |
| | 1261 | new_list[i] = value; |
| | 1262 | } |
| | 1263 | return new_list; |
| | 1264 | }, |
| | 1265 | }, |
| 1232 | } | 1266 | } |
| 1233 | } | 1267 | } |
| 1234 | | 1268 | |
| ... | @@ -1487,11 +1521,15 @@ fn typeToEnum(comptime T: type) TypeId { | ... | @@ -1487,11 +1521,15 @@ fn typeToEnum(comptime T: type) TypeId { |
| 1487 | .Float => .float, | 1521 | .Float => .float, |
| 1488 | .Bool => .bool, | 1522 | .Bool => .bool, |
| 1489 | .Enum => .@"enum", | 1523 | .Enum => .@"enum", |
| 1490 | else => switch (T) { | 1524 | .Pointer => |pointer| switch (pointer.child) { |
| 1491 | []const u8 => .string, | 1525 | u8 => .string, |
| 1492 | []const []const u8 => .list, | 1526 | []const u8 => .list, |
| 1493 | else => @compileError("Unsupported type: " ++ @typeName(T)), | 1527 | else => switch (@typeInfo(pointer.child)) { |
| | 1528 | .Enum => .enum_list, |
| | 1529 | else => @compileError("Unsupported type: " ++ @typeName(T)), |
| | 1530 | }, |
| 1494 | }, | 1531 | }, |
| | 1532 | else => @compileError("Unsupported type: " ++ @typeName(T)), |
| 1495 | }, | 1533 | }, |
| 1496 | }; | 1534 | }; |
| 1497 | } | 1535 | } |