Skip to content

Instantly share code, notes, and snippets.

@rjmcguire
Last active December 22, 2015 06:29
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 rjmcguire/6431542 to your computer and use it in GitHub Desktop.
Save rjmcguire/6431542 to your computer and use it in GitHub Desktop.
Little demo of allowing basic types to implement interfaces.
module traits;
import traits_impl;
import std.typecons;
void main() {
MyInt i = 0x34342343;
writebytes(i);
writebytes2(1);
//writebytes(1); // Cannot call Implements on basic types unless you specify the module for lookup, type:int
}
//enum Order { Big };
//interface IRawBytes { ubyte[] bytes(Order); }
interface IRawBytes { ubyte[] bytes(); }
void writebytes(T)(T item) if (Implements!(T, IRawBytes)) {
import std.stdio : writeln;
writeln(item.bytes);
}
void writebytes2(T)(T item) if (Implements!(T, IRawBytes, __MODULE__)) {
import std.stdio : writeln;
writeln(item.bytes);
}
ubyte[] bytes(ref int i) {
ubyte* ptr;
ptr = cast(ubyte*)&i;
return ptr[0..i.sizeof];
}
typedef int MyInt;
ubyte[] bytes(ref MyInt i) {
ubyte* ptr;
ptr = cast(ubyte*)&i;
return ptr[0..i.sizeof];
}
import std.traits;
import std.typetuple;
import std.typecons;
// Implementation ======================
/** true if T implements interface I using UFCS or methods */
bool Implements(T,I, string mod = "")() {//if (isInterface!I) {
static assert(!(mod=="" && is(T==int)), "Cannot call Implements on basic types unless you specify the module for lookup, type:"~ T.stringof);
bool check() {
static if (mod.length <= 0)
mixin("import "~ moduleName!T ~";");
else
mixin("import "~ mod ~";");
static if (!is(T == int)) //__traits(compiles, moduleName!T))
foreach (m; __traits(allMembers, I)) {
foreach( overload; MemberFunctionsTuple!(I, m) ) {
alias ReturnType!overload RetType;
alias ParameterTypeTuple!overload params;
alias ParameterValueTuple!params Values;
alias ValuesString!Values parms;
T v;
static if (is(RetType == void)) {
//pragma(msg, "v."~m~"("~parms~")", " ", __traits(compiles, mixin("v."~m~"("~Values.stringof[6..$-1]~")")));
enum s = "v."~m~"("~parms~")";
static if (!__traits(compiles, mixin(s))) {
pragma(msg, "missing: "~ fullyQualifiedName!T ~"."~m~params.stringof);
return false;
}
} else {
RetType ret;
//pragma(msg, "v."~m~"("~parms~")", " ", __traits(compiles, mixin("ret = v."~m~"("~Values.stringof[6..$-1]~")")))
enum s = "ret = v."~m~"("~parms~")";
static if (!__traits(compiles, mixin(s))) {
pragma(msg, "missing: "~ fullyQualifiedName!RetType ~" "~ fullyQualifiedName!T ~"."~m~params.stringof);
return false;
}
}
}
}
return true;
}
static if(check())
return true;
else {
pragma(msg, fullyQualifiedName!T ~", does not implement interface: "~ fullyQualifiedName!I);
return false;
}
}
string ValuesString(Values...)() {
static if (Values.length>0) {
return Values.stringof[6..$-1];
} else {
return "";
}
}
template ParameterValueTuple(Specs...) {
template parseSpecs(Specs...)
{
static if (Specs.length == 0)
{
alias TypeTuple!() parseSpecs;
}
else static if (is(Specs[0]))
{
static if (is(typeof(Specs[1]) : string))
{
alias TypeTuple!(Specs[0 .. 2].init,
parseSpecs!(Specs[2 .. $])) parseSpecs;
}
else
{
alias TypeTuple!(Specs[0].init,
parseSpecs!(Specs[1 .. $])) parseSpecs;
}
}
else
{
static assert(0, "Attempted to instantiate Tuple with an "
~"invalid argument: "~ Specs[0].stringof);
}
}
alias parseSpecs!Specs ParameterValueTuple;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment