1 /** 2 * Copyright: Copyright (c) 2010-2011 Jacob Carlborg. 3 * Authors: Jacob Carlborg 4 * Version: Initial created: Jan 29, 2010 5 * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost Software License 1.0) 6 */ 7 module orange.util.Use; 8 9 import std.typetuple; 10 import std.typecons; 11 import std.traits; 12 13 alias ReturnType ReturnTypeOf; 14 15 /** 16 * This struct can be used to implement, what looks similar to, new statements. This 17 * struct overloads the "in" operator which a delegate can be passed to. The delegate 18 * passed to the "in" operator will then be called at an appropriate time decided by the 19 * implementation of the function returning the Use struct. 20 * 21 * Examples: 22 * --- 23 * Use!(void delegate (), bool) unless (bool condition) 24 * { 25 * Use!(void delegate (), bool) use; 26 * use.args[1] = condition; 27 * 28 * use.args[0] = (void delegate () dg, bool condition) { 29 * if (!condition) 30 * dg(); 31 * }; 32 * 33 * return use; 34 * } 35 * 36 * int a = 3; 37 * int b = 4; 38 * 39 * unless(a == b) in { 40 * println("a != b"); 41 * }; 42 * --- 43 */ 44 struct Use (ARGS...) 45 { 46 static assert (ARGS.length > 0); 47 48 private 49 { 50 alias ReturnTypeOf!(ARGS[0]) ReturnType; 51 52 static if (ARGS.length >= 2) 53 alias Tuple!(ReturnType delegate (ARGS), ARGS[1 .. $]) NEW_ARGS; 54 55 else 56 alias Tuple!(ReturnType delegate (ARGS)) NEW_ARGS; 57 } 58 59 /** 60 * The first argument will be the delegate that performs some arbitrary operation. The 61 * rest of the arguments will be pass as arguments to the delegate in "args[0]". 62 */ 63 NEW_ARGS args; 64 65 /** 66 * Overloads the "in" operator. The given delegate is supplied by the user and will be 67 * called at a time the implementaion has decided. 68 * 69 * Params: 70 * dg = the user supplied delegate that will be called 71 * 72 * Returns: what ever the delegate stored in "args[0]" returns 73 */ 74 ReturnType opBinary(string op: "in")(ARGS[0] dg) 75 { 76 assert(args[0]); 77 78 // Issue: https://d.puremagic.com/issues/show_bug.cgi?id=11614 79 static if (args.length == 1) 80 return args[0](dg); 81 82 else 83 return args[0](dg, args.expand[1 .. $]); 84 } 85 } 86 87 /** 88 * This is a helper struct used by the "restore" function. It overloads the "in" operator 89 * to allow to taking a delegate. 90 */ 91 struct RestoreStruct (U, T) 92 { 93 /// The delegate that performs the operation. 94 U delegate(U delegate (), ref T) dg; 95 96 /// A pointer to the value to pass to the delegate. 97 T* value; 98 99 /** 100 * Overloads the "in" operator. It will simply call the delegate stored in the struct 101 * passing in the given delegate and the value stored in the struct. 102 * 103 * Params: 104 * deleg = the delegate to pass the delegate stored in the struct 105 * 106 * Returns: whatever the delegate stored in the struct returns 107 * 108 * See_Also: restore 109 */ 110 U opBinary(string op: "in")(U delegate () deleg) 111 { 112 return dg(deleg, *value); 113 } 114 } 115 116 /** 117 * Restores the given variable to the value it was when it was passed to the function 118 * after the delegate has finished. 119 * 120 * Examples: 121 * --- 122 * int a = 3; 123 * 124 * restore(a) in { 125 * a = 4; 126 * } 127 * 128 * assert(a == 3); 129 * --- 130 * 131 * Params: 132 * val = variable that will be restored 133 * 134 * Returns: a RestoreStruct 135 * 136 * See_Also: RestoreStruct 137 */ 138 RestoreStruct!(U, T) restore (U = void, T) (ref T val) 139 { 140 RestoreStruct!(U, T) restoreStruct; 141 142 restoreStruct.dg = (U delegate () dg, ref T value){ 143 T t = value; 144 145 static if (is(U == void)) 146 { 147 dg(); 148 value = t; 149 } 150 151 else 152 { 153 auto result = dg(); 154 value = t; 155 156 return result; 157 } 158 }; 159 160 restoreStruct.value = &val; 161 162 return restoreStruct; 163 }