Good Morning Everyone,
I have been working a little to present some real world example of where core.reflect might be used.
One of them is automatic wrapper generation.
(For example you might want to call D functions from C# or something).
There is a library called autowrap which does this using templates and string mixins.
Which tries to get the __traits
reflection data into string form as soon as possible in order to avoid template overhead.
Here I am reimplemeting a very small part of their C# wrapper.
import core.reflect.reflect;
import core.reflect.utils;
string getDlangInterfaceType(const Type type)
{
assert(isAggregateType(T));
auto u = unqualType(type);
auto slice_type = cast(TypeSlice) type;
if (slice_type !is null)
{
u = unqualType(slice_type.nextOf);
}
string result;
switch(u.serial)
{
case getType("Duration", ReflectFlags.Default, sc).serial :
result = "Marshalled_Duration";
break;
case getType("DateTime", ReflectFlags.Default, sc).serial :
case getType("Date", ReflectFlags.Default, sc).serial :
case getType("TimeOfDay", ReflectFlags.Default, sc).serial :
result = "Marshalled_std_datetime_date";
break;
case getType("SysTime", ReflectFlags.Default, sc).serial :
result = "Marshalled_std_datetime_systime";
break;
default :
result = getAggregate(u).fqn();
}
if (slice_type)
{
return result ~= "[]";
}
return result;
}
static assert(() {
auto st = nodeFromName("SysTime");
return st.getType().getDlangInterfaceType();
} () == "Marshalled_std_datetime_systime");
// works at compile time.
struct S
{
DateTime[] dates;
}
static immutable s = nodeFromName("S", ReflectFlags.Members);
void main()
{
string result;
printf("%s\n", getType(s)
.fields()[0]
.getType()
.getDlangInterfaceType().ptr
);
// works at runtime as well -- output: "Marshalled_std_datetime_date[]"
// perhaps with some garbage at the end if you are unlucky and it's not a '\0'
}
Note the functions getType
,getAggregate
, fields
fqn
and unqualType
are defined in the core.reflect utility module
As a comparison here is the version which exists in autowrap/csharp
today:
private string getDLangInterfaceType(T)() {
import core.time : Duration;
import std.datetime.date : Date, DateTime, TimeOfDay;
import std.datetime.systime : SysTime;
import std.traits : fullyQualifiedName, Unqual;
alias U = Unqual!T;
// FIXME This code really should be reworked so that there's no need to
// check for arrays of date/time types, but rather it's part of the general
// array handling.
static if(is(U == Duration))
return "Marshalled_Duration";
else static if(is(U == DateTime) || is(U == Date) || is(U == TimeOfDay))
return "Marshalled_std_datetime_date";
else static if(is(U == SysTime))
return "Marshalled_std_datetime_systime";
else static if(is(U == Duration[]))
return "Marshalled_Duration[]";
else static if(is(U == DateTime[]) || is(U == Date[]) || is(U == TimeOfDay[]))
return "Marshalled_std_datetime_date[]";
else static if(is(U == SysTime[]))
return "Marshalled_std_datetime_systime[]";
else
return fullyQualifiedName!T;
}
As you can see the version in auto-wrap appears to be shorter.
mainly because there are no separate lines for the types DateTime
Time
and TimeOfDay
.
Also note that you cannot use the getType which takes a string at runtime.
the only reason this works is because the cases are supposed to be constant expressions and at compile time it gets constant-folded into
case 2658LU:
{
result = "Marshalled_Duration";
break;
}
case 53134LU:
case 55933LU:
case 56951LU:
{
result = "Marshalled_std_datetime_date";
break;
}
case 99806LU:
{
result = "Marshalled_std_datetime_systime";
break;
}