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