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 /**
517 *   Struct-wrapper to handle result of computations,
518 *   that can fail.
519 *
520 *   Example:
521 *   ---------
522 *   class A {}
523 *   
524 *   auto a = new A();
525 *   auto ma = Maybe!A(a);
526 *   auto mb = Maybe!A(null);
527 *   
528 *   assert(!ma.isNothing);
529 *   assert(mb.isNothing);
530 *   
531 *   assert(ma.get == a);
532 *   assertThrown!Error(mb.get);
533 *   
534 *   bool ncase = false, jcase = false;
535 *   ma.map(() {ncase = true;}, (v) {jcase = true;});
536 *   assert(jcase && !ncase);
537 *   
538 *   ncase = jcase = false;
539 *   mb.map(() {ncase = true;}, (v) {jcase = true;});
540 *   assert(!jcase && ncase);
541 *   ---------
542 */
543 struct Maybe(T)
544     if(is(T == class) || is(T == interface) 
545         || isPointer!T || isArray!T) 
546 {
547     private T value;
548     
549     /// Alias to stored type
550     alias T StoredType;
551     
552     /**
553     *   Constructing Maybe from $(B value).
554     *   If pointer is $(B null) methods: $(B isNothing) returns true and 
555     *   $(B get) throws Error.
556     */
557     this(T value) pure
558     {
559         this.value = value;
560     }
561     
562     /**
563     *   Constructing empty Maybe.
564     *   If Maybe is created with the method, it is considred empty
565     *   and $(B isNothing) returns false.
566     */
567     static Maybe!T nothing()
568     {
569         return Maybe!T(null);
570     } 
571     
572     /// Returns true if stored value is null
573     bool isNothing() const
574     {
575         return value is null;
576     }
577     
578     /**
579     *   Unwrap value from Maybe.
580     *   If stored value is $(B null), Error is thrown.
581     */
582     T get()
583     {
584         assert(value !is null, "Stored reference is null!");
585         return value;
586     }
587     
588     /**
589     *   Unwrap value from Maybe.
590     *   If stored value is $(B null), Error is thrown.
591     */
592     const(T) get() const
593     {
594         assert(value !is null, "Stored reference is null!");
595         return value;
596     }
597     
598     /**
599     *   If struct holds $(B null), then $(B nothingCase) result
600     *   is returned. If struct holds not $(B null) value, then
601     *   $(justCase) result is returned. $(B justCase) is fed
602     *   with unwrapped value.
603     */
604     U map(U)(U delegate() nothingCase, U delegate(T) justCase)
605     {
606         return isNothing ? nothingCase() : justCase(value);
607     }
608     
609     /**
610     *   If struct holds $(B null), then $(B nothingCase) result
611     *   is returned. If struct holds not $(B null) value, then
612     *   $(justCase) result is returned. $(B justCase) is fed
613     *   with unwrapped value.
614     */
615     U map(U)(U delegate() nothingCase, U delegate(const T) justCase) const
616     {
617         return isNothing ? nothingCase() : justCase(value);
618     }
619 }
620 
621 unittest
622 {
623     class A {}
624     
625     auto a = new A();
626     auto ma = Maybe!A(a);
627     auto mb = Maybe!A(null);
628     
629     assert(!ma.isNothing);
630     assert(mb.isNothing);
631     
632     assert(ma.get == a);
633     assertThrown!Error(mb.get);
634     
635     bool ncase = false, jcase = false;
636     ma.map(() {ncase = true;}, (v) {jcase = true;});
637     assert(jcase && !ncase);
638     
639     ncase = jcase = false;
640     mb.map(() {ncase = true;}, (v) {jcase = true;});
641     assert(!jcase && ncase);
642 }
643 
644 /**
645 *   Struct-wrapper to handle result of computations,
646 *   that can fail.
647 *
648 *   Example:
649 *   ---------
650 *   struct A {}
651 *   
652 *   auto ma = Maybe!A(A());
653 *   auto mb = Maybe!A.nothing;
654 *   
655 *   assert(!ma.isNothing);
656 *   assert(mb.isNothing);
657 *   
658 *   assert(ma.get == A());
659 *   assertThrown!Error(mb.get);
660 *   
661 *   bool ncase = false, jcase = false;
662 *   ma.map(() {ncase = true;}, (v) {jcase = true;});
663 *   assert(jcase && !ncase);
664 *   
665 *   ncase = jcase = false;
666 *   mb.map(() {ncase = true;}, (v) {jcase = true;});
667 *   assert(!jcase && ncase);
668 *   ---------
669 */
670 struct Maybe(T)
671     if(is(T == struct) || isAssociativeArray!T || isBasicType!T) 
672 {
673     private bool empty;
674     private T value;
675     
676     /// Alias to stored type
677     alias T StoredType;
678     
679     /**
680     *   Constructing empty Maybe.
681     *   If Maybe is created with the method, it is considred empty
682     *   and $(B isNothing) returns false.
683     */
684     static Maybe!T nothing()
685     {
686         Maybe!T ret;
687         ret.empty = true;
688         return ret;
689     } 
690     
691     /**
692     *   Constructing Maybe from $(B value).
693     *   If Maybe is created with the constructor, it is considered non empty
694     *   and $(B isNothing) returns false.
695     */
696     this(T value) pure
697     {
698         this.value = value;
699         empty = false;
700     }
701     
702     /// Returns true if stored value is null
703     bool isNothing() const
704     {
705         return empty;
706     }
707     
708     /**
709     *   Unwrap value from Maybe.
710     *   If the Maybe is empty, Error is thrown.
711     */
712     T get()
713     {
714         assert(!empty, "Stored value is null!");
715         return value;
716     }
717     
718     /**
719     *   Unwrap value from Maybe.
720     *   If the Maybe is empty, Error is thrown.
721     */
722     const(T) get() const
723     {
724         assert(!empty, "Stored value is null!");
725         return value;
726     }
727     
728     /**
729     *   If struct holds $(B null), then $(B nothingCase) result
730     *   is returned. If struct holds not $(B null) value, then
731     *   $(justCase) result is returned. $(B justCase) is fed
732     *   with unwrapped value.
733     */
734     U map(U)(U delegate() nothingCase, U delegate(T) justCase)
735     {
736         return isNothing ? nothingCase() : justCase(value);
737     }
738     
739     /**
740     *   If struct holds $(B null), then $(B nothingCase) result
741     *   is returned. If struct holds not $(B null) value, then
742     *   $(justCase) result is returned. $(B justCase) is fed
743     *   with unwrapped value.
744     */
745     U map(U)(U delegate() nothingCase, U delegate(const T) justCase) const
746     {
747         return isNothing ? nothingCase() : justCase(value);
748     }
749 }
750 
751 unittest
752 {
753     struct A {}
754     
755     auto ma = Maybe!A(A());
756     auto mb = Maybe!A.nothing;
757     
758     assert(!ma.isNothing);
759     assert(mb.isNothing);
760     
761     assert(ma.get == A());
762     assertThrown!Error(mb.get);
763     
764     bool ncase = false, jcase = false;
765     ma.map(() {ncase = true;}, (v) {jcase = true;});
766     assert(jcase && !ncase);
767     
768     ncase = jcase = false;
769     mb.map(() {ncase = true;}, (v) {jcase = true;});
770     assert(!jcase && ncase);
771 }
772 
773 /**
774 *   Transforms delegate into lazy range. Generation is stopped, when
775 *   $(B genfunc) returns $(B Maybe!T.nothing).
776 *
777 *   Example:
778 *   --------
779 *   assert( (() => Maybe!int(1)).generator.take(10).equal(1.repeat.take(10)) );
780 *   assert( (() => Maybe!int.nothing).generator.empty);
781 *   assert( (() 
782 *           {
783 *               static size_t i = 0;
784 *               return i++ < 10 ? Maybe!int(1) : Maybe!int.nothing;
785 *           }
786 *           ).generator.equal(1.repeat.take(10)));
787 *   
788 *   class A {}
789 *   auto a = new A();
790 *   
791 *   assert( (() => Maybe!A(a)).generator.take(10).equal(a.repeat.take(10)) );
792 *   assert( (() => Maybe!A.nothing).generator.empty);
793 *   assert( (() 
794 *           {
795 *               static size_t i = 0;
796 *               return i++ < 10 ? Maybe!A(a) : Maybe!A.nothing;
797 *           }
798 *           ).generator.equal(a.repeat.take(10)));
799 *   --------
800 */
801 auto generator(T)(Maybe!T delegate() genfunc)
802 {
803     struct Sequencer
804     {
805         private Maybe!T currvalue;
806         
807         T front()
808         {
809             assert(!currvalue.isNothing, "Generator range is empty!");
810             return currvalue.get;
811         }
812         
813         bool empty()
814         {
815             return currvalue.isNothing;
816         }
817         
818         void popFront()
819         {
820             currvalue = genfunc();
821         }
822     }
823     static assert(isInputRange!Sequencer);
824     
825     auto s = Sequencer();
826     s.popFront;
827     return s;
828 }
829 unittest
830 {
831     assert( (() => Maybe!int(1)).generator.take(10).equal(1.repeat.take(10)) );
832     assert( (() => Maybe!int.nothing).generator.empty);
833     assert( (() 
834             {
835                 static size_t i = 0;
836                 return i++ < 10 ? Maybe!int(1) : Maybe!int.nothing;
837             }
838             ).generator.equal(1.repeat.take(10)));
839     
840     class A {}
841     auto a = new A();
842     
843     assert( (() => Maybe!A(a)).generator.take(10).equal(a.repeat.take(10)) );
844     assert( (() => Maybe!A.nothing).generator.empty);
845     assert( (() 
846             {
847                 static size_t i = 0;
848                 return i++ < 10 ? Maybe!A(a) : Maybe!A.nothing;
849             }
850             ).generator.equal(a.repeat.take(10)));
851 }
852 
853 private template TypesOf(T...)
854 {
855     static if(T.length == 1)
856         alias TypesOf = typeof(T[0]);
857     else
858         alias TypesOf = TypeTuple!(typeof(T[0]), TypesOf!(T[1..$]));
859 }
860 
861 /**
862 *   Allows to fast retreiving results from functions that returns a tuple.
863 */
864 @property void tie(T...)(Tuple!(TypesOf!T) t)
865 {
866     foreach(i, ref var; T)
867     {
868         T[i] = t[i];
869     }
870 }
871 /// Example
872 unittest
873 {
874     Tuple!(int, string) foo()
875     {
876         return tuple(1, "a");
877     }
878     
879     int x;
880     string y;
881     
882     tie!(x,y) = foo();
883     assert(x == 1 && y == "a");
884 }