const std = @import("std"); const std_dispatch = struct { fn dispatch_type(comptime types: var, a: type, b: type) type { for (@typeInfo(@TypeOf(types)).Struct.fields) |field| { if (@field(types, field.name)(a, b)) |typ| { return typ; } } std.debug.panic("no type", .{}); } fn dispatch_impl(comptime impls: var, comptime types: var, a: type, b: type) fn(a,b) types(a,b) { for (@typeInfo(@TypeOf(impls)).Struct.fields) |field| { if (@field(impls, field.name)(a, b)) |impl| { return impl; } } std.debug.panic("no impl", .{}); } }; const std_math = struct { fn add_type(comptime a: type, comptime b: type) type { const typ = comptime std_dispatch.dispatch_type(@import("root").add_types, a, b); return typ; } fn add(a: var, b: var) add_type(@TypeOf(a), @TypeOf(b)) { const impl = comptime std_dispatch.dispatch_impl(@import("root").add_impls, add_type, @TypeOf(a), @TypeOf(b)); return impl(a,b); } }; const lib_foo = struct { const Vec2 = [2]usize; fn add_vec_vec(a: Vec2, b: Vec2) Vec2 { return .{a[0]+b[0], a[1]+b[1]}; } fn add_type(comptime a: type, comptime b: type) ?type { if (a == Vec2 and b == Vec2) { return Vec2; } return null; } fn add_impl(comptime a: type, comptime b: type) if (add_type(a,b)) |typ| ?fn(a,b) typ else @TypeOf(null) { if (a == Vec2 and b == Vec2) { return add_vec_vec; } return null; } }; const lib_bar = struct { const Mat2 = [4]usize; fn add_mat_mat(a: Mat2, b: Mat2) Mat2 { return .{a[0]+b[0], a[1]+b[1], a[2]+b[2], a[3]+b[3]}; } fn add_type(comptime a: type, comptime b: type) ?type { if (a == Mat2 and b == Mat2) { return Mat2; } return null; } fn add_impl(comptime a: type, comptime b: type) if (add_type(a,b)) |typ| ?fn(a,b) typ else @TypeOf(null) { if (a == Mat2 and b == Mat2) { return add_mat_mat; } return null; } }; // root file const add_types = .{ lib_foo.add_type, lib_bar.add_type, }; const add_impls = .{ lib_foo.add_impl, lib_bar.add_impl, }; pub fn main() !void { const c1 = std_math.add([2]usize{1,4243}, [2]usize{1,1}); const c2 = std_math.add([4]usize{1,2,3,4}, [4]usize{1,1,1,1}); std.debug.warn("{} {}\n{} {} {} {}\n", .{c1[0], c1[1], c2[0], c2[1], c2[2], c2[3]}); // _ = add(0,0); }