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:
@typeInfo(T).Struct.fields
inside an inline for
loop. The compiler errors with "index
is not comptime-known".[]const u8
by concatenating the field names and values, but I run into lifetime and allocation issues since I can't allocate memory at comptime.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!
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.