#(comptime?) function wrapper

1 messages · Page 1 of 1 (latest)

rare topaz
#

I am trying to create a function that can take any function pointer and "wrap" it so that it takes data from a lua VM and feeds it to the function, and then pushes the return values to the VM. I have a few questions:

  • Is there any way I can make the comptime type field only accept function pointers (but accept any function pointer)?
  • How can I print out/use the type info of the function? The compiler says values of type '[]const builtin.Type.Fn.Param' must be comptime-known, but index value is runtime-known.
  • How much of this, if any, can I do at comptime?
  • How much static code can the comptime function generate, or is that too macro-like?
upper stream
#
  1. no, but you can do a comptime check and @compileError if a function pointer was not provided
  2. I'm not sure if you can print it out, but you can use it. look in std/builtin.zig for the type of Type.Fn.Param and other stuff
  3. should be able to do everything except for the things that need to happen at runtime
  4. comptime code can't generate static code but it can repeat it (inline for), conditionally execute it, define constant values, ... . It can do most of the same things macros can but without the ability to actually generate code
rare topaz
#

I see

#

I tried to switch over the std.builtin.Type but it didnt work…

upper stream
#

that should work

rare topaz
#

I’m not at my computer this second but it said it expected some kind of type option for the switch case or something

upper stream
#

don't know what error that is.

switch(@typeInfo(i32)) {
    .Pointer => {  },
    else => @compileError("not allowed"),
}

this works

rare topaz
#

Oh right it can assume the enum

#

I’ll take another look at it later when I get back to my computer

rare topaz
#

Alright, with trial and error I've gotten it to at least print out stuff. With this I think I will be able to figure out what I can pop and push on the lua VM's stack

fn getTInfo(comptime val: anytype) void {
    const kind = @typeInfo(@TypeOf(val));
    switch (kind) {
        .Fn => |func| {
            inline for (func.params) |param| {
                std.debug.print("{any}\n", .{param});
            }
        },
        else => {
            std.debug.print("Something else", .{});
        },
    }
}

heady tendon
rare topaz
#

hmm, okay

#

I was also having trouble finding a way to actually pass the arguments gotten from the Lua VM stack as positional arguments

stark hill
# rare topaz I was also having trouble finding a way to actually pass the arguments gotten fr...

Hi, did you get this working?! I was looking at references to my repo and found this. I'm doing something similar to your goal with a current bindings generator project.

I will say for mine, I'm taking my input (in my case a .json and a .h file) and made a generator which creates .zig files that wraps the functions defined in the .json and .h. these generated .zig files are then imported into my main module.

rare topaz
stark hill
rare topaz
#

Oh. Hm

#

I might take another crack at it later then

stark hill
#

if passing the array doesn't work directly, try creating a tuple to temporarily store the arguments in.

rare topaz
#

Is that comptime?

#

It is, right, since it’s an @ thing

stark hill
#

I don't believe so, but I don't know for sure. I don't have a reason to believe @call has runtime overhead compared to a normal function call.

rare topaz
#

I would sketch it out now but the wifi in this room I’m in doesn’t work and I hate typing code on my phone

heady tendon
rare topaz
# stark hill I don't believe so, but I don't know for sure. I don't have a reason to believe ...

Completely untested but something like this, maybe?

pub fn wrapFunctionPointer(comptime func: anytype) !CFn {
    return struct {
        fn wrapped(ls: *ziglua.LuaState) c_int {
            const kind = @typeInfo(@TypeOf(func));
            const params = switch (kind) {
                .Fn => |f| f.params,
                else => {
                    Lua.raiseErrorStr(ls, "Attempted to wrap type that wasn't a function: {}", .{func});
                    return 0;
                },
            };

            comptime var args = .{};

            inline for (params, 0..) |param, i| {
                if (param.type) |t| {
                    args[i] = try ls.toAny(t, -1);
                }
            }
            @call(.{}, func, args);
            return if (kind.Fn.return_type) |_|
                1
            else
                0;
        }
    }.wrapped;
}