Switching on an errorset

I am writing a Zig library, let’s call it mylib that lets a user register a callback function which is called by mylib. The user defined callback can return an error that goes beyond MyLibError errorset. When processing an error from the callback I would like to pass through the errors from within MyLibError errorset and handle the errors that are not in it. Something like this

// zig-ish pseudocode
switch (err) {
    .MyLibError => |e| {return e;},
    else => |err| {handle err somehow}

There is a solution in another thread Is there a nicer way to check if an error is in an error set? - #2 by n0s4 but I find it too verbose. Is there a more elegant way to switch on errorsets?

Here is one way using a switch with inline else:

const std = @import("std");

const Error1 = error{ Foo, Bar };
const Error2 = error{ Baz, Qux };

const Error = Error1 || Error2;

fn handleSome(err: Error) !void {
    const Some = Error1;
    return switch (err) {
        inline else => |e| if (@hasField(std.meta.FieldEnum(Some), @errorName(e))) {} else e,
    };
}

pub fn main() !void {
    try handleSome(error.Foo); // this one is handled (by doing nothing)
    try handleSome(error.Bar); // this one too

    try handleSome(error.Baz); // this fails
}

Or with a helper function it becomes:

pub inline fn errorSet(comptime Err: type, err: anytype) bool {
    return @hasField(std.meta.FieldEnum(Err), @errorName(err));
}

fn handleSome(err: Error) !void {
    return switch (err) {
        inline else => |e| if (errorSet(Error1, e)) {} else e,
    };
}
4 Likes