Commit f7aa4f5280

Bas van den Berg <BarabasGitHub@users.noreply.github.com>
2020-02-24 22:15:04
Processed review comments. Updated documentation, used the typinfo for field access, generate compile error on allowzero and set C poitners to null
1 parent 195195d
Changed files (1)
lib
lib/std/mem.zig
@@ -276,8 +276,12 @@ pub fn set(comptime T: type, dest: []T, value: T) void {
         d.* = value;
 }
 
+/// Generally, Zig users are encouraged to explicitly initialize all fields of a struct explicitly rather than using this function.
+/// However, it is recognized that there are sometimes use cases for initializing all fields to a "zero" value. For example, when
+/// interfacing with a C API where this practice is more common and relied upon. If you are performing code review and see this
+/// function used, examine closely - it may be a code smell.
 /// Zero initializes the type.
-/// This can be used to zero initialize a C-struct.
+/// This can be used to zero initialize a any type for which it makes sense. Structs will be initialized recursively.
 pub fn zeroes(comptime T: type) T {
     switch (@typeInfo(T)) {
         .ComptimeInt, .Int, .ComptimeFloat, .Float => {
@@ -295,7 +299,7 @@ pub fn zeroes(comptime T: type) T {
         .Optional, .Null => {
             return null;
         },
-        .Struct => {
+        .Struct => |struct_info| {
             if (@sizeOf(T) == 0) return T{};
             if (comptime meta.containerLayout(T) == .Extern) {
                 var item: T = undefined;
@@ -303,25 +307,23 @@ pub fn zeroes(comptime T: type) T {
                 return item;
             } else {
                 var structure: T = undefined;
-                comptime var field_i = 0;
-                inline while (field_i < @memberCount(T)) : (field_i += 1) {
-                    @field(structure, @memberName(T, field_i)) = zeroes(@TypeOf(@field(structure, @memberName(T, field_i))));
+                inline for (struct_info.fields) |field| {
+                    @field(structure, field.name) = zeroes(@TypeOf(@field(structure, field.name)));
                 }
                 return structure;
             }
         },
         .Pointer => |ptr_info| {
-            if (ptr_info.is_allowzero) {
-                return null;
-            } else {
-                switch (ptr_info.size) {
-                    .Slice => {
-                        return &[_]ptr_info.child{};
-                    },
-                    .One, .Many, .C => {
-                        @compileError("Can't set a non nullable pointer to zero.");
-                    },
-                }
+            switch (ptr_info.size) {
+                .Slice => {
+                    return &[_]ptr_info.child{};
+                },
+                .C => {
+                    return null;
+                },
+                .One, .Many => {
+                    @compileError("Can't set a non nullable pointer to zero.");
+                },
             }
         },
         .Array => |info| {
@@ -372,6 +374,7 @@ test "mem.zeroes" {
 
         const Pointers = struct {
             optional: ?*u8,
+            c_pointer: [*c]u8,
             slice: []u8,
         };
         pointers: Pointers,
@@ -397,6 +400,7 @@ test "mem.zeroes" {
     testing.expectEqual(@as(f32, 0), b.integral_types.float_32);
     testing.expectEqual(@as(f64, 0), b.integral_types.float_64);
     testing.expectEqual(@as(?*u8, null), b.pointers.optional);
+    testing.expectEqual(@as([*c]u8, null), b.pointers.c_pointer);
     testing.expectEqual(@as([]u8, &[_]u8{}), b.pointers.slice);
     for (b.array) |e| {
         testing.expectEqual(@as(u32, 0), e);