| ... | ... | @@ -276,8 +276,12 @@ pub fn set(comptime T: type, dest: []T, value: T) void { |
| 276 | 276 | d.* = value; |
| 277 | 277 | } |
| 278 | 278 | |
| 279 | /// Generally, Zig users are encouraged to explicitly initialize all fields of a struct explicitly rather than using this function. |
| 280 | /// However, it is recognized that there are sometimes use cases for initializing all fields to a "zero" value. For example, when |
| 281 | /// interfacing with a C API where this practice is more common and relied upon. If you are performing code review and see this |
| 282 | /// function used, examine closely - it may be a code smell. |
| 279 | 283 | /// Zero initializes the type. |
| 280 | | /// This can be used to zero initialize a C-struct. |
| 284 | /// This can be used to zero initialize a any type for which it makes sense. Structs will be initialized recursively. |
| 281 | 285 | pub fn zeroes(comptime T: type) T { |
| 282 | 286 | switch (@typeInfo(T)) { |
| 283 | 287 | .ComptimeInt, .Int, .ComptimeFloat, .Float => { |
| ... | ... | @@ -295,7 +299,7 @@ pub fn zeroes(comptime T: type) T { |
| 295 | 299 | .Optional, .Null => { |
| 296 | 300 | return null; |
| 297 | 301 | }, |
| 298 | | .Struct => { |
| 302 | .Struct => |struct_info| { |
| 299 | 303 | if (@sizeOf(T) == 0) return T{}; |
| 300 | 304 | if (comptime meta.containerLayout(T) == .Extern) { |
| 301 | 305 | var item: T = undefined; |
| ... | ... | @@ -303,25 +307,23 @@ pub fn zeroes(comptime T: type) T { |
| 303 | 307 | return item; |
| 304 | 308 | } else { |
| 305 | 309 | var structure: T = undefined; |
| 306 | | comptime var field_i = 0; |
| 307 | | inline while (field_i < @memberCount(T)) : (field_i += 1) { |
| 308 | | @field(structure, @memberName(T, field_i)) = zeroes(@TypeOf(@field(structure, @memberName(T, field_i)))); |
| 310 | inline for (struct_info.fields) |field| { |
| 311 | @field(structure, field.name) = zeroes(@TypeOf(@field(structure, field.name))); |
| 309 | 312 | } |
| 310 | 313 | return structure; |
| 311 | 314 | } |
| 312 | 315 | }, |
| 313 | 316 | .Pointer => |ptr_info| { |
| 314 | | if (ptr_info.is_allowzero) { |
| 315 | | return null; |
| 316 | | } else { |
| 317 | | switch (ptr_info.size) { |
| 318 | | .Slice => { |
| 319 | | return &[_]ptr_info.child{}; |
| 320 | | }, |
| 321 | | .One, .Many, .C => { |
| 322 | | @compileError("Can't set a non nullable pointer to zero."); |
| 323 | | }, |
| 324 | | } |
| 317 | switch (ptr_info.size) { |
| 318 | .Slice => { |
| 319 | return &[_]ptr_info.child{}; |
| 320 | }, |
| 321 | .C => { |
| 322 | return null; |
| 323 | }, |
| 324 | .One, .Many => { |
| 325 | @compileError("Can't set a non nullable pointer to zero."); |
| 326 | }, |
| 325 | 327 | } |
| 326 | 328 | }, |
| 327 | 329 | .Array => |info| { |
| ... | ... | @@ -372,6 +374,7 @@ test "mem.zeroes" { |
| 372 | 374 | |
| 373 | 375 | const Pointers = struct { |
| 374 | 376 | optional: ?*u8, |
| 377 | c_pointer: [*c]u8, |
| 375 | 378 | slice: []u8, |
| 376 | 379 | }; |
| 377 | 380 | pointers: Pointers, |
| ... | ... | @@ -397,6 +400,7 @@ test "mem.zeroes" { |
| 397 | 400 | testing.expectEqual(@as(f32, 0), b.integral_types.float_32); |
| 398 | 401 | testing.expectEqual(@as(f64, 0), b.integral_types.float_64); |
| 399 | 402 | testing.expectEqual(@as(?*u8, null), b.pointers.optional); |
| 403 | testing.expectEqual(@as([*c]u8, null), b.pointers.c_pointer); |
| 400 | 404 | testing.expectEqual(@as([]u8, &[_]u8{}), b.pointers.slice); |
| 401 | 405 | for (b.array) |e| { |
| 402 | 406 | testing.expectEqual(@as(u32, 0), e); |