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