@@ -408,104 +408,179 @@ fn createChildOnly(
408
408
return child ;
409
409
}
410
410
411
- fn userInputOptionsFromArgs (allocator : Allocator , args : anytype ) UserInputOptionsMap {
412
- var user_input_options = UserInputOptionsMap .init (allocator );
411
+ fn userInputOptionsFromArgs (arena : Allocator , args : anytype ) UserInputOptionsMap {
412
+ var map = UserInputOptionsMap .init (arena );
413
413
inline for (@typeInfo (@TypeOf (args )).@"struct" .fields ) | field | {
414
- const v = @field (args , field .name );
415
- const T = @TypeOf (v );
416
- switch (T ) {
417
- Target .Query = > {
418
- user_input_options .put (field .name , .{
419
- .name = field .name ,
420
- .value = .{ .scalar = v .zigTriple (allocator ) catch @panic ("OOM" ) },
421
- .used = false ,
422
- }) catch @panic ("OOM" );
423
- user_input_options .put ("cpu" , .{
424
- .name = "cpu" ,
425
- .value = .{ .scalar = v .serializeCpuAlloc (allocator ) catch @panic ("OOM" ) },
426
- .used = false ,
427
- }) catch @panic ("OOM" );
428
- },
429
- ResolvedTarget = > {
430
- user_input_options .put (field .name , .{
431
- .name = field .name ,
432
- .value = .{ .scalar = v .query .zigTriple (allocator ) catch @panic ("OOM" ) },
433
- .used = false ,
434
- }) catch @panic ("OOM" );
435
- user_input_options .put ("cpu" , .{
436
- .name = "cpu" ,
437
- .value = .{ .scalar = v .query .serializeCpuAlloc (allocator ) catch @panic ("OOM" ) },
438
- .used = false ,
439
- }) catch @panic ("OOM" );
440
- },
441
- LazyPath = > {
442
- user_input_options .put (field .name , .{
414
+ if (field .type == @Type (.null )) continue ;
415
+ addUserInputOptionFromArg (arena , & map , field , field .type , @field (args , field .name ));
416
+ }
417
+ return map ;
418
+ }
419
+
420
+ fn addUserInputOptionFromArg (
421
+ arena : Allocator ,
422
+ map : * UserInputOptionsMap ,
423
+ field : std.builtin.Type.StructField ,
424
+ comptime T : type ,
425
+ /// If null, the value won't be added, but `T` will still be type-checked.
426
+ maybe_value : ? T ,
427
+ ) void {
428
+ switch (T ) {
429
+ Target .Query = > return if (maybe_value ) | v | {
430
+ map .put (field .name , .{
431
+ .name = field .name ,
432
+ .value = .{ .scalar = v .zigTriple (arena ) catch @panic ("OOM" ) },
433
+ .used = false ,
434
+ }) catch @panic ("OOM" );
435
+ map .put ("cpu" , .{
436
+ .name = "cpu" ,
437
+ .value = .{ .scalar = v .serializeCpuAlloc (arena ) catch @panic ("OOM" ) },
438
+ .used = false ,
439
+ }) catch @panic ("OOM" );
440
+ },
441
+ ResolvedTarget = > return if (maybe_value ) | v | {
442
+ map .put (field .name , .{
443
+ .name = field .name ,
444
+ .value = .{ .scalar = v .query .zigTriple (arena ) catch @panic ("OOM" ) },
445
+ .used = false ,
446
+ }) catch @panic ("OOM" );
447
+ map .put ("cpu" , .{
448
+ .name = "cpu" ,
449
+ .value = .{ .scalar = v .query .serializeCpuAlloc (arena ) catch @panic ("OOM" ) },
450
+ .used = false ,
451
+ }) catch @panic ("OOM" );
452
+ },
453
+ std .zig .BuildId = > return if (maybe_value ) | v | {
454
+ map .put (field .name , .{
455
+ .name = field .name ,
456
+ .value = .{ .scalar = std .fmt .allocPrint (arena , "{f}" , .{v }) catch @panic ("OOM" ) },
457
+ .used = false ,
458
+ }) catch @panic ("OOM" );
459
+ },
460
+ LazyPath = > return if (maybe_value ) | v | {
461
+ map .put (field .name , .{
462
+ .name = field .name ,
463
+ .value = .{ .lazy_path = v .dupeInner (arena ) },
464
+ .used = false ,
465
+ }) catch @panic ("OOM" );
466
+ },
467
+ []const LazyPath = > return if (maybe_value ) | v | {
468
+ var list = ArrayList (LazyPath ).initCapacity (arena , v .len ) catch @panic ("OOM" );
469
+ for (v ) | lp | list .appendAssumeCapacity (lp .dupeInner (arena ));
470
+ map .put (field .name , .{
471
+ .name = field .name ,
472
+ .value = .{ .lazy_path_list = list },
473
+ .used = false ,
474
+ }) catch @panic ("OOM" );
475
+ },
476
+ []const u8 = > return if (maybe_value ) | v | {
477
+ map .put (field .name , .{
478
+ .name = field .name ,
479
+ .value = .{ .scalar = arena .dupe (u8 , v ) catch @panic ("OOM" ) },
480
+ .used = false ,
481
+ }) catch @panic ("OOM" );
482
+ },
483
+ []const []const u8 = > return if (maybe_value ) | v | {
484
+ var list = ArrayList ([]const u8 ).initCapacity (arena , v .len ) catch @panic ("OOM" );
485
+ for (v ) | s | list .appendAssumeCapacity (arena .dupe (u8 , s ) catch @panic ("OOM" ));
486
+ map .put (field .name , .{
487
+ .name = field .name ,
488
+ .value = .{ .list = list },
489
+ .used = false ,
490
+ }) catch @panic ("OOM" );
491
+ },
492
+ else = > switch (@typeInfo (T )) {
493
+ .bool = > return if (maybe_value ) | v | {
494
+ map .put (field .name , .{
443
495
.name = field .name ,
444
- .value = .{ .lazy_path = v . dupeInner ( allocator ) },
496
+ .value = .{ .scalar = if ( v ) "true" else "false" },
445
497
.used = false ,
446
498
}) catch @panic ("OOM" );
447
499
},
448
- []const LazyPath = > {
449
- var list = ArrayList (LazyPath ).initCapacity (allocator , v .len ) catch @panic ("OOM" );
450
- for (v ) | lp | list .appendAssumeCapacity (lp .dupeInner (allocator ));
451
- user_input_options .put (field .name , .{
500
+ .@"enum" , .enum_literal = > return if (maybe_value ) | v | {
501
+ map .put (field .name , .{
452
502
.name = field .name ,
453
- .value = .{ .lazy_path_list = list },
503
+ .value = .{ .scalar = @tagName ( v ) },
454
504
.used = false ,
455
505
}) catch @panic ("OOM" );
456
506
},
457
- [] const u8 = > {
458
- user_input_options .put (field .name , .{
507
+ .comptime_int , .int = > return if ( maybe_value ) | v | {
508
+ map .put (field .name , .{
459
509
.name = field .name ,
460
- .value = .{ .scalar = v },
510
+ .value = .{ .scalar = std . fmt . allocPrint ( arena , "{d}" , .{ v }) catch @panic ( "OOM" ) },
461
511
.used = false ,
462
512
}) catch @panic ("OOM" );
463
513
},
464
- []const []const u8 = > {
465
- var list = ArrayList ([]const u8 ).initCapacity (allocator , v .len ) catch @panic ("OOM" );
466
- list .appendSliceAssumeCapacity (v );
467
-
468
- user_input_options .put (field .name , .{
514
+ .comptime_float , .float = > return if (maybe_value ) | v | {
515
+ map .put (field .name , .{
469
516
.name = field .name ,
470
- .value = .{ .list = list },
517
+ .value = .{ .scalar = std . fmt . allocPrint ( arena , "{x}" , .{ v }) catch @panic ( "OOM" ) },
471
518
.used = false ,
472
519
}) catch @panic ("OOM" );
473
520
},
474
- else = > switch (@typeInfo (T )) {
475
- .bool = > {
476
- user_input_options .put (field .name , .{
477
- .name = field .name ,
478
- .value = .{ .scalar = if (v ) "true" else "false" },
479
- .used = false ,
480
- }) catch @panic ("OOM" );
481
- },
482
- .@"enum" , .enum_literal = > {
483
- user_input_options .put (field .name , .{
484
- .name = field .name ,
485
- .value = .{ .scalar = @tagName (v ) },
486
- .used = false ,
487
- }) catch @panic ("OOM" );
521
+ .pointer = > | ptr_info | switch (ptr_info .size ) {
522
+ .one = > switch (@typeInfo (ptr_info .child )) {
523
+ .array = > | array_info | {
524
+ comptime var slice_info = ptr_info ;
525
+ slice_info .size = .slice ;
526
+ slice_info .is_const = true ;
527
+ slice_info .child = array_info .child ;
528
+ slice_info .sentinel_ptr = null ;
529
+ addUserInputOptionFromArg (
530
+ arena ,
531
+ map ,
532
+ field ,
533
+ @Type (.{ .pointer = slice_info }),
534
+ maybe_value orelse null ,
535
+ );
536
+ return ;
537
+ },
538
+ else = > {},
488
539
},
489
- .comptime_int , .int = > {
490
- user_input_options .put (field .name , .{
491
- .name = field .name ,
492
- .value = .{ .scalar = std .fmt .allocPrint (allocator , "{d}" , .{v }) catch @panic ("OOM" ) },
493
- .used = false ,
494
- }) catch @panic ("OOM" );
540
+ .slice = > switch (@typeInfo (ptr_info .child )) {
541
+ .@"enum" = > return if (maybe_value ) | v | {
542
+ var list = ArrayList ([]const u8 ).initCapacity (arena , v .len ) catch @panic ("OOM" );
543
+ for (v ) | tag | list .appendAssumeCapacity (@tagName (tag ));
544
+ map .put (field .name , .{
545
+ .name = field .name ,
546
+ .value = .{ .list = list },
547
+ .used = false ,
548
+ }) catch @panic ("OOM" );
549
+ },
550
+ else = > {
551
+ comptime var slice_info = ptr_info ;
552
+ slice_info .is_const = true ;
553
+ slice_info .sentinel_ptr = null ;
554
+ addUserInputOptionFromArg (
555
+ arena ,
556
+ map ,
557
+ field ,
558
+ @Type (.{ .pointer = slice_info }),
559
+ maybe_value orelse null ,
560
+ );
561
+ return ;
562
+ },
495
563
},
496
- .comptime_float , .float = > {
497
- user_input_options .put (field .name , .{
498
- .name = field .name ,
499
- .value = .{ .scalar = std .fmt .allocPrint (allocator , "{e}" , .{v }) catch @panic ("OOM" ) },
500
- .used = false ,
501
- }) catch @panic ("OOM" );
564
+ else = > {},
565
+ },
566
+ .null = > unreachable ,
567
+ .optional = > | info | switch (@typeInfo (info .child )) {
568
+ .optional = > {},
569
+ else = > {
570
+ addUserInputOptionFromArg (
571
+ arena ,
572
+ map ,
573
+ field ,
574
+ info .child ,
575
+ maybe_value orelse null ,
576
+ );
577
+ return ;
502
578
},
503
- else = > @compileError ("option '" ++ field .name ++ "' has unsupported type: " ++ @typeName (T )),
504
579
},
505
- }
580
+ else = > {},
581
+ },
506
582
}
507
-
508
- return user_input_options ;
583
+ @compileError ("option '" ++ field .name ++ "' has unsupported type: " ++ @typeName (field .type ));
509
584
}
510
585
511
586
const OrderedUserValue = union (enum ) {
0 commit comments