From 9eac721f24c7699abdcc8af678154d4536493a6d Mon Sep 17 00:00:00 2001 From: Stephen Gutekanst Date: Mon, 25 Mar 2024 10:49:51 -0700 Subject: [PATCH] module: make send() local args type known Signed-off-by: Stephen Gutekanst --- src/ecs/systems.zig | 2 +- src/module.zig | 45 +++++++++++++++++++++++++-------------------- 2 files changed, 26 insertions(+), 21 deletions(-) diff --git a/src/ecs/systems.zig b/src/ecs/systems.zig index 3cfa5ba6..9d050c6f 100644 --- a/src/ecs/systems.zig +++ b/src/ecs/systems.zig @@ -68,7 +68,7 @@ pub fn World(comptime mods: anytype) type { try world.entities.removeComponent(entity, module_tag, component_name); } - pub inline fn send(m: *@This(), comptime event_name: Modules.LocalEvent, args: anytype) void { + pub inline fn send(m: *@This(), comptime event_name: Modules.LocalEvent, args: Modules.LocalArgsM(M, event_name)) void { const mod_ptr: *Mods = @alignCast(@fieldParentPtr(Mods, @tagName(module_tag), m)); const world = @fieldParentPtr(WorldT, "mod", mod_ptr); world.modules.sendToModule(module_tag, event_name, args); diff --git a/src/module.zig b/src/module.zig index a2d5a54d..b49ba75e 100644 --- a/src/module.zig +++ b/src/module.zig @@ -76,29 +76,34 @@ pub fn Modules(comptime mods: anytype) type { inline for (modules) |M| { _ = Module(M); // Validate the module if (M.name != module_name) continue; - inline for (M.events) |event| { - const Ev = @TypeOf(event); - const name_tag = if (@hasField(Ev, "local")) event.local else continue; - if (name_tag != event_name) continue; - - const Handler = switch (@typeInfo(@TypeOf(event.handler))) { - .Fn => @TypeOf(event.handler), - .Type => |t| switch (@typeInfo(t)) { - .Fn => event.handler, - else => unreachable, - }, - else => unreachable, - }; - - // TODO: passing std.meta.Tuple here instead of TupleHACK results in a compiler - // segfault. The only difference is that TupleHACk does not produce a real tuple, - // `@Type(.{.Struct = .{ .is_tuple = false }})` instead of `.is_tuple = true`. - return UninjectedArgsTuple(TupleHACK, Handler); - } - @compileError("mach: module ." ++ @tagName(M.name) ++ " has no .local event handler for ." ++ @tagName(event_name)); + return LocalArgsM(M, event_name); } } + pub fn LocalArgsM(comptime M: type, event_name: LocalEvent) type { + _ = Module(M); // Validate the module + inline for (M.events) |event| { + const Ev = @TypeOf(event); + const name_tag = if (@hasField(Ev, "local")) event.local else continue; + if (name_tag != event_name) continue; + + const Handler = switch (@typeInfo(@TypeOf(event.handler))) { + .Fn => @TypeOf(event.handler), + .Type => |t| switch (@typeInfo(t)) { + .Fn => event.handler, + else => unreachable, + }, + else => unreachable, + }; + + // TODO: passing std.meta.Tuple here instead of TupleHACK results in a compiler + // segfault. The only difference is that TupleHACk does not produce a real tuple, + // `@Type(.{.Struct = .{ .is_tuple = false }})` instead of `.is_tuple = true`. + return UninjectedArgsTuple(TupleHACK, Handler); + } + @compileError("mach: module ." ++ @tagName(M.name) ++ " has no .local event handler for ." ++ @tagName(event_name)); + } + /// Returns an args tuple representing the standard, uninjected, arguments which the given /// global event handler requires. fn Args(event_name: GlobalEvent) type {