1 module netorcai.json_util;
2 
3 import std.json, std.conv, std.format, std.algorithm, std.exception;
4 
5 /// Reads a boolean from a JSONValue (handling several ways to store it)
6 bool getBool(in JSONValue v)
7 {
8     bool value;
9 
10     if (v.type == JSON_TYPE.TRUE)
11         value = true;
12     else if (v.type == JSON_TYPE.FALSE)
13         value = false;
14     else if (v.type == JSON_TYPE.INTEGER)
15     {
16         enforce([0, 1].canFind(v.integer),
17                 format!"Cannot deduce boolean value from integer %d"(v.integer));
18         value = to!bool(v.integer);
19     }
20     else
21     {
22         enforce(0, "Cannot read bool value from JSONValue " ~ v.toString);
23     }
24 
25     return value;
26 }
27 
28 unittest
29 {
30     auto json = parseJSON(`{"a":true,
31                             "b":false,
32                             "c":0,
33                             "d":1,
34                             "e":2,
35                             "f":42.51}`);
36 
37     assert(json["a"].getBool == true);
38     assert(json["b"].getBool == false);
39     assert(json["c"].getBool == false);
40     assert(json["d"].getBool == true);
41 
42     auto e = collectException(json["e"].getBool);
43     assert(e, "Should NOT be able to retrieve boolean value from JSON integer 2");
44 
45     e = collectException(json["f"].getBool);
46     assert(e, "Should NOT be able to retrieve boolean value from JSON double 42.51");
47 }
48 
49 /// Reads an integer from a JSONValue (handling several ways to store it)
50 int getInt(in JSONValue v)
51 {
52     int value;
53 
54     if (v.type == JSON_TYPE.INTEGER)
55         value = to!int(v.integer);
56     else
57         enforce(0, "Cannot read int value from JSONValue " ~ v.toString);
58 
59     return value;
60 }
61 
62 unittest
63 {
64     auto json = parseJSON(`{"a":-10,
65                             "b":37,
66                             "c":42000,
67                             "d":123456789,
68                             "e":true,
69                             "f":42.51}`);
70 
71     assert(json["a"].getInt == -10);
72     assert(json["b"].getInt == 37);
73     assert(json["c"].getInt == 42_000);
74     assert(json["d"].getInt == 123_456_789);
75 
76     auto e = collectException(json["e"].getInt);
77     assert(e, "Should NOT be able to retrieve integer value from JSON bool");
78 
79     e = collectException(json["f"].getInt);
80     assert(e, "Should NOT be able to retrieve integer value from JSON double 42.51");
81 }
82 
83 /// Reads a double from a JSONValue (handling several ways to store it)
84 double getDouble(in JSONValue v)
85 {
86     double value;
87 
88     if (v.type == JSON_TYPE.FLOAT)
89         value = v.floating;
90     else if (v.type == JSON_TYPE.INTEGER)
91         value = to!double(v.integer);
92     else
93         enforce(0, "Cannot read double value from JSONValue " ~ v.toString);
94 
95     return value;
96 }
97 
98 unittest
99 {
100     auto json = parseJSON(`{"a":-10,
101                             "b":37,
102                             "c":42000,
103                             "d":123456789,
104                             "e":true,
105                             "f":42.51}`);
106 
107     assert(json["a"].getDouble == -10);
108     assert(json["b"].getDouble == 37);
109     assert(json["c"].getDouble == 42_000);
110     assert(json["d"].getDouble == 123_456_789);
111 
112     immutable auto e = collectException(json["e"].getDouble);
113     assert(e, "Should NOT be able to retrieve double value from JSON bool");
114 
115     assert(json["f"].getDouble == 42.51);
116 }