The following is some code I’ve been playing around with. The key function is
getUniqueId, which returns a unique id for any given type:
const std = @import("std");
const Error = error{failure_is_success};
fn fail(comptime _: type) !void {
return Error.failure_is_success;
}
fn getUniqueNumber(comptime T: type) usize {
fail(T) catch {
if (@errorReturnTrace()) |trace| {
return trace.instruction_addresses[0];
}
};
unreachable;
}
const base_opaque = opaque {};
fn getUniqueId(comptime T: type) usize {
const base = getUniqueNumber(base_opaque);
return getUniqueNumber(T) - base;
}
fn Point(comptime T: type) type {
return struct {
x: T,
y: T,
};
}
pub fn main() void {
const types = .{
u32,
i32,
[]u8,
[*:0]u8,
Point(f32),
Point(f64),
@TypeOf(.{ .evil_turtles = "on the loose", .stage = 1 }),
@TypeOf(.{ .evil_turtles = "on the loose", .stage = 2 }),
@TypeOf(Point),
opaque {},
opaque {},
};
inline for (1..3) |round| {
std.debug.print("Round {d}:\n", .{round});
inline for (types) |T| {
const id = getUniqueId(T);
std.debug.print("{s} => {d}\n", .{ @typeName(T), id });
}
std.debug.print("\n", .{});
}
}
Round 1:
u32 => 16
i32 => 352
[]u8 => 688
[*:0]u8 => 1024
opaque.Point(f32) => 1360
opaque.Point(f64) => 1696
struct{comptime evil_turtles: *const [12:0]u8 = "on the loose", comptime stage: comptime_int = 1} => 2032
struct{comptime evil_turtles: *const [12:0]u8 = "on the loose", comptime stage: comptime_int = 2} => 2368
fn (comptime type) type => 2704
opaque.main__opaque_3394 => 3040
opaque.main__opaque_3395 => 3376
Round 2:
u32 => 16
i32 => 352
[]u8 => 688
[*:0]u8 => 1024
opaque.Point(f32) => 1360
opaque.Point(f64) => 1696
struct{comptime evil_turtles: *const [12:0]u8 = "on the loose", comptime stage: comptime_int = 1} => 2032
struct{comptime evil_turtles: *const [12:0]u8 = "on the loose", comptime stage: comptime_int = 2} => 2368
fn (comptime type) type => 2704
opaque.main__opaque_3394 => 3040
opaque.main__opaque_3395 => 3376
Totally hackish but seems to work. Got any idea on how to accomplish the same thing in a cleaner manner?
Cursed. How to do it cleaner? Require that the type gets explicitly declared somewhere, together with other allowed types and then for example use the index. Error if the type wasn't declared. Don't abuse comptime for things it isn't meant for. Another possibility would be to research/work on examples/arguments/code for this proposal for having a type-id https://github.com/ziglang/zig/issues/5459
– SzeHmmm, that should be a viable approach. Just recursively collect all the types in to an array first, then do the lookup. Actually, we only need to know the number of types beforehand so we have a large enough array.
– chung-leongMaybe merge tuples with ++ and at the end use the tuple to initialize the array with inferred size, or use it directly to convert to the index. Possibly adding a dedupe step that makes sure that duplicate types are removed.
– Sze