1 module hjson.adapter;
2 
3 package(hjson):
4 
5 import std.json : JSONValue, JSONType, JSONException;
6 
7 struct StdJsonSerializer
8 {
9     pure @system:
10 
11     JSONValue* result;
12 
13     uint objectBegin()
14     {
15         if(noRootAggregate)
16         {
17             result.object = null;
18             push(result);
19         }
20         else 
21         {
22             JSONValue obj;
23             obj.object = null;
24             
25             if(top.type == JSONType.object)
26             {
27                 top.object[key] = obj;
28                 push(&top.object[key]);
29             }
30             else
31             {
32                 top.array ~= obj;
33                 push(&top.array[$-1]);
34             }
35         }
36         return 0;
37     }
38 
39     void objectEnd(uint state)
40     in(!noRootAggregate && top.type == JSONType.object)
41     {
42         pop();
43     }
44 
45     uint arrayBegin()
46     {
47         if(noRootAggregate)
48         {
49             result.array = [];
50             push(result);
51         }
52         else
53         {
54             JSONValue arr;
55             arr.array = [];
56             if(top.type == JSONType.object)
57             {
58                 top.object[key] = arr;
59                 push(&top.object[key]);
60             }
61             else
62             {
63                 top.array ~= arr;
64                 push(&top.array[$-1]);
65             }
66         }
67         return 0;
68     }
69 
70     void arrayEnd(size_t state)
71     in(!noRootAggregate && top.type == JSONType.array)
72     {
73         pop();
74     }
75 
76     void putKey(const char[] key)
77     {
78         this.key = key;
79     }
80     void putValue(T)(T value)
81     {
82         if(noRootAggregate) 
83             *result = value;
84         else if(top.type == JSONType.object)
85             top.object[key] = JSONValue(value);
86         else top.array ~= JSONValue(value);
87     }
88     void elemBegin() {}
89     void flush() {} 
90 
91     private:
92 
93     void push(JSONValue* value){stack ~= value;}
94     ref inout(JSONValue) top() inout {return *(stack[$-1]);}
95     void pop() {stack.length = stack.length-1;}
96     bool noRootAggregate() const {return stack.length == 0;}
97 
98     JSONValue*[] stack;
99     const(char)[] key;
100 
101     invariant(
102         noRootAggregate || 
103         top.type == JSONType.object || 
104         top.type == JSONType.array
105     );
106 }
107 
108 version(unittest):
109 version(Have_unit_threaded):
110 
111 import unit_threaded;
112 
113 @("StdJsonSerializer")
114 unittest
115 {
116     import std.json : parseJSON, JSONValue;
117 
118     JSONValue value;
119     auto ser = StdJsonSerializer(&value);
120     auto o = ser.objectBegin();
121         ser.putKey("hello"); ser.putValue("world");
122         ser.putKey("foo"); ser.putValue(1234);
123         ser.putKey("null"); ser.putValue(null);
124         ser.putKey("array");
125         auto a = ser.arrayBegin();
126             ser.elemBegin; ser.putValue(1);
127             ser.elemBegin; ser.putValue("abc");
128             ser.elemBegin; ser.putValue(false);
129         ser.arrayEnd(a);
130         ser.putKey("afterArray"); ser.putValue(42);
131     ser.objectEnd(o);
132 
133     value.should == parseJSON(q"<
134         {
135             "hello" : "world",
136             "foo" : 1234,
137             "null" : null,
138             "array" : [1, "abc", false],
139             "afterArray" : 42
140         }
141     >");
142 }