const std = @import("std"); const Module = struct { init: *const fn (std.mem.Allocator) *anyopaque, deinit: *const fn (*anyopaque, std.mem.Allocator) void, update: *const fn (*anyopaque, std.mem.Allocator) void, }; const Foo = struct { fn init(alloc: std.mem.Allocator) *@This() { return alloc.create(@This()) catch @panic("OOM"); } fn deinit(self: *@This(), alloc: std.mem.Allocator) void { alloc.destroy(self); } fn update(self: *@This(), alloc: std.mem.Allocator) void { _ = self; _ = alloc; std.log.debug("Hello, {s}", .{@typeName(@This())}); } }; const Bar = struct { fn init(alloc: std.mem.Allocator) *@This() { return alloc.create(@This()) catch @panic("OOM"); } fn deinit(self: *@This(), alloc: std.mem.Allocator) void { alloc.destroy(self); } fn update(self: *@This(), alloc: std.mem.Allocator) void { _ = self; _ = alloc; std.log.debug("Hello, {s}", .{@typeName(@This())}); } }; const Modules = .{ Foo, Bar, }; pub fn main() !void { // comptime var modules: [Modules.len]Module = undefined; comptime var modules: [Modules.len]type = undefined; inline for (Modules, &modules) |Mod, *mod| { mod.* = struct { pub fn init(alloc: std.mem.Allocator) void { } }; // mod.* = .{ // .init = @ptrCast(&Mod.init), // .deinit = @ptrCast(&Mod.deinit), // .update = @ptrCast(&Mod.update), // }; } var gpa = std.heap.GeneralPurposeAllocator(.{}){}; defer _ = gpa.deinit(); const alloc = gpa.allocator(); var states: [Modules.len]*anyopaque = undefined; for (modules, &states) |mod, *state| { state.* = mod.init(alloc); } defer for (modules, states) |mod, state| { mod.deinit(state, alloc); }; std.log.debug("Performing update...", .{}); for (modules, states) |mod, state| { mod.update(state, alloc); } }