Determining whether a particular union tag is present in a list of tags

Given a union (enum) and a comptime-known array of some (but not all) of the keys, is there an idiomatic/tidier way to do determine if a particular key is present in the array at runtime?

Right now I’m building a list of all the indices at comptime and using indexOfScalar on the index list at runtime.

(zig 0.15.2)

const std = @import("std");

const ExampleUnionEnum = union (enum) {
    first: void,
    second: usize,
    third: f32,
};

fn array_to_index_array(
    comptime count: usize,
    comptime entries: [count]ExampleUnionEnum,
) [count]usize
{
   var result: [count]usize = undefined; 

   for (entries, &result)
       |entry, *target|
   {
       target.* = @intFromEnum(entry);
   }

   return result;
}

const example_haystack = [_]ExampleUnionEnum{
    .{ .first = {}, },
    .{ .second = 12 },
};
const example_haystack_as_indices = array_to_index_array(
    example_haystack.len,
    example_haystack,
);

test
{
    try std.testing.expect(
        std.mem.indexOfScalar(
            usize,
            &example_haystack_as_indices,
            @intFromEnum(ExampleUnionEnum{.first = {}}),
        ) != null
    );

    try std.testing.expect(
        std.mem.indexOfScalar(
            usize,
            &example_haystack_as_indices,
            @intFromEnum(ExampleUnionEnum{.third = 12.5}),
        ) == null
    );
}

Thanks all!

You can call indexOfScalar at compile time by doing comptime std.mem.indexOfScalar(...)

I would suggest using the tag enum instead of usize. You can get the tag type with std.meta.Tag.

you can also just compare a union value to the tag, so you can

const tag = std.meta.Tag(ExampleUnionEnum).first;
const idx = for (example_haystack, 0..) |v, i| {
    if (v == tag) break i;
} else null;

The compiler can optimise it into SIMD.