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.aedi.util.traits.partial;
31 
32 import aermicioi.aedi.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 static if (__traits(hasMember, std.meta, "ApplyLeft")) {
108     alias partialPrefixed = ApplyLeft;
109 } else {
110     /**
111     Prefix a template with a set of arguments.
112 
113     Prefix a template with a set of arguments.
114     A prefixed template will have first arguments to be
115     Args, and rest of passed arguments afterwards (Sargs).
116 
117     Params:
118         pred = prefixable template
119         Args = arguments that are prefixed
120         Sargs = arguments that are suffixed
121     **/
122     template partialPrefixed(alias pred, Args...) {
123         template partialPrefixed(Sargs...) {
124             alias partialPrefixed = pred!(Args, Sargs);
125         }
126     }
127 }
128 
129 static if (__traits(hasMember, std.meta, "ApplyLeft")) {
130 
131     alias partialSuffixed = ApplyRight;
132 } else {
133 
134     /**
135     Suffix a template with a set of arguments.
136 
137     Suffix a template with a set of arguments.
138     A suffixed template will have first arguments to be
139     Args, and rest of passed arguments afterwards (Sargs).
140 
141     Params:
142         pred = prefixable template
143         Args = arguments that are suffixed
144         Sargs = arguments that are prefixed
145     **/
146     template partialSuffixed(alias pred, Args...) {
147         template partialSuffixed(Sargs...) {
148             alias partialSuffixed = pred!(Sargs, Args);
149         }
150     }
151 }
152 
153 /**
154 Instantiate a template with Args, and apply them
155 to pred.
156 
157 Params:
158     Args = contained arguments
159     pred = a template that Args will be passed to.
160 **/
161 template applyArgs(Args...) {
162     template applyArgs(alias pred) {
163         alias applyArgs = pred!Args;
164     }
165 }
166 
167 /**
168 Apply to Preds a set of Args.
169 
170 Apply to Preds a set of Args.
171 Given a set of Preds, apply for each Args,
172 and return a Tuple of results.
173 
174 Params:
175     Preds = predicates that will receive Args.
176     Args = arguments that are suffixed
177 **/
178 template partial(Preds...) {
179 
180     template partial(Args...) {
181         alias partial = staticMap!(
182             applyArgs!Args,
183             Preds
184         );
185     }
186 }
187 
188 /**
189 Chain a set of templates, and apply Args as input.
190 
191 Chain a set of templates, and apply Args as input.
192 Description
193 
194 Params:
195 	Preds = a set of predicates to be chained.
196 	Args = arguments passed to chained predicates.
197 
198 Returns:
199 	Result of executing chained Preds with Args.
200 **/
201 template chain(predicates...) {
202     template chain(args...) {
203 
204         template impl(predicates...) {
205             static if (predicates.length > 0) {
206                 alias predicate = predicates[0];
207                 alias impl = predicate!(impl!(predicates[1 .. $]));
208             } else {
209                 alias impl = args;
210             }
211         }
212 
213         alias chain = impl!predicates;
214     }
215 }
216 
217 /**
218 Reverse the order of arguments.
219 
220 Params:
221     args = tuple of template arguments.
222 **/
223 template reverse(args...) {
224     static if (args.length > 0) {
225         alias reverse = AliasSeq!(args[$ - 1], reverse!(args[0 .. $ - 2]));
226     } else {
227         alias reverse = args[0];
228     }
229 }
230 
231 
232 /**
233 Execute trueBranch or falseBranch depending on pred!Args bool result.
234 
235 Params:
236     pred = template depending on which a trueBranch or falseBranch will be executed.
237     trueBranch = template to be executed when pred!Args is true.
238     falseBranch = template to be executed when pred!Args is false.
239 
240 Return:
241     Result of trueBranch or falseBranch depending on pred!Args
242 **/
243 template if_(alias pred, alias trueBranch, alias falseBranch) {
244     template if_ (Args...) {
245         static if (pred!Args) {
246             static if (isTemplate!trueBranch) {
247                 alias if_ = trueBranch!Args;
248             } else {
249                 alias if_ = trueBranch;
250             }
251         } else {
252             static if (isTemplate!trueBranch) {
253                 alias if_ = falseBranch!Args;
254             } else {
255                 alias if_ = falseBranch;
256             }
257         }
258     }
259 }
260 
261 /**
262 Execute pred, if it does not have any compiler errors.
263 
264 Params:
265     pred = template that will be executed if it does not contain errors.
266     response = a response if pred will fail.
267 
268 Return:
269     Result of pred if it does not contain errors or response otherwise
270 **/
271 alias failable(alias pred, alias response) =
272     if_!(
273         partialPrefixed!(
274             compiles,
275             pred
276         ),
277         pred,
278         response
279     );
280 
281 template get(size_t index) {
282     template get(args...) {
283         alias get = args[index];
284     }
285 }
286 
287 template tee(alias predicate, args...) {
288     alias tee = args;
289 
290     alias executed = predicate!args;
291 }
292 
293 alias onFail(alias pred) =
294     if_!(
295         isTrue,
296         isTrue,
297         chain!(
298             get!0,
299             partialPrefixed!(
300                 tee,
301                 pred
302             )
303         )
304     );
305 
306 alias onFailPrint(string error) =
307     onFail!(
308         partialSuffixed!(
309             pragmaMsg,
310             error
311         )
312     );
313 
314 template staticAssert(alias predicate, string error) {
315     template staticAssert(args...) {
316         static assert(predicate!args, error);
317 
318         enum bool staticAssert = predicate!args;
319     }
320 }
321 
322 auto curry(Dg, Args...)(Dg func, auto ref Args args)
323     if (isSomeFunction!Dg) {
324     class Curry {
325         private {
326             Args args;
327             Dg func;
328         }
329 
330         public {
331             this(ref Args args, Dg func) {
332                 this.args = args;
333                 this.func = func;
334             }
335 
336             ReturnType!Dg opCall(Parameters!Dg[Args.length .. $] args) {
337                 static if (is(ReturnType!Dg == void)) {
338                     func(this.args, args);
339                 } else {
340                     return func(this.args, args);
341                 }
342             }
343         }
344     }
345 
346     Curry curry = new Curry(args, func);
347 
348     return &curry.opCall;
349 }
350 
351 template allSatisfied(alias T, Predicates...) {
352 
353     static if (Predicates.length > 1) {
354         enum bool allSatisfied = allSatisfied!(T, Predicates[0]) && allSatisfied!(T, Predicates[1..$]);
355     } else {
356         alias P = Predicates[0];
357         enum bool allSatisfied = P!T;
358     }
359 }
360 
361 template anySatisfied(alias T, Predicates...) {
362 
363     static if (Predicates.length > 1) {
364         enum bool anySatisfied = anySatisfied!(T, Predicates[0]) || anySatisfied!(T, Predicates[1..$]);
365     } else {
366         alias P = Predicates[0];
367         enum bool anySatisfied = P!T;
368     }
369 }