1 /**
2 License:
3 	Boost Software License - Version 1.0 - August 17th, 2003
4 
5 	Permission is hereby granted, free of charge, to any person or organization
6 	obtaining a copy of the software and accompanying documentation covered by
7 	this license (the "Software") to use, reproduce, display, distribute,
8 	execute, and transmit the Software, and to prepare derivative works of the
9 	Software, and to permit third-parties to whom the Software is furnished to
10 	do so, all subject to the following:
11 	
12 	The copyright notices in the Software and this entire statement, including
13 	the above license grant, this restriction and the following disclaimer,
14 	must be included in all copies of the Software, in whole or in part, and
15 	all derivative works of the Software, unless such copies or derivative
16 	works are solely in the form of machine-executable object code generated by
17 	a source language processor.
18 	
19 	THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20 	IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 	FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
22 	SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
23 	FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
24 	ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
25 	DEALINGS IN THE SOFTWARE.
26 
27 Authors:
28 	aermicioi
29 **/
30 module aermicioi.util.traits.partial;
31 
32 import aermicioi.util.traits.traits;
33 import std.meta;
34 import std.traits;
35 
36 /**
37 Instantiate a template that will check equality of first with second
38 
39 Params:
40     first = first element
41     second = second element
42     
43 Returns:
44     bool true if equal, false otherwise 
45 **/
46 template eq(alias first) {
47     enum bool eq(alias second) = (first == second);
48 }
49 
50 /**
51 Instantiate a template that will check if first is greater than second
52 
53 Params:
54     first = first element
55     second = second element
56     
57 Returns:
58     bool true if greater, false otherwise 
59 **/
60 template gt(alias first) {
61     enum bool eq(alias second) = (first > second);
62 }
63 
64 /**
65 Instantiate a template that will check if first is less than second
66 
67 Params:
68     first = first element
69     second = second element
70     
71 Returns:
72     bool true if lesser, false otherwise 
73 **/
74 template lt(alias first) {
75     enum bool eq(alias second) = (first < second);
76 }
77 
78 /**
79 Instantiate a template that will check if first is greater or equal than second
80 
81 Params:
82     first = first element
83     second = second element
84     
85 Returns:
86     bool true if greater or equal, false otherwise 
87 **/
88 template gte(alias first) {
89     enum bool eq(alias second) = (first >= second);
90 }
91 
92 /**
93 Instantiate a template that will check if first is less or equal than second
94 
95 Params:
96     first = first element
97     second = second element
98     
99 Returns:
100     bool true if lesser or equal, false otherwise 
101 **/
102 template lte(alias first) {
103     enum bool eq(alias second) = (first <= second);
104 }
105 
106 /**
107 Prefix a template with a set of arguments.
108 
109 Prefix a template with a set of arguments.
110 A prefixed template will have first arguments to be
111 Args, and rest of passed arguments afterwards (Sargs).
112 
113 Params:
114     pred = prefixable template
115     Args = arguments that are prefixed
116     Sargs = arguments that are suffixed
117 **/
118 template partialPrefixed(alias pred, Args...) {
119     template partialPrefixed(Sargs...) {
120         alias partialPrefixed = pred!(Args, Sargs);
121     }
122 }
123 
124 /**
125 Suffix a template with a set of arguments.
126 
127 Suffix a template with a set of arguments.
128 A suffixed template will have first arguments to be
129 Args, and rest of passed arguments afterwards (Sargs).
130 
131 Params:
132     pred = prefixable template
133     Args = arguments that are suffixed
134     Sargs = arguments that are prefixed
135 **/
136 template partialSuffixed(alias pred, Args...) {
137     template partialSuffixed(Sargs...) {
138         alias partialSuffixed = pred!(Sargs, Args);
139     }
140 }
141 
142 /**
143 Instantiate a template with Args, and apply them
144 to pred.
145 
146 Params:
147     Args = contained arguments
148     pred = a template that Args will be passed to.
149 **/
150 template applyArgs(Args...) {
151     template applyArgs(alias pred) {
152         alias applyArgs = pred!Args;
153     }
154 }
155 
156 /**
157 Apply to Preds a set of Args.
158 
159 Apply to Preds a set of Args.
160 Given a set of Preds, apply for each Args,
161 and return a Tuple of results.
162 
163 Params:
164     Preds = predicates that will receive Args.
165     Args = arguments that are suffixed
166 **/
167 template partial(Preds...) {
168     
169     template partial(Args...) {
170         alias partial = staticMap!(
171             applyArgs!Args,
172             Preds
173         );
174     }
175 }
176 
177 /**
178 Chain a set of templates, and apply Args as input.
179 
180 Chain a set of templates, and apply Args as input.
181 Description
182 
183 Params:
184 	Preds = a set of predicates to be chained.
185 	Args = arguments passed to chained predicates.
186 
187 Returns:
188 	Result of executing chained Preds with Args.
189 **/
190 template chain(predicates...) {
191     template chain(args...) {
192         
193         template impl(predicates...) {
194             static if (predicates.length > 0) {
195                 alias predicate = predicates[0];
196                 alias impl = predicate!(impl!(predicates[1 .. $]));
197             } else {
198                 alias impl = args;
199             }
200         }
201         
202         alias chain = impl!predicates;
203     }
204 }
205 
206 /**
207 Reverse the order of arguments.
208 
209 Params:
210     args = tuple of template arguments.
211 **/
212 template reverse(args...) {
213     static if (args.length > 0) {
214         alias reverse = AliasSeq!(args[$ - 1], reverse!(args[0 .. $ - 2]));
215     } else {
216         alias reverse = args[0];
217     }
218 }
219 
220 
221 /**
222 Execute trueBranch or falseBranch depending on pred!Args bool result.
223 
224 Params:
225     pred = template depending on which a trueBranch or falseBranch will be executed.
226     trueBranch = template to be executed when pred!Args is true.
227     falseBranch = template to be executed when pred!Args is false.
228     
229 Return:
230     Result of trueBranch or falseBranch depending on pred!Args
231 **/
232 template if_(alias pred, alias trueBranch, alias falseBranch) {
233     template if_ (Args...) {
234         static if (pred!Args) {
235             static if (isTemplate!trueBranch) {
236                 alias if_ = trueBranch!Args;
237             } else {
238                 alias if_ = trueBranch;
239             }
240         } else {
241             static if (isTemplate!trueBranch) {
242                 alias if_ = falseBranch!Args;
243             } else {
244                 alias if_ = falseBranch;
245             }
246         }
247     }
248 }
249 
250 /**
251 Execute pred, if it does not have any compiler errors.
252 
253 Params:
254     pred = template that will be executed if it does not contain errors.
255     response = a response if pred will fail.
256     
257 Return:
258     Result of pred if it does not contain errors or response otherwise
259 **/
260 alias failable(alias pred, alias response) =
261     if_!(
262         partialPrefixed!(
263             compiles,
264             pred
265         ),
266         pred,
267         response
268     );
269     
270 template get(size_t index) {
271     template get(args...) {
272         alias get = args[index];
273     }
274 }
275     
276 template tee(alias predicate, args...) {
277     alias tee = args;
278     
279     alias executed = predicate!args;
280 }
281 
282 alias onFail(alias pred) = 
283     if_!(
284         isTrue,
285         isTrue,
286         chain!(
287             get!0,
288             partialPrefixed!(
289                 tee,
290                 pred
291             )
292         )
293     );
294     
295 alias onFailPrint(string error) = 
296     onFail!(
297         partialSuffixed!(
298             pragmaMsg,
299             error
300         )
301     );
302 
303 template staticAssert(alias predicate, string error) {
304     template staticAssert(args...) {
305         static assert(predicate!args, error);
306         
307         enum bool staticAssert = predicate!args;
308     }
309 }
310 
311 auto curry(Dg, Args...)(Dg func, auto ref Args args)
312     if (isSomeFunction!Dg) {
313     import std.typecons;
314     class Curry {
315         private {
316             Tuple!Args args;
317             Dg func;
318         }
319         
320         public {
321             this(ref Args args, Dg func) {
322                 this.args = tuple!(args);
323                 this.func = func;
324             }
325             
326             ReturnType!Dg opCall(Parameters!Dg[Args.length .. $] args) {
327                 static if (is(ReturnType!Dg == void)) {
328                     func(this.args.expand, args);
329                 } else {
330                     return func(this.args.expand, args);
331                 }
332             }
333         }
334     }
335     
336     Curry curry = new Curry(args, func);
337     
338     return &curry.opCall;
339 }