1 /**
2  * Method binding - using alias inference patch
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.binding;
15 
16 import ae.utils.meta : thisOf;
17 import ae.utils.meta.caps;
18 import ae.utils.meta.reference;
19 
20 /// Create unbound functor of a method
21 template unboundFunctorOf(alias f)
22 {
23 	static @property auto unboundFunctorOf()
24 	{
25 		UnboundFunctorOf!f r;
26 		return r;
27 	}
28 }
29 struct UnboundFunctorOf(alias f)
30 {
31 	alias opCall = f;
32 
33 	alias R = RefType!(thisOf!f);
34 	auto bind(R r) { return boundFunctorOf!f(r); }
35 }
36 
37 /// Create bound functor of a method
38 template boundFunctorOf(alias f)
39 {
40 	static @property auto boundFunctorOf(T)(T context)
41 	{
42 		BoundFunctorOf!(T, f) r;
43 		r.context = context;
44 		return r;
45 	}
46 }
47 
48 /// ditto
49 @property auto boundFunctorOf(alias f)()
50 if (is(typeof(this))) // haveMethodAliasBinding
51 {
52 	BoundFunctorOf!(RefType!(typeof(this)), f) r;
53 	r.context = this.reference;
54 	return r;
55 }
56 
57 struct BoundFunctorOf(R, alias f)
58 {
59 	R context;
60 	template opCall(Args...)
61 	{
62 		alias Ret = typeof(__traits(child, context, f)(Args.init));
63 		Ret opCall(auto ref Args args)
64 		{
65 			return __traits(child, context, f)(args);
66 		}
67 	}
68 
69 	/// Ignore - BoundFunctors are already bound
70 	auto bind(R)(R r) { return this; }
71 }
72 
73 static if (haveChildTrait)
74 unittest
75 {
76 	static struct Test
77 	{
78 		void caller(Func)(Func func)
79 		{
80 			func();
81 		}
82 
83 		int i = 0;
84 
85 		void callee()
86 		{
87 			i++;
88 		}
89 
90 		void test()
91 		{
92 			caller(unboundFunctorOf!callee.bind(&this));
93 			assert(i == 1);
94 
95 			static if (haveMethodAliasBinding) // or is it haveAliasCtxInference ?
96 			{
97 				caller(unboundFunctorOf!callee);
98 				caller(  boundFunctorOf!callee);
99 
100 				assert(i == 3);
101 			}
102 
103 			static struct S
104 			{
105 				int i = 0;
106 
107 				void callee()
108 				{
109 					i++;
110 				}
111 			}
112 			S s;
113 			caller(boundFunctorOf!(S.callee)(&s));
114 
115 			assert(s.i == 1);
116 		}
117 	}
118 
119 	Test test;
120 	test.test();
121 }