serializationreflectioncode-generationcompile-timezig

How can I iterate over struct fields at compile time in Zig to generate a serializer?


I'm learning Zig and I'm trying to write a generic function that automatically serializes any struct into JSON. In languages like Rust or Go, there are libraries that can iterate over the fields of a struct at compile time. I was hoping to do something similar in Zig using @typeInfo.

Here is a simplified example of what I'm trying to do:

const std = @import("std");

const Example = struct {
    a: i32,
    b: []const u8,
    c: bool,
};

pub fn toJson(comptime T: type, value: T) []const u8 {
    // iterate over T's fields here
    // return a JSON string like {"a":1,"b":"hello","c":true}
}

I tried inspecting @typeInfo(T) and matching on TypeInfo.Struct to get the fields array, but I can't figure out how to loop over it in a way that works at compile time. If I write a normal for loop inside the function, Zig complains that it cannot evaluate it at compile time. If I try to use inline for, I get "expected comptime expression" errors. I've also looked at examples in the standard library but they use hard-coded field names.

What I've tried:

Is there a supported way in Zig (0.11 or 0.12) to iterate over the fields of a struct at compile time so I can generate code based on them? Or is this not possible and I need to manually write serialization functions for each struct?

Any pointers or examples would be greatly appreciated!


Solution

  • In Zig 0.14.1, you need to use @TypeOf and @field:

    const std = @import("std");
    
    test "fields" {
        const U1s = packed struct {
            a: u1,
            b: u1,
            c: u1,
        };
    
        const x = U1s{ .a = 1, .b = 0, .c = 0 };
        inline for (std.meta.fields(@TypeOf(x))) |f| {
            std.debug.print(f.name ++ " {}\n", .{ @as(f.type, @field(x, f.name)) });
        }
    }
    

    This prints:

    $ zig build test
    test
    └─ run test stderr
    a 1
    b 0
    c 0
    
    

    It should be very similar in 0.11 and 0.12.