1 module postgresql.value;
2 
3 import std.conv: to;
4 import std.array: appender;
5 import std.format: format;
6 import std.datetime: Date, TimeOfDay, DateTime, SysTime;
7 
8 import std.bigint;
9 import std.traits;
10 import std.algorithm.comparison: among;
11 
12 import postgresql.core;
13 import postgresql.protocol: PGType;
14 
15 struct Value
16 {
17 @safe:
18 
19     enum Type : ubyte
20     {
21         null_,      // null
22         bool_,      // bool
23         integer,    // long
24         float_,     // double
25         bytes,      // ubyte[]
26         str,        // string
27         array,      // Value[]
28         map,        // Value[Value]
29     }
30 
31     package
32     {
33         PGType       _tag;
34         Type         _type;
35         bool         _bool_;
36         long         _integer;
37         double       _float_;
38         ubyte[]      _bytes;
39         string       _str;
40         Value[]      _array;
41         Value[Value] _map;
42         SysTime      _dateTime;
43         BigInt       _bigInt;
44 
45         enum warnNotArray = "Container in not 'Value.Type.array'";
46         enum warnNotMap   = "Container in not 'Value.Type.map'";
47     }
48 
49     @property bool isNull() const nothrow @nogc
50     {
51         return _type == Type.null_;
52     }
53     /// ditto
54     unittest
55     {
56         Value v1;
57         auto  v2 = Value(null);
58         auto  v3 = Value(Value.Type.null_);
59         assert(v1.isNull);
60         assert(v2.isNull);
61         assert(v3.isNull);
62     }
63 
64     @property bool isType(string t)() const nothrow @nogc
65     {
66         mixin("return _type == Type." ~ t ~ ";");
67     }
68 
69     @property PGType tag() const nothrow @nogc
70     {
71         return _tag;
72     }
73     ///
74     @property void tag(PGType t) nothrow
75     {
76         _tag = t;
77     }
78 
79     @property Type type() const nothrow @nogc
80     {
81         return _type;
82     }
83     ///
84     unittest
85     {
86         assert(Value(true).type                == Value.Type.bool_);
87         assert(Value(string[].init).type       == Value.Type.array);
88         assert(Value(string[string].init).isType!"map");
89         // TODO:
90     }
91 
92     alias opDollar = length;
93     @property size_t length() const nothrow @nogc
94     {
95         switch(_type) with (Type)
96         {
97             case bytes: return _bytes.length;
98             case str:   return _str.length;
99             case array: return _array.length;
100             case map:   return _map.length;
101             default:
102         }
103 
104         version (CBOR_STRICT)
105         {
106             assert(false);
107         } else {
108             return 0;
109         }
110     }
111     /// ditto
112     unittest
113     {
114         // bytes
115         ubyte[] t = [1, 2, 3, 4, 5, 6, 7, 8, 9];
116         auto v1 = Value(t);
117         assert(v1.isType!"bytes" && v1.length == 9);
118 
119         // string
120         auto v2 = Value("12345678");
121         assert(v2.isType!"str"   && v2.length == 8);
122 
123         // array
124         auto v3 = Value([1, 2, 3, 4, 5, 6, 7]);
125         assert(v3.isType!"array" && v3.length == 7);
126 
127         // map
128         auto v4 = Value([
129             "1":"",
130             "2":"",
131             "3":"",
132             "4":"",
133             "5":"",
134             "6":"",
135         ]);
136         assert(v4.isType!"map"   && v4.length == 6);
137     }
138 
139     this(in Type t) nothrow
140     {
141         _type = t;
142     }
143     /// ditto
144     this(T)(in T other) pure
145     if (isOwnPOD!T || is(Unqual!T == Value))
146     {
147         save(other);
148     }
149     /// ditto
150     this(T)(in T[] value) pure
151     if (isValue!T && !is(Unqual!T == ubyte))
152     {
153         _type  = Type.array;
154         foreach(v; value)
155         {
156             _array ~= Value(v);
157         }
158     }
159     /// ditto
160     this(K,V)(in V[K] value) pure
161     if ((is(Unqual!K == string) || is(Unqual!K == Value)) && isValue!V)
162     {
163         _type  = Type.map;
164         foreach(k, v; value)
165         {
166             _map[Value(k)] = Value(v);
167         }
168     }
169     ///
170     unittest
171     {
172         assert(Value(null).type == Value.Type.null_);
173         assert(Value(true).type == Value.Type.bool_);
174         assert(Value(-123).type == Value.Type.integer);
175         assert(Value(+123).type == Value.Type.integer);
176         assert(Value(3.14).type == Value.Type.float_);
177         assert(Value("ad").type == Value.Type.str);
178         assert(Value(["ab","cd"]).type == Value.Type.array);
179         assert(Value(["ab":"cd"]).type == Value.Type.map);
180     }
181 
182     bool opEquals()(auto ref const Value other) const nothrow @nogc
183     {
184         if ( _type != other._type )
185         {
186             return false;
187         }
188 
189         final switch(_type) with (Type)
190         {
191             case null_:   return true;
192             case bool_:   return _bool_   == other._bool_;
193             case integer: return _integer == other._integer;
194             case float_:  return _float_  == other._float_;
195             case bytes:   return _bytes   == other._bytes;
196             case str:     return _str     == other._str;
197             case array:   return _array   == other._array;
198             case map:     return _map     == other._map;
199         }
200     }
201     /// ditto
202     bool opEquals(T)(in T other) const nothrow @nogc
203     if (isValue!T)
204     {
205         enum t = typeId!T;
206         static if (t == Type.null_)
207         {
208             return _type == Type.null_;
209         }
210         else
211         {
212             mixin("return _type == t && _" ~ t.to!string ~ " == other;");
213         }
214     }
215     /// ditto
216     unittest
217     {
218         assert(Value(null) != Value(1));
219 
220         // null
221         assert(Value(null) == null);
222         assert(Value(null) == Value(null));
223 
224         // bool
225         assert(Value(false) == false);
226         assert(Value(true)  == Value(true));
227 
228         // integer
229         assert(Value(0xDEADC0DE) == 0xDEADC0DE);
230         assert(Value(0X12345678) == Value(0X12345678));
231 
232         // floating point
233         assert(Value(1234.5678) == 1234.5678);
234         assert(Value(9876.5432) == Value(9876.5432));
235 
236         // bytes
237         ubyte[] a = [1,2,3,4];
238         ubyte[] b = [1,2,3,4];
239         assert(Value(a) == b);
240         assert(Value(a) == Value(b));
241 
242         // string
243         assert(Value("foo") == "foo");
244         assert(Value("bar") == Value("bar"));
245 
246         // array
247         assert(Value(["foo","bar"]) == Value(["foo","bar"]));
248 
249         // map
250         assert(Value(["foo":"bar", "fuz":"buz"]) == Value(["fuz":"buz", "foo":"bar"]));
251     }
252 
253 
254     @property T opCast(T)() const @trusted
255     {
256         static if( is(T == bool) )
257         {
258             final switch( _type ) with (Type)
259             {
260                 case null_:   return false;
261                 case bool_:   return _bool_;
262                 case integer: return _integer != 0;
263                 case float_:  return _float_  != 0;
264                 case bytes:   return _bytes.length > 0;
265                 case str:     return _str.length   > 0;
266                 case array:   return _array.length > 0;
267                 case map:     return _map.length   > 0;
268             }
269         }
270         else static if(
271             is(T == int)   || is(T == long)
272          || is(T == float) || is(T == double)
273          || is(T == real))
274         {
275             final switch( _type ) with (Type)
276             {
277                 case null_:   return 0;
278                 case bool_:   return _bool_ ? 1 : 0;
279                 case integer: return cast(T) _integer;
280                 case float_:  return cast(T) _float_;
281                 case bytes:   return T.init;
282                 case str:     return _str.to!T;
283                 case array:   return T.init;
284                 case map:     return T.init;
285             }
286         }
287         else static if( is(T == ubyte[]))
288         {
289             switch( _type ) with (Type)
290             {
291                 default:    return cast(T) toString.dup;
292                 case null_: return cast(T) null;
293                 case bool_: return cast(T) [_bool_ ? 1 : 0];
294                 case bytes: return cast(T) _bytes.dup;
295                 case str:   return cast(T) _str.dup;
296             }
297         }
298         else static if( is(T == string) )
299         {
300             switch( _type ) with (Type)
301             {
302                 default:    return cast(T) toString.dup;
303                 case null_: return cast(T) null;
304                 case bytes: return cast(T) _bytes.dup;
305                 case str:   return cast(T) _str.dup;
306             }
307         }
308         else static if( is(T == Value[]) )
309         {
310             switch( _type ) with (Type)
311             {
312                 default:         return T.init;
313                 case Type.array: return _array.clone;
314             }
315         }
316         else static if( is(T == Value[Value]) )
317         {
318             switch( _type ){
319                 default:
320                 return T.init;
321                 case Type.map:
322                 return _map;
323             }
324         }
325         else static assert(0, format("%s can't cast to %s", Value.stringof,  T.stringof));
326     }
327     ///
328     unittest
329     {
330         Value v;
331         ubyte[] bytesNil;
332         ubyte[] bytesOne = [1];
333         Value[] emptyArray;
334         Value[Value] emptyMap;
335 
336         v = null;
337         // null to bool
338         assert(cast(bool)   v == false);
339         // null to int
340         assert(cast(long)   v == 0);
341         // null to float
342         assert(cast(double) v == 0.0);
343         // null to bytes
344         assert(cast(ubyte[]) v == bytesNil);
345         // null to string
346         assert(cast(string) v == "");
347         // null to array
348         //assert(cast(Value[]) v == emptyArray);
349 
350         v = true;
351         // bool to double
352         assert(cast(bool)   v == true);
353         assert(cast(double) v == 1.0);
354         // bool to integer
355         assert(cast(long)   v == 1);
356         // bool to bytes
357         assert(cast(ubyte[]) v == bytesOne);
358         // bool to string
359         assert(cast(string)  v == "true");
360         // Array
361         //assert(cast(Value[]) v == Value[]);
362 
363         v = 3.14;
364         assert(cast(bool)   v == true);
365         assert(cast(double) v == 3.14);
366         assert(cast(long)   v == 3);
367         assert(cast(string) v == "3.14");
368 
369         v = int(-42);
370         assert(cast(bool)   v == true);
371         assert(cast(double) v == -42.0);
372         assert(cast(long)   v == -42);
373         assert(cast(string) v == "-42");
374 
375         v = long(42);
376         assert(cast(bool)   v == true);
377         assert(cast(double) v == 42.0);
378         assert(cast(long)   v == 42);
379         assert(cast(string) v == "42");
380 
381         // bytes
382         ubyte[] buf = [0x61, 0x62, 0x63, 0x64];
383         v = buf;
384 
385         import std.math: isNaN;
386         assert(cast(bool)   v == true);
387         assert((cast(double) v).isNaN);
388         assert(cast(long)   v == 0);
389         assert(cast(string) v == "abcd");
390 
391         v = "42";
392         assert(cast(bool)   v == true);
393         assert(cast(double) v == 42.0);
394         assert(cast(long)   v == 42);
395         assert(cast(string) v == "42");
396 
397         v = "abc";
398         assert(cast(bool)   v == true);
399         assert(cast(string) v == "abc");
400 
401         import std.exception;
402         import std.conv;
403         assertThrown!ConvException(cast(double) v == 0.0);
404         assertThrown!ConvException(cast(long)   v == 42);
405     }
406 
407     ref Value opAssign(T)(in T other) pure
408     if (isValue!T || is(Unqual!T == Value))
409     {
410         save(other);
411         return this;
412     }
413     ///
414     unittest
415     {
416         Value v;
417 
418         v = null;
419         assert(v.type == Value.Type.null_);
420 
421         v = true;
422         assert(v.type == Value.Type.bool_);
423 
424         v = int(-42);
425         assert(v.type == Value.Type.integer);
426 
427         v = long(42);
428         assert(v.type == Value.Type.integer);
429 
430         v = double(3.14);
431         assert(v.type == Value.Type.float_);
432 
433         v = "foo";
434         assert(v.type == Value.Type.str);
435     }
436 
437 
438     void opOpAssign(string op, T)(T other) pure
439     if (!is(Unqual!T == typeof(null)) && isValue!T)
440     {
441         opOpAssign!op(Value(other));
442     }
443     ///
444     void opOpAssign(string op)(Value other) pure
445     if (op == "+" || op == "-" || op == "*" || op == "/" || op == "%" || op =="~")
446     {
447         immutable warn = format("Restricted binary operation '%s=' between '%s' and '%s'", op, _type, other._type);
448 
449         static if( op.among("+", "-", "*", "/"))
450         {
451             assert(_type == other._type, warn);
452 
453             if( _type == Type.integer )
454             {
455                 mixin("_integer " ~ op~ "= other._integer;");
456             }
457             else if( _type == Type.float_)
458             {
459                 mixin("_float_" ~ op ~ "= other._float_;");
460             }
461             else assert(0, warn);
462         }
463         else static if( op == "~" )
464         {
465             if (_type == Type.bytes)
466             {
467                 assert(_type == other._type, warn);
468                 _bytes ~= other._bytes.dup;
469             }
470             else if (_type == Type.str)
471             {
472                 assert(_type == other._type, warn);
473                 _str ~= other._str.dup;
474             }
475             else if (_type == Type.array)
476             {
477                 if (other._type == Type.array)
478                 {
479                     foreach(v; other._array)
480                     {
481                         _array ~= v.clone;
482                     }
483                 }
484                 else
485                 {
486                     _array ~= other.clone;
487                 }
488             }
489             else assert(0, warn);
490         }
491         else assert(0, warn);
492     }
493     ///
494     unittest
495     {
496         // Int
497         auto vInt = Value(42);
498         vInt /= 2;
499         assert(vInt == 21);
500         vInt *= 4;
501         assert(vInt == 84);
502         vInt -= 4;
503         assert(vInt == 80);
504         vInt += 20;
505         assert(vInt == 100);
506 
507         // Float
508         auto vFload = Value(42.0);
509         vFload -= 1.0;
510         assert(vFload == 41.0);
511         vFload /= 2.0;
512         assert(vFload == 20.5);
513         vFload += 10.0;
514         assert(vFload == 30.5);
515         vFload *= 2.0;
516         assert(vFload == 61.0);
517 
518         // bytes
519         ubyte[] b1 = [1, 2];
520         ubyte[] b2 = [3, 4];
521         ubyte[] b3 = [1, 2, 3, 4];
522         auto vBytes = Value(b1);
523         vBytes ~= b2;
524         assert(vBytes == b3);
525 
526         // string
527         auto vStr = Value("Hello");
528         vStr ~= " world!";
529         assert(vStr == "Hello world!");
530 
531         // Array
532         auto vArray = Value(["abc", "def", "xyz"]);
533         vArray ~= "foo";
534         assert(vArray == Value(["abc", "def", "xyz", "foo"]));
535         vArray ~= Value(["fuz", "buz"]);
536         assert(vArray == Value(["abc", "def", "xyz", "foo", "fuz", "buz"]));
537     }
538 
539     /// Has key
540     bool has(in string key) const nothrow
541     {
542         return has(Value(key));
543     }
544     /// ditto
545     bool has(Value key) const nothrow
546     {
547         if (_type == Type.map)
548         {
549             return (key in _map) !is null;
550         }
551         else assert(0, warnNotMap);
552     }
553     /// ditto
554     unittest
555     {
556         auto v = Value(["foo":1, "bar":2]);
557         assert(v.has("foo"));
558         assert(!v.has("baz"));
559         assert(v.has(Value("bar")));
560     }
561 
562     Value take(in string key)
563     {
564         return take(Value(key));
565     }
566     /// ditto
567     Value take(Value key)
568     {
569         // FIXME: const?
570         auto tmp = opIndex(key);
571         remove(key);
572         return tmp;
573     }
574     /// ditto
575     unittest
576     {
577         auto v1 = Value(["a":1, "b":2]);
578         auto v2 = v1.take("b");
579         assert(v1 == Value(["a":1]));
580         assert(v2 == 2);
581     }
582 
583     // Remove value by key
584     void remove(in string key) nothrow
585     {
586         remove(Value(key));
587     }
588     /// ditto
589     void remove(Value key) nothrow
590     {
591         if (_type == Type.map)
592         {
593             _map.remove(key);
594         }
595         else assert(0, warnNotMap);
596     }
597     /// ditto
598     unittest
599     {
600         auto v1 = Value(["a":1, "b":2]);
601         v1.remove("b");
602         assert(v1 == Value(["a":1]));
603     }
604 
605     Value get(in string key, in string failback) const pure
606     {
607         return get(Value(key), Value(failback));
608     }
609     /// ditto
610     Value get(in string key, Value failback = Value()) const pure
611     {
612         return get(Value(key), failback);
613     }
614     /// ditto
615     Value get(Value key, Value failback = Value()) const pure
616     {
617         if( auto pv = key in _map)
618             return pv.clone;
619 
620         return failback;
621     }
622     /// ditto
623     unittest
624     {
625         auto v1 = Value(["a":1, "b":2]);
626         assert(v1.get("a") == 1);
627         assert(v1.get("b") == 2);
628         assert(v1.get("c").isNull);
629         assert(v1.get("d", "3") == "3");
630         assert(v1.get("e", Value(3)) == 3);
631         assert(v1.get(Value("f"), Value(4)) == 4);
632     }
633 
634     ref inout(Value) opIndex(size_t idx) inout nothrow
635     {
636         if (_type == Type.array)
637         {
638             return _array[idx];
639         }
640         else assert(0, warnNotArray);
641     }
642     ///
643     unittest
644     {
645         auto value = Value(Value.Type.array);
646 
647         value ~= true;
648         value ~= 42;
649         value ~= 3.14;
650         value ~= "foo";
651 
652         assert(value[0] == true);
653         assert(value[1] == 42);
654         assert(value[2] == 3.14);
655         assert(value[3] == "foo");
656     }
657 
658     /// Assign value by key
659     void opIndexAssign(in Value val, in string key) pure
660     {
661         if (_type == Type.map)
662         {
663             _map[Value(key)] = val.clone;
664         }
665         else assert(false, warnNotMap);
666     }
667     /// ditto
668     void opIndexAssign(in Value val, in Value key) pure
669     {
670         if (_type == Type.map)
671         {
672             _map[key.clone] = val.clone;
673         }
674         else assert(false, warnNotMap);
675     }
676     /// ditto
677     void opIndexAssign(T)(T val, in string key) pure
678     if (isValue!T)
679     {
680         if (_type == Type.map)
681         {
682             _map[Value(key)] = Value(val);
683         }
684         else assert(false, warnNotMap);
685     }
686     /// ditto
687     void opIndexAssign(T)(in T val, in Value key) pure
688     if (isValue!T)
689     {
690         if (_type == Type.map)
691         {
692             _map[key.clone] = Value(val);
693         }
694         else assert(false, warnNotMap);
695     }
696 
697     /// Get value by key
698     ref inout(Value) opIndex(in string key) inout pure
699     {
700         return opIndex(Value(key));
701     }
702     /// ditto
703     ref inout(Value) opIndex(in Value key) inout pure
704     {
705         if (_type == Type.map)
706         {
707             return _map[key.clone];
708         }
709         else assert(false, warnNotMap);
710     }
711     ///
712     unittest
713     {
714         Value v1 = cast(Value[Value]) null;
715         const string abc = "abc";
716         const Value  def = Value("def");
717 
718         v1["abc"] = true;
719         v1[def] = 3.14;
720         v1[Value("xyz")] = Value("foo");
721 
722 
723         assert(v1["abc"] == true);
724         assert(v1["def"] == 3.14);
725         assert(v1["xyz"] == "foo");
726 
727         // const
728         const Value  v2  = v1;
729 
730         assert(v2[abc] == true);
731         assert(v2[def] == 3.14);
732         assert(v2[Value("xyz")] == "foo");
733     }
734 
735     Value opBinary(string op)(in Value other)
736     const {
737         assert(_type == other._type, format("Binary operation '%s' between %s and %s", op, _type, other._type));
738         static if( op == "&&" || op == "||")
739         {
740             if (_type == Type.bool_)
741             {
742                 mixin("return Value(_boolean " ~ op ~ " other._boolean);");
743             }
744             else assert(0);
745         }
746         else static if( op == "+" || op == "-" || op == "*" || op == "/" || op == "%")
747         {
748             if( _type == Type.integer )
749             {
750                 mixin("return Value(_integer " ~ op ~ " other._integer);");
751             }
752             else if( _type == Type.float_ )
753             {
754                 mixin("return Value(_float_ " ~ op ~ " other._float_);");
755             }
756             else assert(false);
757         }
758         else static if( op == "~" )
759         {
760             if( _type == Type.str )
761             {
762                 return Value(_str ~ other._str);
763             }
764             else if (_type == Type.array)
765             {
766                 return Value(_array ~ other._array);
767             }
768             else assert(false);
769         } else static assert(format("Unsupported operator '%s'", op));
770     }
771     /// ditto
772     unittest
773     {
774 
775     }
776 
777     mixin(opApply1!"");         // opApply(ref val)
778     //mixin(opApply1!"immutable");// opApply(ref immutable val)
779     mixin(opApply1!"const");      // opApply(ref const val)
780     ///
781     unittest
782     {
783         int   i = 10;
784         // Array
785         foreach(v; Value([10, 11]))
786         {
787             //assert(v == i++);
788         }
789 
790         // Map, ref
791         // One item coz random key order
792         foreach(v; Value(["1":"a"]))
793         {
794             assert(v == "a");
795         }
796     }
797     ////mixin(opApply2Array!"");         // opApply(ref const size_t key, ref val)
798     ////mixin(opApply2Array!"immutable");// opApply(ref const size_t key, ref immutable val)
799     mixin(opApply2Array!"const");      // opApply(ref const size_t key, ref const val)
800     unittest
801     {
802         size_t i;
803         foreach(ref const size_t k, v; Value([10, 11]))
804         {
805             assert(k == i);
806             assert(v == (i++ + 10));
807         }
808     }
809     ////mixin(opApply2Map!"");         // opApply(ref Value)
810     ////mixin(opApply2Map!"immutable");// opApply(ref immutable Value)
811     mixin(opApply2Map!"const");    // opApply(ref const Value)
812     ///
813     unittest
814     {
815         foreach(ref const Value k, v; Value(["1":"1", "2":"2"]))
816         {
817             assert(k == v);
818         }
819     }
820 
821     Value[] toArray() const
822     {
823         Value[] ret;
824         if (_type == Type.array)
825         {
826             foreach (i; _array)
827             {
828                 ret ~= i.clone;
829             }
830         }
831         return ret;
832     }
833     ///
834     unittest
835     {
836         assert([Value(1), Value(2), Value(3)] == Value([1, 2, 3]).toArray);
837     }
838 
839     Value[Value] toMap() const
840     {
841         Value[Value] ret;
842         if (_type == Type.map)
843         {
844             foreach (k, v; _map)
845             {
846                 ret[k.clone] = v.clone;
847             }
848         }
849         return ret;
850     }
851     ///
852     unittest
853     {
854         assert([Value("foo"):Value("bar"),
855                 Value("fuz"):Value("buz")] == Value(["fuz":"buz", "foo":"bar"]).toMap);
856     }
857 
858     string toString() const
859     {
860         //
861         final switch (_type) with (Type)
862         {
863             case null_:   return null.stringof;
864             case bool_:   return _bool_.to!string;
865             case integer: return _integer.to!string;
866             case float_:  return _float_.to!string;
867             case bytes:   return _bytes.to!string;
868             case str:     return _str.to!string;
869             case array:
870             case map:
871                 return this.toJsonString;
872         }
873         assert(0);
874     }
875     ///
876     unittest
877     {
878         Value v;
879 
880         v = null;
881         assert(v.toString == "null");
882 
883         v = true;
884         assert(v.toString == "true");
885 
886         v = int(-42);
887         assert(v.toString == "-42");
888 
889         v = long(42);
890         assert(v.toString == "42");
891 
892         v = double(3.14);
893         assert(v.toString == "3.14");
894 
895         ubyte[] t = [1,2,3,4];
896         v = t;
897         assert(v.toString == "[1, 2, 3, 4]");
898 
899         v = "foo";
900         assert(v.toString == "foo");
901 
902         v = Value([1, 2, 3, 4]);
903         assert(v.toString == "[1,2,3,4]");
904 
905         v = [Value("data"): Value([1, 2, 3, 4])];
906         assert(v.toString == "{\"data\":[1,2,3,4]}");
907     }
908 
909     hash_t toHash() const nothrow @trusted
910     {
911         static hash_t getHash(T)(T* v) nothrow @safe
912         {
913             return typeid(T).getHash(v);
914         }
915 
916         final switch (_type) with (Type)
917         {
918             case null_:   return 0;
919             case bool_:   return getHash(&_bool_);
920             case integer: return getHash(&_integer);
921             case float_:  return getHash(&_float_);
922             case bytes:   return getHash(&_bytes);
923             case str:     return getHash(&_str);
924             case array:
925                 hash_t ret;
926                 foreach (elem; _array)
927                 {
928                     ret ^= elem.toHash();
929                 }
930                 return ret;
931             case map:
932                 try
933                 {
934                     hash_t ret;
935                     foreach (ref key, ref value; _map)
936                     {
937                         ret ^= getHash(&key);
938                         ret ^= value.toHash();
939                     }
940                     return ret;
941                 } catch (Throwable) assert(0);
942         }
943     }
944     ///
945     unittest
946     {
947         ubyte[] t = [1,2,3,4];
948         assert(Value(null).toHash == Value(null).toHash);
949         assert(Value(true).toHash == Value(true).toHash);
950         assert(Value(false).toHash == Value(false).toHash);
951         assert(Value(-1234567).toHash == Value(-1234567).toHash);
952         assert(Value(+1234567).toHash == Value(+1234567).toHash);
953         assert(Value(3.14).toHash == Value(3.14).toHash);
954         assert(Value(t).toHash == Value(t).toHash);
955         assert(Value("foo").toHash == Value("foo").toHash);
956         assert(Value([1,2,3,4]).toHash == Value([1,2,3,4]).toHash);
957         assert(Value(["foo":"bar", "fuz":"buz"]).toHash == Value(["fuz":"buz","foo":"bar"]).toHash);
958     }
959 
960     alias dup = clone;
961     Value clone() const pure
962     {
963         Value other;
964         final switch(_type) with (Type)
965         {
966             case null_:   return other.save(null);
967             case bool_:   return other.save(_bool_);
968             case integer: return other.save(_integer);
969             case float_:  return other.save(_float_);
970             case bytes:   return other.save(_bytes);
971             case str:     return other.save(_str);
972             case array:   return other.save(_array);
973             case map:     return other.save(_map);
974         }
975     }
976     ///
977     unittest
978     {
979         Value v;
980         ubyte[] b = [1, 2, 3, 4];
981 
982         v = null;
983         assert(v.clone.isType!"null_");
984 
985         v = true;
986         assert(v.clone.isType!"bool_");
987 
988         v = int(-42);
989         assert(v.clone.isType!"integer");
990 
991         v = long(42);
992         assert(v.clone.isType!"integer");
993 
994         v = double(3.14);
995         assert(v.clone.isType!"float_");
996 
997         v = b;
998         assert(v.clone.isType!"bytes" && v == b);
999 
1000         v = "foo";
1001         assert(v.clone.isType!"str");
1002 
1003         v = Value(["abc", "def", "xyz"]);
1004         assert(v.clone.isType!"array" && v == Value(["abc", "def", "xyz"]));
1005 
1006         v = Value(["foo":"bar"]);
1007         assert(v.clone.isType!"map" && v == Value(["foo":"bar"]));
1008     }
1009 
1010     private Value save(T)(in T other) pure
1011     {
1012         static if (is(Unqual!T == Value))
1013         {
1014             final switch(other._type) with (Type)
1015             {
1016                 case null_:   return save(null);
1017                 case bool_:   return save(other._bool_);
1018                 case integer: return save(other._integer);
1019                 case float_:  return save(other._float_);
1020                 case bytes:   return save(other._bytes);
1021                 case str:     return save(other._str);
1022                 case array:   return save(other._array);
1023                 case map:     return save(other._map);
1024             }
1025         }
1026         else
1027         {
1028             enum t = typeId!T;
1029             _type  = t;
1030 
1031             _array.length = 0;
1032             _map = null;
1033 
1034             static if (t == Type.null_)
1035             {
1036                 // Nothing
1037             }
1038             else static if (t == Type.bytes || t == Type.str)
1039             {
1040                 mixin("_" ~ t.to!string ~ " = other.dup;");
1041             }
1042             else static if (t == Type.array)
1043             {
1044                 _array = null;
1045                 foreach(ref v; other)
1046                 {
1047                     _array ~= v.clone;
1048                 }
1049             }
1050             else static if (t == Type.map)
1051             {
1052                 _map = null;
1053                 foreach(k, v; other)
1054                 {
1055                     _map[Value(k)] = v.clone;
1056                 }
1057             }
1058             else static if (t != Type.null_)
1059             {
1060                 mixin("_" ~ t.to!string ~ " = other;");
1061             }
1062             else assert(0, "Not implemented save for type " ~ T.stringof);
1063             return this;
1064         }
1065     }
1066 
1067 
1068     static @property Type typeId(T)() nothrow @nogc
1069     {
1070         static if( is(Unqual!T == typeof(null)) )                return Type.null_;
1071         else static if( is(Unqual!T == bool) )                   return Type.bool_;
1072         else static if( isIntegral!T)                            return Type.integer;
1073         else static if( isFloatingPoint!T )                      return Type.float_;
1074         else static if( is(Unqual!T == ubyte[]) )                return Type.bytes;
1075         else static if( is(Unqual!T == const(ubyte)[]))          return Type.bytes;
1076         else static if( is(Unqual!T == string) )                 return Type.str;
1077         else static if( is(Unqual!T == Value[]) )              return Type.array;
1078         else static if( is(Unqual!T == const(Value)[]))        return Type.array;
1079         else static if( is(Unqual!T == Value[Value]) )       return Type.map;
1080         else static if( is(Unqual!T == const(Value)[Value])) return Type.map;
1081         else static if( is(Unqual!T == Value[string]))         return Type.map;
1082         else static if( is(Unqual!T == const(Value)[string]))  return Type.map;
1083         else static assert(false, "Unsupported type '%s'".format(T.stringof));
1084     }
1085     ///
1086     unittest
1087     {
1088         assert(Value.typeId!bool   == Type.bool_);
1089         assert(Value.typeId!string == Type.str);
1090         assert(Value.typeId!byte   == Type.integer);
1091         assert(Value.typeId!ubyte  == Type.integer);
1092         assert(Value.typeId!short  == Type.integer);
1093         assert(Value.typeId!ushort == Type.integer);
1094         assert(Value.typeId!int    == Type.integer);
1095         assert(Value.typeId!uint   == Type.integer);
1096         assert(Value.typeId!long   == Type.integer);
1097         assert(Value.typeId!ulong  == Type.integer);
1098         assert(Value.typeId!float  == Type.float_);
1099         assert(Value.typeId!double == Type.float_);
1100         assert(Value.typeId!real   == Type.float_);
1101         assert(Value.typeId!(Value[Value]) == Type.map);
1102         // TODO:
1103     }
1104 }
1105 
1106 // Helpers
1107 Value getValue(T)(ref const (Value[string]) map, string key, lazy T defVal = null)
1108 if (isValue!T)
1109 {
1110     if( auto pv = key in map)
1111     {
1112         return pv.clone;
1113     }
1114     return Value(defVal);
1115 }
1116 
1117 Value getValue(K,T)(ref const (Value[Value]) map, string key, lazy T defVal = null)
1118 if (isValue!T)
1119 {
1120     if( auto pv = Value(key) in map)
1121     {
1122         return pv.clone;
1123     }
1124     return Value(defVal);
1125 }
1126 
1127 
1128 Value[] valueArray(T...)(T args)
1129 {
1130     Value[] result;
1131     foreach(arg; args)
1132     {
1133         result ~= Value(arg);
1134     }
1135     return result;
1136 }
1137 unittest
1138 {
1139     auto a1 = valueArray(null, false, 42, 3.14, "foo", Value("false"));
1140     assert(a1[0] == null);
1141     assert(a1[1] == false);
1142     assert(a1[2] == 42);
1143     assert(a1[3] == 3.14);
1144     assert(a1[4] == "foo");
1145     assert(a1[5] == "false");
1146 
1147     auto a2 = valueArray(false, true, a1);
1148 
1149     assert(a2[0] == false);
1150     assert(a2[1] == true);
1151     assert(a2[2] == a1);
1152 }
1153 
1154 
1155 string toJsonString(in Value val) @trusted
1156 {
1157     import std.json;
1158 
1159     JSONValue _toJson(in Value src)
1160     {
1161         final switch (src.type) with (Value.Type)
1162         {
1163             case null_:
1164                 return JSONValue(null);
1165             case bool_:
1166                 return JSONValue(src._bool_);
1167             case integer:
1168                 return JSONValue(src._integer);
1169             case float_:
1170                 return JSONValue(src._float_);
1171             case bytes:
1172             case str:
1173                 return JSONValue(src.to!string);
1174             case array: {
1175                 JSONValue[] vals;
1176                 foreach (val; src._array)
1177                 {
1178                     vals ~= _toJson(val);
1179                 }
1180                 return JSONValue(vals);
1181             }
1182             case map: {
1183                 JSONValue[string] vals;
1184                 foreach (key, val; src._map)
1185                 {
1186                     vals[key.to!string] = _toJson(val);
1187                 }
1188                 return JSONValue(vals);
1189             }
1190         }
1191     }
1192 
1193     return _toJson(val).toString();
1194 }
1195 ///
1196 unittest
1197 {
1198     assert(`{"a":null}`  == Value(["a": Value(null)]).toJsonString);
1199     assert(`{"a":true}`  == Value(["a": true]).toJsonString);
1200     assert(`{"a":false}` == Value(["a": false]).toJsonString);
1201     //Precision mismatch
1202     //assert(`{"a":3.14}`  == Value(["a": 3.14]).toJsonString);
1203     assert(`{"a":42}`    == Value(["a": 42]).toJsonString);
1204     assert(`{"a":[1,2,3,4]}` == Value(["a": Value([1,2,3,4])]).toJsonString);
1205 }
1206 
1207 
1208 Value fromJsonString(in string s) @trusted
1209 {
1210     import std.json;
1211 
1212     Value _(in JSONValue src)
1213     {
1214         final switch (src.type) with (JSON_TYPE)
1215         {
1216             case NULL:      return Value(null);
1217             case TRUE:      return Value(true);
1218             case FALSE:     return Value(false);
1219             case UINTEGER:  return Value(cast(int) src.uinteger);
1220             case INTEGER:   return Value(src.integer);
1221             case FLOAT:     return Value(src.floating);
1222             case STRING:    return Value(src.str);
1223             case ARRAY: {
1224                 Value[] vals;
1225                 foreach (val; src.array)
1226                 {
1227                     vals ~= _(val);
1228                 }
1229                 return Value(vals);
1230             }
1231             case OBJECT: {
1232                 Value[string] vals;
1233                 foreach (key, val; src.object)
1234                 {
1235                     vals[key] = _(val);
1236                 }
1237                 return Value(vals);
1238             }
1239         }
1240     }
1241 
1242     return _(parseJSON(s));
1243 }
1244 ///
1245 unittest
1246 {
1247     assert(fromJsonString(`{"a":null}`) == Value(["a": Value(null)]));
1248     assert(fromJsonString(`{"a":true}`) == Value(["a": true]));
1249     assert(fromJsonString(`{"a":false}`) == Value(["a": false]));
1250     assert(fromJsonString(`{"a":3.14}`) == Value(["a": 3.14]));
1251     assert(fromJsonString(`{"a":42}`)   == Value(["a": 42]));
1252     assert(fromJsonString(`{"a":[1,2,3,4]}`) == Value(["a": Value([1,2,3,4])]));
1253 }
1254 
1255 private enum bool isOwnPOD(T) = is(Unqual!T == typeof(null))
1256                              || is(Unqual!T == bool)
1257                              || isIntegral!T
1258                              || isFloatingPoint!T
1259                              || is(Unqual!T == ubyte[])
1260                              || is(Unqual!T == const(ubyte)[])
1261                              || is(Unqual!T == string);
1262 
1263 
1264 private enum bool isValue(T) = isOwnPOD!T
1265                             || is(Unqual!T == Value)
1266                             || is(Unqual!T == Value[])
1267                             || is(Unqual!T == const(Value)[])
1268                             || is(Unqual!T == Value[string])
1269                             || is(Unqual!T == const(Value)[string])
1270                             || is(Unqual!T == Value[Value])
1271                             || is(Unqual!T == const(Value)[Value])
1272                             ;
1273 
1274 
1275 
1276 private template opApply1(string t)
1277 {
1278     const char[] opApply1 = `
1279     int opApply(scope int delegate(ref ` ~ t ~ ` Value) dg) ` ~ t ~ ` @trusted
1280     {
1281         if ( _type == Type.array )
1282         {
1283             foreach(ref ` ~ t ~ ` v; _array )
1284             {
1285                 if( auto ret = dg(v) )
1286                 {
1287                     return ret;
1288                 }
1289             }
1290             return 0;
1291         }
1292         else if ( _type == Type.map )
1293         {
1294             foreach(ref ` ~ t ~ ` v; _map )
1295             {
1296                 if( auto ret = dg(v) )
1297                 {
1298                     return ret;
1299                 }
1300             }
1301             return 0;
1302         }
1303         else assert(0);
1304     }
1305 `;
1306 }
1307 
1308 private template opApply2Array(string t)
1309 {
1310     const char[] opApply2Array = `
1311     int opApply(scope int delegate(ref const size_t, ref ` ~ t ~ ` Value) dg) ` ~ t ~ ` @trusted
1312     {
1313         if ( _type == Type.array )
1314         {
1315             foreach ( ref const idx, ref ` ~ t ~ ` v; _array )
1316             {
1317                 if ( auto ret = dg(idx, v) )
1318                 {
1319                     return ret;
1320                 }
1321             }
1322             return 0;
1323         }
1324         else assert(0);
1325     }
1326 `;
1327 }
1328 
1329 private template opApply2Map(string t)
1330 {
1331     const char[] opApply2Map = `
1332 int opApply(scope int delegate(ref const Value, ref `~t~` Value) dg) `~t~` @trusted
1333     {
1334         if ( _type == Type.map )
1335         {
1336             foreach ( ref const idx, ref `~t~` v; _map )
1337             {
1338                 if ( auto ret = dg(idx, v) )
1339                 {
1340                     return ret;
1341                 }
1342             }
1343             return 0;
1344         }
1345         else assert(0);
1346     }
1347 `;
1348 }