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 {
51 	BoundFunctorOf!(RefType!(typeof(this)), f) r;
52 	r.context = this.reference;
53 	return r;
54 }
55 
56 struct BoundFunctorOf(R, alias f)
57 {
58 	R context;
59 	template opCall(Args...)
60 	{
61 		alias Ret = typeof(__traits(child, context, f)(Args.init));
62 		Ret opCall(auto ref Args args)
63 		{
64 			return __traits(child, context, f)(args);
65 		}
66 	}
67 
68 	/// Ignore - BoundFunctors are already bound
69 	auto bind(R)(R r) { return this; }
70 }
71 
72 static if (haveAliasCtxInference && haveMethodAliasBinding)
73 unittest
74 {
75 	static struct Test
76 	{
77 		void caller(Func)(Func func)
78 		{
79 			func();
80 		}
81 
82 		int i = 0;
83 
84 		void callee()
85 		{
86 			i++;
87 		}
88 
89 		void test()
90 		{
91 			caller(unboundFunctorOf!callee);
92 			caller(  boundFunctorOf!callee);
93 
94 			assert(i == 2);
95 
96 			static struct S
97 			{
98 				int i = 0;
99 
100 				void callee()
101 				{
102 					i++;
103 				}
104 			}
105 			S s;
106 			caller(boundFunctorOf!(S.callee)(&s));
107 
108 			assert(s.i == 1);
109 		}
110 	}
111 
112 	Test test;
113 	test.test();
114 }