Zig Comptime Registry
A type registry is a comptime list of types that code can look up by name. A lookup walks the list at compile time and returns the matching type.
Counting Registry Entries
This program holds a list of two types. It prints how many types the list holds.
const std = @import("std");
const Cat = struct { pub const kind = "cat"; sound: []const u8 };
const Dog = struct { pub const kind = "dog"; sound: []const u8 };
const registry = [_]type{ Cat, Dog };
pub fn main() !void {
const out = std.io.getStdOut().writer();
try out.print("{}\n", .{registry.len});
}Looking Up A Type
This program looks up the dog entry by name. It builds that type and prints its name and sound.
const std = @import("std");
const Cat = struct { pub const kind = "cat"; sound: []const u8 };
const Dog = struct { pub const kind = "dog"; sound: []const u8 };
const Unknown = struct { pub const kind = "unknown"; sound: []const u8 };
const registry = [_]type{ Cat, Dog };
fn lookup(comptime name: []const u8) type {
inline for (registry) |T| {
if (std.mem.eql(u8, T.kind, name)) return T;
}
return Unknown;
}
pub fn main() !void {
const out = std.io.getStdOut().writer();
const D = lookup("dog");
const d = D{ .sound = "woof" };
try out.print("{s} {s}\n", .{ D.kind, d.sound });
}A Miss Returns A Fallback
This program looks up a name that is not in the list. It prints the name of the fallback type.
const std = @import("std");
const Cat = struct { pub const kind = "cat"; sound: []const u8 };
const Dog = struct { pub const kind = "dog"; sound: []const u8 };
const Unknown = struct { pub const kind = "unknown"; sound: []const u8 };
const registry = [_]type{ Cat, Dog };
fn lookup(comptime name: []const u8) type {
inline for (registry) |T| {
if (std.mem.eql(u8, T.kind, name)) return T;
}
return Unknown;
}
pub fn main() !void {
const out = std.io.getStdOut().writer();
const U = lookup("fish");
try out.print("{s}\n", .{U.kind});
}Example
const std = @import("std");
const Cat = struct { pub const kind = "cat"; sound: []const u8 };
const Dog = struct { pub const kind = "dog"; sound: []const u8 };
const Bird = struct { pub const kind = "bird"; sound: []const u8 };
const registry = [_]type{ Cat, Dog, Bird };
fn lookup(comptime name: []const u8) type {
inline for (registry) |T| {
if (std.mem.eql(u8, T.kind, name)) return T;
}
return Cat;
}
pub fn main() !void {
const out = std.io.getStdOut().writer();
const B = lookup("bird");
const b = B{ .sound = "tweet" };
try out.print("{s} {s}\n", .{ B.kind, b.sound });
}Key points
- Type registry: a type registry is a comptime list of types that can be looked up by name.
- A lookup: a lookup is a comptime search that returns the type whose name matches.
- Each entry in the list carries a name that the lookup can compare.
- A lookup that finds no match returns a fallback type, so the program still compiles.
- The registry list is fixed at compile time, so new entries are added by editing the list.
- Registry code stays small, because one lookup function serves every entry.
The list holds three types, each with a name and a sound. The lookup walks the list and returns the bird type. The main function builds that type and prints its name and sound.
Try it Yourself
Edit the code, then press Run.
Running is simulated
Exercise
What does a type registry lookup return for a name that is in the list?