Skip to content

Instantly share code, notes, and snippets.

@atilaneves
Last active May 25, 2016 21:30
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save atilaneves/b40c4d030c70686ffa3b8543018f6a7e to your computer and use it in GitHub Desktop.
Save atilaneves/b40c4d030c70686ffa3b8543018f6a7e to your computer and use it in GitHub Desktop.
Create an object of a voldemort struct type that implements an interface
import std.traits;
template Identity(alias T) {
alias Identity = T;
}
template InterfaceToStruct(T) if(is(T == interface)) {
string mixinStr() {
import std.conv: to;
string str = "struct Impl {\n";
str ~= q{
@property void returnValue(string memberStr, V)(V value) if(!isDelegate!V) {
alias member = Identity!(__traits(getMember, T, memberStr));
mixin(memberStr ~ `Impl = ` ~ Parameters!member.stringof ~ `{ return value; };`);
}
@property void returnValue(string memberStr, V)(V value) if(isDelegate!V) {
mixin(memberStr ~ "Impl = value;");
}
};
str ~= "\n";
foreach(memberStr; __traits(allMembers, T)) {
alias member = Identity!(__traits(getMember, T, memberStr));
alias R = ReturnType!member;
static if(isAbstractFunction!member) {
// this is the name of the delegate that implements the functionality
enum implName = memberStr ~ "Impl";
// special case for return type void
static if(is(R == void)) {
enum prefix = " if(" ~ implName ~ " !is null) ";
}
else {
enum prefix = " return " ~
implName ~ " is null ? " ~ R.stringof ~ ".init : ";
}
// body of the "real" function (e.g. popFront)
string body_ = implName ~ "(";
foreach(i, _; Parameters!member) {
body_ ~= "arg" ~ i.to!string ~ ", ";
}
body_ ~= ");\n";
// declare a delegate member variable to hold the implementation
str ~= " " ~ R.stringof ~ ` delegate` ~ Parameters!member.stringof ~
" " ~ implName ~ ";\n";
// declare the "real" function (e.g. popFront)
str ~= " " ~ R.stringof ~ ` ` ~ memberStr ~ "(";
foreach(i, param; Parameters!member) {
str ~= param.stringof ~ " arg" ~ i.to!string ~ ", ";
}
// fill in the body, forwarding to the implementation delegate
// if not null, else return T.init
str ~= ") {\n" ~ prefix ~ body_ ~ " }\n";
}
}
str ~= "}\n";
return str;
}
enum _str = mixinStr;
mixin(_str); // horcrux Voldemort type
auto InterfaceToStruct() {
return Impl();
}
}
unittest {
import std.range.interfaces: InputRange;
import std.range: take, isInputRange;
import std.algorithm: equal;
auto r = InterfaceToStruct!(InputRange!int);
static assert(isInputRange!(typeof(r))); //it's an InputRange alright...
static assert(is(typeof(r) == struct)); // and a struct, not an interface
// r is now a default InputRange of int, so an infinite range of 0
// front: 0 (int.init)
// popFront: does nothing
// empty: false (bool.init)
assert(equal(r.take(5), [0, 0, 0, 0, 0])); // need `take` since r is infinite
r.returnValue!"front" = 42;
assert(equal(r.take(5), [42, 42, 42, 42, 42])); // need `take` since r is infinite
int i;
r.returnValue!"empty" = () { return i++ == 3; };
assert(equal(r, [42, 42, 42])); // r is no longer infinite
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment