#Comptime Code Inclusion

1 messages · Page 1 of 1 (latest)

cerulean igloo
#

is there something equivalent to:

pub const thing = enum {
  one,
  two,
  three,
#if (@import("build_options").opt)
  four,
  five,
#endif
  six,
  seven,
};

in zig? How should I tackle this problem? Thank you!

hushed shard
cerulean igloo
hushed shard
cerulean igloo
#

I'm making an enum for #defines in a c header:

#define PREFIX_ONE 1
#define PREFIX_TWO 2
#define PREFIX_THREE 3
#ifdef SOME_CONDITION
#define PREFIX_FOUR 4
#define PREFIX_FIVE 5
#endif /* SOME_CONDITION */
#define PREFIX_SIX 6
#define PREFIX_SEVEN 7
hushed shard
cerulean igloo
#

it's bindings for a c project

hushed shard
#

maybe something like this?

#
PREFIX_ONE = 1,
PREFIX_TWO = 2,
PREFIX_THREE = 3,
PREFIX_FOUR = if(truthy) 4 else undefined,
PREFIX_FIVE = if(truthy) 5 else undefined,
PREFIX_SIX = 6,
PREFIX_SEVEN = 7
};```
olive pollen
#

that wouldn't make them conditionally included

#

they'd just be undefined

hushed shard
#

yeah, but I thought he could check if they were undefined and then trow error

olive pollen
#

you can't check for undefined

#

undefined isn't a "defined" value lol

cerulean igloo
olive pollen
#

it just means "don't assign a value", meaning, let it be whatever garbage value was already there

olive pollen
#

at any rate, if you don't want the duplication, you could write with @Type

cerulean igloo
#

is there a way to generate an enum at comptime such that you can call type.add("four", 4) or something?

#

and do it that way?

olive pollen
#

not arbitrarily

#

but you can do so imperatively in a specific scope

#

typing up an example

#
const Thing = @Type(.{ .Enum = blk: {
    const fields = [_]EnumField{
        enumField("one", 1),
        enumField("two", 2),
        enumField("three", 3),
    } ++ (if (some_condition) [_]EnumField{
        enumField("four", 4),
        enumField("five", 5),
    } else [_]EnumField{}) ++ [_]EnumField{
        enumField("six", 6),
        enumField("seven", 7),
    };

    break :blk .{
        .tag_type = std.meta.IntFittingRange(1, 7),
        .is_exhaustive = true,
        .decls = &.{},
        .fields = &fields,
    };
} });

// for convenience
const EnumField = std.builtin.Type.EnumField;
inline fn enumField(comptime name: []const u8, value: comptime_int) EnumField {
    return .{ .name = name, .value = value };
}
#

there's other ways you can write this

cerulean igloo
#

oh that's great, I didn't know that was possible

olive pollen
#

e.g. you could declare var fields: []const EnumField = &.{}; and imperatively concatenate only the fields you need fields = fields ++ &[_]EnumField{ .{ .name = "foo", .value = 3 } };

cerulean igloo
#

I think I'll go with your second suggestion, probably will look a little nicer

#

Thank you so much @olive pollen and @hushed shard !

olive pollen
#

you could also write a utility function that makes it look nicer

hushed shard
olive pollen
#
const Thing = ConditionalEnumFields(.{
    .one = true,
    .two = true,
    .three = true,
    .four = some_condition,
    .five = some_condition,
    .six = true,
    .seven = true,
});

fn ConditionalEnumFields(comptime field_bools: anytype) type {
    const field_infos = @typeInfo(@TypeOf(field_bools)).Struct.fields;

    var fields: []const std.builtin.Type.EnumField = &.{};

    for (field_infos, 0..) |field, i| {
        if (!@field(field_bools, field.name)) continue;
        fields = fields ++ &[_]std.builtin.Type.EnumField{.{
            .name = field.name,
            .value = i,
        }};
    }

    return @Type(.{ .Enum = .{
        .tag_type = std.meta.IntFittingRange(0, field_infos.len - 1),
        .is_exhaustive = true,
        .decls = &.{},
        .fields = fields,
    } });
}
cerulean igloo
#

I shall be taking this

olive pollen
#

didn't test it at all, might have some errors

#

also caveat: ZLS will not be able to autocomplete this

#

and the enum will not be able to have methods

cerulean igloo
hushed shard
# olive pollen ```ts const Thing = ConditionalEnumFields(.{ .one = true, .two = true, ...

i just tested the code and fixed some thing ```zig fn ConditionalEnumFields(comptime field_bools: anytype) type {
const field_infos = @typeInfo(@TypeOf(field_bools)).Struct.fields;

var fields: []const std.builtin.Type.EnumField = &.{};

for (field_infos, 0..) |field, i| {
    if (!@field(field_bools, field.name)) continue;
    fields = fields ++ &[_]std.builtin.Type.EnumField{.{
        .name = field.name,
        .value = i,
    }};
}

return @Type(.{ .Enum = .{ .tag_type = std.math.IntFittingRange(0, field_infos.len - 1), .fields = fields, .decls = &.{}, .is_exhaustive = true } });

}``` Please be welcome to correct me if you find any errors in the code

olive pollen
#

note: you can put a comma after .is_exhaustive = true and have zig fmt split it over multiple lines

#

what did you fix?

#

ah the array syntax

#

good catch

hushed shard
#
  • std.meta.IntFittingRange doesn't exist
olive pollen
#

righto

hushed shard
#

so i changed it to std.math.IntFittingRange

olive pollen
#

always get that one confused