#Enum unknown at comptime

1 messages · Page 1 of 1 (latest)

patent stone
#

Hello,

I have enum:

pub const BuiltinCommand = enum {
    exit,
    echo,
    type,
    pwd,
    cd
 };

defined at enums.zig file,
I am importing that file, and want to iterate over members of that enum, so I wrote:

    fn _set_builtin_commands(self: *CommandMap) !void {
        for (std.meta.fields(enums.BuiltinCommand)) |command| {
            try self.map.put(
                try self.arena_allocator.dupe(@tagName(command)),
                .{
                    .buildin_command = command
                }
            );
        }
    }

But it raises error that says:
error: values of type '[]const builtin.Type.EnumField' must be comptime-known, but index value is runtime-known

I don't get it, this enums are comptime known right? Why I am getting this error, and how to fix that.

thanks for help!

heavy temple
#

use inline for, also std.enums.EnumMap already exists

#

you can use std.meta.stringToEnum to convert string to enum as well

patent stone
#

could you write code snippet of code you propose? I am not sure i understand, i am newbie at zig

#

also i do not understand why message says what it says

#

and it would be great to udnerstand it

heavy temple
#

the for loop runs runtime because it has runtime stuff in it, you can force it in comptime with for (comptime std.meta.fields(enums.BuiltinCommand)) |command| { but you will hit another error due to mixing runtime with comptime code

#

so what you need to do is use inline for instead so it unrolls it
also @tagName(command) is wrong and instead you wanted command.name as fields don't return the enum itself

patent stone
#

this is an string hasp map

heavy temple
#

Do you need string hash map if you only store enums?

patent stone
#

it stores Union:

const Command = union {
    buildin_command: enums.BuiltinCommand,
    installed_command: InstalledCommand
};
#

InstalledCommand is struct

#

I am using it to match token that it is command, i am looking by string at map, to find if command exists, and what type of command it is

heavy temple
#

okay, you need to use the inline for anyways then

#

also you don't have to dupe the key as it's comptime known (thus will always exist in memory)

patent stone
#

what is inline for?

#

i never heard of it

heavy temple
#

it unrolls the loop

patent stone
#

but key is string

heavy temple
#

key is string, but field.value is known comptime in this case

#

you don't need to dupe it

#

you only need to dupe runtime known strings which do not outlive the map

patent stone
#

ok, but do i get it correcly, using @TagName, or there is other way? to get string

heavy temple
#

you don't need tagName std.meta.fields return std.builtin.Type.EnumField

#

and EnumField has name field

#
    fn _set_builtin_commands(self: *CommandMap) !void {
        inline for (std.meta.fields(enums.BuiltinCommand)) |field| {
            try self.map.put(
                field.name,
                .{ .buildin_command = @enumFromInt(field.value) },
            );
        }
    }
patent stone
#

oh i see

#

error: expected type 'enums.BuiltinCommand', found 'builtin.Type.EnumField'
.buildin_command = field

#

value also does not work

#

StringToEnum should i call?

lavish garden
#

Comptime vs runtime stuff is confusing at first, but once you get the grasp of it, it is mostly a matter of adding inline here and there

heavy temple
lavish garden
#

To try and make the previous error clear: input to @tagName (as well as many @builtin functions, and -almost?- anything to do with types) has to be comptime-known, however you were doing a for (which made the values runtime known instead), which then failed.

By adding inline/comptime you force the compiler to evaluate your loop during compilation, allowing the function to be used

patent stone
#

Thanks!