#What is the expected type of the 3rd parameter 'args' of @call?

1 messages · Page 1 of 1 (latest)

gentle sequoia
#

It's declared as anytype. The sample usage seems to be a tuple. Is there a way to dynamically pass in argument values to the 'args' parameter of @call?

I'm trying to do dynamic dispatch. E.g.

fn foo(a: u8, b: i32) void {...}
fn bar(a: f64) void {...}

fn dispatch(func: anytype, json_args: []std.json.Value) !void {
    // ... unpack json_args to .{arg1, arg2, ...}
    @call(.auto, func, .{arg1, arg2, ...});
}

dispatch(foo, ...)
dispatch(bar, ...)
wintry niche
#

there's no way for the length to be determined at runtime, since it directly affects the calling convention

#

if you know that there are only 1,2,3 args you could do something like

switch (json_args.len) {
  1 => @call(.auto, func, .{ json_args[0] });
  2 => @call(.auto, func, .{ json_args[0], json_args[1] });
  ...
#

but i do wonder why you would need to determine the number of arguments at runtime, why not just have foo and bar take in a slice of json values and then work with that?

gentle sequoia
#

The number of arguments can be determine during comptime. Basically the functions are registered and put into a map. During runtime, the JSON data comes in and the matching function is dispatched.

#

Let's say I can use @typeInfo() to get the parameter count from the func.

#
    const fn_info = @typeInfo(func).Fn;
    switch(fn_info.params.len) {
       0 => @call(.auto, func, .{}),
       1 => @call(.auto, func, 
                  .{ mapArg(json_args[0], fn_info.params[0]) }),
       ...
    }
#

Would that work?

wintry niche
#

yeah that would work

#

hmm, i am still a bit suspious of this usecase, im still not sure when you would need this

gentle sequoia
#

I'm building a JSON-RPC library. The RPC message has a method and a list of parameters. On the receiving side, a handler for each method is registered. The handler function has the matching arguments for the message's parameters. In runtime, when the JSON message comes in, I need to look up the registered handler, unpacked the parameters and convert them to the function's arguments, and dispatch to it. It sounds simple but got very involved.

gentle sequoia
#

Is it possible to use @field to update a tuple?

dusty schooner
#

Just index it

gentle sequoia
#

Tuple really is immutable. I'll see if I can use code gen during comptime to create the tuple with arbitrary length.

dusty schooner
#

Tuple length is, sure, but the values aren't unless the object is const

gentle sequoia
#

Can I make a function that takes in a comptime tuple type, a json.Value array, and return a constructed tuple of the tuple type? The function can iterate over the fields of the tuple type in comptime?

dusty schooner
#

Sure, why not?

gentle sequoia
#

Thanks everyone for all the help. I've finally got setting arbitrary length tuple working. In case anyone wonders,

#
fn makeTuple(comptime tuple_type: type) tuple_type {
    const tt_info = @typeInfo(tuple_type).@"struct";
    var tuple: tuple_type = undefined;
    inline for (tt_info.fields, 0..)|field, i| {
        std.debug.print("@\"{d}\": {any}\n", .{i, field});
        @field(tuple, field.name) = 42;
    }
    return tuple;
}
#

I did end up using @field to update the tuple. One key factor is the tuple type created must set is_comptime to false for its fields' type to allow for mutable tuple.