Skip to content

Instantly share code, notes, and snippets.

@travisstaloch
Last active September 11, 2022 16:15
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save travisstaloch/a8def7b20eda3e3b2046781f08ddc5c9 to your computer and use it in GitHub Desktop.
Save travisstaloch/a8def7b20eda3e3b2046781f08ddc5c9 to your computer and use it in GitHub Desktop.
Attempt to create tagged union instance from runtime known tag.
const std = @import("std");
const Tag = enum {
A,
B,
C,
};
const Tagged = union(Tag) {
A: bool,
B: i32,
C: []const u8,
};
pub fn main() anyerror!void {
// this works
var tagged = Tagged{ .A = true };
std.debug.warn("{}\n", tagged);
tagged = Tagged{ .B = 42 };
std.debug.warn("{}\n", tagged);
var tag = @as(Tag, tagged);
tag = .C;
std.debug.warn("{}\n", tag);
// these don't work: can't evaluate constant expression
// tagName must be comptime known
// tagged = @unionInit(Tagged, @tagName(tag), false);
// tagged = @unionInit(Tagged, std.meta.tagName(tag), false);
// @field(tagged, @tagName(tag)) = 42;
// this doesn't work: see below
// tagged = initTagged(tag, "foo");
// this works. there must be an easier way?
tagged = try initTagged2(tag, "foo");
tagged = try initTagged2(tag, "foo"[0..]);
std.debug.warn("{}\n", tagged);
tagged = try initTagged3(tag, "foo");
std.debug.warn("{}\n", tagged);
}
// error: expected type 'bool', found '[3]u8'
// fn initTagged(tag: Tag, val: var) Tagged {
// return switch(tag) {
// .A => Tagged{.A = val},
// .B => Tagged{.B = val},
// .C => Tagged{.C = val},
// };
// }
fn initTagged2(tag: Tag, val: var) !Tagged {
// std.debug.warn(@typeName(@typeOf(val)) ++ "\n");
return switch (tag) {
.A => switch (@typeOf(val)) {
bool => Tagged{ .A = val },
else => {
return error.InvalidUnionValue;
},
},
.B => switch (@typeOf(val)) {
i32 => Tagged{ .B = val },
else => {
return error.InvalidUnionValue;
},
},
.C => switch (@typeId(@typeOf(val))) {
.Array,
.Pointer,
=> Tagged{ .C = val },
else => {
return error.InvalidUnionValue;
},
},
};
}
fn initTagged3(tag: Tag, val: var) !Tagged {
const uT = @typeInfo(Tagged).Union;
inline for (uT.fields) |unionField| {
if (@intToEnum(Tag, unionField.enum_field.?.value) == tag) {
if (unionField.field_type == @typeOf(val)) {
return @unionInit(Tagged, unionField.name, val);
} else {
unreachable;
}
}
}
return error.Invalid;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment