Add apply() to generically extract the contained value.

See also #3.
This commit is contained in:
Sönke Ludwig 2017-05-28 22:05:19 +02:00
parent e4c5ec700a
commit 50e80dc0d9
No known key found for this signature in database
GPG key ID: D95E8DB493EE314C

View file

@ -8,6 +8,7 @@
module taggedalgebraic;
import std.typetuple;
import std.traits : isInstanceOf;
// TODO:
// - distinguish between @property and non@-property methods.
@ -617,6 +618,64 @@ inout(T) get(T, U)(inout(TaggedAlgebraic!U) ta)
return ta.trustedGet!T;
}
/** Calls a the given callback with the static type of the contained value.
The `handler` callback must be a lambda or a single-argument template
function that accepts all possible types that the given `TaggedAlgebraic`
can hold.
Returns:
If `handler` has a non-void return value, its return value gets
forwarded to the caller.
*/
auto apply(alias handler, TA)(TA ta)
if (isInstanceOf!(TaggedAlgebraic, TA))
{
final switch (ta.kind) {
foreach (i, fn; TA.fieldNames) {
case __traits(getMember, ta.Kind, fn):
return handler(get!(TA.FieldTypes[i])(ta));
}
}
}
///
unittest {
union U {
int i;
string s;
}
alias TA = TaggedAlgebraic!U;
auto ta = TA(12);
bool matched = false;
ta.apply!((v) {
static if (is(typeof(v) == int)) {
assert(v == 12);
assert(!matched);
matched = true;
} else {
assert(false);
}
});
assert(matched);
ta = TA("foo");
matched = false;
ta.apply!((v) {
static if (is(typeof(v) == string)) {
assert(v == "foo");
assert(!matched);
matched = true;
} else {
assert(false);
}
});
assert(matched);
}
/// Convenience type that can be used for union fields that have no value (`void` is not allowed).
struct Void {}