| ... | ... | @@ -431,34 +431,48 @@ pub fn zeroInit(comptime T: type, init: anytype) T { |
| 431 | 431 | .Struct => |struct_info| { |
| 432 | 432 | switch (@typeInfo(Init)) { |
| 433 | 433 | .Struct => |init_info| { |
| 434 | | var value = std.mem.zeroes(T); |
| 435 | | |
| 436 | | inline for (struct_info.fields) |field| { |
| 437 | | if (field.default_value) |default_value_ptr| { |
| 438 | | const default_value = @ptrCast(*align(1) const field.type, default_value_ptr).*; |
| 439 | | @field(value, field.name) = default_value; |
| 440 | | } |
| 441 | | } |
| 442 | | |
| 443 | 434 | if (init_info.is_tuple) { |
| 444 | | inline for (init_info.fields) |field, i| { |
| 445 | | @field(value, struct_info.fields[i].name) = @field(init, field.name); |
| 435 | if (init_info.fields.len > struct_info.fields.len) { |
| 436 | @compileError("Tuple initializer has more elments than there are fields in `" ++ @typeName(T) ++ "`"); |
| 437 | } |
| 438 | } else { |
| 439 | inline for (init_info.fields) |field| { |
| 440 | if (!@hasField(T, field.name)) { |
| 441 | @compileError("Encountered an initializer for `" ++ field.name ++ "`, but it is not a field of " ++ @typeName(T)); |
| 442 | } |
| 446 | 443 | } |
| 447 | | return value; |
| 448 | 444 | } |
| 449 | 445 | |
| 450 | | inline for (init_info.fields) |field| { |
| 451 | | if (!@hasField(T, field.name)) { |
| 452 | | @compileError("Encountered an initializer for `" ++ field.name ++ "`, but it is not a field of " ++ @typeName(T)); |
| 446 | var value: T = undefined; |
| 447 | |
| 448 | inline for (struct_info.fields) |field, i| { |
| 449 | if (field.is_comptime) { |
| 450 | continue; |
| 453 | 451 | } |
| 454 | 452 | |
| 455 | | switch (@typeInfo(field.type)) { |
| 456 | | .Struct => { |
| 457 | | @field(value, field.name) = zeroInit(field.type, @field(init, field.name)); |
| 458 | | }, |
| 459 | | else => { |
| 460 | | @field(value, field.name) = @field(init, field.name); |
| 461 | | }, |
| 453 | if (init_info.is_tuple and init_info.fields.len > i) { |
| 454 | @field(value, field.name) = @field(init, init_info.fields[i].name); |
| 455 | } else if (@hasField(@TypeOf(init), field.name)) { |
| 456 | switch (@typeInfo(field.type)) { |
| 457 | .Struct => { |
| 458 | @field(value, field.name) = zeroInit(field.type, @field(init, field.name)); |
| 459 | }, |
| 460 | else => { |
| 461 | @field(value, field.name) = @field(init, field.name); |
| 462 | }, |
| 463 | } |
| 464 | } else if (field.default_value) |default_value_ptr| { |
| 465 | const default_value = @ptrCast(*align(1) const field.type, default_value_ptr).*; |
| 466 | @field(value, field.name) = default_value; |
| 467 | } else { |
| 468 | switch (@typeInfo(field.type)) { |
| 469 | .Struct => { |
| 470 | @field(value, field.name) = std.mem.zeroInit(field.type, .{}); |
| 471 | }, |
| 472 | else => { |
| 473 | @field(value, field.name) = std.mem.zeroes(@TypeOf(@field(value, field.name))); |
| 474 | }, |
| 475 | } |
| 462 | 476 | } |
| 463 | 477 | } |
| 464 | 478 | |
| ... | ... | @@ -538,6 +552,24 @@ test "zeroInit" { |
| 538 | 552 | .foo = 69, |
| 539 | 553 | .bar = 420, |
| 540 | 554 | }, b); |
| 555 | |
| 556 | const Baz = struct { |
| 557 | foo: [:0]const u8 = "bar", |
| 558 | }; |
| 559 | |
| 560 | const baz1 = zeroInit(Baz, .{}); |
| 561 | try testing.expectEqual(Baz{}, baz1); |
| 562 | |
| 563 | const baz2 = zeroInit(Baz, .{ .foo = "zab" }); |
| 564 | try testing.expectEqualSlices(u8, "zab", baz2.foo); |
| 565 | |
| 566 | const NestedBaz = struct { |
| 567 | bbb: Baz, |
| 568 | }; |
| 569 | const nested_baz = zeroInit(NestedBaz, .{}); |
| 570 | try testing.expectEqual(NestedBaz{ |
| 571 | .bbb = Baz{}, |
| 572 | }, nested_baz); |
| 541 | 573 | } |
| 542 | 574 | |
| 543 | 575 | /// Compares two slices of numbers lexicographically. O(n). |