1 /** 2 * Proxy objects 3 * 4 * License: 5 * This Source Code Form is subject to the terms of 6 * the Mozilla Public License, v. 2.0. If a copy of 7 * the MPL was not distributed with this file, You 8 * can obtain one at http://mozilla.org/MPL/2.0/. 9 * 10 * Authors: 11 * Vladimir Panteleev <vladimir@thecybershadow.net> 12 */ 13 14 module ae.utils.meta.proxy; 15 16 import std.traits; 17 18 import ae.utils.meta.caps; 19 import ae.utils.meta.reference; 20 21 /// Mixes in an opDispatch that forwards to the specified target prefix. 22 mixin template StringMixinProxy(string targetPrefix) 23 { 24 // from std.typecons.Proxy 25 template opDispatch(string name) 26 { 27 static if (is(typeof(mixin(targetPrefix~name)) == function)) 28 { 29 // non template function 30 auto ref opDispatch(this X, Args...)(auto ref Args args) { return mixin(targetPrefix~name~q{(args)}); } 31 } 32 else static if (is(typeof({ enum x = mixin(targetPrefix~name); }))) 33 { 34 // built-in type field, manifest constant, and static non-mutable field 35 enum opDispatch = mixin(targetPrefix~name); 36 } 37 else static if (is(typeof(mixin(targetPrefix~name))) 38 || (is(typeof(__traits(getOverloads, __traits(parent, mixin(targetPrefix~name)), name))) 39 && __traits(getOverloads, __traits(parent, mixin(targetPrefix~name)), name).length != 0 40 ) 41 ) 42 { 43 // field or property function 44 @property auto ref opDispatch(this X)() { return mixin(targetPrefix~name ); } 45 @property auto ref opDispatch(this X, V)(auto ref V v) { return mixin(targetPrefix~name~q{ = v}); } 46 } 47 else 48 { 49 // member template 50 template opDispatch(T...) 51 { 52 enum targs = T.length ? "!T" : ""; 53 auto ref opDispatch(this X, Args...)(auto ref Args args){ return mixin(targetPrefix~name~targs~q{(args)}); } 54 } 55 } 56 } 57 } 58 59 /// Instantiates to a type that points to a named 60 /// sub-aggregate of a struct or class. 61 template SubProxy(alias S, string exp) 62 { 63 alias RefType!S R; 64 65 struct SubProxy 66 { 67 R _subProxy; 68 69 this(R s) { _subProxy = s; } 70 71 mixin StringMixinProxy!(q{_subProxy..} ~ exp); 72 } 73 } 74 75 alias parentOf(alias a) = Identity!(__traits(parent, a)); 76 77 /// Returns a type that points to a sub-aggregate 78 /// (mixin or template alias) of a struct or class. 79 /// Requires __traits(child) support. 80 template scopeProxy(alias a) 81 { 82 @property auto scopeProxy() 83 { 84 return ScopeProxy!a(this.reference); 85 } 86 87 static @property auto scopeProxy(R)(R r) 88 { 89 return ScopeProxy!a(r); 90 } 91 } 92 93 template ScopeProxy(alias a) 94 { 95 static assert(haveChildTrait, "Your compiler doesn't support __traits(child)"); 96 97 alias parentOf!a S; 98 alias RefType!S R; 99 100 struct ScopeProxy 101 { 102 R _scopeProxy; 103 104 this(R s) { _scopeProxy = s; } 105 106 mixin StringMixinProxy!q{__traits(child, _scopeProxy, a).}; 107 } 108 } 109 110 static if (haveChildTrait) 111 unittest 112 { 113 // Can't declare template at statement level 114 static struct Dummy 115 { 116 static template T(alias a) 117 { 118 void set(int n) 119 { 120 a = n; 121 } 122 } 123 } 124 125 static struct S 126 { 127 int i; 128 alias t = Dummy.T!i; 129 130 auto getProxy() { return scopeProxy!t; } 131 } 132 133 { 134 S s; 135 auto w = ScopeProxy!(S.t)(&s); 136 w.set(42); 137 assert(s.i == 42); 138 } 139 140 { 141 S s; 142 auto w = scopeProxy!(S.t)(&s); 143 w.set(42); 144 assert(s.i == 42); 145 } 146 147 { 148 S s; 149 auto w = s.getProxy(); 150 w.set(42); 151 assert(s.i == 42); 152 } 153 154 { 155 S s; 156 auto w = SubProxy!(S, "t.")(&s); 157 w.set(42); 158 assert(s.i == 42); 159 } 160 }