Getting an error by name at comptime

I’m working on a function that “decamelizes” an error name. So OutOfMemory becomes “Out of memory”. The messages are generated at
comptime. The problem I’m having is that I can’t get an error from a name within the inline loop responsible for runtime matching. When I tried err == @field(ET, e.name), I get “TODO handle inferred error sets here”. So now I’m resorting to string comparison, which seems sort of dumb:

fn getErrorMessage(err: anytype) [:0]const u8 {
    @setEvalBranchQuota(200000);
    const ET = @TypeOf(err);
    inline for (@typeInfo(ET).error_set.?) |e| {
        if (std.mem.eql(u8, @errorName(err), e.name)) {
            const message = comptime decamelize: {
                var cap_count: usize = 0;
                for (e.name, 0..) |letter, i| {
                    if (i > 0 and std.ascii.isUpper(letter)) cap_count += 1;
                }
                var buffer: [e.name.len + cap_count + 1]u8 = undefined;
                var index: usize = 0;
                for (e.name, 0..) |letter, i| {
                    if (std.ascii.isUpper(letter)) {
                        if (i > 0) {
                            buffer[index] = ' ';
                            index += 1;
                            buffer[index] = std.ascii.toLower(letter);
                        } else {
                            buffer[index] = letter;
                        }
                    } else {
                        buffer[index] = letter;
                    }
                    index += 1;
                }
                buffer[index] = 0;
                break :decamelize buffer;
            };
            return @ptrCast(&message);
        }
    } else unreachable;
}

Switch on the error with an inline else?

1 Like

Ah, that’s it! I forgot we can do that. So the function is now:

fn getErrorMessage(err: anytype) [:0]const u8 {
    @setEvalBranchQuota(200000);
    switch (err) {
        inline else => |e| {
            const message = comptime decamelize: {
                const name = @errorName(e);
                var cap_count: usize = 0;
                for (name, 0..) |letter, i| {
                    if (i > 0 and std.ascii.isUpper(letter)) cap_count += 1;
                }
                var buffer: [name.len + cap_count + 1]u8 = undefined;
                var index: usize = 0;
                for (name, 0..) |letter, i| {
                    if (std.ascii.isUpper(letter)) {
                        if (i > 0) {
                            buffer[index] = ' ';
                            index += 1;
                            buffer[index] = std.ascii.toLower(letter);
                        } else {
                            buffer[index] = letter;
                        }
                    } else {
                        buffer[index] = letter;
                    }
                    index += 1;
                }
                buffer[index] = 0;
                break :decamelize buffer;
            };
            return @ptrCast(&message);
        },
    }
}
1 Like