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 }