i would like to automatically “reify” a struct type whose fields are pointers to functions implemented within another container… said another way, i’m trying to write a generic function that encapsulates the “function-pointer-table” design pattern commonly used when implementing abstract interfaces…
here’s my current attempt:
const std = @import("std");
const print = std.log.debug;
const Impl = struct {
pub fn foo(x: u32) void {
print("foo({d})", .{x});
}
pub fn bar() void {
print("bar", .{});
}
};
fn ItabFrom(T: type) type {
const ti = @typeInfo(T);
comptime var fld_list: []const std.builtin.Type.StructField = &.{};
inline for (ti.Struct.decls) |d| {
const dval = @field(T, d.name);
const dti = @typeInfo(@TypeOf(dval));
if (dti == .Fn) {
const FT = @Type(.{ .Pointer = .{
.size = .One,
.is_const = true,
.is_volatile = false,
.alignment = 1,
.address_space = .generic,
.child = @TypeOf(dval),
.is_allowzero = false,
.sentinel = null,
} });
const fld = std.builtin.Type.StructField{
.name = d.name,
.type = FT,
.default_value = dval,
.is_comptime = false,
.alignment = 0,
};
fld_list = fld_list ++ ([_]std.builtin.Type.StructField{fld})[0..];
}
}
const IT = @Type(.{ .Struct = .{
.layout = .auto,
.fields = fld_list,
.decls = &.{},
.is_tuple = false,
.backing_integer = null,
} });
return IT;
}
pub fn main() void {
const IT = ItabFrom(Impl);
print("size = {d}", .{@sizeOf(IT)});
}
but here’s the output i receive when compiling this program (under 0.12.0):
src\main.zig:42:16: error: comptime dereference requires 'fn (u32) void' to have a well-defined layout
const IT = @Type(.{ .Struct = .{
^~~~~
src\main.zig:53:24: note: called from here
const IT = ItabFrom(Impl);
~~~~~~~~^~~~~~
my goal is for this synthesized struct to effectively match the following explicitly defined struct (which i could tediously write by hand):
const Impl = struct {
foo: *const fn (u32) void = &Impl.foo,
bar: *const fn () void = &Impl.bar,
};
my use-case is somewhat simpler than the “classic vtable”, in that my functions do NOT have a self
parameter; no need to carry around an opaque ptr in the interface struct…