| // Copyright 2012 The Rust Project Developers. See the COPYRIGHT |
| // file at the top-level directory of this distribution and at |
| // http://rust-lang.org/COPYRIGHT. |
| // |
| // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or |
| // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license |
| // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your |
| // option. This file may not be copied, modified, or distributed |
| // except according to those terms. |
| |
| // Rust JSON serialization library |
| // Copyright (c) 2011 Google Inc. |
| |
| #[forbid(non_camel_case_types)]; |
| #[allow(missing_doc)]; |
| |
| //! json serialization |
| |
| use core::prelude::*; |
| |
| use core::char; |
| use core::float; |
| use core::hashmap::HashMap; |
| use core::io::{WriterUtil, ReaderUtil}; |
| use core::io; |
| use core::str; |
| use core::to_str; |
| use core::vec; |
| |
| use serialize::Encodable; |
| use serialize; |
| use sort::Sort; |
| |
| /// Represents a json value |
| pub enum Json { |
| Number(float), |
| String(~str), |
| Boolean(bool), |
| List(List), |
| Object(~Object), |
| Null, |
| } |
| |
| pub type List = ~[Json]; |
| pub type Object = HashMap<~str, Json>; |
| |
| #[deriving(Eq)] |
| /// If an error occurs while parsing some JSON, this is the structure which is |
| /// returned |
| pub struct Error { |
| /// The line number at which the error occurred |
| line: uint, |
| /// The column number at which the error occurred |
| col: uint, |
| /// A message describing the type of the error |
| msg: @~str, |
| } |
| |
| fn escape_str(s: &str) -> ~str { |
| let mut escaped = ~"\""; |
| for s.iter().advance |c| { |
| match c { |
| '"' => escaped += "\\\"", |
| '\\' => escaped += "\\\\", |
| '\x08' => escaped += "\\b", |
| '\x0c' => escaped += "\\f", |
| '\n' => escaped += "\\n", |
| '\r' => escaped += "\\r", |
| '\t' => escaped += "\\t", |
| _ => escaped += str::from_char(c) |
| } |
| }; |
| |
| escaped += "\""; |
| |
| escaped |
| } |
| |
| fn spaces(n: uint) -> ~str { |
| let mut ss = ~""; |
| for n.times { ss.push_str(" "); } |
| return ss; |
| } |
| |
| /// A structure for implementing serialization to JSON. |
| pub struct Encoder { |
| priv wr: @io::Writer, |
| } |
| |
| /// Creates a new JSON encoder whose output will be written to the writer |
| /// specified. |
| pub fn Encoder(wr: @io::Writer) -> Encoder { |
| Encoder { |
| wr: wr |
| } |
| } |
| |
| impl serialize::Encoder for Encoder { |
| fn emit_nil(&mut self) { self.wr.write_str("null") } |
| |
| fn emit_uint(&mut self, v: uint) { self.emit_float(v as float); } |
| fn emit_u64(&mut self, v: u64) { self.emit_float(v as float); } |
| fn emit_u32(&mut self, v: u32) { self.emit_float(v as float); } |
| fn emit_u16(&mut self, v: u16) { self.emit_float(v as float); } |
| fn emit_u8(&mut self, v: u8) { self.emit_float(v as float); } |
| |
| fn emit_int(&mut self, v: int) { self.emit_float(v as float); } |
| fn emit_i64(&mut self, v: i64) { self.emit_float(v as float); } |
| fn emit_i32(&mut self, v: i32) { self.emit_float(v as float); } |
| fn emit_i16(&mut self, v: i16) { self.emit_float(v as float); } |
| fn emit_i8(&mut self, v: i8) { self.emit_float(v as float); } |
| |
| fn emit_bool(&mut self, v: bool) { |
| if v { |
| self.wr.write_str("true"); |
| } else { |
| self.wr.write_str("false"); |
| } |
| } |
| |
| fn emit_f64(&mut self, v: f64) { self.emit_float(v as float); } |
| fn emit_f32(&mut self, v: f32) { self.emit_float(v as float); } |
| fn emit_float(&mut self, v: float) { |
| self.wr.write_str(float::to_str_digits(v, 6u)); |
| } |
| |
| fn emit_char(&mut self, v: char) { self.emit_str(str::from_char(v)) } |
| fn emit_str(&mut self, v: &str) { self.wr.write_str(escape_str(v)) } |
| |
| fn emit_enum(&mut self, _name: &str, f: &fn(&mut Encoder)) { f(self) } |
| |
| fn emit_enum_variant(&mut self, |
| name: &str, |
| _id: uint, |
| cnt: uint, |
| f: &fn(&mut Encoder)) { |
| // enums are encoded as strings or vectors: |
| // Bunny => "Bunny" |
| // Kangaroo(34,"William") => ["Kangaroo",[34,"William"]] |
| |
| if cnt == 0 { |
| self.wr.write_str(escape_str(name)); |
| } else { |
| self.wr.write_char('['); |
| self.wr.write_str(escape_str(name)); |
| self.wr.write_char(','); |
| f(self); |
| self.wr.write_char(']'); |
| } |
| } |
| |
| fn emit_enum_variant_arg(&mut self, idx: uint, f: &fn(&mut Encoder)) { |
| if idx != 0 { |
| self.wr.write_char(','); |
| } |
| f(self); |
| } |
| |
| fn emit_enum_struct_variant(&mut self, |
| name: &str, |
| id: uint, |
| cnt: uint, |
| f: &fn(&mut Encoder)) { |
| self.emit_enum_variant(name, id, cnt, f) |
| } |
| |
| fn emit_enum_struct_variant_field(&mut self, |
| _: &str, |
| idx: uint, |
| f: &fn(&mut Encoder)) { |
| self.emit_enum_variant_arg(idx, f) |
| } |
| |
| fn emit_struct(&mut self, _: &str, _: uint, f: &fn(&mut Encoder)) { |
| self.wr.write_char('{'); |
| f(self); |
| self.wr.write_char('}'); |
| } |
| |
| fn emit_struct_field(&mut self, |
| name: &str, |
| idx: uint, |
| f: &fn(&mut Encoder)) { |
| if idx != 0 { self.wr.write_char(','); } |
| self.wr.write_str(escape_str(name)); |
| self.wr.write_char(':'); |
| f(self); |
| } |
| |
| fn emit_tuple(&mut self, len: uint, f: &fn(&mut Encoder)) { |
| self.emit_seq(len, f) |
| } |
| fn emit_tuple_arg(&mut self, idx: uint, f: &fn(&mut Encoder)) { |
| self.emit_seq_elt(idx, f) |
| } |
| |
| fn emit_tuple_struct(&mut self, |
| _name: &str, |
| len: uint, |
| f: &fn(&mut Encoder)) { |
| self.emit_seq(len, f) |
| } |
| fn emit_tuple_struct_arg(&mut self, idx: uint, f: &fn(&mut Encoder)) { |
| self.emit_seq_elt(idx, f) |
| } |
| |
| fn emit_option(&mut self, f: &fn(&mut Encoder)) { f(self); } |
| fn emit_option_none(&mut self) { self.emit_nil(); } |
| fn emit_option_some(&mut self, f: &fn(&mut Encoder)) { f(self); } |
| |
| fn emit_seq(&mut self, _len: uint, f: &fn(&mut Encoder)) { |
| self.wr.write_char('['); |
| f(self); |
| self.wr.write_char(']'); |
| } |
| |
| fn emit_seq_elt(&mut self, idx: uint, f: &fn(&mut Encoder)) { |
| if idx != 0 { |
| self.wr.write_char(','); |
| } |
| f(self) |
| } |
| |
| fn emit_map(&mut self, _len: uint, f: &fn(&mut Encoder)) { |
| self.wr.write_char('{'); |
| f(self); |
| self.wr.write_char('}'); |
| } |
| |
| fn emit_map_elt_key(&mut self, idx: uint, f: &fn(&mut Encoder)) { |
| if idx != 0 { self.wr.write_char(','); } |
| f(self) |
| } |
| |
| fn emit_map_elt_val(&mut self, _idx: uint, f: &fn(&mut Encoder)) { |
| self.wr.write_char(':'); |
| f(self) |
| } |
| } |
| |
| /// Another encoder for JSON, but prints out human-readable JSON instead of |
| /// compact data |
| pub struct PrettyEncoder { |
| priv wr: @io::Writer, |
| priv indent: uint, |
| } |
| |
| /// Creates a new encoder whose output will be written to the specified writer |
| pub fn PrettyEncoder(wr: @io::Writer) -> PrettyEncoder { |
| PrettyEncoder { |
| wr: wr, |
| indent: 0, |
| } |
| } |
| |
| impl serialize::Encoder for PrettyEncoder { |
| fn emit_nil(&mut self) { self.wr.write_str("null") } |
| |
| fn emit_uint(&mut self, v: uint) { self.emit_float(v as float); } |
| fn emit_u64(&mut self, v: u64) { self.emit_float(v as float); } |
| fn emit_u32(&mut self, v: u32) { self.emit_float(v as float); } |
| fn emit_u16(&mut self, v: u16) { self.emit_float(v as float); } |
| fn emit_u8(&mut self, v: u8) { self.emit_float(v as float); } |
| |
| fn emit_int(&mut self, v: int) { self.emit_float(v as float); } |
| fn emit_i64(&mut self, v: i64) { self.emit_float(v as float); } |
| fn emit_i32(&mut self, v: i32) { self.emit_float(v as float); } |
| fn emit_i16(&mut self, v: i16) { self.emit_float(v as float); } |
| fn emit_i8(&mut self, v: i8) { self.emit_float(v as float); } |
| |
| fn emit_bool(&mut self, v: bool) { |
| if v { |
| self.wr.write_str("true"); |
| } else { |
| self.wr.write_str("false"); |
| } |
| } |
| |
| fn emit_f64(&mut self, v: f64) { self.emit_float(v as float); } |
| fn emit_f32(&mut self, v: f32) { self.emit_float(v as float); } |
| fn emit_float(&mut self, v: float) { |
| self.wr.write_str(float::to_str_digits(v, 6u)); |
| } |
| |
| fn emit_char(&mut self, v: char) { self.emit_str(str::from_char(v)) } |
| fn emit_str(&mut self, v: &str) { self.wr.write_str(escape_str(v)); } |
| |
| fn emit_enum(&mut self, _name: &str, f: &fn(&mut PrettyEncoder)) { |
| f(self) |
| } |
| |
| fn emit_enum_variant(&mut self, |
| name: &str, |
| _: uint, |
| cnt: uint, |
| f: &fn(&mut PrettyEncoder)) { |
| if cnt == 0 { |
| self.wr.write_str(escape_str(name)); |
| } else { |
| self.wr.write_char('['); |
| self.indent += 2; |
| self.wr.write_char('\n'); |
| self.wr.write_str(spaces(self.indent)); |
| self.wr.write_str(escape_str(name)); |
| self.wr.write_str(",\n"); |
| f(self); |
| self.wr.write_char('\n'); |
| self.indent -= 2; |
| self.wr.write_str(spaces(self.indent)); |
| self.wr.write_char(']'); |
| } |
| } |
| |
| fn emit_enum_variant_arg(&mut self, |
| idx: uint, |
| f: &fn(&mut PrettyEncoder)) { |
| if idx != 0 { |
| self.wr.write_str(",\n"); |
| } |
| self.wr.write_str(spaces(self.indent)); |
| f(self) |
| } |
| |
| fn emit_enum_struct_variant(&mut self, |
| name: &str, |
| id: uint, |
| cnt: uint, |
| f: &fn(&mut PrettyEncoder)) { |
| self.emit_enum_variant(name, id, cnt, f) |
| } |
| |
| fn emit_enum_struct_variant_field(&mut self, |
| _: &str, |
| idx: uint, |
| f: &fn(&mut PrettyEncoder)) { |
| self.emit_enum_variant_arg(idx, f) |
| } |
| |
| |
| fn emit_struct(&mut self, |
| _: &str, |
| len: uint, |
| f: &fn(&mut PrettyEncoder)) { |
| if len == 0 { |
| self.wr.write_str("{}"); |
| } else { |
| self.wr.write_char('{'); |
| self.indent += 2; |
| f(self); |
| self.wr.write_char('\n'); |
| self.indent -= 2; |
| self.wr.write_str(spaces(self.indent)); |
| self.wr.write_char('}'); |
| } |
| } |
| |
| fn emit_struct_field(&mut self, |
| name: &str, |
| idx: uint, |
| f: &fn(&mut PrettyEncoder)) { |
| if idx == 0 { |
| self.wr.write_char('\n'); |
| } else { |
| self.wr.write_str(",\n"); |
| } |
| self.wr.write_str(spaces(self.indent)); |
| self.wr.write_str(escape_str(name)); |
| self.wr.write_str(": "); |
| f(self); |
| } |
| |
| fn emit_tuple(&mut self, len: uint, f: &fn(&mut PrettyEncoder)) { |
| self.emit_seq(len, f) |
| } |
| fn emit_tuple_arg(&mut self, idx: uint, f: &fn(&mut PrettyEncoder)) { |
| self.emit_seq_elt(idx, f) |
| } |
| |
| fn emit_tuple_struct(&mut self, |
| _: &str, |
| len: uint, |
| f: &fn(&mut PrettyEncoder)) { |
| self.emit_seq(len, f) |
| } |
| fn emit_tuple_struct_arg(&mut self, |
| idx: uint, |
| f: &fn(&mut PrettyEncoder)) { |
| self.emit_seq_elt(idx, f) |
| } |
| |
| fn emit_option(&mut self, f: &fn(&mut PrettyEncoder)) { f(self); } |
| fn emit_option_none(&mut self) { self.emit_nil(); } |
| fn emit_option_some(&mut self, f: &fn(&mut PrettyEncoder)) { f(self); } |
| |
| fn emit_seq(&mut self, len: uint, f: &fn(&mut PrettyEncoder)) { |
| if len == 0 { |
| self.wr.write_str("[]"); |
| } else { |
| self.wr.write_char('['); |
| self.indent += 2; |
| f(self); |
| self.wr.write_char('\n'); |
| self.indent -= 2; |
| self.wr.write_str(spaces(self.indent)); |
| self.wr.write_char(']'); |
| } |
| } |
| |
| fn emit_seq_elt(&mut self, idx: uint, f: &fn(&mut PrettyEncoder)) { |
| if idx == 0 { |
| self.wr.write_char('\n'); |
| } else { |
| self.wr.write_str(",\n"); |
| } |
| self.wr.write_str(spaces(self.indent)); |
| f(self) |
| } |
| |
| fn emit_map(&mut self, len: uint, f: &fn(&mut PrettyEncoder)) { |
| if len == 0 { |
| self.wr.write_str("{}"); |
| } else { |
| self.wr.write_char('{'); |
| self.indent += 2; |
| f(self); |
| self.wr.write_char('\n'); |
| self.indent -= 2; |
| self.wr.write_str(spaces(self.indent)); |
| self.wr.write_char('}'); |
| } |
| } |
| |
| fn emit_map_elt_key(&mut self, idx: uint, f: &fn(&mut PrettyEncoder)) { |
| if idx == 0 { |
| self.wr.write_char('\n'); |
| } else { |
| self.wr.write_str(",\n"); |
| } |
| self.wr.write_str(spaces(self.indent)); |
| f(self); |
| } |
| |
| fn emit_map_elt_val(&mut self, _idx: uint, f: &fn(&mut PrettyEncoder)) { |
| self.wr.write_str(": "); |
| f(self); |
| } |
| } |
| |
| impl<E: serialize::Encoder> serialize::Encodable<E> for Json { |
| fn encode(&self, e: &mut E) { |
| match *self { |
| Number(v) => v.encode(e), |
| String(ref v) => v.encode(e), |
| Boolean(v) => v.encode(e), |
| List(ref v) => v.encode(e), |
| Object(ref v) => v.encode(e), |
| Null => e.emit_nil(), |
| } |
| } |
| } |
| |
| /// Encodes a json value into a io::writer |
| pub fn to_writer(wr: @io::Writer, json: &Json) { |
| let mut encoder = Encoder(wr); |
| json.encode(&mut encoder) |
| } |
| |
| /// Encodes a json value into a string |
| pub fn to_str(json: &Json) -> ~str { |
| io::with_str_writer(|wr| to_writer(wr, json)) |
| } |
| |
| /// Encodes a json value into a io::writer |
| pub fn to_pretty_writer(wr: @io::Writer, json: &Json) { |
| let mut encoder = PrettyEncoder(wr); |
| json.encode(&mut encoder) |
| } |
| |
| /// Encodes a json value into a string |
| pub fn to_pretty_str(json: &Json) -> ~str { |
| io::with_str_writer(|wr| to_pretty_writer(wr, json)) |
| } |
| |
| #[allow(missing_doc)] |
| pub struct Parser { |
| priv rdr: @io::Reader, |
| priv ch: char, |
| priv line: uint, |
| priv col: uint, |
| } |
| |
| /// Decode a json value from an io::reader |
| pub fn Parser(rdr: @io::Reader) -> Parser { |
| Parser { |
| rdr: rdr, |
| ch: rdr.read_char(), |
| line: 1, |
| col: 1, |
| } |
| } |
| |
| impl Parser { |
| pub fn parse(&mut self) -> Result<Json, Error> { |
| match self.parse_value() { |
| Ok(value) => { |
| // Skip trailing whitespaces. |
| self.parse_whitespace(); |
| // Make sure there is no trailing characters. |
| if self.eof() { |
| Ok(value) |
| } else { |
| self.error(~"trailing characters") |
| } |
| } |
| Err(e) => Err(e) |
| } |
| } |
| } |
| |
| impl Parser { |
| fn eof(&self) -> bool { self.ch == -1 as char } |
| |
| fn bump(&mut self) { |
| self.ch = self.rdr.read_char(); |
| |
| if self.ch == '\n' { |
| self.line += 1u; |
| self.col = 1u; |
| } else { |
| self.col += 1u; |
| } |
| } |
| |
| fn next_char(&mut self) -> char { |
| self.bump(); |
| self.ch |
| } |
| |
| fn error<T>(&self, msg: ~str) -> Result<T, Error> { |
| Err(Error { line: self.line, col: self.col, msg: @msg }) |
| } |
| |
| fn parse_value(&mut self) -> Result<Json, Error> { |
| self.parse_whitespace(); |
| |
| if self.eof() { return self.error(~"EOF while parsing value"); } |
| |
| match self.ch { |
| 'n' => self.parse_ident("ull", Null), |
| 't' => self.parse_ident("rue", Boolean(true)), |
| 'f' => self.parse_ident("alse", Boolean(false)), |
| '0' .. '9' | '-' => self.parse_number(), |
| '"' => |
| match self.parse_str() { |
| Ok(s) => Ok(String(s)), |
| Err(e) => Err(e), |
| }, |
| '[' => self.parse_list(), |
| '{' => self.parse_object(), |
| _ => self.error(~"invalid syntax") |
| } |
| } |
| |
| fn parse_whitespace(&mut self) { |
| while char::is_whitespace(self.ch) { self.bump(); } |
| } |
| |
| fn parse_ident(&mut self, ident: &str, value: Json) -> Result<Json, Error> { |
| if ident.iter().all(|c| c == self.next_char()) { |
| self.bump(); |
| Ok(value) |
| } else { |
| self.error(~"invalid syntax") |
| } |
| } |
| |
| fn parse_number(&mut self) -> Result<Json, Error> { |
| let mut neg = 1f; |
| |
| if self.ch == '-' { |
| self.bump(); |
| neg = -1f; |
| } |
| |
| let mut res = match self.parse_integer() { |
| Ok(res) => res, |
| Err(e) => return Err(e) |
| }; |
| |
| if self.ch == '.' { |
| match self.parse_decimal(res) { |
| Ok(r) => res = r, |
| Err(e) => return Err(e) |
| } |
| } |
| |
| if self.ch == 'e' || self.ch == 'E' { |
| match self.parse_exponent(res) { |
| Ok(r) => res = r, |
| Err(e) => return Err(e) |
| } |
| } |
| |
| Ok(Number(neg * res)) |
| } |
| |
| fn parse_integer(&mut self) -> Result<float, Error> { |
| let mut res = 0f; |
| |
| match self.ch { |
| '0' => { |
| self.bump(); |
| |
| // There can be only one leading '0'. |
| match self.ch { |
| '0' .. '9' => return self.error(~"invalid number"), |
| _ => () |
| } |
| } |
| '1' .. '9' => { |
| while !self.eof() { |
| match self.ch { |
| '0' .. '9' => { |
| res *= 10f; |
| res += ((self.ch as int) - ('0' as int)) as float; |
| |
| self.bump(); |
| } |
| _ => break |
| } |
| } |
| } |
| _ => return self.error(~"invalid number") |
| } |
| |
| Ok(res) |
| } |
| |
| fn parse_decimal(&mut self, res: float) -> Result<float, Error> { |
| self.bump(); |
| |
| // Make sure a digit follows the decimal place. |
| match self.ch { |
| '0' .. '9' => (), |
| _ => return self.error(~"invalid number") |
| } |
| |
| let mut res = res; |
| let mut dec = 1f; |
| while !self.eof() { |
| match self.ch { |
| '0' .. '9' => { |
| dec /= 10f; |
| res += (((self.ch as int) - ('0' as int)) as float) * dec; |
| |
| self.bump(); |
| } |
| _ => break |
| } |
| } |
| |
| Ok(res) |
| } |
| |
| fn parse_exponent(&mut self, mut res: float) -> Result<float, Error> { |
| self.bump(); |
| |
| let mut exp = 0u; |
| let mut neg_exp = false; |
| |
| match self.ch { |
| '+' => self.bump(), |
| '-' => { self.bump(); neg_exp = true; } |
| _ => () |
| } |
| |
| // Make sure a digit follows the exponent place. |
| match self.ch { |
| '0' .. '9' => (), |
| _ => return self.error(~"invalid number") |
| } |
| |
| while !self.eof() { |
| match self.ch { |
| '0' .. '9' => { |
| exp *= 10u; |
| exp += (self.ch as uint) - ('0' as uint); |
| |
| self.bump(); |
| } |
| _ => break |
| } |
| } |
| |
| let exp = float::pow_with_uint(10u, exp); |
| if neg_exp { |
| res /= exp; |
| } else { |
| res *= exp; |
| } |
| |
| Ok(res) |
| } |
| |
| fn parse_str(&mut self) -> Result<~str, Error> { |
| let mut escape = false; |
| let mut res = ~""; |
| |
| while !self.eof() { |
| self.bump(); |
| |
| if (escape) { |
| match self.ch { |
| '"' => res.push_char('"'), |
| '\\' => res.push_char('\\'), |
| '/' => res.push_char('/'), |
| 'b' => res.push_char('\x08'), |
| 'f' => res.push_char('\x0c'), |
| 'n' => res.push_char('\n'), |
| 'r' => res.push_char('\r'), |
| 't' => res.push_char('\t'), |
| 'u' => { |
| // Parse \u1234. |
| let mut i = 0u; |
| let mut n = 0u; |
| while i < 4u { |
| match self.next_char() { |
| '0' .. '9' => { |
| n = n * 16u + (self.ch as uint) |
| - ('0' as uint); |
| }, |
| 'a' | 'A' => n = n * 16u + 10u, |
| 'b' | 'B' => n = n * 16u + 11u, |
| 'c' | 'C' => n = n * 16u + 12u, |
| 'd' | 'D' => n = n * 16u + 13u, |
| 'e' | 'E' => n = n * 16u + 14u, |
| 'f' | 'F' => n = n * 16u + 15u, |
| _ => return self.error( |
| ~"invalid \\u escape (unrecognized hex)") |
| } |
| i += 1u; |
| } |
| |
| // Error out if we didn't parse 4 digits. |
| if i != 4u { |
| return self.error( |
| ~"invalid \\u escape (not four digits)"); |
| } |
| |
| res.push_char(n as char); |
| } |
| _ => return self.error(~"invalid escape") |
| } |
| escape = false; |
| } else if self.ch == '\\' { |
| escape = true; |
| } else { |
| if self.ch == '"' { |
| self.bump(); |
| return Ok(res); |
| } |
| res.push_char(self.ch); |
| } |
| } |
| |
| self.error(~"EOF while parsing string") |
| } |
| |
| fn parse_list(&mut self) -> Result<Json, Error> { |
| self.bump(); |
| self.parse_whitespace(); |
| |
| let mut values = ~[]; |
| |
| if self.ch == ']' { |
| self.bump(); |
| return Ok(List(values)); |
| } |
| |
| loop { |
| match self.parse_value() { |
| Ok(v) => values.push(v), |
| Err(e) => return Err(e) |
| } |
| |
| self.parse_whitespace(); |
| if self.eof() { |
| return self.error(~"EOF while parsing list"); |
| } |
| |
| match self.ch { |
| ',' => self.bump(), |
| ']' => { self.bump(); return Ok(List(values)); } |
| _ => return self.error(~"expected `,` or `]`") |
| } |
| }; |
| } |
| |
| fn parse_object(&mut self) -> Result<Json, Error> { |
| self.bump(); |
| self.parse_whitespace(); |
| |
| let mut values = ~HashMap::new(); |
| |
| if self.ch == '}' { |
| self.bump(); |
| return Ok(Object(values)); |
| } |
| |
| while !self.eof() { |
| self.parse_whitespace(); |
| |
| if self.ch != '"' { |
| return self.error(~"key must be a string"); |
| } |
| |
| let key = match self.parse_str() { |
| Ok(key) => key, |
| Err(e) => return Err(e) |
| }; |
| |
| self.parse_whitespace(); |
| |
| if self.ch != ':' { |
| if self.eof() { break; } |
| return self.error(~"expected `:`"); |
| } |
| self.bump(); |
| |
| match self.parse_value() { |
| Ok(value) => { values.insert(key, value); } |
| Err(e) => return Err(e) |
| } |
| self.parse_whitespace(); |
| |
| match self.ch { |
| ',' => self.bump(), |
| '}' => { self.bump(); return Ok(Object(values)); } |
| _ => { |
| if self.eof() { break; } |
| return self.error(~"expected `,` or `}`"); |
| } |
| } |
| } |
| |
| return self.error(~"EOF while parsing object"); |
| } |
| } |
| |
| /// Decodes a json value from an @io::Reader |
| pub fn from_reader(rdr: @io::Reader) -> Result<Json, Error> { |
| let mut parser = Parser(rdr); |
| parser.parse() |
| } |
| |
| /// Decodes a json value from a string |
| pub fn from_str(s: &str) -> Result<Json, Error> { |
| do io::with_str_reader(s) |rdr| { |
| from_reader(rdr) |
| } |
| } |
| |
| /// A structure to decode JSON to values in rust. |
| pub struct Decoder { |
| priv stack: ~[Json], |
| } |
| |
| /// Creates a new decoder instance for decoding the specified JSON value. |
| pub fn Decoder(json: Json) -> Decoder { |
| Decoder { |
| stack: ~[json] |
| } |
| } |
| |
| impl serialize::Decoder for Decoder { |
| fn read_nil(&mut self) -> () { |
| debug!("read_nil"); |
| match self.stack.pop() { |
| Null => (), |
| value => fail!("not a null: %?", value) |
| } |
| } |
| |
| fn read_u64(&mut self) -> u64 { self.read_float() as u64 } |
| fn read_u32(&mut self) -> u32 { self.read_float() as u32 } |
| fn read_u16(&mut self) -> u16 { self.read_float() as u16 } |
| fn read_u8 (&mut self) -> u8 { self.read_float() as u8 } |
| fn read_uint(&mut self) -> uint { self.read_float() as uint } |
| |
| fn read_i64(&mut self) -> i64 { self.read_float() as i64 } |
| fn read_i32(&mut self) -> i32 { self.read_float() as i32 } |
| fn read_i16(&mut self) -> i16 { self.read_float() as i16 } |
| fn read_i8 (&mut self) -> i8 { self.read_float() as i8 } |
| fn read_int(&mut self) -> int { self.read_float() as int } |
| |
| fn read_bool(&mut self) -> bool { |
| debug!("read_bool"); |
| match self.stack.pop() { |
| Boolean(b) => b, |
| value => fail!("not a boolean: %?", value) |
| } |
| } |
| |
| fn read_f64(&mut self) -> f64 { self.read_float() as f64 } |
| fn read_f32(&mut self) -> f32 { self.read_float() as f32 } |
| fn read_float(&mut self) -> float { |
| debug!("read_float"); |
| match self.stack.pop() { |
| Number(f) => f, |
| value => fail!("not a number: %?", value) |
| } |
| } |
| |
| fn read_char(&mut self) -> char { |
| let mut v = ~[]; |
| let s = self.read_str(); |
| for s.iter().advance |c| { v.push(c) } |
| if v.len() != 1 { fail!("string must have one character") } |
| v[0] |
| } |
| |
| fn read_str(&mut self) -> ~str { |
| debug!("read_str"); |
| match self.stack.pop() { |
| String(s) => s, |
| json => fail!("not a string: %?", json) |
| } |
| } |
| |
| fn read_enum<T>(&mut self, name: &str, f: &fn(&mut Decoder) -> T) -> T { |
| debug!("read_enum(%s)", name); |
| f(self) |
| } |
| |
| fn read_enum_variant<T>(&mut self, |
| names: &[&str], |
| f: &fn(&mut Decoder, uint) -> T) |
| -> T { |
| debug!("read_enum_variant(names=%?)", names); |
| let name = match self.stack.pop() { |
| String(s) => s, |
| List(list) => { |
| do vec::consume_reverse(list) |_i, v| { |
| self.stack.push(v); |
| } |
| match self.stack.pop() { |
| String(s) => s, |
| value => fail!("invalid variant name: %?", value), |
| } |
| } |
| ref json => fail!("invalid variant: %?", *json), |
| }; |
| let idx = match names.iter().position_(|n| str::eq_slice(*n, name)) { |
| Some(idx) => idx, |
| None => fail!("Unknown variant name: %?", name), |
| }; |
| f(self, idx) |
| } |
| |
| fn read_enum_variant_arg<T>(&mut self, |
| idx: uint, |
| f: &fn(&mut Decoder) -> T) |
| -> T { |
| debug!("read_enum_variant_arg(idx=%u)", idx); |
| f(self) |
| } |
| |
| fn read_enum_struct_variant<T>(&mut self, |
| names: &[&str], |
| f: &fn(&mut Decoder, uint) -> T) |
| -> T { |
| debug!("read_enum_struct_variant(names=%?)", names); |
| self.read_enum_variant(names, f) |
| } |
| |
| |
| fn read_enum_struct_variant_field<T>(&mut self, |
| name: &str, |
| idx: uint, |
| f: &fn(&mut Decoder) -> T) |
| -> T { |
| debug!("read_enum_struct_variant_field(name=%?, idx=%u)", name, idx); |
| self.read_enum_variant_arg(idx, f) |
| } |
| |
| fn read_struct<T>(&mut self, |
| name: &str, |
| len: uint, |
| f: &fn(&mut Decoder) -> T) |
| -> T { |
| debug!("read_struct(name=%s, len=%u)", name, len); |
| let value = f(self); |
| self.stack.pop(); |
| value |
| } |
| |
| fn read_struct_field<T>(&mut self, |
| name: &str, |
| idx: uint, |
| f: &fn(&mut Decoder) -> T) |
| -> T { |
| debug!("read_struct_field(name=%?, idx=%u)", name, idx); |
| match self.stack.pop() { |
| Object(obj) => { |
| let mut obj = obj; |
| let value = match obj.pop(&name.to_owned()) { |
| None => fail!("no such field: %s", name), |
| Some(json) => { |
| self.stack.push(json); |
| f(self) |
| } |
| }; |
| self.stack.push(Object(obj)); |
| value |
| } |
| value => fail!("not an object: %?", value) |
| } |
| } |
| |
| fn read_tuple<T>(&mut self, f: &fn(&mut Decoder, uint) -> T) -> T { |
| debug!("read_tuple()"); |
| self.read_seq(f) |
| } |
| |
| fn read_tuple_arg<T>(&mut self, |
| idx: uint, |
| f: &fn(&mut Decoder) -> T) |
| -> T { |
| debug!("read_tuple_arg(idx=%u)", idx); |
| self.read_seq_elt(idx, f) |
| } |
| |
| fn read_tuple_struct<T>(&mut self, |
| name: &str, |
| f: &fn(&mut Decoder, uint) -> T) |
| -> T { |
| debug!("read_tuple_struct(name=%?)", name); |
| self.read_tuple(f) |
| } |
| |
| fn read_tuple_struct_arg<T>(&mut self, |
| idx: uint, |
| f: &fn(&mut Decoder) -> T) |
| -> T { |
| debug!("read_tuple_struct_arg(idx=%u)", idx); |
| self.read_tuple_arg(idx, f) |
| } |
| |
| fn read_option<T>(&mut self, f: &fn(&mut Decoder, bool) -> T) -> T { |
| match self.stack.pop() { |
| Null => f(self, false), |
| value => { self.stack.push(value); f(self, true) } |
| } |
| } |
| |
| fn read_seq<T>(&mut self, f: &fn(&mut Decoder, uint) -> T) -> T { |
| debug!("read_seq()"); |
| let len = match self.stack.pop() { |
| List(list) => { |
| let len = list.len(); |
| do vec::consume_reverse(list) |_i, v| { |
| self.stack.push(v); |
| } |
| len |
| } |
| _ => fail!("not a list"), |
| }; |
| f(self, len) |
| } |
| |
| fn read_seq_elt<T>(&mut self, idx: uint, f: &fn(&mut Decoder) -> T) -> T { |
| debug!("read_seq_elt(idx=%u)", idx); |
| f(self) |
| } |
| |
| fn read_map<T>(&mut self, f: &fn(&mut Decoder, uint) -> T) -> T { |
| debug!("read_map()"); |
| let len = match self.stack.pop() { |
| Object(obj) => { |
| let mut obj = obj; |
| let len = obj.len(); |
| do obj.consume |key, value| { |
| self.stack.push(value); |
| self.stack.push(String(key)); |
| } |
| len |
| } |
| json => fail!("not an object: %?", json), |
| }; |
| f(self, len) |
| } |
| |
| fn read_map_elt_key<T>(&mut self, |
| idx: uint, |
| f: &fn(&mut Decoder) -> T) |
| -> T { |
| debug!("read_map_elt_key(idx=%u)", idx); |
| f(self) |
| } |
| |
| fn read_map_elt_val<T>(&mut self, idx: uint, f: &fn(&mut Decoder) -> T) |
| -> T { |
| debug!("read_map_elt_val(idx=%u)", idx); |
| f(self) |
| } |
| } |
| |
| impl Eq for Json { |
| fn eq(&self, other: &Json) -> bool { |
| match (self) { |
| &Number(f0) => |
| match other { &Number(f1) => f0 == f1, _ => false }, |
| &String(ref s0) => |
| match other { &String(ref s1) => s0 == s1, _ => false }, |
| &Boolean(b0) => |
| match other { &Boolean(b1) => b0 == b1, _ => false }, |
| &Null => |
| match other { &Null => true, _ => false }, |
| &List(ref v0) => |
| match other { &List(ref v1) => v0 == v1, _ => false }, |
| &Object(ref d0) => { |
| match other { |
| &Object(ref d1) => { |
| if d0.len() == d1.len() { |
| let mut equal = true; |
| for d0.iter().advance |(k, v0)| { |
| match d1.find(k) { |
| Some(v1) if v0 == v1 => { }, |
| _ => { equal = false; break } |
| } |
| }; |
| equal |
| } else { |
| false |
| } |
| } |
| _ => false |
| } |
| } |
| } |
| } |
| fn ne(&self, other: &Json) -> bool { !self.eq(other) } |
| } |
| |
| /// Test if two json values are less than one another |
| impl Ord for Json { |
| fn lt(&self, other: &Json) -> bool { |
| match (*self) { |
| Number(f0) => { |
| match *other { |
| Number(f1) => f0 < f1, |
| String(_) | Boolean(_) | List(_) | Object(_) | |
| Null => true |
| } |
| } |
| |
| String(ref s0) => { |
| match *other { |
| Number(_) => false, |
| String(ref s1) => s0 < s1, |
| Boolean(_) | List(_) | Object(_) | Null => true |
| } |
| } |
| |
| Boolean(b0) => { |
| match *other { |
| Number(_) | String(_) => false, |
| Boolean(b1) => b0 < b1, |
| List(_) | Object(_) | Null => true |
| } |
| } |
| |
| List(ref l0) => { |
| match *other { |
| Number(_) | String(_) | Boolean(_) => false, |
| List(ref l1) => (*l0) < (*l1), |
| Object(_) | Null => true |
| } |
| } |
| |
| Object(ref d0) => { |
| match *other { |
| Number(_) | String(_) | Boolean(_) | List(_) => false, |
| Object(ref d1) => { |
| let mut d0_flat = ~[]; |
| let mut d1_flat = ~[]; |
| |
| // FIXME #4430: this is horribly inefficient... |
| for d0.iter().advance |(k, v)| { |
| d0_flat.push((@copy *k, @copy *v)); |
| } |
| d0_flat.qsort(); |
| |
| for d1.iter().advance |(k, v)| { |
| d1_flat.push((@copy *k, @copy *v)); |
| } |
| d1_flat.qsort(); |
| |
| d0_flat < d1_flat |
| } |
| Null => true |
| } |
| } |
| |
| Null => { |
| match *other { |
| Number(_) | String(_) | Boolean(_) | List(_) | |
| Object(_) => |
| false, |
| Null => true |
| } |
| } |
| } |
| } |
| fn le(&self, other: &Json) -> bool { !(*other).lt(&(*self)) } |
| fn ge(&self, other: &Json) -> bool { !(*self).lt(other) } |
| fn gt(&self, other: &Json) -> bool { (*other).lt(&(*self)) } |
| } |
| |
| /// A trait for converting values to JSON |
| trait ToJson { |
| /// Converts the value of `self` to an instance of JSON |
| fn to_json(&self) -> Json; |
| } |
| |
| impl ToJson for Json { |
| fn to_json(&self) -> Json { copy *self } |
| } |
| |
| impl ToJson for @Json { |
| fn to_json(&self) -> Json { (**self).to_json() } |
| } |
| |
| impl ToJson for int { |
| fn to_json(&self) -> Json { Number(*self as float) } |
| } |
| |
| impl ToJson for i8 { |
| fn to_json(&self) -> Json { Number(*self as float) } |
| } |
| |
| impl ToJson for i16 { |
| fn to_json(&self) -> Json { Number(*self as float) } |
| } |
| |
| impl ToJson for i32 { |
| fn to_json(&self) -> Json { Number(*self as float) } |
| } |
| |
| impl ToJson for i64 { |
| fn to_json(&self) -> Json { Number(*self as float) } |
| } |
| |
| impl ToJson for uint { |
| fn to_json(&self) -> Json { Number(*self as float) } |
| } |
| |
| impl ToJson for u8 { |
| fn to_json(&self) -> Json { Number(*self as float) } |
| } |
| |
| impl ToJson for u16 { |
| fn to_json(&self) -> Json { Number(*self as float) } |
| } |
| |
| impl ToJson for u32 { |
| fn to_json(&self) -> Json { Number(*self as float) } |
| } |
| |
| impl ToJson for u64 { |
| fn to_json(&self) -> Json { Number(*self as float) } |
| } |
| |
| impl ToJson for float { |
| fn to_json(&self) -> Json { Number(*self) } |
| } |
| |
| impl ToJson for f32 { |
| fn to_json(&self) -> Json { Number(*self as float) } |
| } |
| |
| impl ToJson for f64 { |
| fn to_json(&self) -> Json { Number(*self as float) } |
| } |
| |
| impl ToJson for () { |
| fn to_json(&self) -> Json { Null } |
| } |
| |
| impl ToJson for bool { |
| fn to_json(&self) -> Json { Boolean(*self) } |
| } |
| |
| impl ToJson for ~str { |
| fn to_json(&self) -> Json { String(copy *self) } |
| } |
| |
| impl ToJson for @~str { |
| fn to_json(&self) -> Json { String(copy **self) } |
| } |
| |
| impl<A:ToJson,B:ToJson> ToJson for (A, B) { |
| fn to_json(&self) -> Json { |
| match *self { |
| (ref a, ref b) => { |
| List(~[a.to_json(), b.to_json()]) |
| } |
| } |
| } |
| } |
| |
| impl<A:ToJson,B:ToJson,C:ToJson> ToJson for (A, B, C) { |
| fn to_json(&self) -> Json { |
| match *self { |
| (ref a, ref b, ref c) => { |
| List(~[a.to_json(), b.to_json(), c.to_json()]) |
| } |
| } |
| } |
| } |
| |
| impl<A:ToJson> ToJson for ~[A] { |
| fn to_json(&self) -> Json { List(self.map(|elt| elt.to_json())) } |
| } |
| |
| impl<A:ToJson + Copy> ToJson for HashMap<~str, A> { |
| fn to_json(&self) -> Json { |
| let mut d = HashMap::new(); |
| for self.iter().advance |(key, value)| { |
| d.insert(copy *key, value.to_json()); |
| } |
| Object(~d) |
| } |
| } |
| |
| impl<A:ToJson> ToJson for Option<A> { |
| fn to_json(&self) -> Json { |
| match *self { |
| None => Null, |
| Some(ref value) => value.to_json() |
| } |
| } |
| } |
| |
| impl to_str::ToStr for Json { |
| fn to_str(&self) -> ~str { to_str(self) } |
| } |
| |
| impl to_str::ToStr for Error { |
| fn to_str(&self) -> ~str { |
| fmt!("%u:%u: %s", self.line, self.col, *self.msg) |
| } |
| } |
| |
| #[cfg(test)] |
| mod tests { |
| use core::prelude::*; |
| |
| use super::*; |
| |
| use core::hashmap::HashMap; |
| use core::io; |
| use core::result; |
| |
| use std::serialize::Decodable; |
| |
| #[deriving(Eq, Encodable, Decodable)] |
| enum Animal { |
| Dog, |
| Frog(~str, int) |
| } |
| |
| #[deriving(Eq, Encodable, Decodable)] |
| struct Inner { |
| a: (), |
| b: uint, |
| c: ~[~str], |
| } |
| |
| #[deriving(Eq, Encodable, Decodable)] |
| struct Outer { |
| inner: ~[Inner], |
| } |
| |
| fn mk_object(items: &[(~str, Json)]) -> Json { |
| let mut d = ~HashMap::new(); |
| |
| for items.iter().advance |item| { |
| match *item { |
| (ref key, ref value) => { d.insert(copy *key, copy *value); }, |
| } |
| }; |
| |
| Object(d) |
| } |
| |
| #[test] |
| fn test_write_null() { |
| assert_eq!(to_str(&Null), ~"null"); |
| assert_eq!(to_pretty_str(&Null), ~"null"); |
| } |
| |
| |
| #[test] |
| fn test_write_number() { |
| assert_eq!(to_str(&Number(3f)), ~"3"); |
| assert_eq!(to_pretty_str(&Number(3f)), ~"3"); |
| |
| assert_eq!(to_str(&Number(3.1f)), ~"3.1"); |
| assert_eq!(to_pretty_str(&Number(3.1f)), ~"3.1"); |
| |
| assert_eq!(to_str(&Number(-1.5f)), ~"-1.5"); |
| assert_eq!(to_pretty_str(&Number(-1.5f)), ~"-1.5"); |
| |
| assert_eq!(to_str(&Number(0.5f)), ~"0.5"); |
| assert_eq!(to_pretty_str(&Number(0.5f)), ~"0.5"); |
| } |
| |
| #[test] |
| fn test_write_str() { |
| assert_eq!(to_str(&String(~"")), ~"\"\""); |
| assert_eq!(to_pretty_str(&String(~"")), ~"\"\""); |
| |
| assert_eq!(to_str(&String(~"foo")), ~"\"foo\""); |
| assert_eq!(to_pretty_str(&String(~"foo")), ~"\"foo\""); |
| } |
| |
| #[test] |
| fn test_write_bool() { |
| assert_eq!(to_str(&Boolean(true)), ~"true"); |
| assert_eq!(to_pretty_str(&Boolean(true)), ~"true"); |
| |
| assert_eq!(to_str(&Boolean(false)), ~"false"); |
| assert_eq!(to_pretty_str(&Boolean(false)), ~"false"); |
| } |
| |
| #[test] |
| fn test_write_list() { |
| assert_eq!(to_str(&List(~[])), ~"[]"); |
| assert_eq!(to_pretty_str(&List(~[])), ~"[]"); |
| |
| assert_eq!(to_str(&List(~[Boolean(true)])), ~"[true]"); |
| assert_eq!( |
| to_pretty_str(&List(~[Boolean(true)])), |
| ~"\ |
| [\n \ |
| true\n\ |
| ]" |
| ); |
| |
| assert_eq!(to_str(&List(~[ |
| Boolean(false), |
| Null, |
| List(~[String(~"foo\nbar"), Number(3.5f)]) |
| ])), ~"[false,null,[\"foo\\nbar\",3.5]]"); |
| assert_eq!( |
| to_pretty_str(&List(~[ |
| Boolean(false), |
| Null, |
| List(~[String(~"foo\nbar"), Number(3.5f)]) |
| ])), |
| ~"\ |
| [\n \ |
| false,\n \ |
| null,\n \ |
| [\n \ |
| \"foo\\nbar\",\n \ |
| 3.5\n \ |
| ]\n\ |
| ]" |
| ); |
| } |
| |
| #[test] |
| fn test_write_object() { |
| assert_eq!(to_str(&mk_object([])), ~"{}"); |
| assert_eq!(to_pretty_str(&mk_object([])), ~"{}"); |
| |
| assert_eq!( |
| to_str(&mk_object([(~"a", Boolean(true))])), |
| ~"{\"a\":true}" |
| ); |
| assert_eq!( |
| to_pretty_str(&mk_object([(~"a", Boolean(true))])), |
| ~"\ |
| {\n \ |
| \"a\": true\n\ |
| }" |
| ); |
| |
| assert_eq!( |
| to_str(&mk_object([ |
| (~"b", List(~[ |
| mk_object([(~"c", String(~"\x0c\r"))]), |
| mk_object([(~"d", String(~""))]) |
| ])) |
| ])), |
| ~"{\ |
| \"b\":[\ |
| {\"c\":\"\\f\\r\"},\ |
| {\"d\":\"\"}\ |
| ]\ |
| }" |
| ); |
| assert_eq!( |
| to_pretty_str(&mk_object([ |
| (~"b", List(~[ |
| mk_object([(~"c", String(~"\x0c\r"))]), |
| mk_object([(~"d", String(~""))]) |
| ])) |
| ])), |
| ~"\ |
| {\n \ |
| \"b\": [\n \ |
| {\n \ |
| \"c\": \"\\f\\r\"\n \ |
| },\n \ |
| {\n \ |
| \"d\": \"\"\n \ |
| }\n \ |
| ]\n\ |
| }" |
| ); |
| |
| let a = mk_object([ |
| (~"a", Boolean(true)), |
| (~"b", List(~[ |
| mk_object([(~"c", String(~"\x0c\r"))]), |
| mk_object([(~"d", String(~""))]) |
| ])) |
| ]); |
| |
| // We can't compare the strings directly because the object fields be |
| // printed in a different order. |
| assert_eq!(copy a, from_str(to_str(&a)).unwrap()); |
| assert_eq!(copy a, from_str(to_pretty_str(&a)).unwrap()); |
| } |
| |
| #[test] |
| fn test_write_enum() { |
| let animal = Dog; |
| assert_eq!( |
| do io::with_str_writer |wr| { |
| let mut encoder = Encoder(wr); |
| animal.encode(&mut encoder); |
| }, |
| ~"\"Dog\"" |
| ); |
| assert_eq!( |
| do io::with_str_writer |wr| { |
| let mut encoder = PrettyEncoder(wr); |
| animal.encode(&mut encoder); |
| }, |
| ~"\"Dog\"" |
| ); |
| |
| let animal = Frog(~"Henry", 349); |
| assert_eq!( |
| do io::with_str_writer |wr| { |
| let mut encoder = Encoder(wr); |
| animal.encode(&mut encoder); |
| }, |
| ~"[\"Frog\",\"Henry\",349]" |
| ); |
| assert_eq!( |
| do io::with_str_writer |wr| { |
| let mut encoder = PrettyEncoder(wr); |
| animal.encode(&mut encoder); |
| }, |
| ~"\ |
| [\n \ |
| \"Frog\",\n \ |
| \"Henry\",\n \ |
| 349\n\ |
| ]" |
| ); |
| } |
| |
| #[test] |
| fn test_write_some() { |
| let value = Some(~"jodhpurs"); |
| let s = do io::with_str_writer |wr| { |
| let mut encoder = Encoder(wr); |
| value.encode(&mut encoder); |
| }; |
| assert_eq!(s, ~"\"jodhpurs\""); |
| |
| let value = Some(~"jodhpurs"); |
| let s = do io::with_str_writer |wr| { |
| let mut encoder = PrettyEncoder(wr); |
| value.encode(&mut encoder); |
| }; |
| assert_eq!(s, ~"\"jodhpurs\""); |
| } |
| |
| #[test] |
| fn test_write_none() { |
| let value: Option<~str> = None; |
| let s = do io::with_str_writer |wr| { |
| let mut encoder = Encoder(wr); |
| value.encode(&mut encoder); |
| }; |
| assert_eq!(s, ~"null"); |
| |
| let s = do io::with_str_writer |wr| { |
| let mut encoder = Encoder(wr); |
| value.encode(&mut encoder); |
| }; |
| assert_eq!(s, ~"null"); |
| } |
| |
| #[test] |
| fn test_trailing_characters() { |
| assert_eq!(from_str("nulla"), |
| Err(Error {line: 1u, col: 5u, msg: @~"trailing characters"})); |
| assert_eq!(from_str("truea"), |
| Err(Error {line: 1u, col: 5u, msg: @~"trailing characters"})); |
| assert_eq!(from_str("falsea"), |
| Err(Error {line: 1u, col: 6u, msg: @~"trailing characters"})); |
| assert_eq!(from_str("1a"), |
| Err(Error {line: 1u, col: 2u, msg: @~"trailing characters"})); |
| assert_eq!(from_str("[]a"), |
| Err(Error {line: 1u, col: 3u, msg: @~"trailing characters"})); |
| assert_eq!(from_str("{}a"), |
| Err(Error {line: 1u, col: 3u, msg: @~"trailing characters"})); |
| } |
| |
| #[test] |
| fn test_read_identifiers() { |
| assert_eq!(from_str("n"), |
| Err(Error {line: 1u, col: 2u, msg: @~"invalid syntax"})); |
| assert_eq!(from_str("nul"), |
| Err(Error {line: 1u, col: 4u, msg: @~"invalid syntax"})); |
| |
| assert_eq!(from_str("t"), |
| Err(Error {line: 1u, col: 2u, msg: @~"invalid syntax"})); |
| assert_eq!(from_str("truz"), |
| Err(Error {line: 1u, col: 4u, msg: @~"invalid syntax"})); |
| |
| assert_eq!(from_str("f"), |
| Err(Error {line: 1u, col: 2u, msg: @~"invalid syntax"})); |
| assert_eq!(from_str("faz"), |
| Err(Error {line: 1u, col: 3u, msg: @~"invalid syntax"})); |
| |
| assert_eq!(from_str("null"), Ok(Null)); |
| assert_eq!(from_str("true"), Ok(Boolean(true))); |
| assert_eq!(from_str("false"), Ok(Boolean(false))); |
| assert_eq!(from_str(" null "), Ok(Null)); |
| assert_eq!(from_str(" true "), Ok(Boolean(true))); |
| assert_eq!(from_str(" false "), Ok(Boolean(false))); |
| } |
| |
| #[test] |
| fn test_decode_identifiers() { |
| let mut decoder = Decoder(from_str("null").unwrap()); |
| let v: () = Decodable::decode(&mut decoder); |
| assert_eq!(v, ()); |
| |
| let mut decoder = Decoder(from_str("true").unwrap()); |
| let v: bool = Decodable::decode(&mut decoder); |
| assert_eq!(v, true); |
| |
| let mut decoder = Decoder(from_str("false").unwrap()); |
| let v: bool = Decodable::decode(&mut decoder); |
| assert_eq!(v, false); |
| } |
| |
| #[test] |
| fn test_read_number() { |
| assert_eq!(from_str("+"), |
| Err(Error {line: 1u, col: 1u, msg: @~"invalid syntax"})); |
| assert_eq!(from_str("."), |
| Err(Error {line: 1u, col: 1u, msg: @~"invalid syntax"})); |
| |
| assert_eq!(from_str("-"), |
| Err(Error {line: 1u, col: 2u, msg: @~"invalid number"})); |
| assert_eq!(from_str("00"), |
| Err(Error {line: 1u, col: 2u, msg: @~"invalid number"})); |
| assert_eq!(from_str("1."), |
| Err(Error {line: 1u, col: 3u, msg: @~"invalid number"})); |
| assert_eq!(from_str("1e"), |
| Err(Error {line: 1u, col: 3u, msg: @~"invalid number"})); |
| assert_eq!(from_str("1e+"), |
| Err(Error {line: 1u, col: 4u, msg: @~"invalid number"})); |
| |
| assert_eq!(from_str("3"), Ok(Number(3f))); |
| assert_eq!(from_str("3.1"), Ok(Number(3.1f))); |
| assert_eq!(from_str("-1.2"), Ok(Number(-1.2f))); |
| assert_eq!(from_str("0.4"), Ok(Number(0.4f))); |
| assert_eq!(from_str("0.4e5"), Ok(Number(0.4e5f))); |
| assert_eq!(from_str("0.4e+15"), Ok(Number(0.4e15f))); |
| assert_eq!(from_str("0.4e-01"), Ok(Number(0.4e-01f))); |
| assert_eq!(from_str(" 3 "), Ok(Number(3f))); |
| } |
| |
| #[test] |
| fn test_decode_numbers() { |
| let mut decoder = Decoder(from_str("3").unwrap()); |
| let v: float = Decodable::decode(&mut decoder); |
| assert_eq!(v, 3f); |
| |
| let mut decoder = Decoder(from_str("3.1").unwrap()); |
| let v: float = Decodable::decode(&mut decoder); |
| assert_eq!(v, 3.1f); |
| |
| let mut decoder = Decoder(from_str("-1.2").unwrap()); |
| let v: float = Decodable::decode(&mut decoder); |
| assert_eq!(v, -1.2f); |
| |
| let mut decoder = Decoder(from_str("0.4").unwrap()); |
| let v: float = Decodable::decode(&mut decoder); |
| assert_eq!(v, 0.4f); |
| |
| let mut decoder = Decoder(from_str("0.4e5").unwrap()); |
| let v: float = Decodable::decode(&mut decoder); |
| assert_eq!(v, 0.4e5f); |
| |
| let mut decoder = Decoder(from_str("0.4e15").unwrap()); |
| let v: float = Decodable::decode(&mut decoder); |
| assert_eq!(v, 0.4e15f); |
| |
| let mut decoder = Decoder(from_str("0.4e-01").unwrap()); |
| let v: float = Decodable::decode(&mut decoder); |
| assert_eq!(v, 0.4e-01f); |
| } |
| |
| #[test] |
| fn test_read_str() { |
| assert_eq!(from_str("\""), |
| Err(Error {line: 1u, col: 2u, msg: @~"EOF while parsing string" |
| })); |
| assert_eq!(from_str("\"lol"), |
| Err(Error {line: 1u, col: 5u, msg: @~"EOF while parsing string" |
| })); |
| |
| assert_eq!(from_str("\"\""), Ok(String(~""))); |
| assert_eq!(from_str("\"foo\""), Ok(String(~"foo"))); |
| assert_eq!(from_str("\"\\\"\""), Ok(String(~"\""))); |
| assert_eq!(from_str("\"\\b\""), Ok(String(~"\x08"))); |
| assert_eq!(from_str("\"\\n\""), Ok(String(~"\n"))); |
| assert_eq!(from_str("\"\\r\""), Ok(String(~"\r"))); |
| assert_eq!(from_str("\"\\t\""), Ok(String(~"\t"))); |
| assert_eq!(from_str(" \"foo\" "), Ok(String(~"foo"))); |
| assert_eq!(from_str("\"\\u12ab\""), Ok(String(~"\u12ab"))); |
| assert_eq!(from_str("\"\\uAB12\""), Ok(String(~"\uAB12"))); |
| } |
| |
| #[test] |
| fn test_decode_str() { |
| let mut decoder = Decoder(from_str("\"\"").unwrap()); |
| let v: ~str = Decodable::decode(&mut decoder); |
| assert_eq!(v, ~""); |
| |
| let mut decoder = Decoder(from_str("\"foo\"").unwrap()); |
| let v: ~str = Decodable::decode(&mut decoder); |
| assert_eq!(v, ~"foo"); |
| |
| let mut decoder = Decoder(from_str("\"\\\"\"").unwrap()); |
| let v: ~str = Decodable::decode(&mut decoder); |
| assert_eq!(v, ~"\""); |
| |
| let mut decoder = Decoder(from_str("\"\\b\"").unwrap()); |
| let v: ~str = Decodable::decode(&mut decoder); |
| assert_eq!(v, ~"\x08"); |
| |
| let mut decoder = Decoder(from_str("\"\\n\"").unwrap()); |
| let v: ~str = Decodable::decode(&mut decoder); |
| assert_eq!(v, ~"\n"); |
| |
| let mut decoder = Decoder(from_str("\"\\r\"").unwrap()); |
| let v: ~str = Decodable::decode(&mut decoder); |
| assert_eq!(v, ~"\r"); |
| |
| let mut decoder = Decoder(from_str("\"\\t\"").unwrap()); |
| let v: ~str = Decodable::decode(&mut decoder); |
| assert_eq!(v, ~"\t"); |
| |
| let mut decoder = Decoder(from_str("\"\\u12ab\"").unwrap()); |
| let v: ~str = Decodable::decode(&mut decoder); |
| assert_eq!(v, ~"\u12ab"); |
| |
| let mut decoder = Decoder(from_str("\"\\uAB12\"").unwrap()); |
| let v: ~str = Decodable::decode(&mut decoder); |
| assert_eq!(v, ~"\uAB12"); |
| } |
| |
| #[test] |
| fn test_read_list() { |
| assert_eq!(from_str("["), |
| Err(Error {line: 1u, col: 2u, msg: @~"EOF while parsing value"})); |
| assert_eq!(from_str("[1"), |
| Err(Error {line: 1u, col: 3u, msg: @~"EOF while parsing list"})); |
| assert_eq!(from_str("[1,"), |
| Err(Error {line: 1u, col: 4u, msg: @~"EOF while parsing value"})); |
| assert_eq!(from_str("[1,]"), |
| Err(Error {line: 1u, col: 4u, msg: @~"invalid syntax"})); |
| assert_eq!(from_str("[6 7]"), |
| Err(Error {line: 1u, col: 4u, msg: @~"expected `,` or `]`"})); |
| |
| assert_eq!(from_str("[]"), Ok(List(~[]))); |
| assert_eq!(from_str("[ ]"), Ok(List(~[]))); |
| assert_eq!(from_str("[true]"), Ok(List(~[Boolean(true)]))); |
| assert_eq!(from_str("[ false ]"), Ok(List(~[Boolean(false)]))); |
| assert_eq!(from_str("[null]"), Ok(List(~[Null]))); |
| assert_eq!(from_str("[3, 1]"), |
| Ok(List(~[Number(3f), Number(1f)]))); |
| assert_eq!(from_str("\n[3, 2]\n"), |
| Ok(List(~[Number(3f), Number(2f)]))); |
| assert_eq!(from_str("[2, [4, 1]]"), |
| Ok(List(~[Number(2f), List(~[Number(4f), Number(1f)])]))); |
| } |
| |
| #[test] |
| fn test_decode_list() { |
| let mut decoder = Decoder(from_str("[]").unwrap()); |
| let v: ~[()] = Decodable::decode(&mut decoder); |
| assert_eq!(v, ~[]); |
| |
| let mut decoder = Decoder(from_str("[null]").unwrap()); |
| let v: ~[()] = Decodable::decode(&mut decoder); |
| assert_eq!(v, ~[()]); |
| |
| let mut decoder = Decoder(from_str("[true]").unwrap()); |
| let v: ~[bool] = Decodable::decode(&mut decoder); |
| assert_eq!(v, ~[true]); |
| |
| let mut decoder = Decoder(from_str("[true]").unwrap()); |
| let v: ~[bool] = Decodable::decode(&mut decoder); |
| assert_eq!(v, ~[true]); |
| |
| let mut decoder = Decoder(from_str("[3, 1]").unwrap()); |
| let v: ~[int] = Decodable::decode(&mut decoder); |
| assert_eq!(v, ~[3, 1]); |
| |
| let mut decoder = Decoder(from_str("[[3], [1, 2]]").unwrap()); |
| let v: ~[~[uint]] = Decodable::decode(&mut decoder); |
| assert_eq!(v, ~[~[3], ~[1, 2]]); |
| } |
| |
| #[test] |
| fn test_read_object() { |
| assert_eq!(from_str("{"), |
| Err(Error { |
| line: 1u, |
| col: 2u, |
| msg: @~"EOF while parsing object"})); |
| assert_eq!(from_str("{ "), |
| Err(Error { |
| line: 1u, |
| col: 3u, |
| msg: @~"EOF while parsing object"})); |
| assert_eq!(from_str("{1"), |
| Err(Error { |
| line: 1u, |
| col: 2u, |
| msg: @~"key must be a string"})); |
| assert_eq!(from_str("{ \"a\""), |
| Err(Error { |
| line: 1u, |
| col: 6u, |
| msg: @~"EOF while parsing object"})); |
| assert_eq!(from_str("{\"a\""), |
| Err(Error { |
| line: 1u, |
| col: 5u, |
| msg: @~"EOF while parsing object"})); |
| assert_eq!(from_str("{\"a\" "), |
| Err(Error { |
| line: 1u, |
| col: 6u, |
| msg: @~"EOF while parsing object"})); |
| |
| assert_eq!(from_str("{\"a\" 1"), |
| Err(Error {line: 1u, col: 6u, msg: @~"expected `:`"})); |
| assert_eq!(from_str("{\"a\":"), |
| Err(Error {line: 1u, col: 6u, msg: @~"EOF while parsing value"})); |
| assert_eq!(from_str("{\"a\":1"), |
| Err(Error { |
| line: 1u, |
| col: 7u, |
| msg: @~"EOF while parsing object"})); |
| assert_eq!(from_str("{\"a\":1 1"), |
| Err(Error {line: 1u, col: 8u, msg: @~"expected `,` or `}`"})); |
| assert_eq!(from_str("{\"a\":1,"), |
| Err(Error { |
| line: 1u, |
| col: 8u, |
| msg: @~"EOF while parsing object"})); |
| |
| assert_eq!(result::unwrap(from_str("{}")), mk_object([])); |
| assert_eq!(result::unwrap(from_str("{\"a\": 3}")), |
| mk_object([(~"a", Number(3.0f))])); |
| |
| assert_eq!(result::unwrap(from_str( |
| "{ \"a\": null, \"b\" : true }")), |
| mk_object([ |
| (~"a", Null), |
| (~"b", Boolean(true))])); |
| assert_eq!(result::unwrap( |
| from_str("\n{ \"a\": null, \"b\" : true }\n")), |
| mk_object([ |
| (~"a", Null), |
| (~"b", Boolean(true))])); |
| assert_eq!(result::unwrap(from_str( |
| "{\"a\" : 1.0 ,\"b\": [ true ]}")), |
| mk_object([ |
| (~"a", Number(1.0)), |
| (~"b", List(~[Boolean(true)])) |
| ])); |
| assert_eq!(result::unwrap(from_str( |
| ~"{" + |
| "\"a\": 1.0, " + |
| "\"b\": [" + |
| "true," + |
| "\"foo\\nbar\", " + |
| "{ \"c\": {\"d\": null} } " + |
| "]" + |
| "}")), |
| mk_object([ |
| (~"a", Number(1.0f)), |
| (~"b", List(~[ |
| Boolean(true), |
| String(~"foo\nbar"), |
| mk_object([ |
| (~"c", mk_object([(~"d", Null)])) |
| ]) |
| ])) |
| ])); |
| } |
| |
| #[test] |
| fn test_decode_struct() { |
| let s = ~"{ |
| \"inner\": [ |
| { \"a\": null, \"b\": 2, \"c\": [\"abc\", \"xyz\"] } |
| ] |
| }"; |
| let mut decoder = Decoder(from_str(s).unwrap()); |
| let v: Outer = Decodable::decode(&mut decoder); |
| assert_eq!( |
| v, |
| Outer { |
| inner: ~[ |
| Inner { a: (), b: 2, c: ~[~"abc", ~"xyz"] } |
| ] |
| } |
| ); |
| } |
| |
| #[test] |
| fn test_decode_option() { |
| let mut decoder = Decoder(from_str("null").unwrap()); |
| let value: Option<~str> = Decodable::decode(&mut decoder); |
| assert_eq!(value, None); |
| |
| let mut decoder = Decoder(from_str("\"jodhpurs\"").unwrap()); |
| let value: Option<~str> = Decodable::decode(&mut decoder); |
| assert_eq!(value, Some(~"jodhpurs")); |
| } |
| |
| #[test] |
| fn test_decode_enum() { |
| let mut decoder = Decoder(from_str("\"Dog\"").unwrap()); |
| let value: Animal = Decodable::decode(&mut decoder); |
| assert_eq!(value, Dog); |
| |
| let mut decoder = |
| Decoder(from_str("[\"Frog\",\"Henry\",349]").unwrap()); |
| let value: Animal = Decodable::decode(&mut decoder); |
| assert_eq!(value, Frog(~"Henry", 349)); |
| } |
| |
| #[test] |
| fn test_decode_map() { |
| let s = ~"{\"a\": \"Dog\", \"b\": [\"Frog\", \"Henry\", 349]}"; |
| let mut decoder = Decoder(from_str(s).unwrap()); |
| let mut map: HashMap<~str, Animal> = Decodable::decode(&mut decoder); |
| |
| assert_eq!(map.pop(&~"a"), Some(Dog)); |
| assert_eq!(map.pop(&~"b"), Some(Frog(~"Henry", 349))); |
| } |
| |
| #[test] |
| fn test_multiline_errors() { |
| assert_eq!(from_str("{\n \"foo\":\n \"bar\""), |
| Err(Error { |
| line: 3u, |
| col: 8u, |
| msg: @~"EOF while parsing object"})); |
| } |
| } |