#Meta Struct Field Access

1 messages · Page 1 of 1 (latest)

thorn glen
#

I am looking to dynamically set a structs field based on a string.

I have a project (physics simulator) that is configured at runtime via a json.

One of the elements, is initialized with a get field and a set field, and Id like to be able to mutably access a struct field based on these strings.

I tried using @field and std.meta methods but unfortunatly, the get_field is configured at runtime and thus fails to evaluate at comptime.

        self.get_val = switch (self.connection_getter.?){
            inline else => |impl| @field(impl, self.get_field)
        };

        switch (self.connection_setter.?){
            inline else => |impl| @field(impl, self.set_field) = self.set_val
        }

Is there a good way to map strings to struct fields? If that string is not accessible at comptime?

deft slate
#

if you have list of all possible strings e.g. enum, use std.meta.stringToEnum and then inline else switch on that

#

const field = std.meta.stringToEnum(std.meta.enumField(T), str) orelse return error.UnknownField;

#

for example

#

now you can switch on field and inline else with @tagName can convert it back to string

thorn glen
#

Mm, so this would require taking all struct fields to an enum?

wicked willow
deft slate
#

Ah yeah

thorn glen
#

Struggling a bit with this still @deft slate

I have a "interface" aka enum that holds types of SimObjects

Simobjects:
    Type1: *thing... ect

When attempting to inline implementations I get a cannot evaluate at comptime error

src/sim.zig:154:54: error: unable to resolve comptime value
            inline else => |impl| std.meta.FieldEnum(impl)
                                                     ^~~~
src/sim.zig:154:54: note: argument to comptime parameter must be comptime-known
/home/jowilson/zig-linux-x86_64-0.14.0-dev.3445+6c3cbb0c8/lib/std/meta.zig:511:18: note: parameter declared comptime here
pub fn FieldEnum(comptime T: type) type {
                 ^~~~~~~~

Attmping to implement (toy function):

    pub fn get_field(self: *const Self, field: []const u8) !void{
        const field_enum = switch (self.*){
            inline else => |impl| std.meta.FieldEnum(impl)
        };

        const field_result = std.meta.stringToEnum(field_enum, field);

        std.log.err("{any}", .{field_result});
    }
#

Additionally, not all fields will be the same return type... so that will be intresting... feels like the wrong ptter or the wrong implementation.

Maybe I can pass in the return type I expect with anytype...? Feels wrong

deft slate
#

^ during comptime the type can be inferred, during runtime you have to make sure you get the types right or you get runtime panic

#

if you don't know the types ahead of time for runtime, you have to implement your own "runtime type information", so basically enum and then list in the Meta struct where each field is assigned to one enum value (integer, string) and so on

thorn glen
#

hmmmm...... so I am still struggling to get this working without having to write this out for every single object..... which is fine if I have to

pub const SimObject = union(enum) {
    const Self = @This();

    // Fluids
    ConstantMdot: *restrictions.ConstantMdot,
    Orifice: *restrictions.Orifice,
    VoidVolume: *volumes.VoidVolume,
    StaticVolume: *volumes.StaticVolume,
    UpwindedSteadyVolume: *volumes.UpwindedSteadyVolume,

I keep running into control flow issues when attempting to inline over them ie:

    pub fn get_field(self: *const Self, field: []const u8, T: type) !T {
        const FieldEnum = switch (self.*) {
            inline else => |impl| std.meta.FieldEnum(@TypeOf(impl)),
        };

        const field_tag = std.meta.stringToEnum(FieldEnum, field) orelse return error.UnregonizedField;

        std.log.err("FieldEnum: {any} \n Field Tag: {any}", .{FeildEnum, field_tag});
    }

Is there a way to extract the base type of the pointer here to allow me to contruct this at comptime?

thorn glen
#

@deft slate sorry for double ping but I am so close I can feel it haha

        ~~~~^~~~~~~~
src/sim.zig:125:36: error: unable to evaluate comptime expression
                return @field(ptr, @tagName(tag));
                                   ^~~~~~~~~~~~~
src/sim.zig:125:45: note: operation is runtime due to this operand
                return @field(ptr, @tagName(tag));

I was able to get the base type of the pointer but sadly @tagName still gives me a control flow issue because its evaluted at runtime for some reason?

    pub fn get_field(self: *const Self, field: []const u8) !f64 {
        switch (self.*) {
            inline else => |ptr| {
                const T = std.meta.Child(@TypeOf(ptr));
                const tenum = std.meta.FieldEnum(T);

                // Error check this is a valid field
                const tag = std.meta.stringToEnum(tenum, field) orelse {
                    std.log.err("Obj [{s}] cannot grab field [{s}] for it does not exist", .{ self.name(), field });
                    return error.InvalidInput;
                };

                return @field(ptr, @tagName(tag));
            },
        }
next saddle