How to check whether a value is a function pointer?

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.