Improve dynamic type conversion.

- Uses std.conv.to to implement opCast instead of just supporting implicit type conversions
- Adds .toString to make to!string(ta) return the expected result
This commit is contained in:
Sönke Ludwig 2016-04-04 13:40:58 +02:00
parent c59fae1b2e
commit a0415ed13c

View file

@ -125,22 +125,43 @@ struct TaggedAlgebraic(U) if (is(U == union) || is(U == struct))
}
/// Enables conversion or extraction of the stored value.
T opCast(T)() inout
T opCast(T)()
{
import std.conv : to;
final switch (m_kind) {
foreach (i, FT; FieldTypes) {
case __traits(getMember, Kind, fieldNames[i]):
static if (is(typeof(trustedGet!(fieldNames[i])) : T)) {
return trustedGet!(fieldNames[i]);
static if (is(typeof(to!T(trustedGet!(fieldNames[i]))))) {
return to!T(trustedGet!(fieldNames[i]));
} else {
assert(false, "Cannot cast a "~(cast(Kind)m_kind).to!string~" value to "~T.stringof);
assert(false, "Cannot cast a "~(cast(Kind)m_kind).to!string~" value ("~FT.stringof~") to "~T.stringof);
}
}
}
assert(false); // never reached
}
/// ditto
T opCast(T)() const
{
// this method needs to be duplicated because inout doesn't work with to!()
import std.conv : to;
final switch (m_kind) {
foreach (i, FT; FieldTypes) {
case __traits(getMember, Kind, fieldNames[i]):
static if (is(typeof(to!T(trustedGet!(fieldNames[i]))))) {
return to!T(trustedGet!(fieldNames[i]));
} else {
assert(false, "Cannot cast a "~(cast(Kind)m_kind).to!string~" value ("~FT.stringof~") to "~T.stringof);
}
}
}
assert(false); // never reached
}
/// Uses `cast(string)`/`to!string` to return a string representation of the enclosed value.
string toString() const { return cast(string)this; }
// NOTE: "this TA" is used here as the functional equivalent of inout,
// just that it generates one template instantiation per modifier
@ -200,6 +221,7 @@ struct TaggedAlgebraic(U) if (is(U == union) || is(U == struct))
assert(ta == 12);
assert(cast(int)ta == 12);
assert(cast(long)ta == 12);
assert(cast(short)ta == 12);
ta += 12;
assert(ta == 24);
@ -216,6 +238,30 @@ struct TaggedAlgebraic(U) if (is(U == union) || is(U == struct))
assert(ta.test() == 4);
}
unittest { // std.conv integration
import std.conv : to;
static struct S {
int v;
int test() { return v / 2; }
}
static union Test {
typeof(null) null_;
int number;
string text;
}
alias TA = TaggedAlgebraic!Test;
TA ta;
assert(ta.kind == TA.Kind.null_);
ta = "34";
assert(ta == "34");
assert(to!int(ta) == 34, to!string(to!int(ta)));
assert(to!string(ta) == "34", to!string(ta));
}
/** Multiple fields are allowed to have the same type, in which case the type
ID enum is used to disambiguate.
*/