vibe-core/source/vibe/internal/interfaceproxy.d

317 lines
8.6 KiB
D
Raw Normal View History

2016-11-08 13:48:38 +00:00
module vibe.internal.interfaceproxy;
import vibe.internal.traits;
import std.meta : staticMap;
import std.traits : BaseTypeTuple;
O asInterface(I, O)(O obj) if (is(I == interface) && is(O : I)) { return obj; }
InterfaceProxyClass!(I, O) asInterface(I, O)(O obj) if (is(I == interface) && !is(O : I)) { return new InterfaceProxyClass!(I, O)(obj); }
InterfaceProxy!I interfaceProxy(I, O)(O o) { return InterfaceProxy!I(o); }
2017-07-23 13:04:11 +00:00
private final class InterfaceProxyClass(I, O) : I
2016-11-08 13:48:38 +00:00
{
import std.meta : AliasSeq;
import std.traits : FunctionAttribute, MemberFunctionsTuple, ReturnType, ParameterTypeTuple, functionAttributes;
private {
O m_obj;
}
this(O obj) { m_obj = obj; }
mixin methodDefs!0;
private mixin template methodDefs(size_t idx) {
alias Members = AliasSeq!(__traits(allMembers, I));
static if (idx < Members.length) {
mixin overloadDefs!(Members[idx]);
mixin methodDefs!(idx+1);
}
}
mixin template overloadDefs(string mem) {
alias Overloads = MemberFunctionsTuple!(I, mem);
private static string impl()
{
import std.format : format;
string ret;
foreach (idx, F; Overloads) {
alias R = ReturnType!F;
enum attribs = functionAttributeString!F(false);
static if (__traits(isVirtualMethod, F)) {
static if (is(R == void))
ret ~= q{override %s void %s(ParameterTypeTuple!(Overloads[%s]) params) { m_obj.%s(params); }}
.format(attribs, mem, idx, mem);
else
ret ~= q{override %s ReturnType!(Overloads[%s]) %s(ParameterTypeTuple!(Overloads[%s]) params) { return m_obj.%s(params); }}
.format(attribs, idx, mem, idx, mem);
}
}
return ret;
}
mixin(impl());
}
}
struct InterfaceProxy(I) if (is(I == interface)) {
import std.meta : AliasSeq;
import std.traits : FunctionAttribute, MemberFunctionsTuple, ReturnType, ParameterTypeTuple, functionAttributes;
import vibe.internal.traits : checkInterfaceConformance;
private {
void[4*(void*).sizeof] m_value;
Proxy m_intf;
}
this(IP : InterfaceProxy!J, J)(IP proxy) @safe
{
() @trusted { m_value[] = proxy.m_value[]; } ();
m_intf = proxy.m_intf;
m_intf._postblit(m_value);
}
this(O)(O object) @trusted
{
static assert(O.sizeof <= m_value.length, "Object ("~O.stringof~") is too big to be stored in an InterfaceProxy.");
2016-11-08 13:48:38 +00:00
import std.conv : emplace;
m_intf = ProxyImpl!O.get();
static if (is(O == struct))
emplace!O(m_value[0 .. O.sizeof]);
2016-11-08 13:48:38 +00:00
(cast(O[])m_value[0 .. O.sizeof])[0] = object;
}
~this() @safe
{
clear();
}
this(this) @safe
{
if (m_intf) m_intf._postblit(m_value);
}
void clear() @safe nothrow
{
if (m_intf) {
m_intf._destroy(m_value);
m_intf = null;
() @trusted { (cast(ubyte[])m_value)[] = 0; } ();
2016-11-08 13:48:38 +00:00
}
}
T extract(T)()
@trusted nothrow {
if (!m_intf || m_intf._typeInfo() !is typeid(T))
assert(false, "Extraction of wrong type from InterfaceProxy.");
return (cast(T[])m_value[0 .. T.sizeof])[0];
}
void opAssign(IP : InterfaceProxy!J, J)(IP proxy) @safe
{
static assert(is(J : I), "Can only assign InterfaceProxy instances of derived interfaces.");
clear();
if (proxy.m_intf) {
() @trusted { m_value[] = proxy.m_value[]; } ();
m_intf = proxy.m_intf;
m_intf._postblit(m_value);
}
}
void opAssign(O)(O object) @trusted
if (checkInterfaceConformance!(O, I) is null)
{
static assert(O.sizeof <= m_value.length, "Object is too big to be stored in an InterfaceProxy.");
import std.conv : emplace;
clear();
m_intf = ProxyImpl!O.get();
if (is(O == class))
(cast(O[])m_value[0 .. O.sizeof])[0] = object;
else emplace!O(m_value[0 .. O.sizeof]);
2016-11-08 13:48:38 +00:00
(cast(O[])m_value[0 .. O.sizeof])[0] = object;
}
bool opCast(T)() const @safe nothrow if (is(T == bool)) { return m_intf !is null; }
mixin allMethods!0;
private mixin template allMethods(size_t idx) {
alias Members = AliasSeq!(__traits(allMembers, I));
static if (idx < Members.length) {
static if (__traits(compiles, __traits(getMember, I, Members[idx])))
mixin overloadMethods!(Members[idx]);
mixin allMethods!(idx+1);
}
}
private mixin template overloadMethods(string member) {
alias Overloads = AliasSeq!(__traits(getOverloads, I, member));
private static string impl()
{
import std.format : format;
string ret;
foreach (idx, F; Overloads) {
enum attribs = functionAttributeString!F(false);
enum is_prop = functionAttributes!F & FunctionAttribute.property;
ret ~= q{%s ReturnType!(Overloads[%s]) %s(%s) { return m_intf.%s(m_value, %s); }}
.format(attribs, idx, member, parameterDecls!(F, idx), member, parameterNames!F);
2016-11-08 13:48:38 +00:00
}
return ret;
}
2016-11-08 13:48:38 +00:00
mixin(impl());
}
private interface Proxy : staticMap!(ProxyOf, BaseTypeTuple!I) {
import std.meta : AliasSeq;
import std.traits : FunctionAttribute, MemberFunctionsTuple, ReturnType, ParameterTypeTuple, functionAttributes;
void _destroy(void[] stor) @safe nothrow;
void _postblit(void[] stor) @safe nothrow;
TypeInfo _typeInfo() @safe nothrow;
mixin methodDecls!0;
private mixin template methodDecls(size_t idx) {
alias Members = AliasSeq!(__traits(derivedMembers, I));
static if (idx < Members.length) {
static if (__traits(compiles, __traits(getMember, I, Members[idx])))
mixin overloadDecls!(Members[idx]);
mixin methodDecls!(idx+1);
}
}
private mixin template overloadDecls(string mem) {
alias Overloads = AliasSeq!(__traits(getOverloads, I, mem));
private static string impl()
{
import std.format : format;
string ret;
foreach (idx, F; Overloads) {
enum attribs = functionAttributeString!F(false);
enum vtype = functionAttributeThisType!F("void[]");
ret ~= q{ReturnType!(Overloads[%s]) %s(%s obj, %s) %s;}
.format(idx, mem, vtype, parameterDecls!(F, idx), attribs);
2016-11-08 13:48:38 +00:00
}
return ret;
}
mixin(impl());
}
}
static final class ProxyImpl(O) : Proxy {
static auto get()
{
static ProxyImpl impl;
if (!impl) impl = new ProxyImpl;
return impl;
}
override void _destroy(void[] stor)
2016-11-08 13:48:38 +00:00
@trusted nothrow {
static if (is(O == struct)) {
try destroy(_extract(stor));
catch (Exception e) assert(false, "Destructor has thrown: "~e.msg);
}
2016-11-08 13:48:38 +00:00
}
override void _postblit(void[] stor)
2016-11-08 13:48:38 +00:00
@trusted nothrow {
static if (is(O == struct)) {
try typeid(O).postblit(stor.ptr);
catch (Exception e) assert(false, "Postblit contructor has thrown: "~e.msg);
}
2016-11-08 13:48:38 +00:00
}
override TypeInfo _typeInfo()
2016-11-08 13:48:38 +00:00
@safe nothrow {
return typeid(O);
}
static ref inout(O) _extract(inout(void)[] stor)
@trusted nothrow pure @nogc {
if (stor.length < O.sizeof) assert(false);
return *cast(inout(O)*)stor.ptr;
2016-11-08 13:48:38 +00:00
}
mixin methodDefs!0;
private mixin template methodDefs(size_t idx) {
alias Members = AliasSeq!(__traits(allMembers, I));
static if (idx < Members.length) {
static if (__traits(compiles, __traits(getMember, I, Members[idx])))
mixin overloadDefs!(Members[idx]);
mixin methodDefs!(idx+1);
}
}
private mixin template overloadDefs(string mem) {
alias Overloads = AliasSeq!(__traits(getOverloads, I, mem));
private static string impl()
{
import std.format : format;
string ret;
foreach (idx, F; Overloads) {
alias R = ReturnType!F;
alias P = ParameterTypeTuple!F;
enum attribs = functionAttributeString!F(false);
enum vtype = functionAttributeThisType!F("void[]");
static if (is(R == void))
ret ~= q{override void %s(%s obj, %s) %s { _extract(obj).%s(%s); }}
.format(mem, vtype, parameterDecls!(F, idx), attribs, mem, parameterNames!F);
2016-11-08 13:48:38 +00:00
else
ret ~= q{override ReturnType!(Overloads[%s]) %s(%s obj, %s) %s { return _extract(obj).%s(%s); }}
.format(idx, mem, vtype, parameterDecls!(F, idx), attribs, mem, parameterNames!F);
2016-11-08 13:48:38 +00:00
}
return ret;
}
mixin(impl());
}
}
}
private string parameterDecls(alias F, size_t idx)()
{
import std.format : format;
import std.traits : ParameterTypeTuple, ParameterStorageClass, ParameterStorageClassTuple;
string ret;
alias PST = ParameterStorageClassTuple!F;
foreach (i, PT; ParameterTypeTuple!F) {
static if (i > 0) ret ~= ", ";
static if (PST[i] & ParameterStorageClass.scope_) ret ~= "scope ";
static if (PST[i] & ParameterStorageClass.out_) ret ~= "out ";
static if (PST[i] & ParameterStorageClass.ref_) ret ~= "ref ";
static if (PST[i] & ParameterStorageClass.lazy_) ret ~= "lazy ";
ret ~= format("ParameterTypeTuple!(Overloads[%s])[%s] param_%s", idx, i, i);
}
return ret;
}
private string parameterNames(alias F)()
{
import std.format : format;
import std.traits : ParameterTypeTuple;
string ret;
foreach (i, PT; ParameterTypeTuple!F) {
static if (i > 0) ret ~= ", ";
ret ~= format("param_%s", i);
}
return ret;
}
2016-11-08 13:48:38 +00:00
private alias ProxyOf(I) = InterfaceProxy!I.Proxy;