annotate libphobos/src/std/json.d @ 158:494b0b89df80 default tip

...
author Shinji KONO <kono@ie.u-ryukyu.ac.jp>
date Mon, 25 May 2020 18:13:55 +0900
parents 1830386684a0
children
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
rev   line source
145
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1 // Written in the D programming language.
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3 /**
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
4 JavaScript Object Notation
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
5
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
6 Copyright: Copyright Jeremie Pelletier 2008 - 2009.
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
7 License: $(HTTP www.boost.org/LICENSE_1_0.txt, Boost License 1.0).
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
8 Authors: Jeremie Pelletier, David Herberth
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
9 References: $(LINK http://json.org/)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
10 Source: $(PHOBOSSRC std/_json.d)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
11 */
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
12 /*
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
13 Copyright Jeremie Pelletier 2008 - 2009.
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
14 Distributed under the Boost Software License, Version 1.0.
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
15 (See accompanying file LICENSE_1_0.txt or copy at
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
16 http://www.boost.org/LICENSE_1_0.txt)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
17 */
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
18 module std.json;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
19
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
20 import std.array;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
21 import std.conv;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
22 import std.range.primitives;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
23 import std.traits;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
24
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
25 ///
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
26 @system unittest
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
27 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
28 import std.conv : to;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
29
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
30 // parse a file or string of json into a usable structure
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
31 string s = `{ "language": "D", "rating": 3.5, "code": "42" }`;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
32 JSONValue j = parseJSON(s);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
33 // j and j["language"] return JSONValue,
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
34 // j["language"].str returns a string
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
35 assert(j["language"].str == "D");
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
36 assert(j["rating"].floating == 3.5);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
37
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
38 // check a type
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
39 long x;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
40 if (const(JSONValue)* code = "code" in j)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
41 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
42 if (code.type() == JSON_TYPE.INTEGER)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
43 x = code.integer;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
44 else
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
45 x = to!int(code.str);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
46 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
47
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
48 // create a json struct
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
49 JSONValue jj = [ "language": "D" ];
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
50 // rating doesnt exist yet, so use .object to assign
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
51 jj.object["rating"] = JSONValue(3.5);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
52 // create an array to assign to list
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
53 jj.object["list"] = JSONValue( ["a", "b", "c"] );
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
54 // list already exists, so .object optional
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
55 jj["list"].array ~= JSONValue("D");
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
56
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
57 string jjStr = `{"language":"D","list":["a","b","c","D"],"rating":3.5}`;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
58 assert(jj.toString == jjStr);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
59 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
60
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
61 /**
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
62 String literals used to represent special float values within JSON strings.
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
63 */
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
64 enum JSONFloatLiteral : string
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
65 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
66 nan = "NaN", /// string representation of floating-point NaN
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
67 inf = "Infinite", /// string representation of floating-point Infinity
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
68 negativeInf = "-Infinite", /// string representation of floating-point negative Infinity
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
69 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
70
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
71 /**
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
72 Flags that control how json is encoded and parsed.
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
73 */
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
74 enum JSONOptions
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
75 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
76 none, /// standard parsing
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
77 specialFloatLiterals = 0x1, /// encode NaN and Inf float values as strings
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
78 escapeNonAsciiChars = 0x2, /// encode non ascii characters with an unicode escape sequence
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
79 doNotEscapeSlashes = 0x4, /// do not escape slashes ('/')
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
80 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
81
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
82 /**
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
83 JSON type enumeration
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
84 */
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
85 enum JSON_TYPE : byte
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
86 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
87 /// Indicates the type of a $(D JSONValue).
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
88 NULL,
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
89 STRING, /// ditto
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
90 INTEGER, /// ditto
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
91 UINTEGER,/// ditto
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
92 FLOAT, /// ditto
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
93 OBJECT, /// ditto
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
94 ARRAY, /// ditto
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
95 TRUE, /// ditto
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
96 FALSE /// ditto
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
97 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
98
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
99 /**
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
100 JSON value node
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
101 */
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
102 struct JSONValue
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
103 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
104 import std.exception : enforceEx, enforce;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
105
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
106 union Store
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
107 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
108 string str;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
109 long integer;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
110 ulong uinteger;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
111 double floating;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
112 JSONValue[string] object;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
113 JSONValue[] array;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
114 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
115 private Store store;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
116 private JSON_TYPE type_tag;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
117
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
118 /**
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
119 Returns the JSON_TYPE of the value stored in this structure.
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
120 */
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
121 @property JSON_TYPE type() const pure nothrow @safe @nogc
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
122 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
123 return type_tag;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
124 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
125 ///
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
126 @safe unittest
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
127 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
128 string s = "{ \"language\": \"D\" }";
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
129 JSONValue j = parseJSON(s);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
130 assert(j.type == JSON_TYPE.OBJECT);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
131 assert(j["language"].type == JSON_TYPE.STRING);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
132 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
133
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
134 /***
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
135 * Value getter/setter for $(D JSON_TYPE.STRING).
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
136 * Throws: $(D JSONException) for read access if $(D type) is not
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
137 * $(D JSON_TYPE.STRING).
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
138 */
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
139 @property string str() const pure @trusted
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
140 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
141 enforce!JSONException(type == JSON_TYPE.STRING,
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
142 "JSONValue is not a string");
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
143 return store.str;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
144 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
145 /// ditto
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
146 @property string str(string v) pure nothrow @nogc @safe
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
147 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
148 assign(v);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
149 return v;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
150 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
151 ///
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
152 @safe unittest
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
153 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
154 JSONValue j = [ "language": "D" ];
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
155
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
156 // get value
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
157 assert(j["language"].str == "D");
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
158
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
159 // change existing key to new string
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
160 j["language"].str = "Perl";
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
161 assert(j["language"].str == "Perl");
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
162 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
163
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
164 /***
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
165 * Value getter/setter for $(D JSON_TYPE.INTEGER).
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
166 * Throws: $(D JSONException) for read access if $(D type) is not
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
167 * $(D JSON_TYPE.INTEGER).
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
168 */
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
169 @property inout(long) integer() inout pure @safe
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
170 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
171 enforce!JSONException(type == JSON_TYPE.INTEGER,
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
172 "JSONValue is not an integer");
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
173 return store.integer;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
174 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
175 /// ditto
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
176 @property long integer(long v) pure nothrow @safe @nogc
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
177 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
178 assign(v);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
179 return store.integer;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
180 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
181
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
182 /***
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
183 * Value getter/setter for $(D JSON_TYPE.UINTEGER).
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
184 * Throws: $(D JSONException) for read access if $(D type) is not
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
185 * $(D JSON_TYPE.UINTEGER).
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
186 */
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
187 @property inout(ulong) uinteger() inout pure @safe
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
188 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
189 enforce!JSONException(type == JSON_TYPE.UINTEGER,
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
190 "JSONValue is not an unsigned integer");
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
191 return store.uinteger;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
192 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
193 /// ditto
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
194 @property ulong uinteger(ulong v) pure nothrow @safe @nogc
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
195 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
196 assign(v);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
197 return store.uinteger;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
198 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
199
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
200 /***
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
201 * Value getter/setter for $(D JSON_TYPE.FLOAT). Note that despite
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
202 * the name, this is a $(B 64)-bit `double`, not a 32-bit `float`.
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
203 * Throws: $(D JSONException) for read access if $(D type) is not
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
204 * $(D JSON_TYPE.FLOAT).
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
205 */
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
206 @property inout(double) floating() inout pure @safe
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
207 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
208 enforce!JSONException(type == JSON_TYPE.FLOAT,
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
209 "JSONValue is not a floating type");
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
210 return store.floating;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
211 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
212 /// ditto
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
213 @property double floating(double v) pure nothrow @safe @nogc
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
214 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
215 assign(v);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
216 return store.floating;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
217 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
218
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
219 /***
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
220 * Value getter/setter for $(D JSON_TYPE.OBJECT).
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
221 * Throws: $(D JSONException) for read access if $(D type) is not
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
222 * $(D JSON_TYPE.OBJECT).
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
223 * Note: this is @system because of the following pattern:
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
224 ---
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
225 auto a = &(json.object());
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
226 json.uinteger = 0; // overwrite AA pointer
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
227 (*a)["hello"] = "world"; // segmentation fault
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
228 ---
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
229 */
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
230 @property ref inout(JSONValue[string]) object() inout pure @system
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
231 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
232 enforce!JSONException(type == JSON_TYPE.OBJECT,
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
233 "JSONValue is not an object");
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
234 return store.object;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
235 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
236 /// ditto
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
237 @property JSONValue[string] object(JSONValue[string] v) pure nothrow @nogc @safe
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
238 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
239 assign(v);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
240 return v;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
241 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
242
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
243 /***
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
244 * Value getter for $(D JSON_TYPE.OBJECT).
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
245 * Unlike $(D object), this retrieves the object by value and can be used in @safe code.
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
246 *
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
247 * A caveat is that, if the returned value is null, modifications will not be visible:
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
248 * ---
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
249 * JSONValue json;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
250 * json.object = null;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
251 * json.objectNoRef["hello"] = JSONValue("world");
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
252 * assert("hello" !in json.object);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
253 * ---
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
254 *
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
255 * Throws: $(D JSONException) for read access if $(D type) is not
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
256 * $(D JSON_TYPE.OBJECT).
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
257 */
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
258 @property inout(JSONValue[string]) objectNoRef() inout pure @trusted
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
259 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
260 enforce!JSONException(type == JSON_TYPE.OBJECT,
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
261 "JSONValue is not an object");
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
262 return store.object;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
263 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
264
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
265 /***
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
266 * Value getter/setter for $(D JSON_TYPE.ARRAY).
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
267 * Throws: $(D JSONException) for read access if $(D type) is not
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
268 * $(D JSON_TYPE.ARRAY).
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
269 * Note: this is @system because of the following pattern:
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
270 ---
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
271 auto a = &(json.array());
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
272 json.uinteger = 0; // overwrite array pointer
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
273 (*a)[0] = "world"; // segmentation fault
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
274 ---
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
275 */
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
276 @property ref inout(JSONValue[]) array() inout pure @system
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
277 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
278 enforce!JSONException(type == JSON_TYPE.ARRAY,
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
279 "JSONValue is not an array");
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
280 return store.array;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
281 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
282 /// ditto
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
283 @property JSONValue[] array(JSONValue[] v) pure nothrow @nogc @safe
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
284 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
285 assign(v);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
286 return v;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
287 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
288
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
289 /***
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
290 * Value getter for $(D JSON_TYPE.ARRAY).
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
291 * Unlike $(D array), this retrieves the array by value and can be used in @safe code.
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
292 *
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
293 * A caveat is that, if you append to the returned array, the new values aren't visible in the
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
294 * JSONValue:
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
295 * ---
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
296 * JSONValue json;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
297 * json.array = [JSONValue("hello")];
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
298 * json.arrayNoRef ~= JSONValue("world");
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
299 * assert(json.array.length == 1);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
300 * ---
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
301 *
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
302 * Throws: $(D JSONException) for read access if $(D type) is not
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
303 * $(D JSON_TYPE.ARRAY).
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
304 */
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
305 @property inout(JSONValue[]) arrayNoRef() inout pure @trusted
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
306 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
307 enforce!JSONException(type == JSON_TYPE.ARRAY,
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
308 "JSONValue is not an array");
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
309 return store.array;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
310 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
311
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
312 /// Test whether the type is $(D JSON_TYPE.NULL)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
313 @property bool isNull() const pure nothrow @safe @nogc
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
314 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
315 return type == JSON_TYPE.NULL;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
316 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
317
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
318 private void assign(T)(T arg) @safe
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
319 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
320 static if (is(T : typeof(null)))
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
321 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
322 type_tag = JSON_TYPE.NULL;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
323 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
324 else static if (is(T : string))
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
325 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
326 type_tag = JSON_TYPE.STRING;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
327 string t = arg;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
328 () @trusted { store.str = t; }();
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
329 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
330 else static if (isSomeString!T) // issue 15884
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
331 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
332 type_tag = JSON_TYPE.STRING;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
333 // FIXME: std.array.array(Range) is not deduced as 'pure'
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
334 () @trusted {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
335 import std.utf : byUTF;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
336 store.str = cast(immutable)(arg.byUTF!char.array);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
337 }();
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
338 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
339 else static if (is(T : bool))
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
340 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
341 type_tag = arg ? JSON_TYPE.TRUE : JSON_TYPE.FALSE;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
342 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
343 else static if (is(T : ulong) && isUnsigned!T)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
344 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
345 type_tag = JSON_TYPE.UINTEGER;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
346 store.uinteger = arg;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
347 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
348 else static if (is(T : long))
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
349 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
350 type_tag = JSON_TYPE.INTEGER;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
351 store.integer = arg;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
352 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
353 else static if (isFloatingPoint!T)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
354 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
355 type_tag = JSON_TYPE.FLOAT;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
356 store.floating = arg;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
357 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
358 else static if (is(T : Value[Key], Key, Value))
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
359 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
360 static assert(is(Key : string), "AA key must be string");
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
361 type_tag = JSON_TYPE.OBJECT;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
362 static if (is(Value : JSONValue))
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
363 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
364 JSONValue[string] t = arg;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
365 () @trusted { store.object = t; }();
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
366 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
367 else
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
368 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
369 JSONValue[string] aa;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
370 foreach (key, value; arg)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
371 aa[key] = JSONValue(value);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
372 () @trusted { store.object = aa; }();
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
373 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
374 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
375 else static if (isArray!T)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
376 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
377 type_tag = JSON_TYPE.ARRAY;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
378 static if (is(ElementEncodingType!T : JSONValue))
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
379 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
380 JSONValue[] t = arg;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
381 () @trusted { store.array = t; }();
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
382 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
383 else
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
384 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
385 JSONValue[] new_arg = new JSONValue[arg.length];
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
386 foreach (i, e; arg)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
387 new_arg[i] = JSONValue(e);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
388 () @trusted { store.array = new_arg; }();
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
389 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
390 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
391 else static if (is(T : JSONValue))
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
392 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
393 type_tag = arg.type;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
394 store = arg.store;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
395 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
396 else
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
397 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
398 static assert(false, text(`unable to convert type "`, T.stringof, `" to json`));
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
399 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
400 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
401
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
402 private void assignRef(T)(ref T arg) if (isStaticArray!T)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
403 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
404 type_tag = JSON_TYPE.ARRAY;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
405 static if (is(ElementEncodingType!T : JSONValue))
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
406 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
407 store.array = arg;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
408 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
409 else
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
410 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
411 JSONValue[] new_arg = new JSONValue[arg.length];
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
412 foreach (i, e; arg)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
413 new_arg[i] = JSONValue(e);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
414 store.array = new_arg;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
415 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
416 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
417
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
418 /**
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
419 * Constructor for $(D JSONValue). If $(D arg) is a $(D JSONValue)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
420 * its value and type will be copied to the new $(D JSONValue).
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
421 * Note that this is a shallow copy: if type is $(D JSON_TYPE.OBJECT)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
422 * or $(D JSON_TYPE.ARRAY) then only the reference to the data will
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
423 * be copied.
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
424 * Otherwise, $(D arg) must be implicitly convertible to one of the
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
425 * following types: $(D typeof(null)), $(D string), $(D ulong),
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
426 * $(D long), $(D double), an associative array $(D V[K]) for any $(D V)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
427 * and $(D K) i.e. a JSON object, any array or $(D bool). The type will
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
428 * be set accordingly.
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
429 */
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
430 this(T)(T arg) if (!isStaticArray!T)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
431 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
432 assign(arg);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
433 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
434 /// Ditto
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
435 this(T)(ref T arg) if (isStaticArray!T)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
436 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
437 assignRef(arg);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
438 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
439 /// Ditto
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
440 this(T : JSONValue)(inout T arg) inout
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
441 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
442 store = arg.store;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
443 type_tag = arg.type;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
444 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
445 ///
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
446 @safe unittest
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
447 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
448 JSONValue j = JSONValue( "a string" );
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
449 j = JSONValue(42);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
450
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
451 j = JSONValue( [1, 2, 3] );
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
452 assert(j.type == JSON_TYPE.ARRAY);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
453
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
454 j = JSONValue( ["language": "D"] );
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
455 assert(j.type == JSON_TYPE.OBJECT);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
456 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
457
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
458 void opAssign(T)(T arg) if (!isStaticArray!T && !is(T : JSONValue))
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
459 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
460 assign(arg);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
461 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
462
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
463 void opAssign(T)(ref T arg) if (isStaticArray!T)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
464 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
465 assignRef(arg);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
466 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
467
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
468 /***
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
469 * Array syntax for json arrays.
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
470 * Throws: $(D JSONException) if $(D type) is not $(D JSON_TYPE.ARRAY).
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
471 */
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
472 ref inout(JSONValue) opIndex(size_t i) inout pure @safe
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
473 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
474 auto a = this.arrayNoRef;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
475 enforceEx!JSONException(i < a.length,
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
476 "JSONValue array index is out of range");
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
477 return a[i];
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
478 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
479 ///
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
480 @safe unittest
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
481 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
482 JSONValue j = JSONValue( [42, 43, 44] );
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
483 assert( j[0].integer == 42 );
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
484 assert( j[1].integer == 43 );
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
485 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
486
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
487 /***
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
488 * Hash syntax for json objects.
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
489 * Throws: $(D JSONException) if $(D type) is not $(D JSON_TYPE.OBJECT).
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
490 */
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
491 ref inout(JSONValue) opIndex(string k) inout pure @safe
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
492 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
493 auto o = this.objectNoRef;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
494 return *enforce!JSONException(k in o,
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
495 "Key not found: " ~ k);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
496 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
497 ///
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
498 @safe unittest
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
499 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
500 JSONValue j = JSONValue( ["language": "D"] );
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
501 assert( j["language"].str == "D" );
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
502 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
503
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
504 /***
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
505 * Operator sets $(D value) for element of JSON object by $(D key).
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
506 *
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
507 * If JSON value is null, then operator initializes it with object and then
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
508 * sets $(D value) for it.
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
509 *
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
510 * Throws: $(D JSONException) if $(D type) is not $(D JSON_TYPE.OBJECT)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
511 * or $(D JSON_TYPE.NULL).
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
512 */
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
513 void opIndexAssign(T)(auto ref T value, string key) pure
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
514 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
515 enforceEx!JSONException(type == JSON_TYPE.OBJECT || type == JSON_TYPE.NULL,
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
516 "JSONValue must be object or null");
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
517 JSONValue[string] aa = null;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
518 if (type == JSON_TYPE.OBJECT)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
519 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
520 aa = this.objectNoRef;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
521 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
522
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
523 aa[key] = value;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
524 this.object = aa;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
525 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
526 ///
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
527 @safe unittest
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
528 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
529 JSONValue j = JSONValue( ["language": "D"] );
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
530 j["language"].str = "Perl";
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
531 assert( j["language"].str == "Perl" );
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
532 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
533
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
534 void opIndexAssign(T)(T arg, size_t i) pure
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
535 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
536 auto a = this.arrayNoRef;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
537 enforceEx!JSONException(i < a.length,
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
538 "JSONValue array index is out of range");
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
539 a[i] = arg;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
540 this.array = a;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
541 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
542 ///
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
543 @safe unittest
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
544 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
545 JSONValue j = JSONValue( ["Perl", "C"] );
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
546 j[1].str = "D";
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
547 assert( j[1].str == "D" );
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
548 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
549
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
550 JSONValue opBinary(string op : "~", T)(T arg) @safe
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
551 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
552 auto a = this.arrayNoRef;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
553 static if (isArray!T)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
554 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
555 return JSONValue(a ~ JSONValue(arg).arrayNoRef);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
556 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
557 else static if (is(T : JSONValue))
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
558 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
559 return JSONValue(a ~ arg.arrayNoRef);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
560 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
561 else
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
562 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
563 static assert(false, "argument is not an array or a JSONValue array");
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
564 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
565 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
566
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
567 void opOpAssign(string op : "~", T)(T arg) @safe
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
568 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
569 auto a = this.arrayNoRef;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
570 static if (isArray!T)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
571 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
572 a ~= JSONValue(arg).arrayNoRef;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
573 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
574 else static if (is(T : JSONValue))
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
575 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
576 a ~= arg.arrayNoRef;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
577 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
578 else
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
579 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
580 static assert(false, "argument is not an array or a JSONValue array");
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
581 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
582 this.array = a;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
583 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
584
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
585 /**
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
586 * Support for the $(D in) operator.
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
587 *
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
588 * Tests wether a key can be found in an object.
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
589 *
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
590 * Returns:
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
591 * when found, the $(D const(JSONValue)*) that matches to the key,
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
592 * otherwise $(D null).
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
593 *
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
594 * Throws: $(D JSONException) if the right hand side argument $(D JSON_TYPE)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
595 * is not $(D OBJECT).
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
596 */
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
597 auto opBinaryRight(string op : "in")(string k) const @safe
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
598 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
599 return k in this.objectNoRef;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
600 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
601 ///
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
602 @safe unittest
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
603 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
604 JSONValue j = [ "language": "D", "author": "walter" ];
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
605 string a = ("author" in j).str;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
606 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
607
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
608 bool opEquals(const JSONValue rhs) const @nogc nothrow pure @safe
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
609 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
610 return opEquals(rhs);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
611 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
612
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
613 bool opEquals(ref const JSONValue rhs) const @nogc nothrow pure @trusted
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
614 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
615 // Default doesn't work well since store is a union. Compare only
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
616 // what should be in store.
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
617 // This is @trusted to remain nogc, nothrow, fast, and usable from @safe code.
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
618 if (type_tag != rhs.type_tag) return false;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
619
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
620 final switch (type_tag)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
621 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
622 case JSON_TYPE.STRING:
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
623 return store.str == rhs.store.str;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
624 case JSON_TYPE.INTEGER:
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
625 return store.integer == rhs.store.integer;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
626 case JSON_TYPE.UINTEGER:
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
627 return store.uinteger == rhs.store.uinteger;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
628 case JSON_TYPE.FLOAT:
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
629 return store.floating == rhs.store.floating;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
630 case JSON_TYPE.OBJECT:
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
631 return store.object == rhs.store.object;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
632 case JSON_TYPE.ARRAY:
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
633 return store.array == rhs.store.array;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
634 case JSON_TYPE.TRUE:
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
635 case JSON_TYPE.FALSE:
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
636 case JSON_TYPE.NULL:
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
637 return true;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
638 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
639 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
640
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
641 /// Implements the foreach $(D opApply) interface for json arrays.
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
642 int opApply(scope int delegate(size_t index, ref JSONValue) dg) @system
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
643 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
644 int result;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
645
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
646 foreach (size_t index, ref value; array)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
647 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
648 result = dg(index, value);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
649 if (result)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
650 break;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
651 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
652
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
653 return result;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
654 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
655
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
656 /// Implements the foreach $(D opApply) interface for json objects.
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
657 int opApply(scope int delegate(string key, ref JSONValue) dg) @system
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
658 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
659 enforce!JSONException(type == JSON_TYPE.OBJECT,
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
660 "JSONValue is not an object");
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
661 int result;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
662
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
663 foreach (string key, ref value; object)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
664 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
665 result = dg(key, value);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
666 if (result)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
667 break;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
668 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
669
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
670 return result;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
671 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
672
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
673 /***
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
674 * Implicitly calls $(D toJSON) on this JSONValue.
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
675 *
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
676 * $(I options) can be used to tweak the conversion behavior.
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
677 */
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
678 string toString(in JSONOptions options = JSONOptions.none) const @safe
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
679 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
680 return toJSON(this, false, options);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
681 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
682
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
683 /***
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
684 * Implicitly calls $(D toJSON) on this JSONValue, like $(D toString), but
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
685 * also passes $(I true) as $(I pretty) argument.
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
686 *
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
687 * $(I options) can be used to tweak the conversion behavior
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
688 */
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
689 string toPrettyString(in JSONOptions options = JSONOptions.none) const @safe
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
690 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
691 return toJSON(this, true, options);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
692 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
693 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
694
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
695 /**
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
696 Parses a serialized string and returns a tree of JSON values.
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
697 Throws: $(LREF JSONException) if the depth exceeds the max depth.
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
698 Params:
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
699 json = json-formatted string to parse
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
700 maxDepth = maximum depth of nesting allowed, -1 disables depth checking
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
701 options = enable decoding string representations of NaN/Inf as float values
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
702 */
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
703 JSONValue parseJSON(T)(T json, int maxDepth = -1, JSONOptions options = JSONOptions.none)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
704 if (isInputRange!T && !isInfinite!T && isSomeChar!(ElementEncodingType!T))
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
705 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
706 import std.ascii : isWhite, isDigit, isHexDigit, toUpper, toLower;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
707 import std.typecons : Yes;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
708 JSONValue root;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
709 root.type_tag = JSON_TYPE.NULL;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
710
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
711 // Avoid UTF decoding when possible, as it is unnecessary when
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
712 // processing JSON.
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
713 static if (is(T : const(char)[]))
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
714 alias Char = char;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
715 else
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
716 alias Char = Unqual!(ElementType!T);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
717
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
718 if (json.empty) return root;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
719
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
720 int depth = -1;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
721 Char next = 0;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
722 int line = 1, pos = 0;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
723
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
724 void error(string msg)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
725 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
726 throw new JSONException(msg, line, pos);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
727 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
728
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
729 Char popChar()
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
730 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
731 if (json.empty) error("Unexpected end of data.");
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
732 static if (is(T : const(char)[]))
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
733 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
734 Char c = json[0];
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
735 json = json[1..$];
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
736 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
737 else
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
738 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
739 Char c = json.front;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
740 json.popFront();
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
741 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
742
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
743 if (c == '\n')
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
744 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
745 line++;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
746 pos = 0;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
747 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
748 else
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
749 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
750 pos++;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
751 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
752
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
753 return c;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
754 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
755
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
756 Char peekChar()
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
757 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
758 if (!next)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
759 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
760 if (json.empty) return '\0';
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
761 next = popChar();
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
762 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
763 return next;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
764 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
765
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
766 void skipWhitespace()
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
767 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
768 while (isWhite(peekChar())) next = 0;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
769 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
770
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
771 Char getChar(bool SkipWhitespace = false)()
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
772 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
773 static if (SkipWhitespace) skipWhitespace();
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
774
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
775 Char c;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
776 if (next)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
777 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
778 c = next;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
779 next = 0;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
780 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
781 else
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
782 c = popChar();
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
783
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
784 return c;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
785 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
786
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
787 void checkChar(bool SkipWhitespace = true, bool CaseSensitive = true)(char c)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
788 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
789 static if (SkipWhitespace) skipWhitespace();
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
790 auto c2 = getChar();
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
791 static if (!CaseSensitive) c2 = toLower(c2);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
792
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
793 if (c2 != c) error(text("Found '", c2, "' when expecting '", c, "'."));
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
794 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
795
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
796 bool testChar(bool SkipWhitespace = true, bool CaseSensitive = true)(char c)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
797 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
798 static if (SkipWhitespace) skipWhitespace();
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
799 auto c2 = peekChar();
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
800 static if (!CaseSensitive) c2 = toLower(c2);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
801
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
802 if (c2 != c) return false;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
803
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
804 getChar();
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
805 return true;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
806 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
807
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
808 wchar parseWChar()
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
809 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
810 wchar val = 0;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
811 foreach_reverse (i; 0 .. 4)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
812 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
813 auto hex = toUpper(getChar());
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
814 if (!isHexDigit(hex)) error("Expecting hex character");
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
815 val += (isDigit(hex) ? hex - '0' : hex - ('A' - 10)) << (4 * i);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
816 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
817 return val;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
818 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
819
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
820 string parseString()
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
821 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
822 import std.ascii : isControl;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
823 import std.uni : isSurrogateHi, isSurrogateLo;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
824 import std.utf : encode, decode;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
825
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
826 auto str = appender!string();
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
827
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
828 Next:
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
829 switch (peekChar())
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
830 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
831 case '"':
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
832 getChar();
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
833 break;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
834
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
835 case '\\':
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
836 getChar();
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
837 auto c = getChar();
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
838 switch (c)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
839 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
840 case '"': str.put('"'); break;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
841 case '\\': str.put('\\'); break;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
842 case '/': str.put('/'); break;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
843 case 'b': str.put('\b'); break;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
844 case 'f': str.put('\f'); break;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
845 case 'n': str.put('\n'); break;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
846 case 'r': str.put('\r'); break;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
847 case 't': str.put('\t'); break;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
848 case 'u':
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
849 wchar wc = parseWChar();
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
850 dchar val;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
851 // Non-BMP characters are escaped as a pair of
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
852 // UTF-16 surrogate characters (see RFC 4627).
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
853 if (isSurrogateHi(wc))
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
854 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
855 wchar[2] pair;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
856 pair[0] = wc;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
857 if (getChar() != '\\') error("Expected escaped low surrogate after escaped high surrogate");
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
858 if (getChar() != 'u') error("Expected escaped low surrogate after escaped high surrogate");
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
859 pair[1] = parseWChar();
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
860 size_t index = 0;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
861 val = decode(pair[], index);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
862 if (index != 2) error("Invalid escaped surrogate pair");
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
863 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
864 else
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
865 if (isSurrogateLo(wc))
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
866 error(text("Unexpected low surrogate"));
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
867 else
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
868 val = wc;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
869
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
870 char[4] buf;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
871 immutable len = encode!(Yes.useReplacementDchar)(buf, val);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
872 str.put(buf[0 .. len]);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
873 break;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
874
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
875 default:
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
876 error(text("Invalid escape sequence '\\", c, "'."));
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
877 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
878 goto Next;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
879
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
880 default:
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
881 // RFC 7159 states that control characters U+0000 through
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
882 // U+001F must not appear unescaped in a JSON string.
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
883 auto c = getChar();
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
884 if (isControl(c))
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
885 error("Illegal control character.");
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
886 str.put(c);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
887 goto Next;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
888 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
889
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
890 return str.data.length ? str.data : "";
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
891 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
892
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
893 bool tryGetSpecialFloat(string str, out double val) {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
894 switch (str)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
895 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
896 case JSONFloatLiteral.nan:
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
897 val = double.nan;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
898 return true;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
899 case JSONFloatLiteral.inf:
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
900 val = double.infinity;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
901 return true;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
902 case JSONFloatLiteral.negativeInf:
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
903 val = -double.infinity;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
904 return true;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
905 default:
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
906 return false;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
907 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
908 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
909
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
910 void parseValue(ref JSONValue value)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
911 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
912 depth++;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
913
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
914 if (maxDepth != -1 && depth > maxDepth) error("Nesting too deep.");
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
915
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
916 auto c = getChar!true();
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
917
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
918 switch (c)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
919 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
920 case '{':
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
921 if (testChar('}'))
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
922 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
923 value.object = null;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
924 break;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
925 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
926
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
927 JSONValue[string] obj;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
928 do
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
929 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
930 checkChar('"');
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
931 string name = parseString();
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
932 checkChar(':');
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
933 JSONValue member;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
934 parseValue(member);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
935 obj[name] = member;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
936 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
937 while (testChar(','));
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
938 value.object = obj;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
939
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
940 checkChar('}');
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
941 break;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
942
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
943 case '[':
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
944 if (testChar(']'))
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
945 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
946 value.type_tag = JSON_TYPE.ARRAY;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
947 break;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
948 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
949
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
950 JSONValue[] arr;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
951 do
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
952 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
953 JSONValue element;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
954 parseValue(element);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
955 arr ~= element;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
956 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
957 while (testChar(','));
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
958
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
959 checkChar(']');
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
960 value.array = arr;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
961 break;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
962
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
963 case '"':
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
964 auto str = parseString();
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
965
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
966 // if special float parsing is enabled, check if string represents NaN/Inf
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
967 if ((options & JSONOptions.specialFloatLiterals) &&
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
968 tryGetSpecialFloat(str, value.store.floating))
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
969 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
970 // found a special float, its value was placed in value.store.floating
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
971 value.type_tag = JSON_TYPE.FLOAT;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
972 break;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
973 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
974
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
975 value.type_tag = JSON_TYPE.STRING;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
976 value.store.str = str;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
977 break;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
978
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
979 case '0': .. case '9':
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
980 case '-':
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
981 auto number = appender!string();
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
982 bool isFloat, isNegative;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
983
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
984 void readInteger()
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
985 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
986 if (!isDigit(c)) error("Digit expected");
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
987
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
988 Next: number.put(c);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
989
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
990 if (isDigit(peekChar()))
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
991 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
992 c = getChar();
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
993 goto Next;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
994 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
995 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
996
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
997 if (c == '-')
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
998 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
999 number.put('-');
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1000 c = getChar();
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1001 isNegative = true;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1002 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1003
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1004 readInteger();
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1005
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1006 if (testChar('.'))
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1007 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1008 isFloat = true;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1009 number.put('.');
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1010 c = getChar();
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1011 readInteger();
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1012 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1013 if (testChar!(false, false)('e'))
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1014 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1015 isFloat = true;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1016 number.put('e');
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1017 if (testChar('+')) number.put('+');
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1018 else if (testChar('-')) number.put('-');
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1019 c = getChar();
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1020 readInteger();
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1021 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1022
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1023 string data = number.data;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1024 if (isFloat)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1025 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1026 value.type_tag = JSON_TYPE.FLOAT;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1027 value.store.floating = parse!double(data);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1028 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1029 else
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1030 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1031 if (isNegative)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1032 value.store.integer = parse!long(data);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1033 else
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1034 value.store.uinteger = parse!ulong(data);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1035
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1036 value.type_tag = !isNegative && value.store.uinteger & (1UL << 63) ?
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1037 JSON_TYPE.UINTEGER : JSON_TYPE.INTEGER;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1038 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1039 break;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1040
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1041 case 't':
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1042 case 'T':
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1043 value.type_tag = JSON_TYPE.TRUE;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1044 checkChar!(false, false)('r');
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1045 checkChar!(false, false)('u');
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1046 checkChar!(false, false)('e');
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1047 break;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1048
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1049 case 'f':
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1050 case 'F':
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1051 value.type_tag = JSON_TYPE.FALSE;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1052 checkChar!(false, false)('a');
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1053 checkChar!(false, false)('l');
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1054 checkChar!(false, false)('s');
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1055 checkChar!(false, false)('e');
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1056 break;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1057
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1058 case 'n':
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1059 case 'N':
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1060 value.type_tag = JSON_TYPE.NULL;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1061 checkChar!(false, false)('u');
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1062 checkChar!(false, false)('l');
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1063 checkChar!(false, false)('l');
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1064 break;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1065
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1066 default:
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1067 error(text("Unexpected character '", c, "'."));
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1068 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1069
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1070 depth--;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1071 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1072
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1073 parseValue(root);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1074 return root;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1075 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1076
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1077 @safe unittest
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1078 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1079 enum issue15742objectOfObject = `{ "key1": { "key2": 1 }}`;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1080 static assert(parseJSON(issue15742objectOfObject).type == JSON_TYPE.OBJECT);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1081
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1082 enum issue15742arrayOfArray = `[[1]]`;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1083 static assert(parseJSON(issue15742arrayOfArray).type == JSON_TYPE.ARRAY);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1084 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1085
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1086 @safe unittest
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1087 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1088 // Ensure we can parse and use JSON from @safe code
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1089 auto a = `{ "key1": { "key2": 1 }}`.parseJSON;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1090 assert(a["key1"]["key2"].integer == 1);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1091 assert(a.toString == `{"key1":{"key2":1}}`);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1092 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1093
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1094 @system unittest
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1095 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1096 // Ensure we can parse JSON from a @system range.
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1097 struct Range
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1098 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1099 string s;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1100 size_t index;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1101 @system
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1102 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1103 bool empty() { return index >= s.length; }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1104 void popFront() { index++; }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1105 char front() { return s[index]; }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1106 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1107 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1108 auto s = Range(`{ "key1": { "key2": 1 }}`);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1109 auto json = parseJSON(s);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1110 assert(json["key1"]["key2"].integer == 1);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1111 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1112
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1113 /**
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1114 Parses a serialized string and returns a tree of JSON values.
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1115 Throws: $(REF JSONException, std,json) if the depth exceeds the max depth.
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1116 Params:
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1117 json = json-formatted string to parse
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1118 options = enable decoding string representations of NaN/Inf as float values
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1119 */
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1120 JSONValue parseJSON(T)(T json, JSONOptions options)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1121 if (isInputRange!T && !isInfinite!T && isSomeChar!(ElementEncodingType!T))
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1122 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1123 return parseJSON!T(json, -1, options);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1124 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1125
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1126 /**
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1127 Takes a tree of JSON values and returns the serialized string.
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1128
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1129 Any Object types will be serialized in a key-sorted order.
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1130
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1131 If $(D pretty) is false no whitespaces are generated.
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1132 If $(D pretty) is true serialized string is formatted to be human-readable.
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1133 Set the $(LREF JSONOptions.specialFloatLiterals) flag is set in $(D options) to encode NaN/Infinity as strings.
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1134 */
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1135 string toJSON(const ref JSONValue root, in bool pretty = false, in JSONOptions options = JSONOptions.none) @safe
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1136 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1137 auto json = appender!string();
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1138
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1139 void toStringImpl(Char)(string str) @safe
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1140 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1141 json.put('"');
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1142
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1143 foreach (Char c; str)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1144 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1145 switch (c)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1146 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1147 case '"': json.put("\\\""); break;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1148 case '\\': json.put("\\\\"); break;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1149
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1150 case '/':
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1151 if (!(options & JSONOptions.doNotEscapeSlashes))
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1152 json.put('\\');
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1153 json.put('/');
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1154 break;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1155
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1156 case '\b': json.put("\\b"); break;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1157 case '\f': json.put("\\f"); break;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1158 case '\n': json.put("\\n"); break;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1159 case '\r': json.put("\\r"); break;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1160 case '\t': json.put("\\t"); break;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1161 default:
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1162 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1163 import std.ascii : isControl;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1164 import std.utf : encode;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1165
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1166 // Make sure we do UTF decoding iff we want to
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1167 // escape Unicode characters.
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1168 assert(((options & JSONOptions.escapeNonAsciiChars) != 0)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1169 == is(Char == dchar));
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1170
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1171 with (JSONOptions) if (isControl(c) ||
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1172 ((options & escapeNonAsciiChars) >= escapeNonAsciiChars && c >= 0x80))
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1173 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1174 // Ensure non-BMP characters are encoded as a pair
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1175 // of UTF-16 surrogate characters, as per RFC 4627.
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1176 wchar[2] wchars; // 1 or 2 UTF-16 code units
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1177 size_t wNum = encode(wchars, c); // number of UTF-16 code units
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1178 foreach (wc; wchars[0 .. wNum])
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1179 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1180 json.put("\\u");
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1181 foreach_reverse (i; 0 .. 4)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1182 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1183 char ch = (wc >>> (4 * i)) & 0x0f;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1184 ch += ch < 10 ? '0' : 'A' - 10;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1185 json.put(ch);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1186 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1187 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1188 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1189 else
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1190 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1191 json.put(c);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1192 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1193 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1194 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1195 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1196
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1197 json.put('"');
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1198 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1199
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1200 void toString(string str) @safe
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1201 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1202 // Avoid UTF decoding when possible, as it is unnecessary when
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1203 // processing JSON.
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1204 if (options & JSONOptions.escapeNonAsciiChars)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1205 toStringImpl!dchar(str);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1206 else
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1207 toStringImpl!char(str);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1208 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1209
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1210 void toValue(ref in JSONValue value, ulong indentLevel) @safe
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1211 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1212 void putTabs(ulong additionalIndent = 0)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1213 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1214 if (pretty)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1215 foreach (i; 0 .. indentLevel + additionalIndent)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1216 json.put(" ");
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1217 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1218 void putEOL()
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1219 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1220 if (pretty)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1221 json.put('\n');
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1222 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1223 void putCharAndEOL(char ch)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1224 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1225 json.put(ch);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1226 putEOL();
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1227 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1228
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1229 final switch (value.type)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1230 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1231 case JSON_TYPE.OBJECT:
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1232 auto obj = value.objectNoRef;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1233 if (!obj.length)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1234 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1235 json.put("{}");
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1236 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1237 else
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1238 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1239 putCharAndEOL('{');
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1240 bool first = true;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1241
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1242 void emit(R)(R names)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1243 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1244 foreach (name; names)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1245 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1246 auto member = obj[name];
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1247 if (!first)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1248 putCharAndEOL(',');
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1249 first = false;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1250 putTabs(1);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1251 toString(name);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1252 json.put(':');
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1253 if (pretty)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1254 json.put(' ');
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1255 toValue(member, indentLevel + 1);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1256 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1257 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1258
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1259 import std.algorithm.sorting : sort;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1260 // @@@BUG@@@ 14439
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1261 // auto names = obj.keys; // aa.keys can't be called in @safe code
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1262 auto names = new string[obj.length];
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1263 size_t i = 0;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1264 foreach (k, v; obj)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1265 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1266 names[i] = k;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1267 i++;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1268 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1269 sort(names);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1270 emit(names);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1271
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1272 putEOL();
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1273 putTabs();
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1274 json.put('}');
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1275 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1276 break;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1277
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1278 case JSON_TYPE.ARRAY:
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1279 auto arr = value.arrayNoRef;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1280 if (arr.empty)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1281 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1282 json.put("[]");
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1283 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1284 else
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1285 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1286 putCharAndEOL('[');
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1287 foreach (i, el; arr)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1288 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1289 if (i)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1290 putCharAndEOL(',');
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1291 putTabs(1);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1292 toValue(el, indentLevel + 1);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1293 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1294 putEOL();
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1295 putTabs();
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1296 json.put(']');
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1297 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1298 break;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1299
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1300 case JSON_TYPE.STRING:
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1301 toString(value.str);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1302 break;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1303
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1304 case JSON_TYPE.INTEGER:
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1305 json.put(to!string(value.store.integer));
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1306 break;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1307
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1308 case JSON_TYPE.UINTEGER:
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1309 json.put(to!string(value.store.uinteger));
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1310 break;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1311
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1312 case JSON_TYPE.FLOAT:
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1313 import std.math : isNaN, isInfinity;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1314
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1315 auto val = value.store.floating;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1316
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1317 if (val.isNaN)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1318 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1319 if (options & JSONOptions.specialFloatLiterals)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1320 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1321 toString(JSONFloatLiteral.nan);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1322 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1323 else
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1324 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1325 throw new JSONException(
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1326 "Cannot encode NaN. Consider passing the specialFloatLiterals flag.");
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1327 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1328 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1329 else if (val.isInfinity)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1330 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1331 if (options & JSONOptions.specialFloatLiterals)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1332 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1333 toString((val > 0) ? JSONFloatLiteral.inf : JSONFloatLiteral.negativeInf);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1334 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1335 else
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1336 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1337 throw new JSONException(
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1338 "Cannot encode Infinity. Consider passing the specialFloatLiterals flag.");
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1339 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1340 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1341 else
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1342 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1343 import std.format : format;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1344 // The correct formula for the number of decimal digits needed for lossless round
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1345 // trips is actually:
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1346 // ceil(log(pow(2.0, double.mant_dig - 1)) / log(10.0) + 1) == (double.dig + 2)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1347 // Anything less will round off (1 + double.epsilon)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1348 json.put("%.18g".format(val));
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1349 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1350 break;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1351
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1352 case JSON_TYPE.TRUE:
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1353 json.put("true");
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1354 break;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1355
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1356 case JSON_TYPE.FALSE:
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1357 json.put("false");
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1358 break;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1359
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1360 case JSON_TYPE.NULL:
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1361 json.put("null");
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1362 break;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1363 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1364 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1365
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1366 toValue(root, 0);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1367 return json.data;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1368 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1369
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1370 @safe unittest // bugzilla 12897
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1371 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1372 JSONValue jv0 = JSONValue("test测试");
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1373 assert(toJSON(jv0, false, JSONOptions.escapeNonAsciiChars) == `"test\u6D4B\u8BD5"`);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1374 JSONValue jv00 = JSONValue("test\u6D4B\u8BD5");
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1375 assert(toJSON(jv00, false, JSONOptions.none) == `"test测试"`);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1376 assert(toJSON(jv0, false, JSONOptions.none) == `"test测试"`);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1377 JSONValue jv1 = JSONValue("été");
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1378 assert(toJSON(jv1, false, JSONOptions.escapeNonAsciiChars) == `"\u00E9t\u00E9"`);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1379 JSONValue jv11 = JSONValue("\u00E9t\u00E9");
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1380 assert(toJSON(jv11, false, JSONOptions.none) == `"été"`);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1381 assert(toJSON(jv1, false, JSONOptions.none) == `"été"`);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1382 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1383
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1384 /**
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1385 Exception thrown on JSON errors
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1386 */
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1387 class JSONException : Exception
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1388 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1389 this(string msg, int line = 0, int pos = 0) pure nothrow @safe
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1390 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1391 if (line)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1392 super(text(msg, " (Line ", line, ":", pos, ")"));
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1393 else
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1394 super(msg);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1395 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1396
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1397 this(string msg, string file, size_t line) pure nothrow @safe
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1398 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1399 super(msg, file, line);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1400 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1401 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1402
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1403
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1404 @system unittest
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1405 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1406 import std.exception;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1407 JSONValue jv = "123";
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1408 assert(jv.type == JSON_TYPE.STRING);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1409 assertNotThrown(jv.str);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1410 assertThrown!JSONException(jv.integer);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1411 assertThrown!JSONException(jv.uinteger);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1412 assertThrown!JSONException(jv.floating);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1413 assertThrown!JSONException(jv.object);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1414 assertThrown!JSONException(jv.array);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1415 assertThrown!JSONException(jv["aa"]);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1416 assertThrown!JSONException(jv[2]);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1417
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1418 jv = -3;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1419 assert(jv.type == JSON_TYPE.INTEGER);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1420 assertNotThrown(jv.integer);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1421
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1422 jv = cast(uint) 3;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1423 assert(jv.type == JSON_TYPE.UINTEGER);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1424 assertNotThrown(jv.uinteger);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1425
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1426 jv = 3.0;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1427 assert(jv.type == JSON_TYPE.FLOAT);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1428 assertNotThrown(jv.floating);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1429
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1430 jv = ["key" : "value"];
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1431 assert(jv.type == JSON_TYPE.OBJECT);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1432 assertNotThrown(jv.object);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1433 assertNotThrown(jv["key"]);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1434 assert("key" in jv);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1435 assert("notAnElement" !in jv);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1436 assertThrown!JSONException(jv["notAnElement"]);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1437 const cjv = jv;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1438 assert("key" in cjv);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1439 assertThrown!JSONException(cjv["notAnElement"]);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1440
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1441 foreach (string key, value; jv)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1442 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1443 static assert(is(typeof(value) == JSONValue));
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1444 assert(key == "key");
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1445 assert(value.type == JSON_TYPE.STRING);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1446 assertNotThrown(value.str);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1447 assert(value.str == "value");
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1448 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1449
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1450 jv = [3, 4, 5];
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1451 assert(jv.type == JSON_TYPE.ARRAY);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1452 assertNotThrown(jv.array);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1453 assertNotThrown(jv[2]);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1454 foreach (size_t index, value; jv)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1455 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1456 static assert(is(typeof(value) == JSONValue));
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1457 assert(value.type == JSON_TYPE.INTEGER);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1458 assertNotThrown(value.integer);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1459 assert(index == (value.integer-3));
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1460 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1461
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1462 jv = null;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1463 assert(jv.type == JSON_TYPE.NULL);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1464 assert(jv.isNull);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1465 jv = "foo";
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1466 assert(!jv.isNull);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1467
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1468 jv = JSONValue("value");
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1469 assert(jv.type == JSON_TYPE.STRING);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1470 assert(jv.str == "value");
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1471
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1472 JSONValue jv2 = JSONValue("value");
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1473 assert(jv2.type == JSON_TYPE.STRING);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1474 assert(jv2.str == "value");
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1475
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1476 JSONValue jv3 = JSONValue("\u001c");
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1477 assert(jv3.type == JSON_TYPE.STRING);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1478 assert(jv3.str == "\u001C");
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1479 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1480
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1481 @system unittest
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1482 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1483 // Bugzilla 11504
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1484
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1485 JSONValue jv = 1;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1486 assert(jv.type == JSON_TYPE.INTEGER);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1487
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1488 jv.str = "123";
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1489 assert(jv.type == JSON_TYPE.STRING);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1490 assert(jv.str == "123");
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1491
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1492 jv.integer = 1;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1493 assert(jv.type == JSON_TYPE.INTEGER);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1494 assert(jv.integer == 1);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1495
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1496 jv.uinteger = 2u;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1497 assert(jv.type == JSON_TYPE.UINTEGER);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1498 assert(jv.uinteger == 2u);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1499
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1500 jv.floating = 1.5;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1501 assert(jv.type == JSON_TYPE.FLOAT);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1502 assert(jv.floating == 1.5);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1503
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1504 jv.object = ["key" : JSONValue("value")];
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1505 assert(jv.type == JSON_TYPE.OBJECT);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1506 assert(jv.object == ["key" : JSONValue("value")]);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1507
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1508 jv.array = [JSONValue(1), JSONValue(2), JSONValue(3)];
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1509 assert(jv.type == JSON_TYPE.ARRAY);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1510 assert(jv.array == [JSONValue(1), JSONValue(2), JSONValue(3)]);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1511
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1512 jv = true;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1513 assert(jv.type == JSON_TYPE.TRUE);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1514
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1515 jv = false;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1516 assert(jv.type == JSON_TYPE.FALSE);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1517
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1518 enum E{True = true}
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1519 jv = E.True;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1520 assert(jv.type == JSON_TYPE.TRUE);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1521 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1522
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1523 @system pure unittest
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1524 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1525 // Adding new json element via array() / object() directly
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1526
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1527 JSONValue jarr = JSONValue([10]);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1528 foreach (i; 0 .. 9)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1529 jarr.array ~= JSONValue(i);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1530 assert(jarr.array.length == 10);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1531
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1532 JSONValue jobj = JSONValue(["key" : JSONValue("value")]);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1533 foreach (i; 0 .. 9)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1534 jobj.object[text("key", i)] = JSONValue(text("value", i));
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1535 assert(jobj.object.length == 10);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1536 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1537
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1538 @system pure unittest
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1539 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1540 // Adding new json element without array() / object() access
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1541
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1542 JSONValue jarr = JSONValue([10]);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1543 foreach (i; 0 .. 9)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1544 jarr ~= [JSONValue(i)];
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1545 assert(jarr.array.length == 10);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1546
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1547 JSONValue jobj = JSONValue(["key" : JSONValue("value")]);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1548 foreach (i; 0 .. 9)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1549 jobj[text("key", i)] = JSONValue(text("value", i));
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1550 assert(jobj.object.length == 10);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1551
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1552 // No array alias
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1553 auto jarr2 = jarr ~ [1,2,3];
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1554 jarr2[0] = 999;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1555 assert(jarr[0] == JSONValue(10));
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1556 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1557
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1558 @system unittest
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1559 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1560 // @system because JSONValue.array is @system
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1561 import std.exception;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1562
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1563 // An overly simple test suite, if it can parse a serializated string and
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1564 // then use the resulting values tree to generate an identical
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1565 // serialization, both the decoder and encoder works.
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1566
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1567 auto jsons = [
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1568 `null`,
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1569 `true`,
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1570 `false`,
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1571 `0`,
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1572 `123`,
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1573 `-4321`,
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1574 `0.25`,
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1575 `-0.25`,
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1576 `""`,
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1577 `"hello\nworld"`,
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1578 `"\"\\\/\b\f\n\r\t"`,
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1579 `[]`,
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1580 `[12,"foo",true,false]`,
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1581 `{}`,
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1582 `{"a":1,"b":null}`,
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1583 `{"goodbye":[true,"or",false,["test",42,{"nested":{"a":23.5,"b":0.140625}}]],`
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1584 ~`"hello":{"array":[12,null,{}],"json":"is great"}}`,
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1585 ];
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1586
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1587 enum dbl1_844 = `1.8446744073709568`;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1588 version (MinGW)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1589 jsons ~= dbl1_844 ~ `e+019`;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1590 else
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1591 jsons ~= dbl1_844 ~ `e+19`;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1592
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1593 JSONValue val;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1594 string result;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1595 foreach (json; jsons)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1596 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1597 try
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1598 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1599 val = parseJSON(json);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1600 enum pretty = false;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1601 result = toJSON(val, pretty);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1602 assert(result == json, text(result, " should be ", json));
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1603 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1604 catch (JSONException e)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1605 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1606 import std.stdio : writefln;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1607 writefln(text(json, "\n", e.toString()));
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1608 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1609 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1610
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1611 // Should be able to correctly interpret unicode entities
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1612 val = parseJSON(`"\u003C\u003E"`);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1613 assert(toJSON(val) == "\"\&lt;\&gt;\"");
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1614 assert(val.to!string() == "\"\&lt;\&gt;\"");
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1615 val = parseJSON(`"\u0391\u0392\u0393"`);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1616 assert(toJSON(val) == "\"\&Alpha;\&Beta;\&Gamma;\"");
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1617 assert(val.to!string() == "\"\&Alpha;\&Beta;\&Gamma;\"");
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1618 val = parseJSON(`"\u2660\u2666"`);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1619 assert(toJSON(val) == "\"\&spades;\&diams;\"");
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1620 assert(val.to!string() == "\"\&spades;\&diams;\"");
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1621
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1622 //0x7F is a control character (see Unicode spec)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1623 val = parseJSON(`"\u007F"`);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1624 assert(toJSON(val) == "\"\\u007F\"");
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1625 assert(val.to!string() == "\"\\u007F\"");
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1626
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1627 with(parseJSON(`""`))
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1628 assert(str == "" && str !is null);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1629 with(parseJSON(`[]`))
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1630 assert(!array.length);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1631
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1632 // Formatting
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1633 val = parseJSON(`{"a":[null,{"x":1},{},[]]}`);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1634 assert(toJSON(val, true) == `{
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1635 "a": [
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1636 null,
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1637 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1638 "x": 1
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1639 },
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1640 {},
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1641 []
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1642 ]
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1643 }`);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1644 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1645
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1646 @safe unittest
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1647 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1648 auto json = `"hello\nworld"`;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1649 const jv = parseJSON(json);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1650 assert(jv.toString == json);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1651 assert(jv.toPrettyString == json);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1652 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1653
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1654 @system pure unittest
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1655 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1656 // Bugzilla 12969
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1657
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1658 JSONValue jv;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1659 jv["int"] = 123;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1660
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1661 assert(jv.type == JSON_TYPE.OBJECT);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1662 assert("int" in jv);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1663 assert(jv["int"].integer == 123);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1664
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1665 jv["array"] = [1, 2, 3, 4, 5];
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1666
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1667 assert(jv["array"].type == JSON_TYPE.ARRAY);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1668 assert(jv["array"][2].integer == 3);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1669
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1670 jv["str"] = "D language";
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1671 assert(jv["str"].type == JSON_TYPE.STRING);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1672 assert(jv["str"].str == "D language");
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1673
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1674 jv["bool"] = false;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1675 assert(jv["bool"].type == JSON_TYPE.FALSE);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1676
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1677 assert(jv.object.length == 4);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1678
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1679 jv = [5, 4, 3, 2, 1];
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1680 assert( jv.type == JSON_TYPE.ARRAY );
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1681 assert( jv[3].integer == 2 );
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1682 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1683
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1684 @safe unittest
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1685 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1686 auto s = q"EOF
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1687 [
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1688 1,
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1689 2,
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1690 3,
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1691 potato
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1692 ]
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1693 EOF";
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1694
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1695 import std.exception;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1696
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1697 auto e = collectException!JSONException(parseJSON(s));
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1698 assert(e.msg == "Unexpected character 'p'. (Line 5:3)", e.msg);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1699 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1700
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1701 // handling of special float values (NaN, Inf, -Inf)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1702 @safe unittest
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1703 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1704 import std.exception : assertThrown;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1705 import std.math : isNaN, isInfinity;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1706
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1707 // expected representations of NaN and Inf
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1708 enum {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1709 nanString = '"' ~ JSONFloatLiteral.nan ~ '"',
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1710 infString = '"' ~ JSONFloatLiteral.inf ~ '"',
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1711 negativeInfString = '"' ~ JSONFloatLiteral.negativeInf ~ '"',
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1712 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1713
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1714 // with the specialFloatLiterals option, encode NaN/Inf as strings
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1715 assert(JSONValue(float.nan).toString(JSONOptions.specialFloatLiterals) == nanString);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1716 assert(JSONValue(double.infinity).toString(JSONOptions.specialFloatLiterals) == infString);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1717 assert(JSONValue(-real.infinity).toString(JSONOptions.specialFloatLiterals) == negativeInfString);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1718
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1719 // without the specialFloatLiterals option, throw on encoding NaN/Inf
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1720 assertThrown!JSONException(JSONValue(float.nan).toString);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1721 assertThrown!JSONException(JSONValue(double.infinity).toString);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1722 assertThrown!JSONException(JSONValue(-real.infinity).toString);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1723
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1724 // when parsing json with specialFloatLiterals option, decode special strings as floats
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1725 JSONValue jvNan = parseJSON(nanString, JSONOptions.specialFloatLiterals);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1726 JSONValue jvInf = parseJSON(infString, JSONOptions.specialFloatLiterals);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1727 JSONValue jvNegInf = parseJSON(negativeInfString, JSONOptions.specialFloatLiterals);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1728
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1729 assert(jvNan.floating.isNaN);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1730 assert(jvInf.floating.isInfinity && jvInf.floating > 0);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1731 assert(jvNegInf.floating.isInfinity && jvNegInf.floating < 0);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1732
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1733 // when parsing json without the specialFloatLiterals option, decode special strings as strings
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1734 jvNan = parseJSON(nanString);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1735 jvInf = parseJSON(infString);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1736 jvNegInf = parseJSON(negativeInfString);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1737
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1738 assert(jvNan.str == JSONFloatLiteral.nan);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1739 assert(jvInf.str == JSONFloatLiteral.inf);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1740 assert(jvNegInf.str == JSONFloatLiteral.negativeInf);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1741 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1742
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1743 pure nothrow @safe @nogc unittest
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1744 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1745 JSONValue testVal;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1746 testVal = "test";
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1747 testVal = 10;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1748 testVal = 10u;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1749 testVal = 1.0;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1750 testVal = (JSONValue[string]).init;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1751 testVal = JSONValue[].init;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1752 testVal = null;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1753 assert(testVal.isNull);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1754 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1755
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1756 pure nothrow @safe unittest // issue 15884
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1757 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1758 import std.typecons;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1759 void Test(C)() {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1760 C[] a = ['x'];
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1761 JSONValue testVal = a;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1762 assert(testVal.type == JSON_TYPE.STRING);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1763 testVal = a.idup;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1764 assert(testVal.type == JSON_TYPE.STRING);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1765 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1766 Test!char();
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1767 Test!wchar();
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1768 Test!dchar();
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1769 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1770
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1771 @safe unittest // issue 15885
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1772 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1773 enum bool realInDoublePrecision = real.mant_dig == double.mant_dig;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1774
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1775 static bool test(const double num0)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1776 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1777 import std.math : feqrel;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1778 const json0 = JSONValue(num0);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1779 const num1 = to!double(toJSON(json0));
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1780 static if (realInDoublePrecision)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1781 return feqrel(num1, num0) >= (double.mant_dig - 1);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1782 else
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1783 return num1 == num0;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1784 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1785
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1786 assert(test( 0.23));
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1787 assert(test(-0.23));
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1788 assert(test(1.223e+24));
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1789 assert(test(23.4));
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1790 assert(test(0.0012));
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1791 assert(test(30738.22));
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1792
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1793 assert(test(1 + double.epsilon));
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1794 assert(test(double.min_normal));
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1795 static if (realInDoublePrecision)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1796 assert(test(-double.max / 2));
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1797 else
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1798 assert(test(-double.max));
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1799
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1800 const minSub = double.min_normal * double.epsilon;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1801 assert(test(minSub));
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1802 assert(test(3*minSub));
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1803 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1804
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1805 @safe unittest // issue 17555
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1806 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1807 import std.exception : assertThrown;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1808
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1809 assertThrown!JSONException(parseJSON("\"a\nb\""));
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1810 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1811
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1812 @safe unittest // issue 17556
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1813 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1814 auto v = JSONValue("\U0001D11E");
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1815 auto j = toJSON(v, false, JSONOptions.escapeNonAsciiChars);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1816 assert(j == `"\uD834\uDD1E"`);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1817 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1818
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1819 @safe unittest // issue 5904
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1820 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1821 string s = `"\uD834\uDD1E"`;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1822 auto j = parseJSON(s);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1823 assert(j.str == "\U0001D11E");
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1824 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1825
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1826 @safe unittest // issue 17557
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1827 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1828 assert(parseJSON("\"\xFF\"").str == "\xFF");
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1829 assert(parseJSON("\"\U0001D11E\"").str == "\U0001D11E");
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1830 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1831
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1832 @safe unittest // issue 17553
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1833 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1834 auto v = JSONValue("\xFF");
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1835 assert(toJSON(v) == "\"\xFF\"");
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1836 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1837
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1838 @safe unittest
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1839 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1840 import std.utf;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1841 assert(parseJSON("\"\xFF\"".byChar).str == "\xFF");
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1842 assert(parseJSON("\"\U0001D11E\"".byChar).str == "\U0001D11E");
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1843 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1844
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1845 @safe unittest // JSONOptions.doNotEscapeSlashes (issue 17587)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1846 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1847 assert(parseJSON(`"/"`).toString == `"\/"`);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1848 assert(parseJSON(`"\/"`).toString == `"\/"`);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1849 assert(parseJSON(`"/"`).toString(JSONOptions.doNotEscapeSlashes) == `"/"`);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1850 assert(parseJSON(`"\/"`).toString(JSONOptions.doNotEscapeSlashes) == `"/"`);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1851 }