blob: e68f41a7c3882e4288ec1b7703e1cc00a5bd69dd [file] [log] [blame]
Elly Jones656a2af2011-11-07 23:24:441// Rust JSON serialization library
2// Copyright (c) 2011 Google Inc.
Elly Jonesbd726262011-11-07 19:01:283
Brian Anderson95521c42012-03-08 02:17:304#[doc = "json serialization"];
5
Brian Anderson47d468f2012-03-16 22:14:376import result::{result, ok, err};
Erick Tryzelaar012dec52012-02-26 00:39:327import io;
8import io::{reader_util, writer_util};
Elly Jonesbd726262011-11-07 19:01:289import map;
Patrick Waltonc9375fe2012-03-08 00:48:5710import map::hashmap;
Elly Jonesbd726262011-11-07 19:01:2811
12export json;
Erick Tryzelaarfaccd4a2012-03-05 16:47:2113export error;
Erick Tryzelaar012dec52012-02-26 00:39:3214export to_writer;
Elly Jones656a2af2011-11-07 23:24:4415export to_str;
Erick Tryzelaar012dec52012-02-26 00:39:3216export from_reader;
Elly Jones656a2af2011-11-07 23:24:4417export from_str;
Erick Tryzelaar012dec52012-02-26 00:39:3218export eq;
Erick Tryzelaared5af702012-05-28 19:10:3219export to_json;
Elly Jonesbd726262011-11-07 19:01:2820
Elly Jones656a2af2011-11-07 23:24:4421export num;
22export string;
23export boolean;
24export list;
25export dict;
Erick Tryzelaar012dec52012-02-26 00:39:3226export null;
Elly Jones656a2af2011-11-07 23:24:4427
Brian Anderson95521c42012-03-08 02:17:3028#[doc = "Represents a json value"]
Patrick Waltonc5a407b2012-01-19 23:20:5729enum json {
Patrick Walton194d8e32012-01-20 01:55:3430 num(float),
Erick Tryzelaarb361f6c2012-06-13 00:20:5131 string(@str),
Patrick Walton194d8e32012-01-20 01:55:3432 boolean(bool),
Michael Sullivan98e161f2012-06-29 23:26:5633 list(@~[json]),
Erick Tryzelaarb361f6c2012-06-13 00:20:5134 dict(map::hashmap<str, json>),
Patrick Walton194d8e32012-01-20 01:55:3435 null,
Elly Jonesbd726262011-11-07 19:01:2836}
37
Erick Tryzelaar012dec52012-02-26 00:39:3238type error = {
39 line: uint,
40 col: uint,
Erick Tryzelaarb361f6c2012-06-13 00:20:5141 msg: @str,
Erick Tryzelaar012dec52012-02-26 00:39:3242};
43
Brian Anderson95521c42012-03-08 02:17:3044#[doc = "Serializes a json value into a io::writer"]
Erick Tryzelaar012dec52012-02-26 00:39:3245fn to_writer(wr: io::writer, j: json) {
46 alt j {
47 num(n) { wr.write_str(float::to_str(n, 6u)); }
48 string(s) {
Erick Tryzelaarb361f6c2012-06-13 00:20:5149 wr.write_str(escape_str(*s));
Erick Tryzelaar012dec52012-02-26 00:39:3250 }
51 boolean(b) {
52 wr.write_str(if b { "true" } else { "false" });
53 }
54 list(v) {
55 wr.write_char('[');
Niko Matsakis6b358752012-03-14 18:03:5656 let mut first = true;
Erick Tryzelaarb361f6c2012-06-13 00:20:5157 for (*v).each { |item|
Erick Tryzelaar012dec52012-02-26 00:39:3258 if !first {
59 wr.write_str(", ");
60 }
61 first = false;
62 to_writer(wr, item);
63 };
64 wr.write_char(']');
65 }
66 dict(d) {
67 if d.size() == 0u {
68 wr.write_str("{}");
69 ret;
70 }
71
72 wr.write_str("{ ");
Niko Matsakis6b358752012-03-14 18:03:5673 let mut first = true;
Marijn Haverbeke9053f542012-04-23 11:42:1574 for d.each { |key, value|
Erick Tryzelaar012dec52012-02-26 00:39:3275 if !first {
76 wr.write_str(", ");
77 }
78 first = false;
Erick Tryzelaarb361f6c2012-06-13 00:20:5179 wr.write_str(escape_str(key));
Erick Tryzelaar012dec52012-02-26 00:39:3280 wr.write_str(": ");
81 to_writer(wr, value);
82 };
83 wr.write_str(" }");
84 }
85 null {
86 wr.write_str("null");
87 }
88 }
89}
90
Erick Tryzelaarb361f6c2012-06-13 00:20:5191fn escape_str(s: str) -> str {
92 let mut escaped = "\"";
93 str::chars_iter(s) { |c|
94 alt c {
95 '"' { escaped += "\\\""; }
96 '\\' { escaped += "\\\\"; }
97 '\x08' { escaped += "\\b"; }
98 '\x0c' { escaped += "\\f"; }
99 '\n' { escaped += "\\n"; }
100 '\r' { escaped += "\\r"; }
101 '\t' { escaped += "\\t"; }
102 _ { escaped += str::from_char(c); }
103 }
104 };
105
106 escaped += "\"";
107
108 escaped
109}
110
Brian Anderson95521c42012-03-08 02:17:30111#[doc = "Serializes a json value into a string"]
Elly Jones656a2af2011-11-07 23:24:44112fn to_str(j: json) -> str {
Erick Tryzelaar012dec52012-02-26 00:39:32113 io::with_str_writer { |wr| to_writer(wr, j) }
Elly Jonesbd726262011-11-07 19:01:28114}
115
Erick Tryzelaar012dec52012-02-26 00:39:32116type parser = {
117 rdr: io::reader,
Graydon Hoare6e6798c2012-03-27 01:35:18118 mut ch: char,
119 mut line: uint,
120 mut col: uint,
Erick Tryzelaar012dec52012-02-26 00:39:32121};
Elly Jonesbd726262011-11-07 19:01:28122
Erick Tryzelaar012dec52012-02-26 00:39:32123impl parser for parser {
124 fn eof() -> bool { self.ch == -1 as char }
Elly Jonesbd726262011-11-07 19:01:28125
Erick Tryzelaar012dec52012-02-26 00:39:32126 fn bump() {
127 self.ch = self.rdr.read_char();
128
129 if self.ch == '\n' {
130 self.line += 1u;
131 self.col = 1u;
132 } else {
133 self.col += 1u;
134 }
Elly Jonesbd726262011-11-07 19:01:28135 }
136
Erick Tryzelaar012dec52012-02-26 00:39:32137 fn next_char() -> char {
138 self.bump();
139 self.ch
Elly Jonesbd726262011-11-07 19:01:28140 }
141
Erick Tryzelaarb361f6c2012-06-13 00:20:51142 fn error<T>(+msg: str) -> result<T, error> {
143 err({ line: self.line, col: self.col, msg: @msg })
Elly Jonesbd726262011-11-07 19:01:28144 }
Elly Jonesbd726262011-11-07 19:01:28145
Brian Andersonb968c8e2012-03-13 21:39:28146 fn parse() -> result<json, error> {
Erick Tryzelaar012dec52012-02-26 00:39:32147 alt self.parse_value() {
148 ok(value) {
Tycho Sciecf87c32012-02-29 08:47:17149 // Skip trailing whitespaces.
150 self.parse_whitespace();
Erick Tryzelaar012dec52012-02-26 00:39:32151 // Make sure there is no trailing characters.
152 if self.eof() {
153 ok(value)
154 } else {
155 self.error("trailing characters")
156 }
157 }
158 e { e }
Elly Jonesbd726262011-11-07 19:01:28159 }
Elly Jonesbd726262011-11-07 19:01:28160 }
Elly Jonesbd726262011-11-07 19:01:28161
Brian Andersonb968c8e2012-03-13 21:39:28162 fn parse_value() -> result<json, error> {
Erick Tryzelaar012dec52012-02-26 00:39:32163 self.parse_whitespace();
Elly Jonesbd726262011-11-07 19:01:28164
Erick Tryzelaar012dec52012-02-26 00:39:32165 if self.eof() { ret self.error("EOF while parsing value"); }
166
167 alt self.ch {
168 'n' { self.parse_ident("ull", null) }
169 't' { self.parse_ident("rue", boolean(true)) }
170 'f' { self.parse_ident("alse", boolean(false)) }
171 '0' to '9' | '-' { self.parse_number() }
172 '"' {
173 alt self.parse_str() {
174 ok(s) { ok(string(s)) }
175 err(e) { err(e) }
176 }
177 }
178 '[' { self.parse_list() }
179 '{' { self.parse_object() }
180 _ { self.error("invalid syntax") }
181 }
182 }
183
184 fn parse_whitespace() {
185 while char::is_whitespace(self.ch) { self.bump(); }
186 }
187
Brian Andersonb968c8e2012-03-13 21:39:28188 fn parse_ident(ident: str, value: json) -> result<json, error> {
Erick Tryzelaar012dec52012-02-26 00:39:32189 if str::all(ident, { |c| c == self.next_char() }) {
190 self.bump();
191 ok(value)
192 } else {
193 self.error("invalid syntax")
194 }
195 }
196
Brian Andersonb968c8e2012-03-13 21:39:28197 fn parse_number() -> result<json, error> {
Niko Matsakis6b358752012-03-14 18:03:56198 let mut neg = 1f;
Erick Tryzelaar012dec52012-02-26 00:39:32199
200 if self.ch == '-' {
201 self.bump();
Marijn Haverbeke4f826d82011-12-16 09:11:00202 neg = -1f;
Elly Jonesbd726262011-11-07 19:01:28203 }
Elly Jonesbd726262011-11-07 19:01:28204
Niko Matsakis6b358752012-03-14 18:03:56205 let mut res = alt self.parse_integer() {
Erick Tryzelaar012dec52012-02-26 00:39:32206 ok(res) { res }
207 err(e) { ret err(e); }
208 };
209
210 if self.ch == '.' {
211 alt self.parse_decimal(res) {
212 ok(r) { res = r; }
213 err(e) { ret err(e); }
Elly Jonesbd726262011-11-07 19:01:28214 }
Elly Jonesbd726262011-11-07 19:01:28215 }
Erick Tryzelaar012dec52012-02-26 00:39:32216
217 if self.ch == 'e' || self.ch == 'E' {
218 alt self.parse_exponent(res) {
219 ok(r) { res = r; }
220 err(e) { ret err(e); }
221 }
222 }
223
224 ok(num(neg * res))
Elly Jonesbd726262011-11-07 19:01:28225 }
226
Brian Andersonb968c8e2012-03-13 21:39:28227 fn parse_integer() -> result<float, error> {
Niko Matsakis6b358752012-03-14 18:03:56228 let mut res = 0f;
Erick Tryzelaar012dec52012-02-26 00:39:32229
230 alt self.ch {
231 '0' {
232 self.bump();
233
234 // There can be only one leading '0'.
235 alt self.ch {
236 '0' to '9' { ret self.error("invalid number"); }
237 _ {}
238 }
239 }
240 '1' to '9' {
241 while !self.eof() {
242 alt self.ch {
243 '0' to '9' {
244 res *= 10f;
245 res += ((self.ch as int) - ('0' as int)) as float;
246
247 self.bump();
248 }
249 _ { break; }
250 }
251 }
252 }
253 _ { ret self.error("invalid number"); }
254 }
255
256 ok(res)
Elly Jonesbd726262011-11-07 19:01:28257 }
258
Brian Andersonb968c8e2012-03-13 21:39:28259 fn parse_decimal(res: float) -> result<float, error> {
Erick Tryzelaar012dec52012-02-26 00:39:32260 self.bump();
261
262 // Make sure a digit follows the decimal place.
263 alt self.ch {
264 '0' to '9' {}
265 _ { ret self.error("invalid number"); }
266 }
267
Niko Matsakis6b358752012-03-14 18:03:56268 let mut res = res;
269 let mut dec = 1f;
Erick Tryzelaar012dec52012-02-26 00:39:32270 while !self.eof() {
271 alt self.ch {
272 '0' to '9' {
Marijn Haverbeke4f826d82011-12-16 09:11:00273 dec /= 10f;
Erick Tryzelaar012dec52012-02-26 00:39:32274 res += (((self.ch as int) - ('0' as int)) as float) * dec;
275
276 self.bump();
277 }
278 _ { break; }
Elly Jonesbd726262011-11-07 19:01:28279 }
Elly Jonesbd726262011-11-07 19:01:28280 }
Elly Jonesbd726262011-11-07 19:01:28281
Erick Tryzelaar012dec52012-02-26 00:39:32282 ok(res)
283 }
284
Brian Andersonb968c8e2012-03-13 21:39:28285 fn parse_exponent(res: float) -> result<float, error> {
Erick Tryzelaar012dec52012-02-26 00:39:32286 self.bump();
287
Niko Matsakis6b358752012-03-14 18:03:56288 let mut res = res;
289 let mut exp = 0u;
290 let mut neg_exp = false;
Erick Tryzelaar012dec52012-02-26 00:39:32291
292 alt self.ch {
293 '+' { self.bump(); }
294 '-' { self.bump(); neg_exp = true; }
295 _ {}
296 }
297
298 // Make sure a digit follows the exponent place.
299 alt self.ch {
300 '0' to '9' {}
301 _ { ret self.error("invalid number"); }
302 }
303
304 while !self.eof() {
305 alt self.ch {
306 '0' to '9' {
307 exp *= 10u;
308 exp += (self.ch as uint) - ('0' as uint);
309
310 self.bump();
311 }
312 _ { break; }
313 }
314 }
315
316 let exp = float::pow_with_uint(10u, exp);
317 if neg_exp {
318 res /= exp;
319 } else {
320 res *= exp;
321 }
322
323 ok(res)
324 }
325
Erick Tryzelaarb361f6c2012-06-13 00:20:51326 fn parse_str() -> result<@str, error> {
Niko Matsakis6b358752012-03-14 18:03:56327 let mut escape = false;
328 let mut res = "";
Erick Tryzelaar012dec52012-02-26 00:39:32329
330 while !self.eof() {
331 self.bump();
332
333 if (escape) {
334 alt self.ch {
335 '"' { str::push_char(res, '"'); }
336 '\\' { str::push_char(res, '\\'); }
337 '/' { str::push_char(res, '/'); }
338 'b' { str::push_char(res, '\x08'); }
339 'f' { str::push_char(res, '\x0c'); }
340 'n' { str::push_char(res, '\n'); }
341 'r' { str::push_char(res, '\r'); }
342 't' { str::push_char(res, '\t'); }
343 'u' {
344 // Parse \u1234.
Niko Matsakis6b358752012-03-14 18:03:56345 let mut i = 0u;
346 let mut n = 0u;
Erick Tryzelaar012dec52012-02-26 00:39:32347 while i < 4u {
348 alt self.next_char() {
349 '0' to '9' {
350 n = n * 10u +
351 (self.ch as uint) - ('0' as uint);
352 }
353 _ { ret self.error("invalid \\u escape"); }
354 }
Niko Matsakis6b358752012-03-14 18:03:56355 i += 1u;
Erick Tryzelaar012dec52012-02-26 00:39:32356 }
357
358 // Error out if we didn't parse 4 digits.
359 if i != 4u {
360 ret self.error("invalid \\u escape");
361 }
362
363 str::push_char(res, n as char);
364 }
365 _ { ret self.error("invalid escape"); }
366 }
367 escape = false;
368 } else if self.ch == '\\' {
369 escape = true;
370 } else {
371 if self.ch == '"' {
372 self.bump();
Erick Tryzelaarb361f6c2012-06-13 00:20:51373 ret ok(@res);
Erick Tryzelaar012dec52012-02-26 00:39:32374 }
375 str::push_char(res, self.ch);
376 }
377 }
378
379 self.error("EOF while parsing string")
380 }
381
Brian Andersonb968c8e2012-03-13 21:39:28382 fn parse_list() -> result<json, error> {
Erick Tryzelaar012dec52012-02-26 00:39:32383 self.bump();
384 self.parse_whitespace();
385
Michael Sullivan98e161f2012-06-29 23:26:56386 let mut values = ~[];
Erick Tryzelaar012dec52012-02-26 00:39:32387
388 if self.ch == ']' {
389 self.bump();
Erick Tryzelaarb361f6c2012-06-13 00:20:51390 ret ok(list(@values));
Erick Tryzelaar012dec52012-02-26 00:39:32391 }
392
Tim Chevalier35400e12012-03-11 04:34:17393 loop {
Erick Tryzelaar012dec52012-02-26 00:39:32394 alt self.parse_value() {
395 ok(v) { vec::push(values, v); }
396 e { ret e; }
397 }
398
399 self.parse_whitespace();
Tim Chevalier35400e12012-03-11 04:34:17400 if self.eof() {
401 ret self.error("EOF while parsing list");
402 }
Erick Tryzelaar012dec52012-02-26 00:39:32403
404 alt self.ch {
405 ',' { self.bump(); }
Erick Tryzelaarb361f6c2012-06-13 00:20:51406 ']' { self.bump(); ret ok(list(@values)); }
Erick Tryzelaar012dec52012-02-26 00:39:32407 _ { ret self.error("expecting ',' or ']'"); }
408 }
Tim Chevalier35400e12012-03-11 04:34:17409 };
Erick Tryzelaar012dec52012-02-26 00:39:32410 }
411
Brian Andersonb968c8e2012-03-13 21:39:28412 fn parse_object() -> result<json, error> {
Erick Tryzelaar012dec52012-02-26 00:39:32413 self.bump();
414 self.parse_whitespace();
415
Brian Anderson3864d6d2012-03-14 19:07:23416 let values = map::str_hash();
Erick Tryzelaar012dec52012-02-26 00:39:32417
418 if self.ch == '}' {
419 self.bump();
420 ret ok(dict(values));
421 }
422
423 while !self.eof() {
424 self.parse_whitespace();
425
426 if self.ch != '"' {
427 ret self.error("key must be a string");
428 }
429
430 let key = alt self.parse_str() {
431 ok(key) { key }
432 err(e) { ret err(e); }
433 };
434
435 self.parse_whitespace();
436
437 if self.ch != ':' {
438 if self.eof() { break; }
439 ret self.error("expecting ':'");
440 }
441 self.bump();
442
443 alt self.parse_value() {
Erick Tryzelaarb361f6c2012-06-13 00:20:51444 ok(value) { values.insert(copy *key, value); }
Erick Tryzelaar012dec52012-02-26 00:39:32445 e { ret e; }
446 }
447 self.parse_whitespace();
448
449 alt self.ch {
450 ',' { self.bump(); }
Tycho Sciecf87c32012-02-29 08:47:17451 '}' { self.bump(); ret ok(dict(values)); }
Erick Tryzelaar012dec52012-02-26 00:39:32452 _ {
453 if self.eof() { break; }
454 ret self.error("expecting ',' or '}'");
455 }
456 }
457 }
458
459 ret self.error("EOF while parsing object");
Elly Jonesbd726262011-11-07 19:01:28460 }
461}
462
Brian Anderson95521c42012-03-08 02:17:30463#[doc = "Deserializes a json value from an io::reader"]
Brian Andersonb968c8e2012-03-13 21:39:28464fn from_reader(rdr: io::reader) -> result<json, error> {
Erick Tryzelaar012dec52012-02-26 00:39:32465 let parser = {
466 rdr: rdr,
Graydon Hoare6e6798c2012-03-27 01:35:18467 mut ch: rdr.read_char(),
468 mut line: 1u,
469 mut col: 1u,
Erick Tryzelaar012dec52012-02-26 00:39:32470 };
471
472 parser.parse()
Elly Jonesbd726262011-11-07 19:01:28473}
474
Brian Anderson95521c42012-03-08 02:17:30475#[doc = "Deserializes a json value from a string"]
Brian Andersonb968c8e2012-03-13 21:39:28476fn from_str(s: str) -> result<json, error> {
Erick Tryzelaar1404a862012-02-29 18:48:57477 io::with_str_reader(s, from_reader)
Erick Tryzelaar012dec52012-02-26 00:39:32478}
479
Brian Anderson95521c42012-03-08 02:17:30480#[doc = "Test if two json values are equal"]
Erick Tryzelaar012dec52012-02-26 00:39:32481fn eq(value0: json, value1: json) -> bool {
482 alt (value0, value1) {
483 (num(f0), num(f1)) { f0 == f1 }
484 (string(s0), string(s1)) { s0 == s1 }
485 (boolean(b0), boolean(b1)) { b0 == b1 }
Erick Tryzelaarb361f6c2012-06-13 00:20:51486 (list(l0), list(l1)) { vec::all2(*l0, *l1, eq) }
Erick Tryzelaar012dec52012-02-26 00:39:32487 (dict(d0), dict(d1)) {
488 if d0.size() == d1.size() {
Niko Matsakis6b358752012-03-14 18:03:56489 let mut equal = true;
Marijn Haverbeke9053f542012-04-23 11:42:15490 for d0.each { |k, v0|
Erick Tryzelaar012dec52012-02-26 00:39:32491 alt d1.find(k) {
492 some(v1) {
493 if !eq(v0, v1) { equal = false; } }
494 none { equal = false; }
495 }
496 };
497 equal
498 } else {
499 false
500 }
501 }
502 (null, null) { true }
503 _ { false }
504 }
Elly Jonesbd726262011-11-07 19:01:28505}
Brian Anderson6e27b272012-01-18 03:05:07506
Erick Tryzelaared5af702012-05-28 19:10:32507iface to_json { fn to_json() -> json; }
508
509impl of to_json for json {
510 fn to_json() -> json { self }
511}
512
Erick Tryzelaar11a56c32012-06-13 15:30:54513impl of to_json for @json {
514 fn to_json() -> json { *self }
515}
516
517impl of to_json for int {
518 fn to_json() -> json { num(self as float) }
519}
520
Erick Tryzelaared5af702012-05-28 19:10:32521impl of to_json for i8 {
522 fn to_json() -> json { num(self as float) }
523}
524
525impl of to_json for i16 {
526 fn to_json() -> json { num(self as float) }
527}
528
529impl of to_json for i32 {
530 fn to_json() -> json { num(self as float) }
531}
532
533impl of to_json for i64 {
534 fn to_json() -> json { num(self as float) }
535}
536
Erick Tryzelaar11a56c32012-06-13 15:30:54537impl of to_json for uint {
538 fn to_json() -> json { num(self as float) }
539}
540
Erick Tryzelaared5af702012-05-28 19:10:32541impl of to_json for u8 {
542 fn to_json() -> json { num(self as float) }
543}
544
545impl of to_json for u16 {
546 fn to_json() -> json { num(self as float) }
547}
548
549impl of to_json for u32 {
550 fn to_json() -> json { num(self as float) }
551}
552
553impl of to_json for u64 {
554 fn to_json() -> json { num(self as float) }
555}
556
557impl of to_json for float {
558 fn to_json() -> json { num(self) }
559}
560
561impl of to_json for f32 {
562 fn to_json() -> json { num(self as float) }
563}
564
565impl of to_json for f64 {
566 fn to_json() -> json { num(self as float) }
567}
568
569impl of to_json for () {
570 fn to_json() -> json { null }
571}
572
573impl of to_json for bool {
574 fn to_json() -> json { boolean(self) }
575}
576
577impl of to_json for str {
Erick Tryzelaarb361f6c2012-06-13 00:20:51578 fn to_json() -> json { string(@copy self) }
579}
580
581impl of to_json for @str {
Erick Tryzelaared5af702012-05-28 19:10:32582 fn to_json() -> json { string(self) }
583}
584
585impl <A: to_json copy, B: to_json copy> of to_json for (A, B) {
586 fn to_json() -> json {
587 let (a, b) = self;
Michael Sullivan98e161f2012-06-29 23:26:56588 list(@~[a.to_json(), b.to_json()])
Erick Tryzelaared5af702012-05-28 19:10:32589 }
590}
591
592impl <A: to_json copy, B: to_json copy, C: to_json copy>
593 of to_json for (A, B, C) {
594 fn to_json() -> json {
595 let (a, b, c) = self;
Michael Sullivan98e161f2012-06-29 23:26:56596 list(@~[a.to_json(), b.to_json(), c.to_json()])
Erick Tryzelaared5af702012-05-28 19:10:32597 }
598}
599
Michael Sullivan98e161f2012-06-29 23:26:56600impl <A: to_json> of to_json for ~[A] {
Erick Tryzelaarb361f6c2012-06-13 00:20:51601 fn to_json() -> json { list(@self.map { |elt| elt.to_json() }) }
Erick Tryzelaared5af702012-05-28 19:10:32602}
603
604impl <A: to_json copy> of to_json for hashmap<str, A> {
605 fn to_json() -> json {
606 let d = map::str_hash();
607 for self.each() { |key, value|
Erick Tryzelaarb361f6c2012-06-13 00:20:51608 d.insert(copy key, value.to_json());
Erick Tryzelaared5af702012-05-28 19:10:32609 }
610 dict(d)
611 }
612}
613
614impl <A: to_json> of to_json for option<A> {
615 fn to_json() -> json {
616 alt self {
617 none { null }
618 some(value) { value.to_json() }
619 }
620 }
621}
622
623impl of to_str::to_str for json {
624 fn to_str() -> str { to_str(self) }
625}
626
Erick Tryzelaara8161762012-06-11 15:32:38627impl of to_str::to_str for error {
628 fn to_str() -> str {
Erick Tryzelaarb361f6c2012-06-13 00:20:51629 #fmt("%u:%u: %s", self.line, self.col, *self.msg)
Erick Tryzelaara8161762012-06-11 15:32:38630 }
631}
632
Brian Anderson6e27b272012-01-18 03:05:07633#[cfg(test)]
634mod tests {
Michael Sullivan98e161f2012-06-29 23:26:56635 fn mk_dict(items: ~[(str, json)]) -> json {
Brian Anderson3864d6d2012-03-14 19:07:23636 let d = map::str_hash();
Erick Tryzelaar012dec52012-02-26 00:39:32637
638 vec::iter(items) { |item|
Erick Tryzelaarb361f6c2012-06-13 00:20:51639 let (key, value) = copy item;
Erick Tryzelaar012dec52012-02-26 00:39:32640 d.insert(key, value);
641 };
642
643 dict(d)
Brian Anderson6e27b272012-01-18 03:05:07644 }
645
646 #[test]
Erick Tryzelaar012dec52012-02-26 00:39:32647 fn test_write_null() {
648 assert to_str(null) == "null";
Brian Anderson6e27b272012-01-18 03:05:07649 }
650
651 #[test]
Erick Tryzelaar012dec52012-02-26 00:39:32652 fn test_write_num() {
653 assert to_str(num(3f)) == "3";
654 assert to_str(num(3.1f)) == "3.1";
655 assert to_str(num(-1.5f)) == "-1.5";
656 assert to_str(num(0.5f)) == "0.5";
Brian Anderson6e27b272012-01-18 03:05:07657 }
658
659 #[test]
Erick Tryzelaar012dec52012-02-26 00:39:32660 fn test_write_str() {
Erick Tryzelaarb361f6c2012-06-13 00:20:51661 assert to_str(string(@"")) == "\"\"";
662 assert to_str(string(@"foo")) == "\"foo\"";
Brian Anderson6e27b272012-01-18 03:05:07663 }
664
665 #[test]
Erick Tryzelaar012dec52012-02-26 00:39:32666 fn test_write_bool() {
667 assert to_str(boolean(true)) == "true";
668 assert to_str(boolean(false)) == "false";
Brian Anderson6e27b272012-01-18 03:05:07669 }
670
671 #[test]
Erick Tryzelaar012dec52012-02-26 00:39:32672 fn test_write_list() {
Michael Sullivan98e161f2012-06-29 23:26:56673 assert to_str(list(@~[])) == "[]";
674 assert to_str(list(@~[boolean(true)])) == "[true]";
675 assert to_str(list(@~[
Erick Tryzelaar012dec52012-02-26 00:39:32676 boolean(false),
677 null,
Michael Sullivan98e161f2012-06-29 23:26:56678 list(@~[string(@"foo\nbar"), num(3.5f)])
679 ])) == "[false, null, [\"foo\\nbar\", 3.5]]";
Erick Tryzelaar012dec52012-02-26 00:39:32680 }
681
682 #[test]
683 fn test_write_dict() {
Michael Sullivan98e161f2012-06-29 23:26:56684 assert to_str(mk_dict(~[])) == "{}";
685 assert to_str(mk_dict(~[("a", boolean(true))])) == "{ \"a\": true }";
686 assert to_str(mk_dict(~[
Erick Tryzelaar012dec52012-02-26 00:39:32687 ("a", boolean(true)),
Michael Sullivan98e161f2012-06-29 23:26:56688 ("b", list(@~[
689 mk_dict(~[("c", string(@"\x0c\r"))]),
690 mk_dict(~[("d", string(@""))])
691 ]))
692 ])) ==
Erick Tryzelaar012dec52012-02-26 00:39:32693 "{ " +
694 "\"a\": true, " +
695 "\"b\": [" +
696 "{ \"c\": \"\\f\\r\" }, " +
697 "{ \"d\": \"\" }" +
698 "]" +
699 " }";
700 }
701
702 #[test]
703 fn test_trailing_characters() {
704 assert from_str("nulla") ==
Erick Tryzelaarb361f6c2012-06-13 00:20:51705 err({line: 1u, col: 5u, msg: @"trailing characters"});
Erick Tryzelaar012dec52012-02-26 00:39:32706 assert from_str("truea") ==
Erick Tryzelaarb361f6c2012-06-13 00:20:51707 err({line: 1u, col: 5u, msg: @"trailing characters"});
Erick Tryzelaar012dec52012-02-26 00:39:32708 assert from_str("falsea") ==
Erick Tryzelaarb361f6c2012-06-13 00:20:51709 err({line: 1u, col: 6u, msg: @"trailing characters"});
Erick Tryzelaar012dec52012-02-26 00:39:32710 assert from_str("1a") ==
Erick Tryzelaarb361f6c2012-06-13 00:20:51711 err({line: 1u, col: 2u, msg: @"trailing characters"});
Michael Sullivan98e161f2012-06-29 23:26:56712 assert from_str("[]a") ==
Erick Tryzelaarb361f6c2012-06-13 00:20:51713 err({line: 1u, col: 3u, msg: @"trailing characters"});
Erick Tryzelaar012dec52012-02-26 00:39:32714 assert from_str("{}a") ==
Erick Tryzelaarb361f6c2012-06-13 00:20:51715 err({line: 1u, col: 3u, msg: @"trailing characters"});
Erick Tryzelaar012dec52012-02-26 00:39:32716 }
717
718 #[test]
719 fn test_read_identifiers() {
720 assert from_str("n") ==
Erick Tryzelaarb361f6c2012-06-13 00:20:51721 err({line: 1u, col: 2u, msg: @"invalid syntax"});
Erick Tryzelaar012dec52012-02-26 00:39:32722 assert from_str("nul") ==
Erick Tryzelaarb361f6c2012-06-13 00:20:51723 err({line: 1u, col: 4u, msg: @"invalid syntax"});
Erick Tryzelaar012dec52012-02-26 00:39:32724
725 assert from_str("t") ==
Erick Tryzelaarb361f6c2012-06-13 00:20:51726 err({line: 1u, col: 2u, msg: @"invalid syntax"});
Erick Tryzelaar012dec52012-02-26 00:39:32727 assert from_str("truz") ==
Erick Tryzelaarb361f6c2012-06-13 00:20:51728 err({line: 1u, col: 4u, msg: @"invalid syntax"});
Erick Tryzelaar012dec52012-02-26 00:39:32729
730 assert from_str("f") ==
Erick Tryzelaarb361f6c2012-06-13 00:20:51731 err({line: 1u, col: 2u, msg: @"invalid syntax"});
Erick Tryzelaar012dec52012-02-26 00:39:32732 assert from_str("faz") ==
Erick Tryzelaarb361f6c2012-06-13 00:20:51733 err({line: 1u, col: 3u, msg: @"invalid syntax"});
Erick Tryzelaar012dec52012-02-26 00:39:32734
735 assert from_str("null") == ok(null);
736 assert from_str("true") == ok(boolean(true));
737 assert from_str("false") == ok(boolean(false));
Tycho Sciecf87c32012-02-29 08:47:17738 assert from_str(" null ") == ok(null);
739 assert from_str(" true ") == ok(boolean(true));
740 assert from_str(" false ") == ok(boolean(false));
Erick Tryzelaar012dec52012-02-26 00:39:32741 }
742
743 #[test]
744 fn test_read_num() {
745 assert from_str("+") ==
Erick Tryzelaarb361f6c2012-06-13 00:20:51746 err({line: 1u, col: 1u, msg: @"invalid syntax"});
Erick Tryzelaar012dec52012-02-26 00:39:32747 assert from_str(".") ==
Erick Tryzelaarb361f6c2012-06-13 00:20:51748 err({line: 1u, col: 1u, msg: @"invalid syntax"});
Erick Tryzelaar012dec52012-02-26 00:39:32749
750 assert from_str("-") ==
Erick Tryzelaarb361f6c2012-06-13 00:20:51751 err({line: 1u, col: 2u, msg: @"invalid number"});
Erick Tryzelaar012dec52012-02-26 00:39:32752 assert from_str("00") ==
Erick Tryzelaarb361f6c2012-06-13 00:20:51753 err({line: 1u, col: 2u, msg: @"invalid number"});
Erick Tryzelaar012dec52012-02-26 00:39:32754 assert from_str("1.") ==
Erick Tryzelaarb361f6c2012-06-13 00:20:51755 err({line: 1u, col: 3u, msg: @"invalid number"});
Erick Tryzelaar012dec52012-02-26 00:39:32756 assert from_str("1e") ==
Erick Tryzelaarb361f6c2012-06-13 00:20:51757 err({line: 1u, col: 3u, msg: @"invalid number"});
Erick Tryzelaar012dec52012-02-26 00:39:32758 assert from_str("1e+") ==
Erick Tryzelaarb361f6c2012-06-13 00:20:51759 err({line: 1u, col: 4u, msg: @"invalid number"});
Erick Tryzelaar012dec52012-02-26 00:39:32760
761 assert from_str("3") == ok(num(3f));
762 assert from_str("3.1") == ok(num(3.1f));
763 assert from_str("-1.2") == ok(num(-1.2f));
764 assert from_str("0.4") == ok(num(0.4f));
765 assert from_str("0.4e5") == ok(num(0.4e5f));
766 assert from_str("0.4e+15") == ok(num(0.4e15f));
767 assert from_str("0.4e-01") == ok(num(0.4e-01f));
Tycho Sciecf87c32012-02-29 08:47:17768 assert from_str(" 3 ") == ok(num(3f));
Erick Tryzelaar012dec52012-02-26 00:39:32769 }
770
771 #[test]
772 fn test_read_str() {
773 assert from_str("\"") ==
Erick Tryzelaarb361f6c2012-06-13 00:20:51774 err({line: 1u, col: 2u, msg: @"EOF while parsing string"});
Erick Tryzelaar012dec52012-02-26 00:39:32775 assert from_str("\"lol") ==
Erick Tryzelaarb361f6c2012-06-13 00:20:51776 err({line: 1u, col: 5u, msg: @"EOF while parsing string"});
Erick Tryzelaar012dec52012-02-26 00:39:32777
Erick Tryzelaarb361f6c2012-06-13 00:20:51778 assert from_str("\"\"") == ok(string(@""));
779 assert from_str("\"foo\"") == ok(string(@"foo"));
780 assert from_str("\"\\\"\"") == ok(string(@"\""));
781 assert from_str("\"\\b\"") == ok(string(@"\x08"));
782 assert from_str("\"\\n\"") == ok(string(@"\n"));
783 assert from_str("\"\\r\"") == ok(string(@"\r"));
784 assert from_str("\"\\t\"") == ok(string(@"\t"));
785 assert from_str(" \"foo\" ") == ok(string(@"foo"));
Erick Tryzelaar012dec52012-02-26 00:39:32786 }
787
788 #[test]
789 fn test_read_list() {
790 assert from_str("[") ==
Erick Tryzelaarb361f6c2012-06-13 00:20:51791 err({line: 1u, col: 2u, msg: @"EOF while parsing value"});
Erick Tryzelaar012dec52012-02-26 00:39:32792 assert from_str("[1") ==
Erick Tryzelaarb361f6c2012-06-13 00:20:51793 err({line: 1u, col: 3u, msg: @"EOF while parsing list"});
Erick Tryzelaar012dec52012-02-26 00:39:32794 assert from_str("[1,") ==
Erick Tryzelaarb361f6c2012-06-13 00:20:51795 err({line: 1u, col: 4u, msg: @"EOF while parsing value"});
Erick Tryzelaar012dec52012-02-26 00:39:32796 assert from_str("[1,]") ==
Erick Tryzelaarb361f6c2012-06-13 00:20:51797 err({line: 1u, col: 4u, msg: @"invalid syntax"});
Erick Tryzelaar012dec52012-02-26 00:39:32798 assert from_str("[6 7]") ==
Erick Tryzelaarb361f6c2012-06-13 00:20:51799 err({line: 1u, col: 4u, msg: @"expecting ',' or ']'"});
Erick Tryzelaar012dec52012-02-26 00:39:32800
Michael Sullivan98e161f2012-06-29 23:26:56801 assert from_str("[]") == ok(list(@~[]));
802 assert from_str("[ ]") == ok(list(@~[]));
803 assert from_str("[true]") == ok(list(@~[boolean(true)]));
804 assert from_str("[ false ]") == ok(list(@~[boolean(false)]));
805 assert from_str("[null]") == ok(list(@~[null]));
806 assert from_str("[3, 1]") == ok(list(@~[num(3f), num(1f)]));
807 assert from_str("\n[3, 2]\n") == ok(list(@~[num(3f), num(2f)]));
Erick Tryzelaar012dec52012-02-26 00:39:32808 assert from_str("[2, [4, 1]]") ==
Michael Sullivan98e161f2012-06-29 23:26:56809 ok(list(@~[num(2f), list(@~[num(4f), num(1f)])]));
Erick Tryzelaar012dec52012-02-26 00:39:32810 }
811
812 #[test]
813 fn test_read_dict() {
814 assert from_str("{") ==
Erick Tryzelaarb361f6c2012-06-13 00:20:51815 err({line: 1u, col: 2u, msg: @"EOF while parsing object"});
Erick Tryzelaar012dec52012-02-26 00:39:32816 assert from_str("{ ") ==
Erick Tryzelaarb361f6c2012-06-13 00:20:51817 err({line: 1u, col: 3u, msg: @"EOF while parsing object"});
Erick Tryzelaar012dec52012-02-26 00:39:32818 assert from_str("{1") ==
Erick Tryzelaarb361f6c2012-06-13 00:20:51819 err({line: 1u, col: 2u, msg: @"key must be a string"});
Erick Tryzelaar012dec52012-02-26 00:39:32820 assert from_str("{ \"a\"") ==
Erick Tryzelaarb361f6c2012-06-13 00:20:51821 err({line: 1u, col: 6u, msg: @"EOF while parsing object"});
Erick Tryzelaar012dec52012-02-26 00:39:32822 assert from_str("{\"a\"") ==
Erick Tryzelaarb361f6c2012-06-13 00:20:51823 err({line: 1u, col: 5u, msg: @"EOF while parsing object"});
Erick Tryzelaar012dec52012-02-26 00:39:32824 assert from_str("{\"a\" ") ==
Erick Tryzelaarb361f6c2012-06-13 00:20:51825 err({line: 1u, col: 6u, msg: @"EOF while parsing object"});
Erick Tryzelaar012dec52012-02-26 00:39:32826
827 assert from_str("{\"a\" 1") ==
Erick Tryzelaarb361f6c2012-06-13 00:20:51828 err({line: 1u, col: 6u, msg: @"expecting ':'"});
Erick Tryzelaar012dec52012-02-26 00:39:32829 assert from_str("{\"a\":") ==
Erick Tryzelaarb361f6c2012-06-13 00:20:51830 err({line: 1u, col: 6u, msg: @"EOF while parsing value"});
Erick Tryzelaar012dec52012-02-26 00:39:32831 assert from_str("{\"a\":1") ==
Erick Tryzelaarb361f6c2012-06-13 00:20:51832 err({line: 1u, col: 7u, msg: @"EOF while parsing object"});
Erick Tryzelaar012dec52012-02-26 00:39:32833 assert from_str("{\"a\":1 1") ==
Erick Tryzelaarb361f6c2012-06-13 00:20:51834 err({line: 1u, col: 8u, msg: @"expecting ',' or '}'"});
Erick Tryzelaar012dec52012-02-26 00:39:32835 assert from_str("{\"a\":1,") ==
Erick Tryzelaarb361f6c2012-06-13 00:20:51836 err({line: 1u, col: 8u, msg: @"EOF while parsing object"});
Erick Tryzelaar012dec52012-02-26 00:39:32837
Michael Sullivan98e161f2012-06-29 23:26:56838 assert eq(result::get(from_str("{}")), mk_dict(~[]));
Erick Tryzelaar012dec52012-02-26 00:39:32839 assert eq(result::get(from_str("{\"a\": 3}")),
Michael Sullivan98e161f2012-06-29 23:26:56840 mk_dict(~[("a", num(3.0f))]));
Erick Tryzelaar012dec52012-02-26 00:39:32841
842 assert eq(result::get(from_str("{ \"a\": null, \"b\" : true }")),
Michael Sullivan98e161f2012-06-29 23:26:56843 mk_dict(~[
Erick Tryzelaarb361f6c2012-06-13 00:20:51844 ("a", null),
Michael Sullivan98e161f2012-06-29 23:26:56845 ("b", boolean(true))]));
Tycho Sci0465d522012-02-29 07:14:43846 assert eq(result::get(from_str("\n{ \"a\": null, \"b\" : true }\n")),
Michael Sullivan98e161f2012-06-29 23:26:56847 mk_dict(~[
Erick Tryzelaarb361f6c2012-06-13 00:20:51848 ("a", null),
Michael Sullivan98e161f2012-06-29 23:26:56849 ("b", boolean(true))]));
Erick Tryzelaar012dec52012-02-26 00:39:32850 assert eq(result::get(from_str("{\"a\" : 1.0 ,\"b\": [ true ]}")),
Michael Sullivan98e161f2012-06-29 23:26:56851 mk_dict(~[
Erick Tryzelaar012dec52012-02-26 00:39:32852 ("a", num(1.0)),
Michael Sullivan98e161f2012-06-29 23:26:56853 ("b", list(@~[boolean(true)]))
854 ]));
Erick Tryzelaar012dec52012-02-26 00:39:32855 assert eq(result::get(from_str(
856 "{" +
857 "\"a\": 1.0, " +
858 "\"b\": [" +
859 "true," +
860 "\"foo\\nbar\", " +
861 "{ \"c\": {\"d\": null} } " +
862 "]" +
863 "}")),
Michael Sullivan98e161f2012-06-29 23:26:56864 mk_dict(~[
Erick Tryzelaar012dec52012-02-26 00:39:32865 ("a", num(1.0f)),
Michael Sullivan98e161f2012-06-29 23:26:56866 ("b", list(@~[
Erick Tryzelaar012dec52012-02-26 00:39:32867 boolean(true),
Erick Tryzelaarb361f6c2012-06-13 00:20:51868 string(@"foo\nbar"),
Michael Sullivan98e161f2012-06-29 23:26:56869 mk_dict(~[
870 ("c", mk_dict(~[("d", null)]))
871 ])
872 ]))
873 ]));
Erick Tryzelaar012dec52012-02-26 00:39:32874 }
875
876 #[test]
877 fn test_multiline_errors() {
878 assert from_str("{\n \"foo\":\n \"bar\"") ==
Erick Tryzelaarb361f6c2012-06-13 00:20:51879 err({line: 3u, col: 8u, msg: @"EOF while parsing object"});
Brian Anderson6e27b272012-01-18 03:05:07880 }
881}