1 // Written in D programming language
2 /**
3 *   Module handles functions and templates that we lazied to factor out to separate module.
4 *
5 *   Function categories:
6 *   <ul>
7 *   <li> JSON de/serialization based on annotations </li>
8 *   <li> Exception handling functions </li>
9 *   <li> Cheat casting functions </li>
10 *   <li> String processing functions (the only one $(B fromStringz))</li>
11 *   <li> Introspecting templates that cannot be found in Phobos </li> 
12 *   <li> Functional styled utilities for optional values and lazy ranges</li> 
13 *   </ul>
14 *
15 *   Copyright: © 2014 DSoftOut
16 *   License: Subject to the terms of the MIT license, as written in the included LICENSE file.
17 *   Authors: Zaramzan <shamyan.roman@gmail.com>, 
18 *            NCrashed <ncrashed@gmail.com>
19 */
20 module util;
21 
22 import std.algorithm;
23 import std.exception;
24 import std.string;
25 import std.conv;
26 import std.container;
27 import std.traits;
28 import std.typecons;
29 import std.typetuple;
30 import std.range;
31 import std.path;
32 import vibe.data.json;
33 
34 enum APPNAME = "pgator";
35 
36 mixin template t_field(T, alias fieldName)
37 {
38 	mixin("private "~T.stringof~" m_"~fieldName~";");
39 	
40 	mixin("private bool f_"~fieldName~";");
41 	
42 	mixin(T.stringof~" "~fieldName~"() @property { return m_"~fieldName~";}");
43 	
44 	mixin("private void "~fieldName~"("~T.stringof~" f) @property { m_"~fieldName~"= f; f_"~fieldName~"=true;}");
45 }
46 
47 //For deserializeFromJson
48 enum required;
49 
50 //For deserializeFromJson
51 enum possible;
52 
53 
54 /**
55 * Deserializes from Json to type T<br>
56 *
57 * Supported only structs yet
58 *
59 * Example:
60 * ----
61 * struct S
62 * {
63 *    @required
64 *	int a; //get value from Json. Throws RequiredFieldException
65 *
66 *    @possible
67 *	int b; //tries to get value from Json
68 *
69 *	int c; //will be ignored
70 * }
71 *
72 * auto s = deserializeFromJson!S(json);
73 * ------
74 *
75 * Authors: Zaramzan <shamyan.roman@gmail.com>
76 */
77 T deserializeFromJson(T)(Json src) if(is(T == struct))
78 {
79 	T ret;
80 		
81 	if (src.type != Json.Type.object)
82 	{
83 		throw new RequiredJsonObject("Required json object");
84 	}
85 	
86 	void processStruct(string mem, bool isMemberOptional, Ret)(out Ret retMem, Json srcMem)
87 	{
88 		static if (is(Ret == Json))
89 		{
90 			retMem = srcMem;
91 		}
92 		else
93 		{
94 			if (srcMem.type == Json.Type.object)
95 			{	
96 				retMem = deserializeFromJson!Ret(srcMem);
97 			}
98 			else
99 			{
100 				// issue #96, is struct has default constructor 
101 				// and marked with @possible and received null
102 				static if(isMemberOptional && __traits(compiles, Ret() ))
103 				{
104 					if(srcMem.type == Json.Type.null_)
105 					{
106 						retMem = Ret();
107 					} else
108 					{
109 						throw new RequiredFieldException(text("Field ", mem, " must be object in json: ", src));
110 					}
111 				} else
112 				{
113 					throw new RequiredFieldException(text("Field ", mem, " must be object in json: ", src)); 
114 				}
115 			}
116 		}
117 	}
118 	
119 	void processArray(string mem, bool isMemberOptional, Ret)(out Ret retMem, Json srcMem)
120 	{
121 		if (srcMem.type == Json.Type.array)
122 		{
123 			alias ElementType!Ret ElemType;
124 			
125 			ElemType[] arr = new ElemType[0];
126 			
127 			foreach(json; srcMem)
128 			{
129 				static if (is(ElemType == struct))
130 				{
131 					arr ~= deserializeFromJson!ElemType(json);
132 				}
133 				else
134 				{
135 				    static if(__traits(compiles, {ElemType t = null;}))
136 				    {
137 				        if(json.type == Json.Type.null_)
138 				        {
139 				            arr ~= null;
140 				            continue;
141 				        }
142 				    } 
143 				    arr ~= json.to!ElemType;
144 				}
145 			}
146 			
147 			retMem = arr;
148 		} 
149 		else
150 		{
151 			// array could be a null for @possible. issue #96
152 			static if(isMemberOptional)
153 			{
154 				if(srcMem.type == Json.Type.null_)
155 				{
156 					retMem = null;
157 				} else
158 				{
159 					throw new RequiredFieldException(text("Field ", mem, " must be array in json: ", src));
160 				}
161 			} else
162 			{
163 				throw new RequiredFieldException(text("Field ", mem, " must be array in json: ", src));
164 			}
165 		}	
166 	}
167 	
168 	foreach(mem; __traits(allMembers, T))
169 	{	
170 		alias getMemberType!(T, mem) MemberType;
171 		enum isMemberRequired = isRequired!(mem, T);
172 		enum isMemberOptional = isOptional!(mem, T);
173 		
174 		enum srcMem = "src."~mem;
175 		enum retMem = "ret."~mem;
176 		
177 		static if (isMemberRequired || isMemberOptional)
178 		{
179 			if (mixin(srcMem).type != Json.Type.undefined)
180 			{
181 				static if(is(MemberType == struct))
182 				{
183 					processStruct!(mem, isMemberOptional)(mixin(retMem), mixin(srcMem));
184 				} 
185 				else static if(isArray!MemberType && !isSomeString!MemberType)
186 				{
187 					processArray!(mem, isMemberOptional)(mixin(retMem), mixin(srcMem));
188 				}
189 				else
190 				{
191 					mixin(retMem) = mixin(srcMem).to!MemberType();
192 				}
193 			}
194 			else static if (isMemberRequired)
195 			{
196 				throw new RequiredFieldException(text("Field ", mem, " required in json: ", src));
197 			}
198 		}
199 		
200 	}
201 	
202 	return ret;
203 }
204 unittest // issue #96
205 {
206 	struct A
207 	{
208 		@possible
209 		ubyte[] a;
210 	}
211 	
212 	auto a = A(null);
213 	assert(deserializeFromJson!A(serializeToJson(a)) == a);
214 	
215 	struct B
216 	{
217 		@possible
218 		A a;
219 	}
220 	
221 	auto b = B(A(null));
222 	assert(deserializeFromJson!B(serializeToJson(b)) == b);
223 }
224 
225 /**
226 * Serializes struct with $(B @required) attributes fields to Json  <br>
227 * 
228 * Example
229 * ------
230 * struct S
231 * {
232 *    @required
233 *	int a = 1; //will be used
234 *
235 *    @possible
236 *	int b = 2; //will be ignored
237 *
238 *	int c; //will be ignored
239 * }
240 *
241 * writeln(serializeRequiredToJson(S())); // { "a":1 }
242 * ------
243 */
244 Json serializeRequiredToJson(T)(T val)
245 {
246 	static assert (is(T == struct), "Need struct type, not "~T.stringof);
247 	
248 	Json ret = Json.emptyObject;
249 	
250 	foreach(mem; __traits(allMembers, T))
251 	{
252 		static if (isRequired!(mem, T))
253 		{
254 			alias getMemberType!(T, mem) MemType;
255 			
256 			alias vibe.data.json.serializeToJson vibeSer;
257 			
258 			static if (is(MemType == struct))
259 			{
260 				ret[mem] = serializeRequiredToJson!MemType(mixin("val."~mem));
261 			}
262 			else static if (isArray!MemType)
263 			{
264 				alias ElementType!MemType EType;
265 				static if (is(EType == struct))
266 				{
267 					auto j1 = Json.emptyArray;
268 				
269 					foreach(elem; mixin("val."~mem))
270 					{
271 						j1 ~= serializeRequiredToJson(elem);
272 					}
273 					
274 					ret[mem] = j1;
275 				}
276 				else
277 				{
278 					ret[mem] = vibeSer(mixin("val."~mem));
279 				}
280 			}
281 			else
282 			{
283 				ret[mem] = vibeSer(mixin("val."~mem));
284 			}
285 		}
286 	}
287 	
288 	return ret;
289 }
290 
291 private bool isRequired(alias mem, T)()
292 {
293   bool flag = false;
294 	foreach(attr;__traits(getAttributes, mixin("T."~mem)))
295 	{
296 		static if (is(attr == required))
297 		{
298 			flag = true;
299       break;
300 		}
301 	}
302 	
303 	return flag;
304 }
305 
306 private bool isOptional(alias mem, T)()
307 {
308   bool flag = false;
309 	foreach(attr;__traits(getAttributes, mixin("T."~mem)))
310 	{
311 		static if (is(attr == possible))
312 		{
313 			flag = true;
314       break;
315 		}
316 	}
317 	
318 	return flag;
319 }
320 
321 class RequiredFieldException:Exception
322 {
323 	this(in string msg)
324 	{
325 		super(msg);
326 	}
327 }
328 
329 class RequiredJsonObject:Exception
330 {
331 	this(in string msg)
332 	{
333 		super(msg);
334 	}
335 }
336 
337 /**
338 * Tries to call function. On exception throws Ex, otherwise return func() result
339 *
340 * Authors: Zaramzan <shamyan.roman@gmail.com>
341 */
342 template tryEx(Ex, alias func)
343 {
344 	static assert(isSomeFunction!func, "func must be some function");
345 	static assert(is(Ex:Exception), "Ex must be Exception");
346 	
347 	auto wrapper(TP...)(TP params)
348 	{	
349 		try
350 		{
351 			return func(params);
352 		}
353 		catch(Exception ex)
354 		{
355 			throw new Ex(ex.msg, ex.file, ex.line);
356 		}
357 	}
358 
359 	alias wrapper tryEx;
360 }
361 
362 /**
363 * Tries to evaluate par. On exception throws Ex, otherwise return par
364 *
365 * Authors: Zaramzan <shamyan.roman@gmail.com>
366 */
367 T tryEx(Ex, T)(lazy T par)
368 {
369 	static assert(is(Ex:Exception), "Ex must be Exception");
370 	
371 	try
372 	{
373 		return par;
374 	}
375 	catch(Exception ex)
376 	{
377 		throw new Ex(ex.msg, ex.file, ex.line);
378 	}
379 }
380 
381 /**
382 * cast to shared type T
383 *
384 * Warning:
385 *	Don't use this, if you want send object to another thread. It just dirty hack.
386 */
387 template toShared(T)
388 {
389 	private alias Unqual!T P;
390 	
391 	shared(P) toShared(T par)
392 	{
393 		return cast(shared P) cast(P) par;
394 	}
395 }
396 
397 /// cast to unqual type T
398 template toUnqual(T)
399 {
400 	private alias Unqual!T P;
401 	
402 	P toUnqual(T par)
403 	{
404 		return cast(P) par;
405 	}
406 }
407 
408 version(unittest)
409 {
410 	bool thrower()
411 	{
412 		throw new Exception("Exception");
413 	}
414 	
415 	class TestException: Exception
416 	{
417 		@safe pure nothrow this(string msg, string file = __FILE__, size_t line = __LINE__, Throwable next = null)
418 		{
419 			super(msg, file, line, next); 
420 		}
421 	}
422 }
423 
424 unittest
425 {
426 	import std.exception;
427 	
428 	assertThrown!TestException(tryEx!TestException(thrower()));
429 }
430 
431 static if (__VERSION__ < 2066) { // from phobos 2.066-b1
432 	import std.c.string;
433 	
434 	/++
435 	    Returns a D-style array of $(D char) given a zero-terminated C-style string.
436 	    The returned array will retain the same type qualifiers as the input.
437 	
438 	    $(RED Important Note:) The returned array is a slice of the original buffer.
439 	    The original data is not changed and not copied.
440 	+/
441 	
442 	inout(char)[] fromStringz(inout(char)* cString) @system pure {
443 	    return cString ? cString[0 .. strlen(cString)] : null;
444 	}
445 	
446 	///
447 	@system pure unittest
448 	{
449 	    assert(fromStringz(null) == null);
450 	    assert(fromStringz("foo") == "foo");
451 	}
452 } else {
453 	public import std.string: fromStringz;
454 }
455 
456 /// getMemberType
457 /**
458 *   Retrieves member type with $(D name) of class $(D Class). If member is agregate 
459 *   type declaration or simply doesn't exist, retrieves no type. You can check it with
460 *   $(D is) operator.
461 *
462 *   Example:
463 *   -----------
464 *   class A 
465 *   {
466 *       int aField;
467 *       string b;
468 *       bool c;
469 *       
470 *       class B {}
471 *       struct C {}
472 *       union D {}
473 *       interface E {}
474 *   }
475 *
476 *   static assert(is(getMemberType!(A, "aField") == int));
477 *   static assert(is(getMemberType!(A, "b") == string));
478 *   static assert(is(getMemberType!(A, "c") == bool));
479 *
480 *   static assert(!is(getMemberType!(A, "B")));
481 *   static assert(!is(getMemberType!(A, "C")));
482 *   static assert(!is(getMemberType!(A, "D")));
483 *   static assert(!is(getMemberType!(A, "E")));
484 *   -----------
485 */
486 template getMemberType(Class, string name)
487 {
488     static if(hasMember!(Class, name))
489         alias typeof(__traits(getMember, Class, name)) getMemberType;
490 }
491 
492 unittest
493 {
494     class A 
495     {
496         int a;
497         string b;
498         bool c;
499 
500         class B {}
501         struct C {}
502         union D {}
503         interface E {}
504     }
505 
506     static assert(is(getMemberType!(A, "a") == int));
507     static assert(is(getMemberType!(A, "b") == string));
508     static assert(is(getMemberType!(A, "c") == bool));
509 
510     static assert(!is(getMemberType!(A, "B")));
511     static assert(!is(getMemberType!(A, "C")));
512     static assert(!is(getMemberType!(A, "D")));
513     static assert(!is(getMemberType!(A, "E")));
514 }
515 
516 /// FieldNameTuple
517 /**
518 *   Retrieves names of all class/struct/union $(D Class) fields excluding technical ones like this, Monitor.
519 *
520 *   Example:
521 *   ---------
522 *   class A 
523 *   {
524 *       int aField;
525 *
526 *       void func1() {}
527 *       static void func2() {}
528 *
529 *       string b;
530 *
531 *       final func3() {}
532 *       abstract void func4();
533 *
534 *       bool c;
535 *   }
536 *
537 *   static assert(FieldNameTuple!A == ["aField","b","c"]);
538 *   ---------
539 */
540 template FieldNameTuple(Class)
541 {
542     template removeFuncs(funcs...)
543     {
544         static if(funcs.length > 0)
545         {
546             // if member is class/struct/interface declaration second part getMemberType returns no type
547             static if( is(getMemberType!(Class, funcs[0]) == function) ||
548                 !is(getMemberType!(Class, funcs[0])) ||
549                 funcs[0] == "this" || funcs[0] == "Monitor" || funcs[0] == "__ctor" ||
550                 funcs[0] == "opEquals" || funcs[0] == "opCmp" || funcs[0] == "opAssign")
551             {
552                 enum removeFuncs = removeFuncs!(funcs[1..$]);
553             }
554             else
555                 enum removeFuncs = [funcs[0]]~removeFuncs!(funcs[1..$]);
556         }
557         else
558             enum removeFuncs = [];
559     }
560 
561     enum temp = removeFuncs!(__traits(allMembers, Class));
562     static if(temp.length > 0)
563         enum FieldNameTuple = temp[0..$-1];
564     else
565         enum FieldNameTuple = [];
566 }
567 
568 // ddoc example
569 /*unittest
570 {
571     class A 
572     {
573         int a;
574 
575         void func1() {}
576         static void func2() {}
577 
578         string b;
579 
580         final func3() {}
581         abstract void func4();
582 
583         bool c;
584     }
585 
586     static assert(FieldNameTuple!A == ["a","b","c"]);
587 }
588 unittest
589 {
590     class P 
591     {
592         void foo() {}
593 
594         real p;
595     }
596 
597     class A : P
598     {
599         int aField;
600 
601         void func1() {}
602         static void func2() {}
603 
604         string b;
605 
606         final void func3() {}
607         abstract void func4();
608 
609         bool c;
610 
611         void function(int,int) da;
612         void delegate(int, int) db;
613 
614         class B {} 
615         B mB;
616 
617         struct C {}
618         C mC;
619 
620         interface D {}
621     }
622 
623     static assert(FieldNameTuple!A == ["aField","b","c","da","db","mB","mC","p"]);
624     static assert(is(getMemberType!(A, "aField") == int));
625     static assert(is(getMemberType!(A, "b") == string));
626     static assert(is(getMemberType!(A, "c") == bool));
627 
628     struct S1
629     {
630         int a;
631         bool b;
632 
633         void foo() {}
634 
635         real c;
636     }
637 
638     static assert(FieldNameTuple!S1 == ["a","b","c"]);
639 
640     union S2
641     {
642         size_t index;
643         void*   pointer;
644     }
645 
646     static assert(FieldNameTuple!S2 == ["index", "pointer"]);
647 
648     class S3
649     {
650 
651     }
652     static assert(FieldNameTuple!S3 == []);
653 
654     // Properties detected as field. To fix.
655     struct S4
656     {
657         @property S4 dup()
658         {
659             return S4();
660         }
661     }
662     static assert(FieldNameTuple!S4 == ["dup"]);
663 }*/
664 
665 /// Removes one element from the list
666 /**
667 *   NEVER use while iterating the $(B list).
668 */
669 void removeOne(T)(ref DList!T list, T elem)
670 {
671    auto toRemove = list[].find(elem).take(1);
672    list.linearRemove(toRemove);
673 }
674 
675 /**
676 *   Struct-wrapper to handle result of computations,
677 *   that can fail.
678 *
679 *   Example:
680 *   ---------
681 *   class A {}
682 *   
683 *   auto a = new A();
684 *   auto ma = Maybe!A(a);
685 *   auto mb = Maybe!A(null);
686 *   
687 *   assert(!ma.isNothing);
688 *   assert(mb.isNothing);
689 *   
690 *   assert(ma.get == a);
691 *   assertThrown!Error(mb.get);
692 *   
693 *   bool ncase = false, jcase = false;
694 *   ma.map(() {ncase = true;}, (v) {jcase = true;});
695 *   assert(jcase && !ncase);
696 *   
697 *   ncase = jcase = false;
698 *   mb.map(() {ncase = true;}, (v) {jcase = true;});
699 *   assert(!jcase && ncase);
700 *   ---------
701 */
702 struct Maybe(T)
703     if(is(T == class) || is(T == interface) 
704         || isPointer!T || isArray!T) 
705 {
706     private T value;
707     
708     /// Alias to stored type
709     alias T StoredType;
710     
711     /**
712     *   Constructing Maybe from $(B value).
713     *   If pointer is $(B null) methods: $(B isNothing) returns true and 
714     *   $(B get) throws Error.
715     */
716     this(T value) pure
717     {
718         this.value = value;
719     }
720     
721     /**
722     *   Constructing empty Maybe.
723     *   If Maybe is created with the method, it is considred empty
724     *   and $(B isNothing) returns false.
725     */
726     static Maybe!T nothing()
727     {
728         return Maybe!T(null);
729     } 
730     
731     /// Returns true if stored value is null
732     bool isNothing() const
733     {
734         return value is null;
735     }
736     
737     /**
738     *   Unwrap value from Maybe.
739     *   If stored value is $(B null), Error is thrown.
740     */
741     T get()
742     {
743         assert(value !is null, "Stored reference is null!");
744         return value;
745     }
746     
747     /**
748     *   Unwrap value from Maybe.
749     *   If stored value is $(B null), Error is thrown.
750     */
751     const(T) get() const
752     {
753         assert(value !is null, "Stored reference is null!");
754         return value;
755     }
756     
757     /**
758     *   If struct holds $(B null), then $(B nothingCase) result
759     *   is returned. If struct holds not $(B null) value, then
760     *   $(justCase) result is returned. $(B justCase) is fed
761     *   with unwrapped value.
762     */
763     U map(U)(U delegate() nothingCase, U delegate(T) justCase)
764     {
765         return isNothing ? nothingCase() : justCase(value);
766     }
767     
768     /**
769     *   If struct holds $(B null), then $(B nothingCase) result
770     *   is returned. If struct holds not $(B null) value, then
771     *   $(justCase) result is returned. $(B justCase) is fed
772     *   with unwrapped value.
773     */
774     U map(U)(U delegate() nothingCase, U delegate(const T) justCase) const
775     {
776         return isNothing ? nothingCase() : justCase(value);
777     }
778 }
779 
780 unittest
781 {
782     class A {}
783     
784     auto a = new A();
785     auto ma = Maybe!A(a);
786     auto mb = Maybe!A(null);
787     
788     assert(!ma.isNothing);
789     assert(mb.isNothing);
790     
791     assert(ma.get == a);
792     assertThrown!Error(mb.get);
793     
794     bool ncase = false, jcase = false;
795     ma.map(() {ncase = true;}, (v) {jcase = true;});
796     assert(jcase && !ncase);
797     
798     ncase = jcase = false;
799     mb.map(() {ncase = true;}, (v) {jcase = true;});
800     assert(!jcase && ncase);
801 }
802 
803 /**
804 *   Struct-wrapper to handle result of computations,
805 *   that can fail.
806 *
807 *   Example:
808 *   ---------
809 *   struct A {}
810 *   
811 *   auto ma = Maybe!A(A());
812 *   auto mb = Maybe!A.nothing;
813 *   
814 *   assert(!ma.isNothing);
815 *   assert(mb.isNothing);
816 *   
817 *   assert(ma.get == A());
818 *   assertThrown!Error(mb.get);
819 *   
820 *   bool ncase = false, jcase = false;
821 *   ma.map(() {ncase = true;}, (v) {jcase = true;});
822 *   assert(jcase && !ncase);
823 *   
824 *   ncase = jcase = false;
825 *   mb.map(() {ncase = true;}, (v) {jcase = true;});
826 *   assert(!jcase && ncase);
827 *   ---------
828 */
829 struct Maybe(T)
830     if(is(T == struct) || isAssociativeArray!T || isBasicType!T) 
831 {
832     private bool empty;
833     private T value;
834     
835     /// Alias to stored type
836     alias T StoredType;
837     
838     /**
839     *   Constructing empty Maybe.
840     *   If Maybe is created with the method, it is considred empty
841     *   and $(B isNothing) returns false.
842     */
843     static Maybe!T nothing()
844     {
845         Maybe!T ret;
846         ret.empty = true;
847         return ret;
848     } 
849     
850     /**
851     *   Constructing Maybe from $(B value).
852     *   If Maybe is created with the constructor, it is considered non empty
853     *   and $(B isNothing) returns false.
854     */
855     this(T value) pure
856     {
857         this.value = value;
858         empty = false;
859     }
860     
861     /// Returns true if stored value is null
862     bool isNothing() const
863     {
864         return empty;
865     }
866     
867     /**
868     *   Unwrap value from Maybe.
869     *   If the Maybe is empty, Error is thrown.
870     */
871     T get()
872     {
873         assert(!empty, "Stored value is null!");
874         return value;
875     }
876     
877     /**
878     *   Unwrap value from Maybe.
879     *   If the Maybe is empty, Error is thrown.
880     */
881     const(T) get() const
882     {
883         assert(!empty, "Stored value is null!");
884         return value;
885     }
886     
887     /**
888     *   If struct holds $(B null), then $(B nothingCase) result
889     *   is returned. If struct holds not $(B null) value, then
890     *   $(justCase) result is returned. $(B justCase) is fed
891     *   with unwrapped value.
892     */
893     U map(U)(U delegate() nothingCase, U delegate(T) justCase)
894     {
895         return isNothing ? nothingCase() : justCase(value);
896     }
897     
898     /**
899     *   If struct holds $(B null), then $(B nothingCase) result
900     *   is returned. If struct holds not $(B null) value, then
901     *   $(justCase) result is returned. $(B justCase) is fed
902     *   with unwrapped value.
903     */
904     U map(U)(U delegate() nothingCase, U delegate(const T) justCase) const
905     {
906         return isNothing ? nothingCase() : justCase(value);
907     }
908 }
909 
910 unittest
911 {
912     struct A {}
913     
914     auto ma = Maybe!A(A());
915     auto mb = Maybe!A.nothing;
916     
917     assert(!ma.isNothing);
918     assert(mb.isNothing);
919     
920     assert(ma.get == A());
921     assertThrown!Error(mb.get);
922     
923     bool ncase = false, jcase = false;
924     ma.map(() {ncase = true;}, (v) {jcase = true;});
925     assert(jcase && !ncase);
926     
927     ncase = jcase = false;
928     mb.map(() {ncase = true;}, (v) {jcase = true;});
929     assert(!jcase && ncase);
930 }
931 
932 /**
933 *   Transforms delegate into lazy range. Generation is stopped, when
934 *   $(B genfunc) returns $(B Maybe!T.nothing).
935 *
936 *   Example:
937 *   --------
938 *   assert( (() => Maybe!int(1)).generator.take(10).equal(1.repeat.take(10)) );
939 *   assert( (() => Maybe!int.nothing).generator.empty);
940 *   assert( (() 
941 *           {
942 *               static size_t i = 0;
943 *               return i++ < 10 ? Maybe!int(1) : Maybe!int.nothing;
944 *           }
945 *           ).generator.equal(1.repeat.take(10)));
946 *   
947 *   class A {}
948 *   auto a = new A();
949 *   
950 *   assert( (() => Maybe!A(a)).generator.take(10).equal(a.repeat.take(10)) );
951 *   assert( (() => Maybe!A.nothing).generator.empty);
952 *   assert( (() 
953 *           {
954 *               static size_t i = 0;
955 *               return i++ < 10 ? Maybe!A(a) : Maybe!A.nothing;
956 *           }
957 *           ).generator.equal(a.repeat.take(10)));
958 *   --------
959 */
960 auto generator(T)(Maybe!T delegate() genfunc)
961 {
962     struct Sequencer
963     {
964         private Maybe!T currvalue;
965         
966         T front()
967         {
968             assert(!currvalue.isNothing, "Generator range is empty!");
969             return currvalue.get;
970         }
971         
972         bool empty()
973         {
974             return currvalue.isNothing;
975         }
976         
977         void popFront()
978         {
979             currvalue = genfunc();
980         }
981     }
982     static assert(isInputRange!Sequencer);
983     
984     auto s = Sequencer();
985     s.popFront;
986     return s;
987 }
988 unittest
989 {
990     assert( (() => Maybe!int(1)).generator.take(10).equal(1.repeat.take(10)) );
991     assert( (() => Maybe!int.nothing).generator.empty);
992     assert( (() 
993             {
994                 static size_t i = 0;
995                 return i++ < 10 ? Maybe!int(1) : Maybe!int.nothing;
996             }
997             ).generator.equal(1.repeat.take(10)));
998     
999     class A {}
1000     auto a = new A();
1001     
1002     assert( (() => Maybe!A(a)).generator.take(10).equal(a.repeat.take(10)) );
1003     assert( (() => Maybe!A.nothing).generator.empty);
1004     assert( (() 
1005             {
1006                 static size_t i = 0;
1007                 return i++ < 10 ? Maybe!A(a) : Maybe!A.nothing;
1008             }
1009             ).generator.equal(a.repeat.take(10)));
1010 }
1011 
1012 private template TypesOf(T...)
1013 {
1014     static if(T.length == 1)
1015         alias TypesOf = typeof(T[0]);
1016     else
1017         alias TypesOf = TypeTuple!(typeof(T[0]), TypesOf!(T[1..$]));
1018 }
1019 
1020 /**
1021 *   Allows to fast retreiving results from functions that returns a tuple.
1022 */
1023 @property void tie(T...)(Tuple!(TypesOf!T) t)
1024 {
1025     foreach(i, ref var; T)
1026     {
1027         T[i] = t[i];
1028     }
1029 }
1030 /// Example
1031 unittest
1032 {
1033     Tuple!(int, string) foo()
1034     {
1035         return tuple(1, "a");
1036     }
1037     
1038     int x;
1039     string y;
1040     
1041     tie!(x,y) = foo();
1042     assert(x == 1 && y == "a");
1043 }