#Do I need anytype and anyopaque in this function?

1 messages · Page 1 of 1 (latest)

cunning karma
#

I want to double check I am not missing some way to fix the parameters for this function. Right now it looks like this:

// Assume MyStruct has a recalculate_speed function
var entity = try readEntity(MyStruct, &my_struct,
    \\panel name "coffee" image "cat"
    \\minimum width=33 height=120
    \\horizontal style tinted
    \\on_resized "recalculate_speed"
)

Basically I am extracting a function list from the anytype so that I can 'attach' names of functions to the concrete 'handler' pointed to by anyopaque:

pub fn readEntity(
    comptime handler_type: anytype,
    handler: *anyopaque, data: []const u8
) Error!?Entity {
    const so = @typeInfo(handler_type);
    if (so != .@"struct") @compileError("callback parameter must be a pointer to a struct");
    const callbacks = comptime 
callbackFunctionList(handler_type);
    //...
}
velvet mantle
#

No you do not need anytype and anyopaque in this example

pub fn readEntity(
    comptime HandlerType: type,
    handler: *HandleType, data: []const u8
) Error!?Entity {

Seems more like what you were going for

#

If you were to use anytype in this example. you wouldn't need the comptime type argument

pub fn readEntity(
    handler: anytype, data: []const u8
) Error!?Entity {
cunning karma
#

Oh, so you can take the variable name from the comptime parameter and use it in the next parameter? I didn't know that might be possible!!.

#

For your seond example, the handler apparently needs to be comptime to extract the function list

#

Or well, I couldnt get it working using your second option.

velvet mantle
#

anytype means that the variable can b of any type. The argument doesn't need to be an actual type

#

For the second example it shouldn't need to be comptime

cunning karma
#

Wow, cool, my tests pass with your option one, so thats an improvement.

#

Now to look at option 2.

#

Ill try it again and check the problem I was having.

velvet mantle
#

you would instead do

pub fn readEntity(
    handler: anytype, data: []const u8
) Error!?Entity {
const HandlerType = @typeInfo(@TypeOf(handle)).pointer.child.?;

#

assuming you pass in a pointer

cunning karma
#

Yes, thats what I was doing.

#

One moment, I'll check.

velvet mantle
#

you'd probably want to handle it more robustly, but that's the gist

cunning karma
#

Yep, I had full type checking just passing a pointer, but I couldnt get one small thing to work.

velvet mantle
#

Personally I prefer option one. It makes the LSP happy and I think provides more clarity. I don't really like to use anytype

cunning karma
#

Yea, you might be right.

velvet mantle
#

And it's a comptime parameter so it doesn't actually take a register or stack space to pass

cunning karma
#

I was doing this, which walked past the pointer to get the struct to list the functions:

    //const po = @TypeOf(handler_type);
    //const pi = @typeInfo(po);
    //if (pi != .pointer) @compileError("callback parameter must be a pointer to a struct.");
    //const so = @typeInfo(pi.pointer.child);
#

...

#

(Im just redoing my old version ....)

velvet mantle
#

Depending on what you're doing you don't need to reflect into the child type; you can just call functions direction on it with the dot syntax

#
const HandlerType = @typeInfo(@TypeOf(handle)).pointer.child.?;
HandlerType.some_function_you_expect_to_exist(...)

and you'll just get a compile error if it doesn't exist

cunning karma
#

Got it, so if I do this, where mystruct is a var:

var mystruct:MyStruct = .{};

pub fn readEntity(
    data: []const u8,
    handler_type: anytype,
    //handler: *handler_type,
) Error!?Entity {
    const po = @TypeOf(handler_type);
    const pi = @typeInfo(po);
    if (pi != .pointer) @compileError("callback parameter must be a pointer to a struct.");
    const so = @typeInfo(pi.pointer.child);
    const handler = so;
    //const so = @typeInfo(handler_type);
    if (so != .@"struct") @compileError("callback parameter must be a pointer to a struct");
    const callbacks = comptime callbackFunctionList(handler_type);

I get stuck with this error which I didnt know how to resolve:

src/EntityParser.zig:22:53: error: unable to resolve comptime value
    const callbacks = comptime callbackFunctionList(handler_type);
#

Then adding comptime like this:

pub fn readEntity(
    data: []const u8,
    comptime handler_type: anytype,

Maks it impossible to pass in a poitner to a var, I think..... not sure

#
src/EntityParser.zig:918:7: error: unable to resolve comptime value
    "data...", &te) orelse unreachable;
velvet mantle
#

assuming you did the following, yes that will not work, because you are passing a runtime variable to a comptime call

readEntity(&mystruct);
#

what does callbackFunctionList do?

cunning karma
#

Yep, and they will be runtime, because in the game engine, the devleoper might use an "add" button to create new entities at runtime....

#

...

#

It gets a list of all functions attached to the anytype struct

#
/// Return the name and pointer to all functions matching the Callback
/// function definition.
pub fn callbackFunctionList(comptime t: type) []const CallbackOption {
    var list: []const CallbackOption = &.{};
    inline for (@typeInfo(t).@"struct".decls) |decl| {
        const f = @field(t, decl.name);
        const info = @typeInfo(@TypeOf(f));
        if (info != .@"fn") continue;
        if (info.@"fn".params.len != 4) continue;
        if (info.@"fn".return_type == null) continue;
        if (@typeInfo(info.@"fn".return_type.?) != .error_union) continue;
        if (@typeInfo(info.@"fn".return_type.?).error_union.payload != void) continue;
        if (@typeInfo(info.@"fn".return_type.?).error_union.error_set != std.mem.Allocator.Error) continue;

        if (info.@"fn".params[0].type == null) continue;
        const t0 = @typeInfo(info.@"fn".params[0].type.?);
        if (t0 != .pointer) continue;
        const t0i = @typeInfo(t0.pointer.child);
        if (t0i != .@"struct") continue;

        //...

        list = list ++ .{CallbackOption{ .name = decl.name, .f = @ptrCast(&f) }};
    }
    return list;
}
velvet mantle
#

It gets a list of all functions attached to the anytype struct
In that case it sounds like you are meaning to pass the type of mystruct not &mystruct?

cunning karma
#

It's not just tye type, because it is meant to read the text data describing the entity, and build a real entity in memory, and "link" the functions to the struct in memory

#

So you would creaet a "Player1" and attach the "on_jump" to spacebar event or something.

#

i.e. readEntity("sprite 'player1' on_event 'jump_function"', Player, &player1);

#

The game engine creates an Entity object and needs to know how to call Player.jump()

velvet mantle
cunning karma
#

That might be the solution.... let me walk down that path.... that gives me different errors.... testing....

#

Thanks so much for your pointers. I;ve never tried this reflection stuff before. Its on the edge of what I know about zig.

#

The problem them becomes, getting the actual pointer out....

#

I might be able to fix this....

#

Its not sentinel_ptr I am assuming

velvet mantle
#

Yeah it's a bit hard to whole the reflection model in your head sometimes

cunning karma
#

woah... its compiling!

velvet mantle
#

What do you mean getting the pointer out?

cunning karma
#

Im getting jumbled up with so many iterations, its working now.

#

Thanks for guiding me through that. I feels frustrating when you are stuck and not sure how to proceed, so I appreciate you stopping in to set me on the right path.

#

So can now do both option 1 and option 2 that you suggested (2 or three parameters)

cunning karma
#

I like 3 parameters because its true zig style. But I want it to be a game engine for kids, so I want to keep it as simple as possible.

#

Maybe one day zig can have its own intro to gaming type engine.

velvet mantle
#

Yeah it'll be cool to see where Mach goes, but it looks like it'll be pretty advanced