[core.reflect] autowrap example

Stefan Koch uplink.coder at googlemail.com
Wed Oct 6 11:43:46 UTC 2021

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 

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)
     auto u = unqualType(type);
     auto slice_type = cast(TypeSlice) type;
     if (slice_type !is null)
         u = unqualType(slice_type.nextOf);

     string result;

         case getType("Duration", ReflectFlags.Default, sc).serial 
             result = "Marshalled_Duration";
         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";
         case getType("SysTime", ReflectFlags.Default, sc).serial :
             result = "Marshalled_std_datetime_systime";
         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)
         // works at runtime as well -- output: 
         // 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 == 
         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[]";
         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 
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";
         case 53134LU:
         case 55933LU:
         case 56951LU:
             result = "Marshalled_std_datetime_date";
         case 99806LU:
             result = "Marshalled_std_datetime_systime";

More information about the Digitalmars-d mailing list