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 }