Is it possible to create a list of concrete compiled types at comptime?

Hello I have a reflection system for a game engine that consist of tagging a type like this:

pub const Enemy = struct {
    pub const refl = ReflectStruct(Enemy, .{ .serializable, .draw_imgui }).fields(&.{ "mana", "health" });
    mana: i32 = 0,
    health: i32 = 100,
};

This works perfect, what ReflectStruct(…) does is return a type with some comptime generated function pointers to serialize etc…

But now I want to know at runtime HOW many of these ReflectStruct types have been generated.
This will allow me to register these types automatically to a runtime ArrayList or Map.

// Currently I have to do this:
// I have to remember to register the type
pub fn gameInit() void {
    registerReflectedType(Enemy);
    registerReflectedType(Enemy2);
    registerReflectedType(Enemy3);
    registerReflectedType(Enemy4);
    registerReflectedType(Enemy5);
    registerReflectedType(Enemy6);
}
// What I want:
// Automatically register all the ReflectedTypes generated at comptime.
// The idea is to add a type to the g_generated_reflected_types_list on each comptime execution of `ReflectStruct` method.
// And then use it at runtime like this:
pub fn gameInit() void {
    registerReflectedTypes(g_generated_reflected_types_list);
}

Is it possible to fill a global comptime array with all the created ReflectStructs created?

I tried with a comptime var global but it doesn’t work…
Also I had a look to this issue: make closure over comptime var a compile error; comptime vars become immutable when they go out of scope · Issue #7396 · ziglang/zig · GitHub

But it’s not clear to me how can be done.

Thank you!!

Yeah, I’ve been wondering about a similar thing myself!

Ability to create a list of things declared at compile time in decentralized manner comes up pretty regularly. Like, even things like test sort of work that way.

There are some linker tricks you can do to achieve this, I am wondering if something similar is possible via zig’s @export machinery (but, realistically, it does feel like this can benefit from being a first-class feature):

2 Likes

The easy way is to register all the declarations in a namespace.

pub fn registerDeclarations(comptime NS: type) void {
    const decls = @typeInfo(NS).@"struct".decls;
    inline for (decls) |decl| {
        const T = @field(NS, decl.name);
        // here or in registerReflectedType filter the types 
        // that declare refl: ReflectStruct
        registerReflectedType(T);
    }
}

Then register all namespaces:

const AllEnemies = @import("enemies.zig");

pub fn main() void {
    registerDeclarations(AllEnemies);
    registerDeclarations(@This());
}

Thanks for your suggestion dimdin.

I haven’t tried it but seems that this will find ALL the types that declare Reflectstruct right?

I’m only interested in the compiled(used) ones not everything.
Maybe I can work with it but it could be super useful to have only the used(compiled) ones.