Last active
September 11, 2022 16:15
-
-
Save travisstaloch/a8def7b20eda3e3b2046781f08ddc5c9 to your computer and use it in GitHub Desktop.
Attempt to create tagged union instance from runtime known tag.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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