Skip to content

Instantly share code, notes, and snippets.

@zigster64
Created October 26, 2022 02:06
Show Gist options
  • Save zigster64/6427884e9038a6cfdfbb56a2b6518285 to your computer and use it in GitHub Desktop.
Save zigster64/6427884e9038a6cfdfbb56a2b6518285 to your computer and use it in GitHub Desktop.
const std = @import("std");
const Stuff = enum { zeroth, first, second, third, somethingElse };
const OtherStuff = enum { zeroth, first, second, third, somethingElse };
const EnumLookupError = error{InvalidName};
// convert a string into a enum field
pub fn stringToEnum(comptime E: type, name: []const u8) EnumLookupError!E {
inline for (std.meta.fields(E)) |e| {
if (std.mem.eql(u8, name, e.name)) {
return @intToEnum(E, e.value);
}
}
return EnumLookupError.InvalidName;
}
test "lookup enum by name" {
// valid lookup by name
var stuff = try stringToEnum(Stuff, "second");
try std.testing.expect(stuff == Stuff.second);
// use the same function with a different enum type
var other_stuff = try stringToEnum(OtherStuff, "third");
try std.testing.expect(other_stuff == OtherStuff.third);
// failed lookup by name
try std.testing.expectError(EnumLookupError.InvalidName, stringToEnum(Stuff, "notFound"));
try std.testing.expectError(EnumLookupError.InvalidName, stringToEnum(OtherStuff, "notFound"));
// this is another way to do it, but only works with comptime known names
var using_field_access = @field(Stuff, "second");
try std.testing.expect(using_field_access == Stuff.second);
}
test "wont compile if not an emum" {
const notAnEnum = struct {
id: usize = 0,
};
_ = notAnEnum{};
// uncomment this to produce a horrific amount of compile errors
// var this_should_not_compile = try stringToEnum(notAnEnum, "id");
// std.debug.print("got {}\n", .{this_should_not_compile});
}
test "convert enum to string" {
// just use tagName here, dont need to loop over the fields
try std.testing.expect(std.mem.eql(u8, @tagName(Stuff.second), "second"));
try std.testing.expect(std.mem.eql(u8, @tagName(OtherStuff.second), "second"));
}
pub const ArrayOfNames = [][]const u8;
// getNamesOfFields returns an array of names of whatever the type is
pub fn getNamesOfFields(comptime T: type, allocator: std.mem.Allocator) !ArrayOfNames {
const fields = std.meta.fields(T);
// create the array first
var names: ArrayOfNames = try allocator.alloc([]const u8, fields.len);
inline for (fields) |f, index| {
names[index] = f.name;
}
return names;
}
test "get the names of the enum as an array of strings" {
const alloc = std.testing.allocator;
var stuffs = try getNamesOfFields(Stuff, std.testing.allocator);
defer alloc.free(stuffs);
try std.testing.expect(std.mem.eql(u8, stuffs[0], "zeroth"));
try std.testing.expect(std.mem.eql(u8, stuffs[1], "first"));
try std.testing.expect(std.mem.eql(u8, stuffs[2], "second"));
try std.testing.expect(std.mem.eql(u8, stuffs[3], "third"));
try std.testing.expect(std.mem.eql(u8, stuffs[4], "somethingElse"));
var other_stuffs = try getNamesOfFields(Stuff, std.testing.allocator);
defer alloc.free(other_stuffs);
try std.testing.expect(std.mem.eql(u8, other_stuffs[0], "zeroth"));
try std.testing.expect(std.mem.eql(u8, other_stuffs[1], "first"));
try std.testing.expect(std.mem.eql(u8, other_stuffs[2], "second"));
try std.testing.expect(std.mem.eql(u8, other_stuffs[3], "third"));
try std.testing.expect(std.mem.eql(u8, other_stuffs[4], "somethingElse"));
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment