It’s not a real project, but I was playing with comptime trying to push the limit and this code just works I’m surprised this works actually but it does.
const std = @import("std");
const Type = std.builtin.Type;
fn last(comptime h: [:0]const u8, comptime n: u8) [:0]const u8 {
@setEvalBranchQuota(2000000);
const index = std.mem.lastIndexOf(u8, h, &.{n}) orelse return h;
return h[index..][1..];
}
pub fn Match(comptime Types: []const type) type {
const Ti = std.math.IntFittingRange(0, Types.len);
@setEvalBranchQuota(2000000);
return @Type(
.{
.@"union" = .{
.layout = .auto,
.tag_type = blk: {
break :blk @Type(
.{
.@"enum" = .{
.tag_type = std.math.IntFittingRange(0, Types.len),
.fields = fields: {
var f: [Types.len]Type.EnumField = undefined;
for (Types, 0..) |t, i| {
f[i] = switch (@typeInfo(@TypeOf(t))) {
.type => .{
.name = last(@typeName(t), '.'),
.value = @as(Ti, @truncate(i)),
},
else => .{
.name = @typeName(t),
.value = @as(Ti, @truncate(i)),
},
};
}
break :fields &f;
},
.decls = &.{},
.is_exhaustive = true,
},
},
);
},
.fields = blk: {
var f: [Types.len]Type.UnionField = undefined;
for (Types, 0..) |t, i| {
f[i] = switch (@typeInfo(@TypeOf(t))) {
.type => .{
.name = last(@typeName(t), '.'),
.type = t,
.alignment = @alignOf(t),
},
else => .{
.name = @typeName(t),
.type = t,
.alignment = @alignOf(t),
},
};
}
break :blk &f;
},
.decls = &.{},
},
},
);
}
pub const Name = struct {
name: []const u8 = "hi",
};
fn bar(x: f32) Match(&.{ f32, Name, i32 }) {
// zig fmt: off
if (x == 1) {
return .{.f32 = x};
} else if (x > 2) {
return .{.Name = .{}};
} else if (x == 3) {
return .{.i32 = 5};
}
else return .{.Name = .{.name = "coucou"}};
}
test "u" {
std.debug.print("{}", .{@TypeOf(Name)});
for (std.meta.fieldNames(Match(&.{f32, Name, i32}))) |s| {
std.debug.print("{s}\n", .{s});
}
for (0..3) |i| {
const res = bar(@floatFromInt(i));
switch (res) {
.f32 => |f| std.debug.print("{d:.2}\n", .{f}),
.Name => |s| std.debug.print("{s}\n", .{s.name}),
.i32 => |d| std.debug.print("{d}\n", .{d}),
}
}
}
I don’t know if there is a use case, if its any useful or not, but it’s pretty cool nonetheless that you can achieve that with the language.