I changed the original post. I think my question boils down to checking whether a struct has a field with a function pointer (of any kind). Here is an example:
const std = @import("std");
const Struct = struct {
handler: *const fn () void,
};
fn hasFnPointer(val: anytype) bool {
const T_info = @typeInfo(@TypeOf(val));
if (T_info != .Struct) return;
inline for (T_info.Struct.fields) |field| {
_ = field;
// Would be great to check this and return:
// if (field.type == function_pointer)
// return true;
}
return false;
}
fn phonyFn() void {}
pub fn main() !void {
const foo = Struct{ .handler = &phonyFn };
std.debug.print("{any}", .{ hasFnPointer(foo) });
}
const std = @import("std");
fn hasFnPointer(val: anytype) bool {
const t_info = @typeInfo(@TypeOf(val));
if (t_info != .Struct) return false;
inline for (t_info.Struct.fields) |field| {
switch (@typeInfo(field.type)) {
.Pointer => |info| {
if (info.size == .One and @typeInfo(info.child) == .Fn) {
return true;
}
},
else => {},
}
}
return false;
}
const StructWFnPtr = struct {
handler: *const fn () void,
};
fn phonyFn() void {}
const StructWNoFnPtr = struct {
a: u32,
b: *const StructWFnPtr,
};
test {
const foo = StructWFnPtr{ .handler = &phonyFn };
try std.testing.expectEqual(true, hasFnPointer(foo));
const bar = StructWNoFnPtr{ .a = 0, .b = &foo };
try std.testing.expectEqual(false, hasFnPointer(bar));
}
In general you can figure out most of this meta type stuff by knowing that @typeInfo(T)
returns an instance of the union of std.builtin.Type
. This union and everything related to it is defined in builtin.zig
in the standard library.
3 Likes
should it be return false;
instead of the naked return;
?
Good call, didn’t catch that.