2014-06-25 20:26:41 -05:00
|
|
|
// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT
|
2012-12-03 18:48:01 -06:00
|
|
|
// 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.
|
|
|
|
|
2011-11-07 17:24:44 -06:00
|
|
|
// Rust JSON serialization library
|
|
|
|
// Copyright (c) 2011 Google Inc.
|
2013-05-31 17:17:22 -05:00
|
|
|
|
2014-03-21 20:05:05 -05:00
|
|
|
#![forbid(non_camel_case_types)]
|
|
|
|
#![allow(missing_doc)]
|
2011-11-07 13:01:28 -06:00
|
|
|
|
2014-01-12 11:32:57 -06:00
|
|
|
/*!
|
|
|
|
JSON parsing and serialization
|
|
|
|
|
|
|
|
# What is JSON?
|
|
|
|
|
|
|
|
JSON (JavaScript Object Notation) is a way to write data in Javascript.
|
2014-06-28 08:59:45 -05:00
|
|
|
Like XML, it allows to encode structured data in a text format that can be easily read by humans.
|
|
|
|
Its simple syntax and native compatibility with JavaScript have made it a widely used format.
|
|
|
|
|
|
|
|
Data types that can be encoded are JavaScript types (see the `Json` enum for more details):
|
|
|
|
|
|
|
|
* `Boolean`: equivalent to rust's `bool`
|
|
|
|
* `Number`: equivalent to rust's `f64`
|
|
|
|
* `String`: equivalent to rust's `String`
|
|
|
|
* `Array`: equivalent to rust's `Vec<T>`, but also allowing objects of different types in the same
|
|
|
|
array
|
|
|
|
* `Object`: equivalent to rust's `Treemap<String, json::Json>`
|
|
|
|
* `Null`
|
2014-01-12 11:32:57 -06:00
|
|
|
|
|
|
|
An object is a series of string keys mapping to values, in `"key": value` format.
|
|
|
|
Arrays are enclosed in square brackets ([ ... ]) and objects in curly brackets ({ ... }).
|
|
|
|
A simple JSON document encoding a person, his/her age, address and phone numbers could look like:
|
|
|
|
|
2014-02-15 01:44:22 -06:00
|
|
|
```ignore
|
2014-01-12 11:32:57 -06:00
|
|
|
{
|
|
|
|
"FirstName": "John",
|
|
|
|
"LastName": "Doe",
|
|
|
|
"Age": 43,
|
|
|
|
"Address": {
|
|
|
|
"Street": "Downing Street 10",
|
|
|
|
"City": "London",
|
|
|
|
"Country": "Great Britain"
|
|
|
|
},
|
|
|
|
"PhoneNumbers": [
|
|
|
|
"+44 1234567",
|
|
|
|
"+44 2345678"
|
|
|
|
]
|
|
|
|
}
|
|
|
|
```
|
|
|
|
|
|
|
|
# Rust Type-based Encoding and Decoding
|
|
|
|
|
2014-06-28 08:59:45 -05:00
|
|
|
Rust provides a mechanism for low boilerplate encoding & decoding of values to and from JSON via
|
|
|
|
the serialization API.
|
2014-02-05 10:52:54 -06:00
|
|
|
To be able to encode a piece of data, it must implement the `serialize::Encodable` trait.
|
|
|
|
To be able to decode a piece of data, it must implement the `serialize::Decodable` trait.
|
2014-06-28 08:59:45 -05:00
|
|
|
The Rust compiler provides an annotation to automatically generate the code for these traits:
|
|
|
|
`#[deriving(Decodable, Encodable)]`
|
2014-01-12 11:32:57 -06:00
|
|
|
|
2014-06-28 08:59:45 -05:00
|
|
|
The JSON API provides an enum `json::Json` and a trait `ToJson` to encode objects.
|
|
|
|
The `ToJson` trait provides a `to_json` method to convert an object into a `json::Json` value.
|
|
|
|
A `json::Json` value can be encoded as a string or buffer using the functions described above.
|
|
|
|
You can also use the `json::Encoder` object, which implements the `Encoder` trait.
|
2014-01-12 11:32:57 -06:00
|
|
|
|
|
|
|
When using `ToJson` the `Encodable` trait implementation is not mandatory.
|
|
|
|
|
|
|
|
# Examples of use
|
|
|
|
|
|
|
|
## Using Autoserialization
|
|
|
|
|
|
|
|
Create a struct called TestStruct1 and serialize and deserialize it to and from JSON
|
|
|
|
using the serialization API, using the derived serialization code.
|
|
|
|
|
|
|
|
```rust
|
2014-02-14 12:10:06 -06:00
|
|
|
extern crate serialize;
|
2014-06-28 08:59:45 -05:00
|
|
|
use serialize::json;
|
2014-01-12 11:32:57 -06:00
|
|
|
|
2014-06-28 08:59:45 -05:00
|
|
|
#[deriving(Decodable, Encodable)] //generate Decodable, Encodable impl.
|
|
|
|
pub struct TestStruct1 {
|
2014-01-12 11:32:57 -06:00
|
|
|
data_int: u8,
|
2014-05-22 18:57:53 -05:00
|
|
|
data_str: String,
|
2014-05-04 22:54:02 -05:00
|
|
|
data_vector: Vec<u8>,
|
2014-06-28 08:59:45 -05:00
|
|
|
}
|
2014-01-12 11:32:57 -06:00
|
|
|
|
|
|
|
fn main() {
|
2014-06-28 08:59:45 -05:00
|
|
|
let object = TestStruct1
|
2014-05-25 05:17:19 -05:00
|
|
|
{data_int: 1, data_str:"toto".to_string(), data_vector:vec![2,3,4,5]};
|
2014-01-12 11:32:57 -06:00
|
|
|
|
2014-06-28 08:59:45 -05:00
|
|
|
// Serialize using `json::encode`
|
|
|
|
let encoded = json::encode(&object);
|
2014-01-12 11:32:57 -06:00
|
|
|
|
2014-06-28 08:59:45 -05:00
|
|
|
// Deserialize using `json::decode`
|
|
|
|
let decoded: TestStruct1 = json::decode(encoded.as_slice()).unwrap();
|
2014-01-12 11:32:57 -06:00
|
|
|
}
|
|
|
|
```
|
|
|
|
|
|
|
|
## Using `ToJson`
|
|
|
|
|
2014-06-28 08:59:45 -05:00
|
|
|
This example uses the `ToJson` trait to generate the JSON string.
|
2014-01-12 11:32:57 -06:00
|
|
|
|
|
|
|
```rust
|
2014-05-29 21:03:06 -05:00
|
|
|
use std::collections::TreeMap;
|
2014-02-21 16:18:39 -06:00
|
|
|
use serialize::json::ToJson;
|
2014-06-28 08:59:45 -05:00
|
|
|
use serialize::json;
|
2014-01-12 11:32:57 -06:00
|
|
|
|
2014-06-28 08:59:45 -05:00
|
|
|
#[deriving(Decodable)]
|
2014-01-12 11:32:57 -06:00
|
|
|
pub struct TestStruct1 {
|
|
|
|
data_int: u8,
|
2014-05-22 18:57:53 -05:00
|
|
|
data_str: String,
|
2014-05-04 22:54:02 -05:00
|
|
|
data_vector: Vec<u8>,
|
2014-01-12 11:32:57 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
impl ToJson for TestStruct1 {
|
|
|
|
fn to_json( &self ) -> json::Json {
|
2014-06-28 08:59:45 -05:00
|
|
|
let mut d = TreeMap::new();
|
2014-05-25 05:17:19 -05:00
|
|
|
d.insert("data_int".to_string(), self.data_int.to_json());
|
|
|
|
d.insert("data_str".to_string(), self.data_str.to_json());
|
|
|
|
d.insert("data_vector".to_string(), self.data_vector.to_json());
|
2014-01-12 11:32:57 -06:00
|
|
|
json::Object(d)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn main() {
|
2014-06-28 08:59:45 -05:00
|
|
|
// Serialize using `ToJson`
|
|
|
|
let test2 = TestStruct1 {data_int: 1, data_str:"toto".to_string(), data_vector:vec![2,3,4,5]};
|
2014-01-12 11:32:57 -06:00
|
|
|
let tjson: json::Json = test2.to_json();
|
2014-06-21 05:39:03 -05:00
|
|
|
let json_str: String = tjson.to_string();
|
2014-01-12 11:32:57 -06:00
|
|
|
|
2014-06-28 08:59:45 -05:00
|
|
|
// Deserialize like before
|
|
|
|
let decoded: TestStruct1 = json::decode(json_str.as_slice()).unwrap();
|
2014-01-12 11:32:57 -06:00
|
|
|
}
|
|
|
|
```
|
|
|
|
|
|
|
|
*/
|
2012-03-07 20:17:30 -06:00
|
|
|
|
2014-06-28 07:34:58 -05:00
|
|
|
use std;
|
2014-05-29 21:03:06 -05:00
|
|
|
use std::collections::{HashMap, TreeMap};
|
2014-06-28 07:34:58 -05:00
|
|
|
use std::{char, f64, fmt, io, num, str};
|
2014-01-15 15:25:09 -06:00
|
|
|
use std::io::MemWriter;
|
2014-06-28 07:34:58 -05:00
|
|
|
use std::mem::{swap, transmute};
|
2014-06-25 20:26:41 -05:00
|
|
|
use std::num::{FPNaN, FPInfinite};
|
2014-04-11 15:21:19 -05:00
|
|
|
use std::str::ScalarValue;
|
2014-05-22 18:57:53 -05:00
|
|
|
use std::string::String;
|
2014-03-30 07:58:02 -05:00
|
|
|
use std::vec::Vec;
|
2013-03-13 13:29:05 -05:00
|
|
|
|
2014-02-21 16:18:39 -06:00
|
|
|
use Encodable;
|
2011-11-07 13:01:28 -06:00
|
|
|
|
2012-07-04 16:53:12 -05:00
|
|
|
/// Represents a json value
|
2014-06-18 01:25:51 -05:00
|
|
|
#[deriving(Clone, PartialEq, PartialOrd)]
|
2012-09-24 11:55:42 -05:00
|
|
|
pub enum Json {
|
2013-09-26 01:26:09 -05:00
|
|
|
Number(f64),
|
2014-05-22 18:57:53 -05:00
|
|
|
String(String),
|
2012-08-11 09:08:42 -05:00
|
|
|
Boolean(bool),
|
2012-09-24 11:55:42 -05:00
|
|
|
List(List),
|
2014-06-28 07:41:40 -05:00
|
|
|
Object(Object),
|
2012-08-11 09:08:42 -05:00
|
|
|
Null,
|
2011-11-07 13:01:28 -06:00
|
|
|
}
|
|
|
|
|
2014-05-04 01:34:26 -05:00
|
|
|
pub type List = Vec<Json>;
|
2014-05-22 18:57:53 -05:00
|
|
|
pub type Object = TreeMap<String, Json>;
|
2012-09-24 11:55:42 -05:00
|
|
|
|
2014-03-30 07:58:02 -05:00
|
|
|
/// The errors that can arise while parsing a JSON stream.
|
2014-05-29 19:45:07 -05:00
|
|
|
#[deriving(Clone, PartialEq)]
|
2014-03-30 07:58:02 -05:00
|
|
|
pub enum ErrorCode {
|
|
|
|
InvalidSyntax,
|
|
|
|
InvalidNumber,
|
|
|
|
EOFWhileParsingObject,
|
|
|
|
EOFWhileParsingList,
|
|
|
|
EOFWhileParsingValue,
|
|
|
|
EOFWhileParsingString,
|
|
|
|
KeyMustBeAString,
|
|
|
|
ExpectedColon,
|
|
|
|
TrailingCharacters,
|
|
|
|
InvalidEscape,
|
|
|
|
InvalidUnicodeCodePoint,
|
|
|
|
LoneLeadingSurrogateInHexEscape,
|
|
|
|
UnexpectedEndOfHexEscape,
|
|
|
|
UnrecognizedHex,
|
|
|
|
NotFourDigit,
|
|
|
|
NotUtf8,
|
|
|
|
}
|
|
|
|
|
2014-05-29 19:45:07 -05:00
|
|
|
#[deriving(Clone, PartialEq, Show)]
|
2014-03-30 07:58:02 -05:00
|
|
|
pub enum ParserError {
|
2014-03-18 12:58:26 -05:00
|
|
|
/// msg, line, col
|
2014-03-30 07:58:02 -05:00
|
|
|
SyntaxError(ErrorCode, uint, uint),
|
|
|
|
IoError(io::IoErrorKind, &'static str),
|
|
|
|
}
|
|
|
|
|
|
|
|
// Builder and Parser have the same errors.
|
|
|
|
pub type BuilderError = ParserError;
|
|
|
|
|
2014-05-29 19:45:07 -05:00
|
|
|
#[deriving(Clone, PartialEq, Show)]
|
2014-03-30 07:58:02 -05:00
|
|
|
pub enum DecoderError {
|
|
|
|
ParseError(ParserError),
|
2014-05-22 18:57:53 -05:00
|
|
|
ExpectedError(String, String),
|
|
|
|
MissingFieldError(String),
|
|
|
|
UnknownVariantError(String),
|
2014-03-30 07:58:02 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
/// Returns a readable error string for a given error code.
|
|
|
|
pub fn error_str(error: ErrorCode) -> &'static str {
|
|
|
|
return match error {
|
|
|
|
InvalidSyntax => "invalid syntax",
|
|
|
|
InvalidNumber => "invalid number",
|
|
|
|
EOFWhileParsingObject => "EOF While parsing object",
|
|
|
|
EOFWhileParsingList => "EOF While parsing list",
|
|
|
|
EOFWhileParsingValue => "EOF While parsing value",
|
|
|
|
EOFWhileParsingString => "EOF While parsing string",
|
|
|
|
KeyMustBeAString => "key must be a string",
|
|
|
|
ExpectedColon => "expected `:`",
|
|
|
|
TrailingCharacters => "trailing characters",
|
|
|
|
InvalidEscape => "invalid escape",
|
|
|
|
UnrecognizedHex => "invalid \\u escape (unrecognized hex)",
|
|
|
|
NotFourDigit => "invalid \\u escape (not four digits)",
|
|
|
|
NotUtf8 => "contents not utf-8",
|
|
|
|
InvalidUnicodeCodePoint => "invalid unicode code point",
|
|
|
|
LoneLeadingSurrogateInHexEscape => "lone leading surrogate in hex escape",
|
|
|
|
UnexpectedEndOfHexEscape => "unexpected end of hex escape",
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-06-28 08:33:37 -05:00
|
|
|
/// Shortcut function to decode a JSON `&str` into an object
|
|
|
|
pub fn decode<T: ::Decodable<Decoder, DecoderError>>(s: &str) -> DecodeResult<T> {
|
|
|
|
let json = match from_str(s) {
|
|
|
|
Ok(x) => x,
|
|
|
|
Err(e) => return Err(ParseError(e))
|
|
|
|
};
|
|
|
|
|
|
|
|
let mut decoder = Decoder::new(json);
|
|
|
|
::Decodable::decode(&mut decoder)
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Shortcut function to encode a `T` into a JSON `String`
|
|
|
|
pub fn encode<'a, T: Encodable<Encoder<'a>, io::IoError>>(object: &T) -> String {
|
|
|
|
let buff = Encoder::buffer_encode(object);
|
|
|
|
str::from_utf8_owned(buff).unwrap()
|
|
|
|
}
|
|
|
|
|
2014-03-30 07:58:02 -05:00
|
|
|
impl fmt::Show for ErrorCode {
|
|
|
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
|
|
error_str(*self).fmt(f)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn io_error_to_error(io: io::IoError) -> ParserError {
|
|
|
|
IoError(io.kind, io.desc)
|
2012-09-24 11:55:42 -05:00
|
|
|
}
|
2012-02-25 18:39:32 -06:00
|
|
|
|
2014-03-18 12:58:26 -05:00
|
|
|
pub type EncodeResult = io::IoResult<()>;
|
2014-03-30 07:58:02 -05:00
|
|
|
pub type DecodeResult<T> = Result<T, DecoderError>;
|
2014-01-29 19:39:12 -06:00
|
|
|
|
2014-07-04 18:36:49 -05:00
|
|
|
pub fn escape_bytes(wr: &mut io::Writer, bytes: &[u8]) -> Result<(), io::IoError> {
|
|
|
|
try!(wr.write_str("\""));
|
|
|
|
|
|
|
|
let mut start = 0;
|
|
|
|
|
|
|
|
for (i, byte) in bytes.iter().enumerate() {
|
|
|
|
let escaped = match *byte {
|
|
|
|
b'"' => "\\\"",
|
|
|
|
b'\\' => "\\\\",
|
|
|
|
b'\x08' => "\\b",
|
|
|
|
b'\x0c' => "\\f",
|
|
|
|
b'\n' => "\\n",
|
|
|
|
b'\r' => "\\r",
|
|
|
|
b'\t' => "\\t",
|
|
|
|
_ => { continue; }
|
|
|
|
};
|
|
|
|
|
|
|
|
if start < i {
|
|
|
|
try!(wr.write(bytes.slice(start, i)));
|
2011-11-07 13:01:28 -06:00
|
|
|
}
|
2014-07-04 18:36:49 -05:00
|
|
|
|
|
|
|
try!(wr.write_str(escaped));
|
|
|
|
|
|
|
|
start = i + 1;
|
2014-07-04 13:08:38 -05:00
|
|
|
}
|
2014-07-04 18:36:49 -05:00
|
|
|
|
|
|
|
if start != bytes.len() {
|
|
|
|
try!(wr.write(bytes.slice_from(start)));
|
|
|
|
}
|
|
|
|
|
|
|
|
wr.write_str("\"")
|
2014-07-04 13:08:38 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
fn escape_str(writer: &mut io::Writer, v: &str) -> Result<(), io::IoError> {
|
|
|
|
escape_bytes(writer, v.as_bytes())
|
|
|
|
}
|
|
|
|
|
|
|
|
fn escape_char(writer: &mut io::Writer, v: char) -> Result<(), io::IoError> {
|
|
|
|
let mut buf = [0, .. 4];
|
|
|
|
v.encode_utf8(buf);
|
|
|
|
escape_bytes(writer, buf)
|
|
|
|
}
|
|
|
|
|
2014-07-04 18:56:23 -05:00
|
|
|
fn spaces(wr: &mut io::Writer, mut n: uint) -> Result<(), io::IoError> {
|
|
|
|
static len: uint = 16;
|
|
|
|
static buf: [u8, ..len] = [b' ', ..len];
|
|
|
|
|
|
|
|
while n >= len {
|
|
|
|
try!(wr.write(buf));
|
|
|
|
n -= len;
|
|
|
|
}
|
|
|
|
|
|
|
|
if n > 0 {
|
|
|
|
wr.write(buf.slice_to(n))
|
|
|
|
} else {
|
|
|
|
Ok(())
|
2014-07-04 13:08:38 -05:00
|
|
|
}
|
2011-11-07 13:01:28 -06:00
|
|
|
}
|
|
|
|
|
2014-06-25 20:26:41 -05:00
|
|
|
fn fmt_number_or_null(v: f64) -> String {
|
|
|
|
match v.classify() {
|
|
|
|
FPNaN | FPInfinite => String::from_str("null"),
|
|
|
|
_ => f64::to_str_digits(v, 6u)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-05-28 22:11:41 -05:00
|
|
|
/// A structure for implementing serialization to JSON.
|
2013-12-10 01:16:18 -06:00
|
|
|
pub struct Encoder<'a> {
|
2014-06-28 07:34:58 -05:00
|
|
|
writer: &'a mut io::Writer,
|
2012-09-24 11:55:42 -05:00
|
|
|
}
|
|
|
|
|
2013-12-10 01:16:18 -06:00
|
|
|
impl<'a> Encoder<'a> {
|
2013-11-29 13:11:52 -06:00
|
|
|
/// Creates a new JSON encoder whose output will be written to the writer
|
|
|
|
/// specified.
|
2014-06-28 07:34:58 -05:00
|
|
|
pub fn new(writer: &'a mut io::Writer) -> Encoder<'a> {
|
|
|
|
Encoder { writer: writer }
|
2013-11-29 13:11:52 -06:00
|
|
|
}
|
2014-01-12 11:32:57 -06:00
|
|
|
|
|
|
|
/// Encode the specified struct into a json [u8]
|
2014-06-28 07:34:58 -05:00
|
|
|
pub fn buffer_encode<T:Encodable<Encoder<'a>, io::IoError>>(object: &T) -> Vec<u8> {
|
|
|
|
//Serialize the object in a string using a writer
|
2014-01-12 11:32:57 -06:00
|
|
|
let mut m = MemWriter::new();
|
2014-06-11 00:18:57 -05:00
|
|
|
// FIXME(14302) remove the transmute and unsafe block.
|
|
|
|
unsafe {
|
2014-01-12 11:32:57 -06:00
|
|
|
let mut encoder = Encoder::new(&mut m as &mut io::Writer);
|
2014-03-18 12:58:26 -05:00
|
|
|
// MemWriter never Errs
|
2014-06-28 07:34:58 -05:00
|
|
|
let _ = object.encode(transmute(&mut encoder));
|
2014-01-12 11:32:57 -06:00
|
|
|
}
|
2014-01-19 02:39:07 -06:00
|
|
|
m.unwrap()
|
2014-01-12 11:32:57 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
/// Encode the specified struct into a json str
|
2014-06-28 08:33:37 -05:00
|
|
|
///
|
|
|
|
/// Note: this function is deprecated. Consider using `json::encode` instead.
|
|
|
|
#[deprecated = "Replaced by `json::encode`"]
|
2014-06-28 07:34:58 -05:00
|
|
|
pub fn str_encode<T: Encodable<Encoder<'a>, io::IoError>>(object: &T) -> String {
|
2014-06-28 08:33:37 -05:00
|
|
|
encode(object)
|
2014-01-12 11:32:57 -06:00
|
|
|
}
|
2012-09-24 11:55:42 -05:00
|
|
|
}
|
|
|
|
|
2014-03-18 12:58:26 -05:00
|
|
|
impl<'a> ::Encoder<io::IoError> for Encoder<'a> {
|
2014-06-28 07:34:58 -05:00
|
|
|
fn emit_nil(&mut self) -> EncodeResult { write!(self.writer, "null") }
|
2013-05-01 19:54:54 -05:00
|
|
|
|
2014-03-18 12:58:26 -05:00
|
|
|
fn emit_uint(&mut self, v: uint) -> EncodeResult { self.emit_f64(v as f64) }
|
|
|
|
fn emit_u64(&mut self, v: u64) -> EncodeResult { self.emit_f64(v as f64) }
|
|
|
|
fn emit_u32(&mut self, v: u32) -> EncodeResult { self.emit_f64(v as f64) }
|
|
|
|
fn emit_u16(&mut self, v: u16) -> EncodeResult { self.emit_f64(v as f64) }
|
|
|
|
fn emit_u8(&mut self, v: u8) -> EncodeResult { self.emit_f64(v as f64) }
|
2013-05-01 19:54:54 -05:00
|
|
|
|
2014-03-18 12:58:26 -05:00
|
|
|
fn emit_int(&mut self, v: int) -> EncodeResult { self.emit_f64(v as f64) }
|
|
|
|
fn emit_i64(&mut self, v: i64) -> EncodeResult { self.emit_f64(v as f64) }
|
|
|
|
fn emit_i32(&mut self, v: i32) -> EncodeResult { self.emit_f64(v as f64) }
|
|
|
|
fn emit_i16(&mut self, v: i16) -> EncodeResult { self.emit_f64(v as f64) }
|
|
|
|
fn emit_i8(&mut self, v: i8) -> EncodeResult { self.emit_f64(v as f64) }
|
2013-05-01 19:54:54 -05:00
|
|
|
|
2014-03-18 12:58:26 -05:00
|
|
|
fn emit_bool(&mut self, v: bool) -> EncodeResult {
|
2013-05-01 19:54:54 -05:00
|
|
|
if v {
|
2014-06-28 07:34:58 -05:00
|
|
|
write!(self.writer, "true")
|
2013-05-01 19:54:54 -05:00
|
|
|
} else {
|
2014-06-28 07:34:58 -05:00
|
|
|
write!(self.writer, "false")
|
2013-05-01 19:54:54 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-03-18 12:58:26 -05:00
|
|
|
fn emit_f64(&mut self, v: f64) -> EncodeResult {
|
2014-06-28 07:34:58 -05:00
|
|
|
write!(self.writer, "{}", fmt_number_or_null(v))
|
2013-10-13 20:48:47 -05:00
|
|
|
}
|
2014-03-18 12:58:26 -05:00
|
|
|
fn emit_f32(&mut self, v: f32) -> EncodeResult { self.emit_f64(v as f64) }
|
2013-05-01 19:54:54 -05:00
|
|
|
|
2014-05-19 19:23:26 -05:00
|
|
|
fn emit_char(&mut self, v: char) -> EncodeResult {
|
2014-07-04 13:08:38 -05:00
|
|
|
escape_char(self.writer, v)
|
2014-05-19 19:23:26 -05:00
|
|
|
}
|
2014-03-18 12:58:26 -05:00
|
|
|
fn emit_str(&mut self, v: &str) -> EncodeResult {
|
2014-07-04 13:08:38 -05:00
|
|
|
escape_str(self.writer, v)
|
2013-10-13 20:48:47 -05:00
|
|
|
}
|
2013-05-01 19:54:54 -05:00
|
|
|
|
2014-06-28 07:34:58 -05:00
|
|
|
fn emit_enum(&mut self, _name: &str, f: |&mut Encoder<'a>| -> EncodeResult) -> EncodeResult {
|
|
|
|
f(self)
|
|
|
|
}
|
2013-05-01 19:54:54 -05:00
|
|
|
|
2014-05-28 11:24:28 -05:00
|
|
|
fn emit_enum_variant(&mut self,
|
|
|
|
name: &str,
|
|
|
|
_id: uint,
|
|
|
|
cnt: uint,
|
|
|
|
f: |&mut Encoder<'a>| -> EncodeResult) -> EncodeResult {
|
|
|
|
// enums are encoded as strings or objects
|
|
|
|
// Bunny => "Bunny"
|
|
|
|
// Kangaroo(34,"William") => {"variant": "Kangaroo", "fields": [34,"William"]}
|
|
|
|
if cnt == 0 {
|
2014-07-04 13:08:38 -05:00
|
|
|
escape_str(self.writer, name)
|
2014-05-28 11:24:28 -05:00
|
|
|
} else {
|
2014-06-28 07:34:58 -05:00
|
|
|
try!(write!(self.writer, "{{\"variant\":"));
|
2014-07-04 13:08:38 -05:00
|
|
|
try!(escape_str(self.writer, name));
|
2014-06-28 07:34:58 -05:00
|
|
|
try!(write!(self.writer, ",\"fields\":["));
|
2014-05-28 11:24:28 -05:00
|
|
|
try!(f(self));
|
2014-06-28 07:34:58 -05:00
|
|
|
write!(self.writer, "]}}")
|
2014-05-28 11:24:28 -05:00
|
|
|
}
|
|
|
|
}
|
2013-05-01 19:54:54 -05:00
|
|
|
|
2014-03-18 12:58:26 -05:00
|
|
|
fn emit_enum_variant_arg(&mut self,
|
|
|
|
idx: uint,
|
|
|
|
f: |&mut Encoder<'a>| -> EncodeResult) -> EncodeResult {
|
2013-05-01 19:54:54 -05:00
|
|
|
if idx != 0 {
|
2014-06-28 07:34:58 -05:00
|
|
|
try!(write!(self.writer, ","));
|
2013-05-01 19:54:54 -05:00
|
|
|
}
|
2014-03-18 12:58:26 -05:00
|
|
|
f(self)
|
2013-05-01 19:54:54 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
fn emit_enum_struct_variant(&mut self,
|
|
|
|
name: &str,
|
|
|
|
id: uint,
|
|
|
|
cnt: uint,
|
2014-03-18 12:58:26 -05:00
|
|
|
f: |&mut Encoder<'a>| -> EncodeResult) -> EncodeResult {
|
2013-05-01 19:54:54 -05:00
|
|
|
self.emit_enum_variant(name, id, cnt, f)
|
|
|
|
}
|
|
|
|
|
|
|
|
fn emit_enum_struct_variant_field(&mut self,
|
|
|
|
_: &str,
|
|
|
|
idx: uint,
|
2014-03-18 12:58:26 -05:00
|
|
|
f: |&mut Encoder<'a>| -> EncodeResult) -> EncodeResult {
|
2013-05-01 19:54:54 -05:00
|
|
|
self.emit_enum_variant_arg(idx, f)
|
|
|
|
}
|
|
|
|
|
2014-05-28 11:24:28 -05:00
|
|
|
fn emit_struct(&mut self,
|
|
|
|
_: &str,
|
|
|
|
_: uint,
|
|
|
|
f: |&mut Encoder<'a>| -> EncodeResult) -> EncodeResult {
|
2014-06-28 07:34:58 -05:00
|
|
|
try!(write!(self.writer, "{{"));
|
2014-05-28 11:24:28 -05:00
|
|
|
try!(f(self));
|
2014-06-28 07:34:58 -05:00
|
|
|
write!(self.writer, "}}")
|
2014-05-28 11:24:28 -05:00
|
|
|
}
|
2013-05-01 19:54:54 -05:00
|
|
|
|
|
|
|
fn emit_struct_field(&mut self,
|
|
|
|
name: &str,
|
|
|
|
idx: uint,
|
2014-03-18 12:58:26 -05:00
|
|
|
f: |&mut Encoder<'a>| -> EncodeResult) -> EncodeResult {
|
2014-06-28 07:34:58 -05:00
|
|
|
if idx != 0 { try!(write!(self.writer, ",")); }
|
2014-07-04 13:08:38 -05:00
|
|
|
try!(escape_str(self.writer, name));
|
|
|
|
try!(write!(self.writer, ":"));
|
2014-03-18 12:58:26 -05:00
|
|
|
f(self)
|
2013-05-01 19:54:54 -05:00
|
|
|
}
|
|
|
|
|
2014-03-18 12:58:26 -05:00
|
|
|
fn emit_tuple(&mut self, len: uint, f: |&mut Encoder<'a>| -> EncodeResult) -> EncodeResult {
|
2013-05-01 19:54:54 -05:00
|
|
|
self.emit_seq(len, f)
|
|
|
|
}
|
2014-03-18 12:58:26 -05:00
|
|
|
fn emit_tuple_arg(&mut self,
|
|
|
|
idx: uint,
|
|
|
|
f: |&mut Encoder<'a>| -> EncodeResult) -> EncodeResult {
|
2013-05-01 19:54:54 -05:00
|
|
|
self.emit_seq_elt(idx, f)
|
|
|
|
}
|
|
|
|
|
|
|
|
fn emit_tuple_struct(&mut self,
|
|
|
|
_name: &str,
|
|
|
|
len: uint,
|
2014-03-18 12:58:26 -05:00
|
|
|
f: |&mut Encoder<'a>| -> EncodeResult) -> EncodeResult {
|
2013-05-01 19:54:54 -05:00
|
|
|
self.emit_seq(len, f)
|
|
|
|
}
|
2014-03-18 12:58:26 -05:00
|
|
|
fn emit_tuple_struct_arg(&mut self,
|
|
|
|
idx: uint,
|
|
|
|
f: |&mut Encoder<'a>| -> EncodeResult) -> EncodeResult {
|
2013-05-01 19:54:54 -05:00
|
|
|
self.emit_seq_elt(idx, f)
|
|
|
|
}
|
|
|
|
|
2014-03-18 12:58:26 -05:00
|
|
|
fn emit_option(&mut self, f: |&mut Encoder<'a>| -> EncodeResult) -> EncodeResult {
|
|
|
|
f(self)
|
|
|
|
}
|
|
|
|
fn emit_option_none(&mut self) -> EncodeResult { self.emit_nil() }
|
|
|
|
fn emit_option_some(&mut self, f: |&mut Encoder<'a>| -> EncodeResult) -> EncodeResult {
|
|
|
|
f(self)
|
|
|
|
}
|
2013-05-01 19:54:54 -05:00
|
|
|
|
2014-03-18 12:58:26 -05:00
|
|
|
fn emit_seq(&mut self, _len: uint, f: |&mut Encoder<'a>| -> EncodeResult) -> EncodeResult {
|
2014-06-28 07:34:58 -05:00
|
|
|
try!(write!(self.writer, "["));
|
2014-03-18 12:58:26 -05:00
|
|
|
try!(f(self));
|
2014-06-28 07:34:58 -05:00
|
|
|
write!(self.writer, "]")
|
2013-05-01 19:54:54 -05:00
|
|
|
}
|
|
|
|
|
2014-03-18 12:58:26 -05:00
|
|
|
fn emit_seq_elt(&mut self, idx: uint, f: |&mut Encoder<'a>| -> EncodeResult) -> EncodeResult {
|
2013-05-01 19:54:54 -05:00
|
|
|
if idx != 0 {
|
2014-06-28 07:34:58 -05:00
|
|
|
try!(write!(self.writer, ","));
|
2013-05-01 19:54:54 -05:00
|
|
|
}
|
|
|
|
f(self)
|
|
|
|
}
|
|
|
|
|
2014-05-28 11:24:28 -05:00
|
|
|
fn emit_map(&mut self, _len: uint, f: |&mut Encoder<'a>| -> EncodeResult) -> EncodeResult {
|
2014-06-28 07:34:58 -05:00
|
|
|
try!(write!(self.writer, "{{"));
|
2014-05-28 11:24:28 -05:00
|
|
|
try!(f(self));
|
2014-06-28 07:34:58 -05:00
|
|
|
write!(self.writer, "}}")
|
2014-05-28 11:24:28 -05:00
|
|
|
}
|
2013-05-01 19:54:54 -05:00
|
|
|
|
2014-03-18 12:58:26 -05:00
|
|
|
fn emit_map_elt_key(&mut self,
|
|
|
|
idx: uint,
|
|
|
|
f: |&mut Encoder<'a>| -> EncodeResult) -> EncodeResult {
|
2014-06-28 07:34:58 -05:00
|
|
|
if idx != 0 { try!(write!(self.writer, ",")) }
|
2014-03-17 02:26:36 -05:00
|
|
|
// ref #12967, make sure to wrap a key in double quotes,
|
|
|
|
// in the event that its of a type that omits them (eg numbers)
|
|
|
|
let mut buf = MemWriter::new();
|
2014-06-11 00:18:57 -05:00
|
|
|
// FIXME(14302) remove the transmute and unsafe block.
|
|
|
|
unsafe {
|
|
|
|
let mut check_encoder = Encoder::new(&mut buf);
|
|
|
|
try!(f(transmute(&mut check_encoder)));
|
|
|
|
}
|
2014-06-28 07:34:58 -05:00
|
|
|
let out = str::from_utf8_owned(buf.unwrap()).unwrap();
|
|
|
|
let out = out.as_slice();
|
|
|
|
let needs_wrapping = out.char_at(0) != '"' && out.char_at_reverse(out.len()) != '"';
|
|
|
|
if needs_wrapping { try!(write!(self.writer, "\"")); }
|
2014-03-18 12:58:26 -05:00
|
|
|
try!(f(self));
|
2014-06-28 07:34:58 -05:00
|
|
|
if needs_wrapping { try!(write!(self.writer, "\"")); }
|
2014-03-18 12:58:26 -05:00
|
|
|
Ok(())
|
2013-05-01 19:54:54 -05:00
|
|
|
}
|
|
|
|
|
2014-03-18 12:58:26 -05:00
|
|
|
fn emit_map_elt_val(&mut self,
|
|
|
|
_idx: uint,
|
|
|
|
f: |&mut Encoder<'a>| -> EncodeResult) -> EncodeResult {
|
2014-06-28 07:34:58 -05:00
|
|
|
try!(write!(self.writer, ":"));
|
2013-05-01 19:54:54 -05:00
|
|
|
f(self)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-05-28 22:11:41 -05:00
|
|
|
/// Another encoder for JSON, but prints out human-readable JSON instead of
|
|
|
|
/// compact data
|
2013-12-10 01:16:18 -06:00
|
|
|
pub struct PrettyEncoder<'a> {
|
2014-06-28 07:34:58 -05:00
|
|
|
writer: &'a mut io::Writer,
|
2014-03-27 17:13:35 -05:00
|
|
|
indent: uint,
|
2013-05-03 19:55:53 -05:00
|
|
|
}
|
|
|
|
|
2013-12-10 01:16:18 -06:00
|
|
|
impl<'a> PrettyEncoder<'a> {
|
2013-11-29 13:11:52 -06:00
|
|
|
/// Creates a new encoder whose output will be written to the specified writer
|
2014-06-28 07:34:58 -05:00
|
|
|
pub fn new<'a>(writer: &'a mut io::Writer) -> PrettyEncoder<'a> {
|
|
|
|
PrettyEncoder { writer: writer, indent: 0 }
|
2013-05-01 19:54:54 -05:00
|
|
|
}
|
2012-09-24 11:55:42 -05:00
|
|
|
}
|
2012-08-30 18:39:56 -05:00
|
|
|
|
2014-03-18 12:58:26 -05:00
|
|
|
impl<'a> ::Encoder<io::IoError> for PrettyEncoder<'a> {
|
2014-06-28 07:34:58 -05:00
|
|
|
fn emit_nil(&mut self) -> EncodeResult { write!(self.writer, "null") }
|
2013-05-01 19:54:54 -05:00
|
|
|
|
2014-03-18 12:58:26 -05:00
|
|
|
fn emit_uint(&mut self, v: uint) -> EncodeResult { self.emit_f64(v as f64) }
|
|
|
|
fn emit_u64(&mut self, v: u64) -> EncodeResult { self.emit_f64(v as f64) }
|
|
|
|
fn emit_u32(&mut self, v: u32) -> EncodeResult { self.emit_f64(v as f64) }
|
|
|
|
fn emit_u16(&mut self, v: u16) -> EncodeResult { self.emit_f64(v as f64) }
|
|
|
|
fn emit_u8(&mut self, v: u8) -> EncodeResult { self.emit_f64(v as f64) }
|
2013-05-01 19:54:54 -05:00
|
|
|
|
2014-03-18 12:58:26 -05:00
|
|
|
fn emit_int(&mut self, v: int) -> EncodeResult { self.emit_f64(v as f64) }
|
|
|
|
fn emit_i64(&mut self, v: i64) -> EncodeResult { self.emit_f64(v as f64) }
|
|
|
|
fn emit_i32(&mut self, v: i32) -> EncodeResult { self.emit_f64(v as f64) }
|
|
|
|
fn emit_i16(&mut self, v: i16) -> EncodeResult { self.emit_f64(v as f64) }
|
|
|
|
fn emit_i8(&mut self, v: i8) -> EncodeResult { self.emit_f64(v as f64) }
|
2013-05-01 19:54:54 -05:00
|
|
|
|
2014-03-18 12:58:26 -05:00
|
|
|
fn emit_bool(&mut self, v: bool) -> EncodeResult {
|
2013-05-01 19:54:54 -05:00
|
|
|
if v {
|
2014-06-28 07:34:58 -05:00
|
|
|
write!(self.writer, "true")
|
2013-05-01 19:54:54 -05:00
|
|
|
} else {
|
2014-06-28 07:34:58 -05:00
|
|
|
write!(self.writer, "false")
|
2013-05-01 19:54:54 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-03-18 12:58:26 -05:00
|
|
|
fn emit_f64(&mut self, v: f64) -> EncodeResult {
|
2014-06-28 07:34:58 -05:00
|
|
|
write!(self.writer, "{}", fmt_number_or_null(v))
|
2013-10-13 20:48:47 -05:00
|
|
|
}
|
2014-05-19 19:23:26 -05:00
|
|
|
fn emit_f32(&mut self, v: f32) -> EncodeResult {
|
|
|
|
self.emit_f64(v as f64)
|
|
|
|
}
|
2013-05-01 19:54:54 -05:00
|
|
|
|
2014-05-19 19:23:26 -05:00
|
|
|
fn emit_char(&mut self, v: char) -> EncodeResult {
|
2014-07-04 13:08:38 -05:00
|
|
|
escape_char(self.writer, v)
|
2014-05-19 19:23:26 -05:00
|
|
|
}
|
2014-03-18 12:58:26 -05:00
|
|
|
fn emit_str(&mut self, v: &str) -> EncodeResult {
|
2014-07-04 13:08:38 -05:00
|
|
|
escape_str(self.writer, v)
|
2014-01-29 19:39:12 -06:00
|
|
|
}
|
2013-05-01 19:54:54 -05:00
|
|
|
|
2014-03-18 12:58:26 -05:00
|
|
|
fn emit_enum(&mut self,
|
|
|
|
_name: &str,
|
|
|
|
f: |&mut PrettyEncoder<'a>| -> EncodeResult) -> EncodeResult {
|
2013-05-01 19:54:54 -05:00
|
|
|
f(self)
|
|
|
|
}
|
|
|
|
|
|
|
|
fn emit_enum_variant(&mut self,
|
|
|
|
name: &str,
|
|
|
|
_: uint,
|
|
|
|
cnt: uint,
|
2014-03-18 12:58:26 -05:00
|
|
|
f: |&mut PrettyEncoder<'a>| -> EncodeResult) -> EncodeResult {
|
2013-05-01 19:54:54 -05:00
|
|
|
if cnt == 0 {
|
2014-07-04 13:08:38 -05:00
|
|
|
escape_str(self.writer, name)
|
2013-05-01 19:54:54 -05:00
|
|
|
} else {
|
|
|
|
self.indent += 2;
|
2014-07-04 13:08:38 -05:00
|
|
|
try!(write!(self.writer, "[\n"));
|
|
|
|
try!(spaces(self.writer, self.indent));
|
|
|
|
try!(escape_str(self.writer, name));
|
|
|
|
try!(write!(self.writer, ",\n"));
|
2014-03-18 12:58:26 -05:00
|
|
|
try!(f(self));
|
2013-05-01 19:54:54 -05:00
|
|
|
self.indent -= 2;
|
2014-07-04 13:08:38 -05:00
|
|
|
try!(write!(self.writer, "\n"));
|
|
|
|
try!(spaces(self.writer, self.indent));
|
|
|
|
write!(self.writer, "]")
|
2013-05-01 19:54:54 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn emit_enum_variant_arg(&mut self,
|
|
|
|
idx: uint,
|
2014-03-18 12:58:26 -05:00
|
|
|
f: |&mut PrettyEncoder<'a>| -> EncodeResult) -> EncodeResult {
|
2013-05-01 19:54:54 -05:00
|
|
|
if idx != 0 {
|
2014-06-28 07:34:58 -05:00
|
|
|
try!(write!(self.writer, ",\n"));
|
2013-05-01 19:54:54 -05:00
|
|
|
}
|
2014-07-04 13:08:38 -05:00
|
|
|
try!(spaces(self.writer, self.indent));
|
2013-05-01 19:54:54 -05:00
|
|
|
f(self)
|
|
|
|
}
|
|
|
|
|
|
|
|
fn emit_enum_struct_variant(&mut self,
|
|
|
|
name: &str,
|
|
|
|
id: uint,
|
|
|
|
cnt: uint,
|
2014-03-18 12:58:26 -05:00
|
|
|
f: |&mut PrettyEncoder<'a>| -> EncodeResult) -> EncodeResult {
|
2013-05-01 19:54:54 -05:00
|
|
|
self.emit_enum_variant(name, id, cnt, f)
|
|
|
|
}
|
|
|
|
|
|
|
|
fn emit_enum_struct_variant_field(&mut self,
|
|
|
|
_: &str,
|
|
|
|
idx: uint,
|
2014-03-18 12:58:26 -05:00
|
|
|
f: |&mut PrettyEncoder<'a>| -> EncodeResult) -> EncodeResult {
|
2013-05-01 19:54:54 -05:00
|
|
|
self.emit_enum_variant_arg(idx, f)
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2014-05-28 11:24:28 -05:00
|
|
|
fn emit_struct(&mut self,
|
|
|
|
_: &str,
|
|
|
|
len: uint,
|
|
|
|
f: |&mut PrettyEncoder<'a>| -> EncodeResult) -> EncodeResult {
|
|
|
|
if len == 0 {
|
2014-06-28 07:34:58 -05:00
|
|
|
write!(self.writer, "{{}}")
|
2014-05-28 11:24:28 -05:00
|
|
|
} else {
|
2014-06-28 07:34:58 -05:00
|
|
|
try!(write!(self.writer, "{{"));
|
2014-05-28 11:24:28 -05:00
|
|
|
self.indent += 2;
|
|
|
|
try!(f(self));
|
|
|
|
self.indent -= 2;
|
2014-07-04 13:08:38 -05:00
|
|
|
try!(write!(self.writer, "\n"));
|
|
|
|
try!(spaces(self.writer, self.indent));
|
|
|
|
write!(self.writer, "}}")
|
2014-05-28 11:24:28 -05:00
|
|
|
}
|
|
|
|
}
|
2013-05-01 19:54:54 -05:00
|
|
|
|
|
|
|
fn emit_struct_field(&mut self,
|
|
|
|
name: &str,
|
|
|
|
idx: uint,
|
2014-03-18 12:58:26 -05:00
|
|
|
f: |&mut PrettyEncoder<'a>| -> EncodeResult) -> EncodeResult {
|
2013-05-01 19:54:54 -05:00
|
|
|
if idx == 0 {
|
2014-06-28 07:34:58 -05:00
|
|
|
try!(write!(self.writer, "\n"));
|
2013-05-01 19:54:54 -05:00
|
|
|
} else {
|
2014-06-28 07:34:58 -05:00
|
|
|
try!(write!(self.writer, ",\n"));
|
2013-05-01 19:54:54 -05:00
|
|
|
}
|
2014-07-04 13:08:38 -05:00
|
|
|
try!(spaces(self.writer, self.indent));
|
|
|
|
try!(escape_str(self.writer, name));
|
|
|
|
try!(write!(self.writer, ": "));
|
2014-03-18 12:58:26 -05:00
|
|
|
f(self)
|
2013-05-01 19:54:54 -05:00
|
|
|
}
|
|
|
|
|
2014-03-18 12:58:26 -05:00
|
|
|
fn emit_tuple(&mut self,
|
|
|
|
len: uint,
|
|
|
|
f: |&mut PrettyEncoder<'a>| -> EncodeResult) -> EncodeResult {
|
2013-05-01 19:54:54 -05:00
|
|
|
self.emit_seq(len, f)
|
|
|
|
}
|
2014-03-18 12:58:26 -05:00
|
|
|
fn emit_tuple_arg(&mut self,
|
|
|
|
idx: uint,
|
|
|
|
f: |&mut PrettyEncoder<'a>| -> EncodeResult) -> EncodeResult {
|
2013-05-01 19:54:54 -05:00
|
|
|
self.emit_seq_elt(idx, f)
|
|
|
|
}
|
|
|
|
|
|
|
|
fn emit_tuple_struct(&mut self,
|
|
|
|
_: &str,
|
|
|
|
len: uint,
|
2014-03-18 12:58:26 -05:00
|
|
|
f: |&mut PrettyEncoder<'a>| -> EncodeResult) -> EncodeResult {
|
2013-05-01 19:54:54 -05:00
|
|
|
self.emit_seq(len, f)
|
|
|
|
}
|
|
|
|
fn emit_tuple_struct_arg(&mut self,
|
|
|
|
idx: uint,
|
2014-03-18 12:58:26 -05:00
|
|
|
f: |&mut PrettyEncoder<'a>| -> EncodeResult) -> EncodeResult {
|
2013-05-01 19:54:54 -05:00
|
|
|
self.emit_seq_elt(idx, f)
|
|
|
|
}
|
|
|
|
|
2014-03-18 12:58:26 -05:00
|
|
|
fn emit_option(&mut self, f: |&mut PrettyEncoder<'a>| -> EncodeResult) -> EncodeResult {
|
|
|
|
f(self)
|
|
|
|
}
|
|
|
|
fn emit_option_none(&mut self) -> EncodeResult { self.emit_nil() }
|
|
|
|
fn emit_option_some(&mut self, f: |&mut PrettyEncoder<'a>| -> EncodeResult) -> EncodeResult {
|
|
|
|
f(self)
|
|
|
|
}
|
2013-05-01 19:54:54 -05:00
|
|
|
|
2014-03-18 12:58:26 -05:00
|
|
|
fn emit_seq(&mut self,
|
|
|
|
len: uint,
|
|
|
|
f: |&mut PrettyEncoder<'a>| -> EncodeResult) -> EncodeResult {
|
2013-05-01 19:54:54 -05:00
|
|
|
if len == 0 {
|
2014-06-28 07:34:58 -05:00
|
|
|
write!(self.writer, "[]")
|
2013-05-01 19:54:54 -05:00
|
|
|
} else {
|
2014-06-28 07:34:58 -05:00
|
|
|
try!(write!(self.writer, "["));
|
2013-05-01 19:54:54 -05:00
|
|
|
self.indent += 2;
|
2014-03-18 12:58:26 -05:00
|
|
|
try!(f(self));
|
2013-05-01 19:54:54 -05:00
|
|
|
self.indent -= 2;
|
2014-07-04 13:08:38 -05:00
|
|
|
try!(write!(self.writer, "\n"));
|
|
|
|
try!(spaces(self.writer, self.indent));
|
|
|
|
write!(self.writer, "]")
|
2013-05-01 19:54:54 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-03-18 12:58:26 -05:00
|
|
|
fn emit_seq_elt(&mut self,
|
|
|
|
idx: uint,
|
|
|
|
f: |&mut PrettyEncoder<'a>| -> EncodeResult) -> EncodeResult {
|
2013-05-01 19:54:54 -05:00
|
|
|
if idx == 0 {
|
2014-06-28 07:34:58 -05:00
|
|
|
try!(write!(self.writer, "\n"));
|
2013-05-01 19:54:54 -05:00
|
|
|
} else {
|
2014-06-28 07:34:58 -05:00
|
|
|
try!(write!(self.writer, ",\n"));
|
2013-05-01 19:54:54 -05:00
|
|
|
}
|
2014-07-04 13:08:38 -05:00
|
|
|
try!(spaces(self.writer, self.indent));
|
2013-05-01 19:54:54 -05:00
|
|
|
f(self)
|
|
|
|
}
|
|
|
|
|
2014-05-28 11:24:28 -05:00
|
|
|
fn emit_map(&mut self,
|
|
|
|
len: uint,
|
|
|
|
f: |&mut PrettyEncoder<'a>| -> EncodeResult) -> EncodeResult {
|
|
|
|
if len == 0 {
|
2014-06-28 07:34:58 -05:00
|
|
|
write!(self.writer, "{{}}")
|
2014-05-28 11:24:28 -05:00
|
|
|
} else {
|
2014-06-28 07:34:58 -05:00
|
|
|
try!(write!(self.writer, "{{"));
|
2014-05-28 11:24:28 -05:00
|
|
|
self.indent += 2;
|
|
|
|
try!(f(self));
|
|
|
|
self.indent -= 2;
|
2014-07-04 13:08:38 -05:00
|
|
|
try!(write!(self.writer, "\n"));
|
|
|
|
try!(spaces(self.writer, self.indent));
|
|
|
|
write!(self.writer, "}}")
|
2014-05-28 11:24:28 -05:00
|
|
|
}
|
|
|
|
}
|
2013-05-01 19:54:54 -05:00
|
|
|
|
2014-03-18 12:58:26 -05:00
|
|
|
fn emit_map_elt_key(&mut self,
|
|
|
|
idx: uint,
|
|
|
|
f: |&mut PrettyEncoder<'a>| -> EncodeResult) -> EncodeResult {
|
2013-05-01 19:54:54 -05:00
|
|
|
if idx == 0 {
|
2014-06-28 07:34:58 -05:00
|
|
|
try!(write!(self.writer, "\n"));
|
2013-05-01 19:54:54 -05:00
|
|
|
} else {
|
2014-06-28 07:34:58 -05:00
|
|
|
try!(write!(self.writer, ",\n"));
|
2013-05-01 19:54:54 -05:00
|
|
|
}
|
2014-07-04 13:08:38 -05:00
|
|
|
try!(spaces(self.writer, self.indent));
|
2014-03-17 02:26:36 -05:00
|
|
|
// ref #12967, make sure to wrap a key in double quotes,
|
|
|
|
// in the event that its of a type that omits them (eg numbers)
|
|
|
|
let mut buf = MemWriter::new();
|
2014-06-11 00:18:57 -05:00
|
|
|
// FIXME(14302) remove the transmute and unsafe block.
|
|
|
|
unsafe {
|
|
|
|
let mut check_encoder = PrettyEncoder::new(&mut buf);
|
|
|
|
try!(f(transmute(&mut check_encoder)));
|
|
|
|
}
|
2014-06-28 07:34:58 -05:00
|
|
|
let out = str::from_utf8_owned(buf.unwrap()).unwrap();
|
|
|
|
let out = out.as_slice();
|
|
|
|
let needs_wrapping = out.char_at(0) != '"' && out.char_at_reverse(out.len()) != '"';
|
|
|
|
if needs_wrapping { try!(write!(self.writer, "\"")); }
|
2014-03-18 12:58:26 -05:00
|
|
|
try!(f(self));
|
2014-06-28 07:34:58 -05:00
|
|
|
if needs_wrapping { try!(write!(self.writer, "\"")); }
|
2014-03-18 12:58:26 -05:00
|
|
|
Ok(())
|
2013-05-01 19:54:54 -05:00
|
|
|
}
|
|
|
|
|
2014-03-18 12:58:26 -05:00
|
|
|
fn emit_map_elt_val(&mut self,
|
|
|
|
_idx: uint,
|
|
|
|
f: |&mut PrettyEncoder<'a>| -> EncodeResult) -> EncodeResult {
|
2014-06-28 07:34:58 -05:00
|
|
|
try!(write!(self.writer, ": "));
|
2014-03-18 12:58:26 -05:00
|
|
|
f(self)
|
2013-05-01 19:54:54 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-03-31 12:37:38 -05:00
|
|
|
impl<E: ::Encoder<S>, S> Encodable<E, S> for Json {
|
|
|
|
fn encode(&self, e: &mut E) -> Result<(), S> {
|
2013-05-01 19:54:54 -05:00
|
|
|
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(),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-02-05 10:52:54 -06:00
|
|
|
impl Json {
|
2014-06-28 07:34:58 -05:00
|
|
|
/// Encodes a json value into an io::writer. Uses a single line.
|
|
|
|
pub fn to_writer(&self, writer: &mut io::Writer) -> EncodeResult {
|
|
|
|
let mut encoder = Encoder::new(writer);
|
2014-03-18 12:58:26 -05:00
|
|
|
self.encode(&mut encoder)
|
2013-08-22 00:32:18 -05:00
|
|
|
}
|
2012-09-24 11:55:42 -05:00
|
|
|
|
2014-05-01 20:02:11 -05:00
|
|
|
/// Encodes a json value into an io::writer.
|
2013-08-22 00:32:18 -05:00
|
|
|
/// Pretty-prints in a more readable format.
|
2014-06-28 07:34:58 -05:00
|
|
|
pub fn to_pretty_writer(&self, writer: &mut io::Writer) -> EncodeResult {
|
|
|
|
let mut encoder = PrettyEncoder::new(writer);
|
2014-03-18 12:58:26 -05:00
|
|
|
self.encode(&mut encoder)
|
2013-08-22 00:32:18 -05:00
|
|
|
}
|
2012-06-12 19:20:51 -05:00
|
|
|
|
2013-08-22 00:32:18 -05:00
|
|
|
/// Encodes a json value into a string
|
2014-05-22 18:57:53 -05:00
|
|
|
pub fn to_pretty_str(&self) -> String {
|
2013-11-29 12:12:08 -06:00
|
|
|
let mut s = MemWriter::new();
|
2014-01-29 19:39:12 -06:00
|
|
|
self.to_pretty_writer(&mut s as &mut io::Writer).unwrap();
|
2014-06-28 07:34:58 -05:00
|
|
|
str::from_utf8_owned(s.unwrap()).unwrap()
|
2013-08-22 00:32:18 -05:00
|
|
|
}
|
2014-03-09 00:30:27 -06:00
|
|
|
|
|
|
|
/// If the Json value is an Object, returns the value associated with the provided key.
|
|
|
|
/// Otherwise, returns None.
|
2014-05-22 18:57:53 -05:00
|
|
|
pub fn find<'a>(&'a self, key: &String) -> Option<&'a Json>{
|
2014-03-09 00:30:27 -06:00
|
|
|
match self {
|
|
|
|
&Object(ref map) => map.find(key),
|
|
|
|
_ => None
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Attempts to get a nested Json Object for each key in `keys`.
|
2014-03-11 22:04:36 -05:00
|
|
|
/// If any key is found not to exist, find_path will return None.
|
2014-03-09 00:30:27 -06:00
|
|
|
/// Otherwise, it will return the Json value associated with the final key.
|
2014-05-22 18:57:53 -05:00
|
|
|
pub fn find_path<'a>(&'a self, keys: &[&String]) -> Option<&'a Json>{
|
2014-03-11 22:04:36 -05:00
|
|
|
let mut target = self;
|
|
|
|
for key in keys.iter() {
|
|
|
|
match target.find(*key) {
|
|
|
|
Some(t) => { target = t; },
|
|
|
|
None => return None
|
|
|
|
}
|
|
|
|
}
|
|
|
|
Some(target)
|
2014-03-09 00:30:27 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
/// If the Json value is an Object, performs a depth-first search until
|
|
|
|
/// a value associated with the provided key is found. If no value is found
|
|
|
|
/// or the Json value is not an Object, returns None.
|
2014-05-22 18:57:53 -05:00
|
|
|
pub fn search<'a>(&'a self, key: &String) -> Option<&'a Json> {
|
2014-03-09 00:30:27 -06:00
|
|
|
match self {
|
|
|
|
&Object(ref map) => {
|
|
|
|
match map.find(key) {
|
|
|
|
Some(json_value) => Some(json_value),
|
|
|
|
None => {
|
|
|
|
let mut value : Option<&'a Json> = None;
|
|
|
|
for (_, v) in map.iter() {
|
|
|
|
value = v.search(key);
|
|
|
|
if value.is_some() {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
value
|
|
|
|
}
|
|
|
|
}
|
|
|
|
},
|
|
|
|
_ => None
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Returns true if the Json value is an Object. Returns false otherwise.
|
|
|
|
pub fn is_object<'a>(&'a self) -> bool {
|
2014-03-11 22:04:36 -05:00
|
|
|
self.as_object().is_some()
|
2014-03-09 00:30:27 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
/// If the Json value is an Object, returns the associated TreeMap.
|
|
|
|
/// Returns None otherwise.
|
|
|
|
pub fn as_object<'a>(&'a self) -> Option<&'a Object> {
|
|
|
|
match self {
|
2014-06-28 07:41:40 -05:00
|
|
|
&Object(ref map) => Some(map),
|
2014-03-09 00:30:27 -06:00
|
|
|
_ => None
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Returns true if the Json value is a List. Returns false otherwise.
|
|
|
|
pub fn is_list<'a>(&'a self) -> bool {
|
2014-03-11 22:04:36 -05:00
|
|
|
self.as_list().is_some()
|
2014-03-09 00:30:27 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
/// If the Json value is a List, returns the associated vector.
|
|
|
|
/// Returns None otherwise.
|
|
|
|
pub fn as_list<'a>(&'a self) -> Option<&'a List> {
|
|
|
|
match self {
|
|
|
|
&List(ref list) => Some(&*list),
|
|
|
|
_ => None
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Returns true if the Json value is a String. Returns false otherwise.
|
2014-03-11 22:04:36 -05:00
|
|
|
pub fn is_string<'a>(&'a self) -> bool {
|
|
|
|
self.as_string().is_some()
|
2014-03-09 00:30:27 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
/// If the Json value is a String, returns the associated str.
|
|
|
|
/// Returns None otherwise.
|
2014-03-11 22:04:36 -05:00
|
|
|
pub fn as_string<'a>(&'a self) -> Option<&'a str> {
|
2014-03-09 00:30:27 -06:00
|
|
|
match *self {
|
|
|
|
String(ref s) => Some(s.as_slice()),
|
|
|
|
_ => None
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Returns true if the Json value is a Number. Returns false otherwise.
|
|
|
|
pub fn is_number(&self) -> bool {
|
2014-03-11 22:04:36 -05:00
|
|
|
self.as_number().is_some()
|
2014-03-09 00:30:27 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
/// If the Json value is a Number, returns the associated f64.
|
|
|
|
/// Returns None otherwise.
|
|
|
|
pub fn as_number(&self) -> Option<f64> {
|
|
|
|
match self {
|
|
|
|
&Number(n) => Some(n),
|
|
|
|
_ => None
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Returns true if the Json value is a Boolean. Returns false otherwise.
|
|
|
|
pub fn is_boolean(&self) -> bool {
|
2014-03-11 22:04:36 -05:00
|
|
|
self.as_boolean().is_some()
|
2014-03-09 00:30:27 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
/// If the Json value is a Boolean, returns the associated bool.
|
|
|
|
/// Returns None otherwise.
|
|
|
|
pub fn as_boolean(&self) -> Option<bool> {
|
|
|
|
match self {
|
|
|
|
&Boolean(b) => Some(b),
|
|
|
|
_ => None
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Returns true if the Json value is a Null. Returns false otherwise.
|
|
|
|
pub fn is_null(&self) -> bool {
|
2014-03-11 22:04:36 -05:00
|
|
|
self.as_null().is_some()
|
2014-03-09 00:30:27 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
/// If the Json value is a Null, returns ().
|
|
|
|
/// Returns None otherwise.
|
|
|
|
pub fn as_null(&self) -> Option<()> {
|
|
|
|
match self {
|
|
|
|
&Null => Some(()),
|
|
|
|
_ => None
|
|
|
|
}
|
|
|
|
}
|
2011-11-07 13:01:28 -06:00
|
|
|
}
|
|
|
|
|
2014-03-30 07:58:02 -05:00
|
|
|
/// The output of the streaming parser.
|
2014-05-29 19:45:07 -05:00
|
|
|
#[deriving(PartialEq, Clone, Show)]
|
2014-03-30 07:58:02 -05:00
|
|
|
pub enum JsonEvent {
|
|
|
|
ObjectStart,
|
|
|
|
ObjectEnd,
|
|
|
|
ListStart,
|
|
|
|
ListEnd,
|
|
|
|
BooleanValue(bool),
|
|
|
|
NumberValue(f64),
|
2014-05-22 18:57:53 -05:00
|
|
|
StringValue(String),
|
2014-03-30 07:58:02 -05:00
|
|
|
NullValue,
|
|
|
|
Error(ParserError),
|
|
|
|
}
|
|
|
|
|
2014-05-29 19:45:07 -05:00
|
|
|
#[deriving(PartialEq, Show)]
|
2014-03-30 07:58:02 -05:00
|
|
|
enum ParserState {
|
|
|
|
// Parse a value in a list, true means first element.
|
|
|
|
ParseList(bool),
|
|
|
|
// Parse ',' or ']' after an element in a list.
|
|
|
|
ParseListComma,
|
|
|
|
// Parse a key:value in an object, true means first element.
|
|
|
|
ParseObject(bool),
|
|
|
|
// Parse ',' or ']' after an element in an object.
|
|
|
|
ParseObjectComma,
|
2014-06-08 12:22:49 -05:00
|
|
|
// Initial state.
|
2014-03-30 07:58:02 -05:00
|
|
|
ParseStart,
|
|
|
|
// Expecting the stream to end.
|
|
|
|
ParseBeforeFinish,
|
|
|
|
// Parsing can't continue.
|
|
|
|
ParseFinished,
|
|
|
|
}
|
|
|
|
|
|
|
|
/// A Stack represents the current position of the parser in the logical
|
|
|
|
/// structure of the JSON stream.
|
|
|
|
/// For example foo.bar[3].x
|
|
|
|
pub struct Stack {
|
|
|
|
stack: Vec<InternalStackElement>,
|
|
|
|
str_buffer: Vec<u8>,
|
|
|
|
}
|
|
|
|
|
|
|
|
/// StackElements compose a Stack.
|
|
|
|
/// For example, Key("foo"), Key("bar"), Index(3) and Key("x") are the
|
|
|
|
/// StackElements compositing the stack that represents foo.bar[3].x
|
2014-05-29 19:45:07 -05:00
|
|
|
#[deriving(PartialEq, Clone, Show)]
|
2014-03-30 07:58:02 -05:00
|
|
|
pub enum StackElement<'l> {
|
|
|
|
Index(u32),
|
|
|
|
Key(&'l str),
|
|
|
|
}
|
|
|
|
|
|
|
|
// Internally, Key elements are stored as indices in a buffer to avoid
|
|
|
|
// allocating a string for every member of an object.
|
2014-05-29 19:45:07 -05:00
|
|
|
#[deriving(PartialEq, Clone, Show)]
|
2014-03-30 07:58:02 -05:00
|
|
|
enum InternalStackElement {
|
|
|
|
InternalIndex(u32),
|
|
|
|
InternalKey(u16, u16), // start, size
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Stack {
|
|
|
|
pub fn new() -> Stack {
|
2014-06-28 07:34:58 -05:00
|
|
|
Stack { stack: Vec::new(), str_buffer: Vec::new() }
|
2014-03-30 07:58:02 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
/// Returns The number of elements in the Stack.
|
|
|
|
pub fn len(&self) -> uint { self.stack.len() }
|
|
|
|
|
2014-06-28 07:34:58 -05:00
|
|
|
/// Returns true if the stack is empty.
|
|
|
|
pub fn is_empty(&self) -> bool { self.stack.is_empty() }
|
2014-03-30 07:58:02 -05:00
|
|
|
|
|
|
|
/// Provides access to the StackElement at a given index.
|
|
|
|
/// lower indices are at the bottom of the stack while higher indices are
|
|
|
|
/// at the top.
|
|
|
|
pub fn get<'l>(&'l self, idx: uint) -> StackElement<'l> {
|
2014-06-28 07:34:58 -05:00
|
|
|
match *self.stack.get(idx) {
|
|
|
|
InternalIndex(i) => { Index(i) }
|
|
|
|
InternalKey(start, size) => {
|
2014-06-28 08:59:45 -05:00
|
|
|
Key(str::from_utf8(
|
|
|
|
self.str_buffer.slice(start as uint, start as uint + size as uint)).unwrap())
|
2014-06-28 07:34:58 -05:00
|
|
|
}
|
2014-03-30 07:58:02 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Compares this stack with an array of StackElements.
|
|
|
|
pub fn is_equal_to(&self, rhs: &[StackElement]) -> bool {
|
|
|
|
if self.stack.len() != rhs.len() { return false; }
|
|
|
|
for i in range(0, rhs.len()) {
|
|
|
|
if self.get(i) != rhs[i] { return false; }
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Returns true if the bottom-most elements of this stack are the same as
|
|
|
|
/// the ones passed as parameter.
|
|
|
|
pub fn starts_with(&self, rhs: &[StackElement]) -> bool {
|
|
|
|
if self.stack.len() < rhs.len() { return false; }
|
|
|
|
for i in range(0, rhs.len()) {
|
|
|
|
if self.get(i) != rhs[i] { return false; }
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Returns true if the top-most elements of this stack are the same as
|
|
|
|
/// the ones passed as parameter.
|
|
|
|
pub fn ends_with(&self, rhs: &[StackElement]) -> bool {
|
|
|
|
if self.stack.len() < rhs.len() { return false; }
|
|
|
|
let offset = self.stack.len() - rhs.len();
|
|
|
|
for i in range(0, rhs.len()) {
|
|
|
|
if self.get(i + offset) != rhs[i] { return false; }
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Returns the top-most element (if any).
|
|
|
|
pub fn top<'l>(&'l self) -> Option<StackElement<'l>> {
|
|
|
|
return match self.stack.last() {
|
|
|
|
None => None,
|
|
|
|
Some(&InternalIndex(i)) => Some(Index(i)),
|
|
|
|
Some(&InternalKey(start, size)) => {
|
|
|
|
Some(Key(str::from_utf8(
|
|
|
|
self.str_buffer.slice(start as uint, (start+size) as uint)
|
|
|
|
).unwrap()))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Used by Parser to insert Key elements at the top of the stack.
|
2014-05-22 18:57:53 -05:00
|
|
|
fn push_key(&mut self, key: String) {
|
2014-03-30 07:58:02 -05:00
|
|
|
self.stack.push(InternalKey(self.str_buffer.len() as u16, key.len() as u16));
|
|
|
|
for c in key.as_bytes().iter() {
|
|
|
|
self.str_buffer.push(*c);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Used by Parser to insert Index elements at the top of the stack.
|
|
|
|
fn push_index(&mut self, index: u32) {
|
|
|
|
self.stack.push(InternalIndex(index));
|
|
|
|
}
|
|
|
|
|
|
|
|
// Used by Parser to remove the top-most element of the stack.
|
|
|
|
fn pop(&mut self) {
|
|
|
|
assert!(!self.is_empty());
|
|
|
|
match *self.stack.last().unwrap() {
|
|
|
|
InternalKey(_, sz) => {
|
|
|
|
let new_size = self.str_buffer.len() - sz as uint;
|
2014-06-28 07:34:58 -05:00
|
|
|
self.str_buffer.truncate(new_size);
|
2014-03-30 07:58:02 -05:00
|
|
|
}
|
|
|
|
InternalIndex(_) => {}
|
|
|
|
}
|
|
|
|
self.stack.pop();
|
|
|
|
}
|
|
|
|
|
|
|
|
// Used by Parser to test whether the top-most element is an index.
|
|
|
|
fn last_is_index(&self) -> bool {
|
|
|
|
if self.is_empty() { return false; }
|
|
|
|
return match *self.stack.last().unwrap() {
|
|
|
|
InternalIndex(_) => true,
|
|
|
|
_ => false,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Used by Parser to increment the index of the top-most element.
|
|
|
|
fn bump_index(&mut self) {
|
|
|
|
let len = self.stack.len();
|
|
|
|
let idx = match *self.stack.last().unwrap() {
|
2014-06-28 07:34:58 -05:00
|
|
|
InternalIndex(i) => { i + 1 }
|
|
|
|
_ => { fail!(); }
|
2014-03-30 07:58:02 -05:00
|
|
|
};
|
|
|
|
*self.stack.get_mut(len - 1) = InternalIndex(idx);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// A streaming JSON parser implemented as an iterator of JsonEvent, consuming
|
|
|
|
/// an iterator of char.
|
2013-07-10 22:03:10 -05:00
|
|
|
pub struct Parser<T> {
|
2014-03-27 17:13:35 -05:00
|
|
|
rdr: T,
|
|
|
|
ch: Option<char>,
|
|
|
|
line: uint,
|
|
|
|
col: uint,
|
2014-03-30 07:58:02 -05:00
|
|
|
// We maintain a stack representing where we are in the logical structure
|
|
|
|
// of the JSON stream.
|
|
|
|
stack: Stack,
|
2014-06-08 12:22:49 -05:00
|
|
|
// A state machine is kept to make it possible to interrupt and resume parsing.
|
2014-03-30 07:58:02 -05:00
|
|
|
state: ParserState,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<T: Iterator<char>> Iterator<JsonEvent> for Parser<T> {
|
|
|
|
fn next(&mut self) -> Option<JsonEvent> {
|
|
|
|
if self.state == ParseFinished {
|
|
|
|
return None;
|
|
|
|
}
|
|
|
|
|
|
|
|
if self.state == ParseBeforeFinish {
|
|
|
|
self.parse_whitespace();
|
|
|
|
// Make sure there is no trailing characters.
|
|
|
|
if self.eof() {
|
|
|
|
self.state = ParseFinished;
|
|
|
|
return None;
|
|
|
|
} else {
|
|
|
|
return Some(self.error_event(TrailingCharacters));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return Some(self.parse());
|
|
|
|
}
|
2012-08-30 18:39:56 -05:00
|
|
|
}
|
|
|
|
|
2013-11-29 13:11:52 -06:00
|
|
|
impl<T: Iterator<char>> Parser<T> {
|
2014-03-30 07:58:02 -05:00
|
|
|
/// Creates the JSON parser.
|
2013-12-03 21:18:35 -06:00
|
|
|
pub fn new(rdr: T) -> Parser<T> {
|
2013-11-29 13:11:52 -06:00
|
|
|
let mut p = Parser {
|
|
|
|
rdr: rdr,
|
2014-02-06 06:56:52 -06:00
|
|
|
ch: Some('\x00'),
|
2013-11-29 13:11:52 -06:00
|
|
|
line: 1,
|
|
|
|
col: 0,
|
2014-03-30 07:58:02 -05:00
|
|
|
stack: Stack::new(),
|
|
|
|
state: ParseStart,
|
2013-11-29 13:11:52 -06:00
|
|
|
};
|
|
|
|
p.bump();
|
2014-03-30 07:58:02 -05:00
|
|
|
return p;
|
2013-11-29 13:11:52 -06:00
|
|
|
}
|
2011-11-07 13:01:28 -06:00
|
|
|
|
2014-03-30 07:58:02 -05:00
|
|
|
/// Provides access to the current position in the logical structure of the
|
|
|
|
/// JSON stream.
|
|
|
|
pub fn stack<'l>(&'l self) -> &'l Stack {
|
2014-07-04 02:56:57 -05:00
|
|
|
return &self.stack;
|
2012-09-24 11:55:42 -05:00
|
|
|
}
|
2012-07-11 17:00:40 -05:00
|
|
|
|
2014-02-06 06:56:52 -06:00
|
|
|
fn eof(&self) -> bool { self.ch.is_none() }
|
|
|
|
fn ch_or_null(&self) -> char { self.ch.unwrap_or('\x00') }
|
2013-03-24 11:41:19 -05:00
|
|
|
fn bump(&mut self) {
|
2014-02-06 06:56:52 -06:00
|
|
|
self.ch = self.rdr.next();
|
2011-11-07 13:01:28 -06:00
|
|
|
|
2014-02-06 06:56:52 -06:00
|
|
|
if self.ch_is('\n') {
|
2012-02-25 18:39:32 -06:00
|
|
|
self.line += 1u;
|
|
|
|
self.col = 1u;
|
2013-07-10 22:03:10 -05:00
|
|
|
} else {
|
|
|
|
self.col += 1u;
|
2011-11-07 13:01:28 -06:00
|
|
|
}
|
2012-02-25 18:39:32 -06:00
|
|
|
}
|
|
|
|
|
2014-02-06 06:56:52 -06:00
|
|
|
fn next_char(&mut self) -> Option<char> {
|
2012-02-25 18:39:32 -06:00
|
|
|
self.bump();
|
|
|
|
self.ch
|
|
|
|
}
|
2014-02-06 06:56:52 -06:00
|
|
|
fn ch_is(&self, c: char) -> bool {
|
|
|
|
self.ch == Some(c)
|
|
|
|
}
|
2012-02-25 18:39:32 -06:00
|
|
|
|
2014-03-30 07:58:02 -05:00
|
|
|
fn error<T>(&self, reason: ErrorCode) -> Result<T, ParserError> {
|
|
|
|
Err(SyntaxError(reason, self.line, self.col))
|
2012-02-25 18:39:32 -06:00
|
|
|
}
|
|
|
|
|
2013-03-24 11:41:19 -05:00
|
|
|
fn parse_whitespace(&mut self) {
|
2014-02-06 06:56:52 -06:00
|
|
|
while self.ch_is(' ') ||
|
|
|
|
self.ch_is('\n') ||
|
|
|
|
self.ch_is('\t') ||
|
|
|
|
self.ch_is('\r') { self.bump(); }
|
2012-02-25 18:39:32 -06:00
|
|
|
}
|
|
|
|
|
2014-03-30 07:58:02 -05:00
|
|
|
fn parse_number(&mut self) -> Result<f64, ParserError> {
|
2013-09-26 01:26:09 -05:00
|
|
|
let mut neg = 1.0;
|
2012-02-25 18:39:32 -06:00
|
|
|
|
2014-02-06 06:56:52 -06:00
|
|
|
if self.ch_is('-') {
|
2012-02-25 18:39:32 -06:00
|
|
|
self.bump();
|
2013-09-26 01:26:09 -05:00
|
|
|
neg = -1.0;
|
2011-11-07 13:01:28 -06:00
|
|
|
}
|
2012-02-25 18:39:32 -06:00
|
|
|
|
2014-06-28 07:34:58 -05:00
|
|
|
let mut res = try!(self.parse_integer());
|
2012-02-25 18:39:32 -06:00
|
|
|
|
2014-02-06 06:56:52 -06:00
|
|
|
if self.ch_is('.') {
|
2014-06-28 07:34:58 -05:00
|
|
|
res = try!(self.parse_decimal(res));
|
2011-11-07 13:01:28 -06:00
|
|
|
}
|
2012-02-25 18:39:32 -06:00
|
|
|
|
2014-02-06 06:56:52 -06:00
|
|
|
if self.ch_is('e') || self.ch_is('E') {
|
2014-06-28 07:34:58 -05:00
|
|
|
res = try!(self.parse_exponent(res));
|
2011-11-07 13:01:28 -06:00
|
|
|
}
|
2012-02-25 18:39:32 -06:00
|
|
|
|
2014-03-30 07:58:02 -05:00
|
|
|
Ok(neg * res)
|
2011-11-07 13:01:28 -06:00
|
|
|
}
|
|
|
|
|
2014-03-30 07:58:02 -05:00
|
|
|
fn parse_integer(&mut self) -> Result<f64, ParserError> {
|
2013-09-26 01:26:09 -05:00
|
|
|
let mut res = 0.0;
|
2011-11-07 13:01:28 -06:00
|
|
|
|
2014-02-06 06:56:52 -06:00
|
|
|
match self.ch_or_null() {
|
|
|
|
'0' => {
|
|
|
|
self.bump();
|
2012-02-25 18:39:32 -06:00
|
|
|
|
2014-06-25 20:26:41 -05:00
|
|
|
// A leading '0' must be the only digit before the decimal point.
|
2014-02-06 06:56:52 -06:00
|
|
|
match self.ch_or_null() {
|
2014-03-30 07:58:02 -05:00
|
|
|
'0' .. '9' => return self.error(InvalidNumber),
|
2014-02-06 06:56:52 -06:00
|
|
|
_ => ()
|
|
|
|
}
|
|
|
|
},
|
|
|
|
'1' .. '9' => {
|
|
|
|
while !self.eof() {
|
|
|
|
match self.ch_or_null() {
|
|
|
|
c @ '0' .. '9' => {
|
|
|
|
res *= 10.0;
|
|
|
|
res += ((c as int) - ('0' as int)) as f64;
|
|
|
|
self.bump();
|
|
|
|
}
|
|
|
|
_ => break,
|
|
|
|
}
|
2012-02-25 18:39:32 -06:00
|
|
|
}
|
|
|
|
}
|
2014-03-30 07:58:02 -05:00
|
|
|
_ => return self.error(InvalidNumber),
|
2011-11-07 13:01:28 -06:00
|
|
|
}
|
2012-08-26 18:54:31 -05:00
|
|
|
Ok(res)
|
2011-11-07 13:01:28 -06:00
|
|
|
}
|
|
|
|
|
2014-06-28 07:34:58 -05:00
|
|
|
fn parse_decimal(&mut self, mut res: f64) -> Result<f64, ParserError> {
|
2012-02-25 18:39:32 -06:00
|
|
|
self.bump();
|
|
|
|
|
|
|
|
// Make sure a digit follows the decimal place.
|
2014-02-06 06:56:52 -06:00
|
|
|
match self.ch_or_null() {
|
|
|
|
'0' .. '9' => (),
|
2014-03-30 07:58:02 -05:00
|
|
|
_ => return self.error(InvalidNumber)
|
2012-02-25 18:39:32 -06:00
|
|
|
}
|
|
|
|
|
2013-09-26 01:26:09 -05:00
|
|
|
let mut dec = 1.0;
|
2012-02-25 18:39:32 -06:00
|
|
|
while !self.eof() {
|
2014-02-06 06:56:52 -06:00
|
|
|
match self.ch_or_null() {
|
|
|
|
c @ '0' .. '9' => {
|
|
|
|
dec /= 10.0;
|
|
|
|
res += (((c as int) - ('0' as int)) as f64) * dec;
|
|
|
|
self.bump();
|
|
|
|
}
|
|
|
|
_ => break,
|
2011-11-07 13:01:28 -06:00
|
|
|
}
|
|
|
|
}
|
2012-02-25 18:39:32 -06:00
|
|
|
|
2012-08-26 18:54:31 -05:00
|
|
|
Ok(res)
|
2011-11-07 13:01:28 -06:00
|
|
|
}
|
|
|
|
|
2014-03-30 07:58:02 -05:00
|
|
|
fn parse_exponent(&mut self, mut res: f64) -> Result<f64, ParserError> {
|
2012-02-25 18:39:32 -06:00
|
|
|
self.bump();
|
|
|
|
|
2012-03-14 13:03:56 -05:00
|
|
|
let mut exp = 0u;
|
|
|
|
let mut neg_exp = false;
|
2012-02-25 18:39:32 -06:00
|
|
|
|
2014-02-06 06:56:52 -06:00
|
|
|
if self.ch_is('+') {
|
|
|
|
self.bump();
|
|
|
|
} else if self.ch_is('-') {
|
|
|
|
self.bump();
|
|
|
|
neg_exp = true;
|
2012-02-25 18:39:32 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
// Make sure a digit follows the exponent place.
|
2014-02-06 06:56:52 -06:00
|
|
|
match self.ch_or_null() {
|
|
|
|
'0' .. '9' => (),
|
2014-03-30 07:58:02 -05:00
|
|
|
_ => return self.error(InvalidNumber)
|
2012-02-25 18:39:32 -06:00
|
|
|
}
|
|
|
|
while !self.eof() {
|
2014-02-06 06:56:52 -06:00
|
|
|
match self.ch_or_null() {
|
|
|
|
c @ '0' .. '9' => {
|
|
|
|
exp *= 10;
|
|
|
|
exp += (c as uint) - ('0' as uint);
|
2012-02-25 18:39:32 -06:00
|
|
|
|
2014-02-06 06:56:52 -06:00
|
|
|
self.bump();
|
|
|
|
}
|
|
|
|
_ => break
|
2012-02-25 18:39:32 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-06-28 07:34:58 -05:00
|
|
|
let exp = num::pow(10_f64, exp);
|
2012-02-25 18:39:32 -06:00
|
|
|
if neg_exp {
|
|
|
|
res /= exp;
|
|
|
|
} else {
|
|
|
|
res *= exp;
|
|
|
|
}
|
|
|
|
|
2012-08-26 18:54:31 -05:00
|
|
|
Ok(res)
|
2011-11-07 13:01:28 -06:00
|
|
|
}
|
|
|
|
|
2014-03-30 07:58:02 -05:00
|
|
|
fn decode_hex_escape(&mut self) -> Result<u16, ParserError> {
|
2014-04-11 15:21:19 -05:00
|
|
|
let mut i = 0u;
|
|
|
|
let mut n = 0u16;
|
2014-06-28 07:34:58 -05:00
|
|
|
while i < 4 && !self.eof() {
|
2014-04-11 15:21:19 -05:00
|
|
|
self.bump();
|
|
|
|
n = match self.ch_or_null() {
|
2014-06-28 07:34:58 -05:00
|
|
|
c @ '0' .. '9' => n * 16 + ((c as u16) - ('0' as u16)),
|
|
|
|
'a' | 'A' => n * 16 + 10,
|
|
|
|
'b' | 'B' => n * 16 + 11,
|
|
|
|
'c' | 'C' => n * 16 + 12,
|
|
|
|
'd' | 'D' => n * 16 + 13,
|
|
|
|
'e' | 'E' => n * 16 + 14,
|
|
|
|
'f' | 'F' => n * 16 + 15,
|
2014-03-30 07:58:02 -05:00
|
|
|
_ => return self.error(InvalidEscape)
|
2014-04-11 15:21:19 -05:00
|
|
|
};
|
|
|
|
|
|
|
|
i += 1u;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Error out if we didn't parse 4 digits.
|
2014-06-28 07:34:58 -05:00
|
|
|
if i != 4 {
|
2014-03-30 07:58:02 -05:00
|
|
|
return self.error(InvalidEscape);
|
2014-04-11 15:21:19 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
Ok(n)
|
|
|
|
}
|
|
|
|
|
2014-05-22 18:57:53 -05:00
|
|
|
fn parse_str(&mut self) -> Result<String, ParserError> {
|
2012-03-14 13:03:56 -05:00
|
|
|
let mut escape = false;
|
2014-05-22 18:57:53 -05:00
|
|
|
let mut res = String::new();
|
2012-02-25 18:39:32 -06:00
|
|
|
|
2013-07-10 22:03:10 -05:00
|
|
|
loop {
|
2012-02-25 18:39:32 -06:00
|
|
|
self.bump();
|
2013-07-10 22:03:10 -05:00
|
|
|
if self.eof() {
|
2014-03-30 07:58:02 -05:00
|
|
|
return self.error(EOFWhileParsingString);
|
2013-07-10 22:03:10 -05:00
|
|
|
}
|
2012-02-25 18:39:32 -06:00
|
|
|
|
2014-01-19 02:21:14 -06:00
|
|
|
if escape {
|
2014-02-06 06:56:52 -06:00
|
|
|
match self.ch_or_null() {
|
|
|
|
'"' => 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'),
|
2014-04-11 15:21:19 -05:00
|
|
|
'u' => match try!(self.decode_hex_escape()) {
|
2014-03-30 07:58:02 -05:00
|
|
|
0xDC00 .. 0xDFFF => return self.error(LoneLeadingSurrogateInHexEscape),
|
2014-04-11 15:21:19 -05:00
|
|
|
|
|
|
|
// Non-BMP characters are encoded as a sequence of
|
|
|
|
// two hex escapes, representing UTF-16 surrogates.
|
|
|
|
n1 @ 0xD800 .. 0xDBFF => {
|
2014-06-28 07:34:58 -05:00
|
|
|
match (self.next_char(), self.next_char()) {
|
2014-04-11 15:21:19 -05:00
|
|
|
(Some('\\'), Some('u')) => (),
|
2014-03-30 07:58:02 -05:00
|
|
|
_ => return self.error(UnexpectedEndOfHexEscape),
|
2014-04-11 15:21:19 -05:00
|
|
|
}
|
2014-02-06 06:56:52 -06:00
|
|
|
|
2014-04-11 15:21:19 -05:00
|
|
|
let buf = [n1, try!(self.decode_hex_escape())];
|
|
|
|
match str::utf16_items(buf.as_slice()).next() {
|
|
|
|
Some(ScalarValue(c)) => res.push_char(c),
|
2014-03-30 07:58:02 -05:00
|
|
|
_ => return self.error(LoneLeadingSurrogateInHexEscape),
|
2014-04-11 15:21:19 -05:00
|
|
|
}
|
2014-02-06 06:56:52 -06:00
|
|
|
}
|
|
|
|
|
2014-04-11 15:21:19 -05:00
|
|
|
n => match char::from_u32(n as u32) {
|
|
|
|
Some(c) => res.push_char(c),
|
2014-03-30 07:58:02 -05:00
|
|
|
None => return self.error(InvalidUnicodeCodePoint),
|
2014-04-11 15:21:19 -05:00
|
|
|
},
|
|
|
|
},
|
2014-03-30 07:58:02 -05:00
|
|
|
_ => return self.error(InvalidEscape),
|
2012-02-25 18:39:32 -06:00
|
|
|
}
|
|
|
|
escape = false;
|
2014-02-06 06:56:52 -06:00
|
|
|
} else if self.ch_is('\\') {
|
2012-02-25 18:39:32 -06:00
|
|
|
escape = true;
|
|
|
|
} else {
|
2014-02-06 06:56:52 -06:00
|
|
|
match self.ch {
|
2014-04-02 18:54:22 -05:00
|
|
|
Some('"') => {
|
|
|
|
self.bump();
|
2014-05-14 23:16:44 -05:00
|
|
|
return Ok(res);
|
2014-04-02 18:54:22 -05:00
|
|
|
},
|
2014-02-06 06:56:52 -06:00
|
|
|
Some(c) => res.push_char(c),
|
|
|
|
None => unreachable!()
|
2012-02-25 18:39:32 -06:00
|
|
|
}
|
2011-11-07 13:01:28 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-03-30 07:58:02 -05:00
|
|
|
// Invoked at each iteration, consumes the stream until it has enough
|
|
|
|
// information to return a JsonEvent.
|
|
|
|
// Manages an internal state so that parsing can be interrupted and resumed.
|
|
|
|
// Also keeps track of the position in the logical structure of the json
|
2014-06-08 12:22:49 -05:00
|
|
|
// stream int the form of a stack that can be queried by the user using the
|
2014-03-30 07:58:02 -05:00
|
|
|
// stack() method.
|
|
|
|
fn parse(&mut self) -> JsonEvent {
|
|
|
|
loop {
|
|
|
|
// The only paths where the loop can spin a new iteration
|
|
|
|
// are in the cases ParseListComma and ParseObjectComma if ','
|
|
|
|
// is parsed. In these cases the state is set to (respectively)
|
|
|
|
// ParseList(false) and ParseObject(false), which always return,
|
|
|
|
// so there is no risk of getting stuck in an infinite loop.
|
|
|
|
// All other paths return before the end of the loop's iteration.
|
|
|
|
self.parse_whitespace();
|
2012-02-25 18:39:32 -06:00
|
|
|
|
2014-03-30 07:58:02 -05:00
|
|
|
match self.state {
|
|
|
|
ParseStart => {
|
|
|
|
return self.parse_start();
|
|
|
|
}
|
|
|
|
ParseList(first) => {
|
|
|
|
return self.parse_list(first);
|
|
|
|
}
|
|
|
|
ParseListComma => {
|
|
|
|
match self.parse_list_comma_or_end() {
|
|
|
|
Some(evt) => { return evt; }
|
|
|
|
None => {}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
ParseObject(first) => {
|
|
|
|
return self.parse_object(first);
|
|
|
|
}
|
|
|
|
ParseObjectComma => {
|
|
|
|
self.stack.pop();
|
|
|
|
if self.ch_is(',') {
|
|
|
|
self.state = ParseObject(false);
|
|
|
|
self.bump();
|
|
|
|
} else {
|
|
|
|
return self.parse_object_end();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
_ => {
|
|
|
|
return self.error_event(InvalidSyntax);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn parse_start(&mut self) -> JsonEvent {
|
|
|
|
let val = self.parse_value();
|
|
|
|
self.state = match val {
|
|
|
|
Error(_) => { ParseFinished }
|
|
|
|
ListStart => { ParseList(true) }
|
|
|
|
ObjectStart => { ParseObject(true) }
|
|
|
|
_ => { ParseBeforeFinish }
|
|
|
|
};
|
|
|
|
return val;
|
|
|
|
}
|
2012-02-25 18:39:32 -06:00
|
|
|
|
2014-03-30 07:58:02 -05:00
|
|
|
fn parse_list(&mut self, first: bool) -> JsonEvent {
|
2014-02-06 06:56:52 -06:00
|
|
|
if self.ch_is(']') {
|
2014-03-30 07:58:02 -05:00
|
|
|
if !first {
|
|
|
|
return self.error_event(InvalidSyntax);
|
|
|
|
}
|
|
|
|
if self.stack.is_empty() {
|
|
|
|
self.state = ParseBeforeFinish;
|
|
|
|
} else {
|
|
|
|
self.state = if self.stack.last_is_index() {
|
|
|
|
ParseListComma
|
|
|
|
} else {
|
|
|
|
ParseObjectComma
|
|
|
|
}
|
|
|
|
}
|
2012-02-25 18:39:32 -06:00
|
|
|
self.bump();
|
2014-03-30 07:58:02 -05:00
|
|
|
return ListEnd;
|
|
|
|
}
|
|
|
|
if first {
|
|
|
|
self.stack.push_index(0);
|
2012-02-25 18:39:32 -06:00
|
|
|
}
|
|
|
|
|
2014-03-30 07:58:02 -05:00
|
|
|
let val = self.parse_value();
|
2012-02-25 18:39:32 -06:00
|
|
|
|
2014-03-30 07:58:02 -05:00
|
|
|
self.state = match val {
|
|
|
|
Error(_) => { ParseFinished }
|
|
|
|
ListStart => { ParseList(true) }
|
|
|
|
ObjectStart => { ParseObject(true) }
|
|
|
|
_ => { ParseListComma }
|
|
|
|
};
|
|
|
|
return val;
|
|
|
|
}
|
2012-02-25 18:39:32 -06:00
|
|
|
|
2014-03-30 07:58:02 -05:00
|
|
|
fn parse_list_comma_or_end(&mut self) -> Option<JsonEvent> {
|
|
|
|
if self.ch_is(',') {
|
|
|
|
self.stack.bump_index();
|
|
|
|
self.state = ParseList(false);
|
|
|
|
self.bump();
|
|
|
|
return None;
|
|
|
|
} else if self.ch_is(']') {
|
|
|
|
self.stack.pop();
|
|
|
|
if self.stack.is_empty() {
|
|
|
|
self.state = ParseBeforeFinish;
|
2014-02-06 06:56:52 -06:00
|
|
|
} else {
|
2014-03-30 07:58:02 -05:00
|
|
|
self.state = if self.stack.last_is_index() {
|
|
|
|
ParseListComma
|
|
|
|
} else {
|
|
|
|
ParseObjectComma
|
|
|
|
}
|
2012-02-25 18:39:32 -06:00
|
|
|
}
|
2014-03-30 07:58:02 -05:00
|
|
|
self.bump();
|
|
|
|
return Some(ListEnd);
|
|
|
|
} else if self.eof() {
|
|
|
|
return Some(self.error_event(EOFWhileParsingList));
|
|
|
|
} else {
|
|
|
|
return Some(self.error_event(InvalidSyntax));
|
|
|
|
}
|
2011-11-07 13:01:28 -06:00
|
|
|
}
|
|
|
|
|
2014-03-30 07:58:02 -05:00
|
|
|
fn parse_object(&mut self, first: bool) -> JsonEvent {
|
|
|
|
if self.ch_is('}') {
|
|
|
|
if !first {
|
|
|
|
self.stack.pop();
|
|
|
|
}
|
|
|
|
if self.stack.is_empty() {
|
|
|
|
self.state = ParseBeforeFinish;
|
|
|
|
} else {
|
|
|
|
self.state = if self.stack.last_is_index() {
|
|
|
|
ParseListComma
|
|
|
|
} else {
|
|
|
|
ParseObjectComma
|
|
|
|
}
|
|
|
|
}
|
|
|
|
self.bump();
|
|
|
|
return ObjectEnd;
|
|
|
|
}
|
|
|
|
if self.eof() {
|
|
|
|
return self.error_event(EOFWhileParsingObject);
|
|
|
|
}
|
|
|
|
if !self.ch_is('"') {
|
|
|
|
return self.error_event(KeyMustBeAString);
|
|
|
|
}
|
|
|
|
let s = match self.parse_str() {
|
|
|
|
Ok(s) => { s }
|
|
|
|
Err(e) => {
|
|
|
|
self.state = ParseFinished;
|
|
|
|
return Error(e);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
self.parse_whitespace();
|
|
|
|
if self.eof() {
|
|
|
|
return self.error_event(EOFWhileParsingObject);
|
|
|
|
} else if self.ch_or_null() != ':' {
|
|
|
|
return self.error_event(ExpectedColon);
|
|
|
|
}
|
|
|
|
self.stack.push_key(s);
|
2012-02-25 18:39:32 -06:00
|
|
|
self.bump();
|
|
|
|
self.parse_whitespace();
|
|
|
|
|
2014-03-30 07:58:02 -05:00
|
|
|
let val = self.parse_value();
|
2012-02-25 18:39:32 -06:00
|
|
|
|
2014-03-30 07:58:02 -05:00
|
|
|
self.state = match val {
|
|
|
|
Error(_) => { ParseFinished }
|
|
|
|
ListStart => { ParseList(true) }
|
|
|
|
ObjectStart => { ParseObject(true) }
|
|
|
|
_ => { ParseObjectComma }
|
|
|
|
};
|
|
|
|
return val;
|
|
|
|
}
|
|
|
|
|
|
|
|
fn parse_object_end(&mut self) -> JsonEvent {
|
2014-02-06 06:56:52 -06:00
|
|
|
if self.ch_is('}') {
|
2014-03-30 07:58:02 -05:00
|
|
|
if self.stack.is_empty() {
|
|
|
|
self.state = ParseBeforeFinish;
|
|
|
|
} else {
|
|
|
|
self.state = if self.stack.last_is_index() {
|
|
|
|
ParseListComma
|
|
|
|
} else {
|
|
|
|
ParseObjectComma
|
|
|
|
}
|
|
|
|
}
|
|
|
|
self.bump();
|
2014-06-28 07:34:58 -05:00
|
|
|
ObjectEnd
|
2014-03-30 07:58:02 -05:00
|
|
|
} else if self.eof() {
|
2014-06-28 07:34:58 -05:00
|
|
|
self.error_event(EOFWhileParsingObject)
|
2014-03-30 07:58:02 -05:00
|
|
|
} else {
|
2014-06-28 07:34:58 -05:00
|
|
|
self.error_event(InvalidSyntax)
|
2012-02-25 18:39:32 -06:00
|
|
|
}
|
2014-03-30 07:58:02 -05:00
|
|
|
}
|
2012-02-25 18:39:32 -06:00
|
|
|
|
2014-03-30 07:58:02 -05:00
|
|
|
fn parse_value(&mut self) -> JsonEvent {
|
|
|
|
if self.eof() { return self.error_event(EOFWhileParsingValue); }
|
|
|
|
match self.ch_or_null() {
|
2014-06-28 07:34:58 -05:00
|
|
|
'n' => { self.parse_ident("ull", NullValue) }
|
|
|
|
't' => { self.parse_ident("rue", BooleanValue(true)) }
|
|
|
|
'f' => { self.parse_ident("alse", BooleanValue(false)) }
|
|
|
|
'0' .. '9' | '-' => match self.parse_number() {
|
2014-03-30 07:58:02 -05:00
|
|
|
Ok(f) => NumberValue(f),
|
|
|
|
Err(e) => Error(e),
|
|
|
|
},
|
2014-06-28 07:34:58 -05:00
|
|
|
'"' => match self.parse_str() {
|
2014-03-30 07:58:02 -05:00
|
|
|
Ok(s) => StringValue(s),
|
|
|
|
Err(e) => Error(e),
|
|
|
|
},
|
|
|
|
'[' => {
|
|
|
|
self.bump();
|
2014-06-28 07:34:58 -05:00
|
|
|
ListStart
|
2014-03-30 07:58:02 -05:00
|
|
|
}
|
|
|
|
'{' => {
|
|
|
|
self.bump();
|
2014-06-28 07:34:58 -05:00
|
|
|
ObjectStart
|
2012-02-25 18:39:32 -06:00
|
|
|
}
|
2014-06-28 07:34:58 -05:00
|
|
|
_ => { self.error_event(InvalidSyntax) }
|
2014-03-30 07:58:02 -05:00
|
|
|
}
|
|
|
|
}
|
2012-02-25 18:39:32 -06:00
|
|
|
|
2014-03-30 07:58:02 -05:00
|
|
|
fn parse_ident(&mut self, ident: &str, value: JsonEvent) -> JsonEvent {
|
|
|
|
if ident.chars().all(|c| Some(c) == self.next_char()) {
|
|
|
|
self.bump();
|
|
|
|
value
|
|
|
|
} else {
|
|
|
|
Error(SyntaxError(InvalidSyntax, self.line, self.col))
|
|
|
|
}
|
|
|
|
}
|
2012-02-25 18:39:32 -06:00
|
|
|
|
2014-03-30 07:58:02 -05:00
|
|
|
fn error_event(&mut self, reason: ErrorCode) -> JsonEvent {
|
|
|
|
self.state = ParseFinished;
|
|
|
|
Error(SyntaxError(reason, self.line, self.col))
|
|
|
|
}
|
|
|
|
}
|
2012-02-25 18:39:32 -06:00
|
|
|
|
2014-03-30 07:58:02 -05:00
|
|
|
/// A Builder consumes a json::Parser to create a generic Json structure.
|
|
|
|
pub struct Builder<T> {
|
|
|
|
parser: Parser<T>,
|
|
|
|
token: Option<JsonEvent>,
|
|
|
|
}
|
2012-02-25 18:39:32 -06:00
|
|
|
|
2014-03-30 07:58:02 -05:00
|
|
|
impl<T: Iterator<char>> Builder<T> {
|
|
|
|
/// Create a JSON Builder.
|
|
|
|
pub fn new(src: T) -> Builder<T> {
|
2014-06-28 07:34:58 -05:00
|
|
|
Builder { parser: Parser::new(src), token: None, }
|
2014-03-30 07:58:02 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
// Decode a Json value from a Parser.
|
|
|
|
pub fn build(&mut self) -> Result<Json, BuilderError> {
|
|
|
|
self.bump();
|
|
|
|
let result = self.build_value();
|
|
|
|
self.bump();
|
|
|
|
match self.token {
|
|
|
|
None => {}
|
|
|
|
Some(Error(e)) => { return Err(e); }
|
|
|
|
ref tok => { fail!("unexpected token {}", tok.clone()); }
|
|
|
|
}
|
2014-06-28 07:34:58 -05:00
|
|
|
result
|
2014-03-30 07:58:02 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
fn bump(&mut self) {
|
|
|
|
self.token = self.parser.next();
|
|
|
|
}
|
|
|
|
|
|
|
|
fn build_value(&mut self) -> Result<Json, BuilderError> {
|
|
|
|
return match self.token {
|
|
|
|
Some(NullValue) => { Ok(Null) }
|
|
|
|
Some(NumberValue(n)) => { Ok(Number(n)) }
|
|
|
|
Some(BooleanValue(b)) => { Ok(Boolean(b)) }
|
|
|
|
Some(StringValue(ref mut s)) => {
|
2014-05-22 18:57:53 -05:00
|
|
|
let mut temp = String::new();
|
2014-03-30 07:58:02 -05:00
|
|
|
swap(s, &mut temp);
|
|
|
|
Ok(String(temp))
|
2012-02-25 18:39:32 -06:00
|
|
|
}
|
2014-03-30 07:58:02 -05:00
|
|
|
Some(Error(e)) => { Err(e) }
|
|
|
|
Some(ListStart) => { self.build_list() }
|
|
|
|
Some(ObjectStart) => { self.build_object() }
|
|
|
|
Some(ObjectEnd) => { self.parser.error(InvalidSyntax) }
|
|
|
|
Some(ListEnd) => { self.parser.error(InvalidSyntax) }
|
|
|
|
None => { self.parser.error(EOFWhileParsingValue) }
|
|
|
|
}
|
|
|
|
}
|
2012-02-25 18:39:32 -06:00
|
|
|
|
2014-03-30 07:58:02 -05:00
|
|
|
fn build_list(&mut self) -> Result<Json, BuilderError> {
|
|
|
|
self.bump();
|
|
|
|
let mut values = Vec::new();
|
|
|
|
|
|
|
|
loop {
|
|
|
|
if self.token == Some(ListEnd) {
|
|
|
|
return Ok(List(values.move_iter().collect()));
|
|
|
|
}
|
|
|
|
match self.build_value() {
|
|
|
|
Ok(v) => values.push(v),
|
|
|
|
Err(e) => { return Err(e) }
|
2012-02-25 18:39:32 -06:00
|
|
|
}
|
2014-03-30 07:58:02 -05:00
|
|
|
self.bump();
|
2012-02-25 18:39:32 -06:00
|
|
|
}
|
2014-03-30 07:58:02 -05:00
|
|
|
}
|
2012-02-25 18:39:32 -06:00
|
|
|
|
2014-03-30 07:58:02 -05:00
|
|
|
fn build_object(&mut self) -> Result<Json, BuilderError> {
|
|
|
|
self.bump();
|
|
|
|
|
2014-06-28 07:41:40 -05:00
|
|
|
let mut values = TreeMap::new();
|
2014-03-30 07:58:02 -05:00
|
|
|
|
2014-06-28 07:34:58 -05:00
|
|
|
loop {
|
2014-03-30 07:58:02 -05:00
|
|
|
match self.token {
|
|
|
|
Some(ObjectEnd) => { return Ok(Object(values)); }
|
|
|
|
Some(Error(e)) => { return Err(e); }
|
|
|
|
None => { break; }
|
|
|
|
_ => {}
|
|
|
|
}
|
|
|
|
let key = match self.parser.stack().top() {
|
2014-05-25 05:17:19 -05:00
|
|
|
Some(Key(k)) => { k.to_string() }
|
2014-03-30 07:58:02 -05:00
|
|
|
_ => { fail!("invalid state"); }
|
|
|
|
};
|
|
|
|
match self.build_value() {
|
|
|
|
Ok(value) => { values.insert(key, value); }
|
|
|
|
Err(e) => { return Err(e); }
|
|
|
|
}
|
|
|
|
self.bump();
|
|
|
|
}
|
|
|
|
return self.parser.error(EOFWhileParsingObject);
|
2011-12-21 14:36:43 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-10-13 20:48:47 -05:00
|
|
|
/// Decodes a json value from an `&mut io::Reader`
|
2014-03-30 07:58:02 -05:00
|
|
|
pub fn from_reader(rdr: &mut io::Reader) -> Result<Json, BuilderError> {
|
2014-01-29 19:39:12 -06:00
|
|
|
let contents = match rdr.read_to_end() {
|
|
|
|
Ok(c) => c,
|
2014-03-30 07:58:02 -05:00
|
|
|
Err(e) => return Err(io_error_to_error(e))
|
2014-01-29 19:39:12 -06:00
|
|
|
};
|
2014-06-28 07:34:58 -05:00
|
|
|
let s = match str::from_utf8_owned(contents) {
|
|
|
|
Ok(s) => s,
|
|
|
|
_ => return Err(SyntaxError(NotUtf8, 0, 0))
|
2014-01-29 19:39:12 -06:00
|
|
|
};
|
2014-05-14 23:16:44 -05:00
|
|
|
let mut builder = Builder::new(s.as_slice().chars());
|
2014-03-30 07:58:02 -05:00
|
|
|
builder.build()
|
2011-11-07 13:01:28 -06:00
|
|
|
}
|
|
|
|
|
2012-12-17 21:31:04 -06:00
|
|
|
/// Decodes a json value from a string
|
2014-03-30 07:58:02 -05:00
|
|
|
pub fn from_str(s: &str) -> Result<Json, BuilderError> {
|
|
|
|
let mut builder = Builder::new(s.chars());
|
2014-06-28 07:34:58 -05:00
|
|
|
builder.build()
|
2012-02-25 18:39:32 -06:00
|
|
|
}
|
|
|
|
|
2013-05-28 22:11:41 -05:00
|
|
|
/// A structure to decode JSON to values in rust.
|
2013-05-03 19:55:53 -05:00
|
|
|
pub struct Decoder {
|
2014-04-17 17:59:07 -05:00
|
|
|
stack: Vec<Json>,
|
2013-05-03 19:55:53 -05:00
|
|
|
}
|
|
|
|
|
2013-11-29 13:11:52 -06:00
|
|
|
impl Decoder {
|
|
|
|
/// Creates a new decoder instance for decoding the specified JSON value.
|
2013-12-03 21:18:35 -06:00
|
|
|
pub fn new(json: Json) -> Decoder {
|
2014-06-28 07:34:58 -05:00
|
|
|
Decoder { stack: vec![json] }
|
2013-05-01 19:54:54 -05:00
|
|
|
}
|
2012-09-24 11:55:42 -05:00
|
|
|
}
|
|
|
|
|
2013-11-23 17:17:34 -06:00
|
|
|
impl Decoder {
|
2014-03-18 12:58:26 -05:00
|
|
|
fn pop(&mut self) -> Json {
|
|
|
|
self.stack.pop().unwrap()
|
2013-11-23 17:17:34 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-03-18 12:58:26 -05:00
|
|
|
macro_rules! expect(
|
|
|
|
($e:expr, Null) => ({
|
|
|
|
match $e {
|
|
|
|
Null => Ok(()),
|
2014-05-25 05:17:19 -05:00
|
|
|
other => Err(ExpectedError("Null".to_string(),
|
2014-05-27 22:44:58 -05:00
|
|
|
format!("{}", other)))
|
2014-03-18 12:58:26 -05:00
|
|
|
}
|
|
|
|
});
|
|
|
|
($e:expr, $t:ident) => ({
|
|
|
|
match $e {
|
|
|
|
$t(v) => Ok(v),
|
2014-05-14 23:16:44 -05:00
|
|
|
other => {
|
2014-05-25 05:17:19 -05:00
|
|
|
Err(ExpectedError(stringify!($t).to_string(),
|
2014-05-27 22:44:58 -05:00
|
|
|
format!("{}", other)))
|
2014-05-14 23:16:44 -05:00
|
|
|
}
|
2013-05-01 19:54:54 -05:00
|
|
|
}
|
2014-03-18 12:58:26 -05:00
|
|
|
})
|
|
|
|
)
|
|
|
|
|
2014-03-30 07:58:02 -05:00
|
|
|
impl ::Decoder<DecoderError> for Decoder {
|
2014-03-18 12:58:26 -05:00
|
|
|
fn read_nil(&mut self) -> DecodeResult<()> {
|
|
|
|
debug!("read_nil");
|
2014-06-28 07:34:58 -05:00
|
|
|
expect!(self.pop(), Null)
|
2013-05-01 19:54:54 -05:00
|
|
|
}
|
|
|
|
|
2014-03-18 12:58:26 -05:00
|
|
|
fn read_u64(&mut self) -> DecodeResult<u64 > { Ok(try!(self.read_f64()) as u64) }
|
|
|
|
fn read_u32(&mut self) -> DecodeResult<u32 > { Ok(try!(self.read_f64()) as u32) }
|
|
|
|
fn read_u16(&mut self) -> DecodeResult<u16 > { Ok(try!(self.read_f64()) as u16) }
|
|
|
|
fn read_u8 (&mut self) -> DecodeResult<u8 > { Ok(try!(self.read_f64()) as u8) }
|
|
|
|
fn read_uint(&mut self) -> DecodeResult<uint> { Ok(try!(self.read_f64()) as uint) }
|
2013-05-01 19:54:54 -05:00
|
|
|
|
2014-03-18 12:58:26 -05:00
|
|
|
fn read_i64(&mut self) -> DecodeResult<i64> { Ok(try!(self.read_f64()) as i64) }
|
|
|
|
fn read_i32(&mut self) -> DecodeResult<i32> { Ok(try!(self.read_f64()) as i32) }
|
|
|
|
fn read_i16(&mut self) -> DecodeResult<i16> { Ok(try!(self.read_f64()) as i16) }
|
|
|
|
fn read_i8 (&mut self) -> DecodeResult<i8 > { Ok(try!(self.read_f64()) as i8) }
|
|
|
|
fn read_int(&mut self) -> DecodeResult<int> { Ok(try!(self.read_f64()) as int) }
|
2013-05-01 19:54:54 -05:00
|
|
|
|
2014-03-18 12:58:26 -05:00
|
|
|
fn read_bool(&mut self) -> DecodeResult<bool> {
|
2013-10-21 15:08:31 -05:00
|
|
|
debug!("read_bool");
|
2014-06-28 07:34:58 -05:00
|
|
|
expect!(self.pop(), Boolean)
|
2013-05-01 19:54:54 -05:00
|
|
|
}
|
|
|
|
|
2014-03-18 12:58:26 -05:00
|
|
|
fn read_f64(&mut self) -> DecodeResult<f64> {
|
2013-10-21 15:08:31 -05:00
|
|
|
debug!("read_f64");
|
2014-03-18 12:58:26 -05:00
|
|
|
match self.pop() {
|
|
|
|
Number(f) => Ok(f),
|
2014-03-17 02:26:36 -05:00
|
|
|
String(s) => {
|
|
|
|
// re: #12967.. a type w/ numeric keys (ie HashMap<uint, V> etc)
|
2014-06-28 07:34:58 -05:00
|
|
|
// is going to have a string here, as per JSON spec.
|
|
|
|
Ok(std::from_str::from_str(s.as_slice()).unwrap())
|
2014-03-17 02:26:36 -05:00
|
|
|
},
|
2014-06-25 20:26:41 -05:00
|
|
|
Null => Ok(f64::NAN),
|
2014-06-28 07:34:58 -05:00
|
|
|
value => Err(ExpectedError("Number".to_string(), format!("{}", value)))
|
2013-05-01 19:54:54 -05:00
|
|
|
}
|
|
|
|
}
|
2014-03-18 11:04:23 -05:00
|
|
|
|
2014-06-28 07:34:58 -05:00
|
|
|
fn read_f32(&mut self) -> DecodeResult<f32> { self.read_f64().map(|x| x as f32) }
|
2013-05-01 19:54:54 -05:00
|
|
|
|
2014-03-18 12:58:26 -05:00
|
|
|
fn read_char(&mut self) -> DecodeResult<char> {
|
|
|
|
let s = try!(self.read_str());
|
2013-11-23 17:17:34 -06:00
|
|
|
{
|
2014-05-14 23:16:44 -05:00
|
|
|
let mut it = s.as_slice().chars();
|
2013-11-23 17:17:34 -06:00
|
|
|
match (it.next(), it.next()) {
|
|
|
|
// exactly one character
|
2014-03-18 12:58:26 -05:00
|
|
|
(Some(c), None) => return Ok(c),
|
2013-11-23 17:17:34 -06:00
|
|
|
_ => ()
|
|
|
|
}
|
|
|
|
}
|
2014-06-28 07:34:58 -05:00
|
|
|
Err(ExpectedError("single character string".to_string(), format!("{}", s)))
|
2013-05-01 19:54:54 -05:00
|
|
|
}
|
|
|
|
|
2014-05-22 18:57:53 -05:00
|
|
|
fn read_str(&mut self) -> DecodeResult<String> {
|
2013-10-21 15:08:31 -05:00
|
|
|
debug!("read_str");
|
2014-06-28 07:34:58 -05:00
|
|
|
expect!(self.pop(), String)
|
2013-05-01 19:54:54 -05:00
|
|
|
}
|
|
|
|
|
2014-03-18 12:58:26 -05:00
|
|
|
fn read_enum<T>(&mut self,
|
|
|
|
name: &str,
|
|
|
|
f: |&mut Decoder| -> DecodeResult<T>) -> DecodeResult<T> {
|
2013-10-21 15:08:31 -05:00
|
|
|
debug!("read_enum({})", name);
|
2013-05-01 19:54:54 -05:00
|
|
|
f(self)
|
|
|
|
}
|
|
|
|
|
|
|
|
fn read_enum_variant<T>(&mut self,
|
|
|
|
names: &[&str],
|
2014-03-18 12:58:26 -05:00
|
|
|
f: |&mut Decoder, uint| -> DecodeResult<T>)
|
|
|
|
-> DecodeResult<T> {
|
2014-05-22 13:28:01 -05:00
|
|
|
debug!("read_enum_variant(names={})", names);
|
2014-03-18 12:58:26 -05:00
|
|
|
let name = match self.pop() {
|
2013-05-01 19:54:54 -05:00
|
|
|
String(s) => s,
|
2013-11-23 17:17:34 -06:00
|
|
|
Object(mut o) => {
|
2014-05-25 05:17:19 -05:00
|
|
|
let n = match o.pop(&"variant".to_string()) {
|
2013-11-23 17:17:34 -06:00
|
|
|
Some(String(s)) => s,
|
2014-05-14 23:16:44 -05:00
|
|
|
Some(val) => {
|
2014-06-28 07:34:58 -05:00
|
|
|
return Err(ExpectedError("String".to_string(), format!("{}", val)))
|
2014-05-14 23:16:44 -05:00
|
|
|
}
|
|
|
|
None => {
|
2014-05-25 05:17:19 -05:00
|
|
|
return Err(MissingFieldError("variant".to_string()))
|
2014-05-14 23:16:44 -05:00
|
|
|
}
|
2013-08-09 19:05:24 -05:00
|
|
|
};
|
2014-05-25 05:17:19 -05:00
|
|
|
match o.pop(&"fields".to_string()) {
|
2013-11-23 17:17:34 -06:00
|
|
|
Some(List(l)) => {
|
Deprecate the rev_iter pattern in all places where a DoubleEndedIterator is provided (everywhere but treemap)
This commit deprecates rev_iter, mut_rev_iter, move_rev_iter everywhere (except treemap) and also
deprecates related functions like rsplit, rev_components, and rev_str_components. In every case,
these functions can be replaced with the non-reversed form followed by a call to .rev(). To make this
more concrete, a translation table for all functional changes necessary follows:
* container.rev_iter() -> container.iter().rev()
* container.mut_rev_iter() -> container.mut_iter().rev()
* container.move_rev_iter() -> container.move_iter().rev()
* sliceorstr.rsplit(sep) -> sliceorstr.split(sep).rev()
* path.rev_components() -> path.components().rev()
* path.rev_str_components() -> path.str_components().rev()
In terms of the type system, this change also deprecates any specialized reversed iterator types (except
in treemap), opting instead to use Rev directly if any type annotations are needed. However, since
methods directly returning reversed iterators are now discouraged, the need for such annotations should
be small. However, in those cases, the general pattern for conversion is to take whatever follows Rev in
the original reversed name and surround it with Rev<>:
* RevComponents<'a> -> Rev<Components<'a>>
* RevStrComponents<'a> -> Rev<StrComponents<'a>>
* RevItems<'a, T> -> Rev<Items<'a, T>>
* etc.
The reasoning behind this change is that it makes the standard API much simpler without reducing readability,
performance, or power. The presence of functions such as rev_iter adds more boilerplate code to libraries
(all of which simply call .iter().rev()), clutters up the documentation, and only helps code by saving two
characters. Additionally, the numerous type synonyms that were used to make the type signatures look nice
like RevItems add even more boilerplate and clutter up the docs even more. With this change, all that cruft
goes away.
[breaking-change]
2014-04-20 23:59:12 -05:00
|
|
|
for field in l.move_iter().rev() {
|
2014-06-28 07:34:58 -05:00
|
|
|
self.stack.push(field);
|
2013-08-09 19:05:24 -05:00
|
|
|
}
|
|
|
|
},
|
2014-05-14 23:16:44 -05:00
|
|
|
Some(val) => {
|
2014-06-28 07:34:58 -05:00
|
|
|
return Err(ExpectedError("List".to_string(), format!("{}", val)))
|
2014-05-14 23:16:44 -05:00
|
|
|
}
|
|
|
|
None => {
|
2014-05-25 05:17:19 -05:00
|
|
|
return Err(MissingFieldError("fields".to_string()))
|
2014-05-14 23:16:44 -05:00
|
|
|
}
|
2013-05-01 19:54:54 -05:00
|
|
|
}
|
2013-08-09 19:05:24 -05:00
|
|
|
n
|
2013-05-01 19:54:54 -05:00
|
|
|
}
|
2014-05-14 23:16:44 -05:00
|
|
|
json => {
|
2014-06-28 07:34:58 -05:00
|
|
|
return Err(ExpectedError("String or Object".to_string(), format!("{}", json)))
|
2014-05-14 23:16:44 -05:00
|
|
|
}
|
2013-05-01 19:54:54 -05:00
|
|
|
};
|
2014-05-14 23:16:44 -05:00
|
|
|
let idx = match names.iter()
|
2014-06-28 07:34:58 -05:00
|
|
|
.position(|n| str::eq_slice(*n, name.as_slice())) {
|
2013-05-01 19:54:54 -05:00
|
|
|
Some(idx) => idx,
|
2014-03-18 12:58:26 -05:00
|
|
|
None => return Err(UnknownVariantError(name))
|
2013-05-01 19:54:54 -05:00
|
|
|
};
|
|
|
|
f(self, idx)
|
|
|
|
}
|
|
|
|
|
2014-03-18 12:58:26 -05:00
|
|
|
fn read_enum_variant_arg<T>(&mut self, idx: uint, f: |&mut Decoder| -> DecodeResult<T>)
|
|
|
|
-> DecodeResult<T> {
|
2013-10-21 15:08:31 -05:00
|
|
|
debug!("read_enum_variant_arg(idx={})", idx);
|
2013-05-01 19:54:54 -05:00
|
|
|
f(self)
|
|
|
|
}
|
|
|
|
|
|
|
|
fn read_enum_struct_variant<T>(&mut self,
|
|
|
|
names: &[&str],
|
2014-03-18 12:58:26 -05:00
|
|
|
f: |&mut Decoder, uint| -> DecodeResult<T>)
|
|
|
|
-> DecodeResult<T> {
|
2014-05-22 13:28:01 -05:00
|
|
|
debug!("read_enum_struct_variant(names={})", names);
|
2013-05-01 19:54:54 -05:00
|
|
|
self.read_enum_variant(names, f)
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
fn read_enum_struct_variant_field<T>(&mut self,
|
|
|
|
name: &str,
|
|
|
|
idx: uint,
|
2014-03-18 12:58:26 -05:00
|
|
|
f: |&mut Decoder| -> DecodeResult<T>)
|
|
|
|
-> DecodeResult<T> {
|
2013-10-21 15:08:31 -05:00
|
|
|
debug!("read_enum_struct_variant_field(name={}, idx={})", name, idx);
|
2013-05-01 19:54:54 -05:00
|
|
|
self.read_enum_variant_arg(idx, f)
|
|
|
|
}
|
|
|
|
|
|
|
|
fn read_struct<T>(&mut self,
|
|
|
|
name: &str,
|
|
|
|
len: uint,
|
2014-03-18 12:58:26 -05:00
|
|
|
f: |&mut Decoder| -> DecodeResult<T>)
|
|
|
|
-> DecodeResult<T> {
|
2013-10-21 15:08:31 -05:00
|
|
|
debug!("read_struct(name={}, len={})", name, len);
|
2014-03-18 12:58:26 -05:00
|
|
|
let value = try!(f(self));
|
|
|
|
self.pop();
|
|
|
|
Ok(value)
|
2013-05-01 19:54:54 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
fn read_struct_field<T>(&mut self,
|
|
|
|
name: &str,
|
|
|
|
idx: uint,
|
2014-03-18 12:58:26 -05:00
|
|
|
f: |&mut Decoder| -> DecodeResult<T>)
|
|
|
|
-> DecodeResult<T> {
|
2013-10-21 15:08:31 -05:00
|
|
|
debug!("read_struct_field(name={}, idx={})", name, idx);
|
2014-03-18 12:58:26 -05:00
|
|
|
let mut obj = try!(expect!(self.pop(), Object));
|
|
|
|
|
2014-05-25 05:17:19 -05:00
|
|
|
let value = match obj.pop(&name.to_string()) {
|
|
|
|
None => return Err(MissingFieldError(name.to_string())),
|
2014-03-18 12:58:26 -05:00
|
|
|
Some(json) => {
|
|
|
|
self.stack.push(json);
|
|
|
|
try!(f(self))
|
2013-05-01 19:54:54 -05:00
|
|
|
}
|
2014-03-18 12:58:26 -05:00
|
|
|
};
|
|
|
|
self.stack.push(Object(obj));
|
|
|
|
Ok(value)
|
2013-05-01 19:54:54 -05:00
|
|
|
}
|
|
|
|
|
2014-03-18 12:58:26 -05:00
|
|
|
fn read_tuple<T>(&mut self, f: |&mut Decoder, uint| -> DecodeResult<T>) -> DecodeResult<T> {
|
2013-10-21 15:08:31 -05:00
|
|
|
debug!("read_tuple()");
|
2013-05-01 19:54:54 -05:00
|
|
|
self.read_seq(f)
|
|
|
|
}
|
|
|
|
|
2014-03-18 12:58:26 -05:00
|
|
|
fn read_tuple_arg<T>(&mut self,
|
|
|
|
idx: uint,
|
|
|
|
f: |&mut Decoder| -> DecodeResult<T>) -> DecodeResult<T> {
|
2013-10-21 15:08:31 -05:00
|
|
|
debug!("read_tuple_arg(idx={})", idx);
|
2013-05-01 19:54:54 -05:00
|
|
|
self.read_seq_elt(idx, f)
|
|
|
|
}
|
|
|
|
|
|
|
|
fn read_tuple_struct<T>(&mut self,
|
|
|
|
name: &str,
|
2014-03-18 12:58:26 -05:00
|
|
|
f: |&mut Decoder, uint| -> DecodeResult<T>)
|
|
|
|
-> DecodeResult<T> {
|
2013-10-21 15:08:31 -05:00
|
|
|
debug!("read_tuple_struct(name={})", name);
|
2013-05-01 19:54:54 -05:00
|
|
|
self.read_tuple(f)
|
|
|
|
}
|
|
|
|
|
|
|
|
fn read_tuple_struct_arg<T>(&mut self,
|
|
|
|
idx: uint,
|
2014-03-18 12:58:26 -05:00
|
|
|
f: |&mut Decoder| -> DecodeResult<T>)
|
|
|
|
-> DecodeResult<T> {
|
2013-10-21 15:08:31 -05:00
|
|
|
debug!("read_tuple_struct_arg(idx={})", idx);
|
2013-05-01 19:54:54 -05:00
|
|
|
self.read_tuple_arg(idx, f)
|
|
|
|
}
|
|
|
|
|
2014-03-18 12:58:26 -05:00
|
|
|
fn read_option<T>(&mut self, f: |&mut Decoder, bool| -> DecodeResult<T>) -> DecodeResult<T> {
|
|
|
|
match self.pop() {
|
2013-05-01 19:54:54 -05:00
|
|
|
Null => f(self, false),
|
|
|
|
value => { self.stack.push(value); f(self, true) }
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-03-18 12:58:26 -05:00
|
|
|
fn read_seq<T>(&mut self, f: |&mut Decoder, uint| -> DecodeResult<T>) -> DecodeResult<T> {
|
2013-10-21 15:08:31 -05:00
|
|
|
debug!("read_seq()");
|
2014-03-18 12:58:26 -05:00
|
|
|
let list = try!(expect!(self.pop(), List));
|
|
|
|
let len = list.len();
|
Deprecate the rev_iter pattern in all places where a DoubleEndedIterator is provided (everywhere but treemap)
This commit deprecates rev_iter, mut_rev_iter, move_rev_iter everywhere (except treemap) and also
deprecates related functions like rsplit, rev_components, and rev_str_components. In every case,
these functions can be replaced with the non-reversed form followed by a call to .rev(). To make this
more concrete, a translation table for all functional changes necessary follows:
* container.rev_iter() -> container.iter().rev()
* container.mut_rev_iter() -> container.mut_iter().rev()
* container.move_rev_iter() -> container.move_iter().rev()
* sliceorstr.rsplit(sep) -> sliceorstr.split(sep).rev()
* path.rev_components() -> path.components().rev()
* path.rev_str_components() -> path.str_components().rev()
In terms of the type system, this change also deprecates any specialized reversed iterator types (except
in treemap), opting instead to use Rev directly if any type annotations are needed. However, since
methods directly returning reversed iterators are now discouraged, the need for such annotations should
be small. However, in those cases, the general pattern for conversion is to take whatever follows Rev in
the original reversed name and surround it with Rev<>:
* RevComponents<'a> -> Rev<Components<'a>>
* RevStrComponents<'a> -> Rev<StrComponents<'a>>
* RevItems<'a, T> -> Rev<Items<'a, T>>
* etc.
The reasoning behind this change is that it makes the standard API much simpler without reducing readability,
performance, or power. The presence of functions such as rev_iter adds more boilerplate code to libraries
(all of which simply call .iter().rev()), clutters up the documentation, and only helps code by saving two
characters. Additionally, the numerous type synonyms that were used to make the type signatures look nice
like RevItems add even more boilerplate and clutter up the docs even more. With this change, all that cruft
goes away.
[breaking-change]
2014-04-20 23:59:12 -05:00
|
|
|
for v in list.move_iter().rev() {
|
2014-03-18 12:58:26 -05:00
|
|
|
self.stack.push(v);
|
|
|
|
}
|
2013-05-01 19:54:54 -05:00
|
|
|
f(self, len)
|
|
|
|
}
|
|
|
|
|
2014-03-18 12:58:26 -05:00
|
|
|
fn read_seq_elt<T>(&mut self,
|
|
|
|
idx: uint,
|
|
|
|
f: |&mut Decoder| -> DecodeResult<T>) -> DecodeResult<T> {
|
2013-10-21 15:08:31 -05:00
|
|
|
debug!("read_seq_elt(idx={})", idx);
|
2013-05-01 19:54:54 -05:00
|
|
|
f(self)
|
|
|
|
}
|
|
|
|
|
2014-03-18 12:58:26 -05:00
|
|
|
fn read_map<T>(&mut self, f: |&mut Decoder, uint| -> DecodeResult<T>) -> DecodeResult<T> {
|
2013-10-21 15:08:31 -05:00
|
|
|
debug!("read_map()");
|
2014-03-18 12:58:26 -05:00
|
|
|
let obj = try!(expect!(self.pop(), Object));
|
|
|
|
let len = obj.len();
|
|
|
|
for (key, value) in obj.move_iter() {
|
|
|
|
self.stack.push(value);
|
|
|
|
self.stack.push(String(key));
|
|
|
|
}
|
2013-05-01 19:54:54 -05:00
|
|
|
f(self, len)
|
|
|
|
}
|
|
|
|
|
2014-03-18 12:58:26 -05:00
|
|
|
fn read_map_elt_key<T>(&mut self, idx: uint, f: |&mut Decoder| -> DecodeResult<T>)
|
|
|
|
-> DecodeResult<T> {
|
2013-10-21 15:08:31 -05:00
|
|
|
debug!("read_map_elt_key(idx={})", idx);
|
2013-05-01 19:54:54 -05:00
|
|
|
f(self)
|
|
|
|
}
|
|
|
|
|
2014-03-18 12:58:26 -05:00
|
|
|
fn read_map_elt_val<T>(&mut self, idx: uint, f: |&mut Decoder| -> DecodeResult<T>)
|
|
|
|
-> DecodeResult<T> {
|
2013-10-21 15:08:31 -05:00
|
|
|
debug!("read_map_elt_val(idx={})", idx);
|
2013-05-01 19:54:54 -05:00
|
|
|
f(self)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-05-28 22:11:41 -05:00
|
|
|
/// A trait for converting values to JSON
|
2013-07-10 18:17:41 -05:00
|
|
|
pub trait ToJson {
|
2013-05-28 22:11:41 -05:00
|
|
|
/// Converts the value of `self` to an instance of JSON
|
|
|
|
fn to_json(&self) -> Json;
|
|
|
|
}
|
2012-05-28 14:10:32 -05:00
|
|
|
|
2014-06-28 07:34:58 -05:00
|
|
|
macro_rules! to_json_impl(
|
|
|
|
($($t:ty), +) => (
|
|
|
|
$(impl ToJson for $t {
|
|
|
|
fn to_json(&self) -> Json { Number(*self as f64) }
|
|
|
|
})+
|
|
|
|
)
|
|
|
|
)
|
2012-05-28 14:10:32 -05:00
|
|
|
|
2014-06-28 07:34:58 -05:00
|
|
|
to_json_impl!(int, i8, i16, i32, i64, uint, u8, u16, u32, u64)
|
2012-05-28 14:10:32 -05:00
|
|
|
|
2014-06-28 07:34:58 -05:00
|
|
|
impl ToJson for Json {
|
|
|
|
fn to_json(&self) -> Json { self.clone() }
|
2012-05-28 14:10:32 -05:00
|
|
|
}
|
|
|
|
|
2013-02-14 13:47:00 -06:00
|
|
|
impl ToJson for f32 {
|
2014-06-25 20:26:41 -05:00
|
|
|
fn to_json(&self) -> Json { (*self as f64).to_json() }
|
2012-05-28 14:10:32 -05:00
|
|
|
}
|
|
|
|
|
2013-02-14 13:47:00 -06:00
|
|
|
impl ToJson for f64 {
|
2014-06-25 20:26:41 -05:00
|
|
|
fn to_json(&self) -> Json {
|
|
|
|
match self.classify() {
|
|
|
|
FPNaN | FPInfinite => Null,
|
2014-06-28 07:34:58 -05:00
|
|
|
_ => Number(*self)
|
2014-06-25 20:26:41 -05:00
|
|
|
}
|
|
|
|
}
|
2012-05-28 14:10:32 -05:00
|
|
|
}
|
|
|
|
|
2013-02-14 13:47:00 -06:00
|
|
|
impl ToJson for () {
|
2013-03-07 20:11:09 -06:00
|
|
|
fn to_json(&self) -> Json { Null }
|
2012-05-28 14:10:32 -05:00
|
|
|
}
|
|
|
|
|
2013-02-14 13:47:00 -06:00
|
|
|
impl ToJson for bool {
|
2013-03-07 20:11:09 -06:00
|
|
|
fn to_json(&self) -> Json { Boolean(*self) }
|
2012-05-28 14:10:32 -05:00
|
|
|
}
|
|
|
|
|
2014-05-22 18:57:53 -05:00
|
|
|
impl ToJson for String {
|
2014-05-14 23:16:44 -05:00
|
|
|
fn to_json(&self) -> Json { String((*self).clone()) }
|
2014-04-30 17:55:04 -05:00
|
|
|
}
|
|
|
|
|
2014-06-29 04:33:45 -05:00
|
|
|
macro_rules! tuple_impl {
|
|
|
|
// use variables to indicate the arity of the tuple
|
|
|
|
($($tyvar:ident),* ) => {
|
|
|
|
// the trailing commas are for the 1 tuple
|
|
|
|
impl<
|
|
|
|
$( $tyvar : ToJson ),*
|
|
|
|
> ToJson for ( $( $tyvar ),* , ) {
|
|
|
|
|
|
|
|
#[inline]
|
|
|
|
#[allow(uppercase_variables)]
|
|
|
|
fn to_json(&self) -> Json {
|
|
|
|
match *self {
|
|
|
|
($(ref $tyvar),*,) => List(vec![$($tyvar.to_json()),*])
|
|
|
|
}
|
2014-06-28 07:34:58 -05:00
|
|
|
}
|
2012-08-02 17:42:56 -05:00
|
|
|
}
|
2012-05-28 14:10:32 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-06-29 04:33:45 -05:00
|
|
|
tuple_impl!{A}
|
|
|
|
tuple_impl!{A, B}
|
|
|
|
tuple_impl!{A, B, C}
|
|
|
|
tuple_impl!{A, B, C, D}
|
|
|
|
tuple_impl!{A, B, C, D, E}
|
|
|
|
tuple_impl!{A, B, C, D, E, F}
|
|
|
|
tuple_impl!{A, B, C, D, E, F, G}
|
|
|
|
tuple_impl!{A, B, C, D, E, F, G, H}
|
|
|
|
tuple_impl!{A, B, C, D, E, F, G, H, I}
|
|
|
|
tuple_impl!{A, B, C, D, E, F, G, H, I, J}
|
|
|
|
tuple_impl!{A, B, C, D, E, F, G, H, I, J, K}
|
|
|
|
tuple_impl!{A, B, C, D, E, F, G, H, I, J, K, L}
|
2012-05-28 14:10:32 -05:00
|
|
|
|
2014-06-28 07:34:58 -05:00
|
|
|
impl<'a, A: ToJson> ToJson for &'a [A] {
|
2014-06-03 10:49:26 -05:00
|
|
|
fn to_json(&self) -> Json { List(self.iter().map(|elt| elt.to_json()).collect()) }
|
|
|
|
}
|
|
|
|
|
2014-06-28 07:34:58 -05:00
|
|
|
impl<A: ToJson> ToJson for Vec<A> {
|
2014-05-02 02:02:15 -05:00
|
|
|
fn to_json(&self) -> Json { List(self.iter().map(|elt| elt.to_json()).collect()) }
|
|
|
|
}
|
|
|
|
|
2014-06-28 07:34:58 -05:00
|
|
|
impl<A: ToJson> ToJson for TreeMap<String, A> {
|
2013-03-07 20:11:09 -06:00
|
|
|
fn to_json(&self) -> Json {
|
2013-07-18 14:37:40 -05:00
|
|
|
let mut d = TreeMap::new();
|
2013-08-03 11:45:23 -05:00
|
|
|
for (key, value) in self.iter() {
|
2013-07-02 14:47:32 -05:00
|
|
|
d.insert((*key).clone(), value.to_json());
|
2012-09-24 11:55:42 -05:00
|
|
|
}
|
2014-06-28 07:41:40 -05:00
|
|
|
Object(d)
|
2012-09-24 11:55:42 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-06-28 07:34:58 -05:00
|
|
|
impl<A: ToJson> ToJson for HashMap<String, A> {
|
2013-07-08 18:21:09 -05:00
|
|
|
fn to_json(&self) -> Json {
|
2013-07-18 14:37:40 -05:00
|
|
|
let mut d = TreeMap::new();
|
2013-08-03 11:45:23 -05:00
|
|
|
for (key, value) in self.iter() {
|
2013-07-02 14:47:32 -05:00
|
|
|
d.insert((*key).clone(), value.to_json());
|
2013-07-08 18:21:09 -05:00
|
|
|
}
|
2014-06-28 07:41:40 -05:00
|
|
|
Object(d)
|
2013-07-08 18:21:09 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-02-20 19:07:17 -06:00
|
|
|
impl<A:ToJson> ToJson for Option<A> {
|
2013-03-07 20:11:09 -06:00
|
|
|
fn to_json(&self) -> Json {
|
|
|
|
match *self {
|
2014-06-28 07:34:58 -05:00
|
|
|
None => Null,
|
|
|
|
Some(ref value) => value.to_json()
|
2012-05-28 14:10:32 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-02-19 20:56:33 -06:00
|
|
|
impl fmt::Show for Json {
|
2013-08-22 00:32:18 -05:00
|
|
|
/// Encodes a json value into a string
|
2014-02-19 20:56:33 -06:00
|
|
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
2014-05-10 16:05:06 -05:00
|
|
|
self.to_writer(f).map_err(|_| fmt::WriteError)
|
2013-08-22 00:32:18 -05:00
|
|
|
}
|
2012-05-28 14:10:32 -05:00
|
|
|
}
|
|
|
|
|
2014-06-28 08:39:49 -05:00
|
|
|
impl std::from_str::FromStr for Json {
|
|
|
|
fn from_str(s: &str) -> Option<Json> {
|
|
|
|
from_str(s).ok()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-01-17 21:05:07 -06:00
|
|
|
#[cfg(test)]
|
|
|
|
mod tests {
|
2014-03-30 07:58:02 -05:00
|
|
|
extern crate test;
|
|
|
|
use self::test::Bencher;
|
2014-02-21 16:18:39 -06:00
|
|
|
use {Encodable, Decodable};
|
|
|
|
use super::{Encoder, Decoder, Error, Boolean, Number, List, String, Null,
|
2014-03-18 12:58:26 -05:00
|
|
|
PrettyEncoder, Object, Json, from_str, ParseError, ExpectedError,
|
2014-03-30 07:58:02 -05:00
|
|
|
MissingFieldError, UnknownVariantError, DecodeResult, DecoderError,
|
|
|
|
JsonEvent, Parser, StackElement,
|
|
|
|
ObjectStart, ObjectEnd, ListStart, ListEnd, BooleanValue, NumberValue, StringValue,
|
|
|
|
NullValue, SyntaxError, Key, Index, Stack,
|
|
|
|
InvalidSyntax, InvalidNumber, EOFWhileParsingObject, EOFWhileParsingList,
|
|
|
|
EOFWhileParsingValue, EOFWhileParsingString, KeyMustBeAString, ExpectedColon,
|
|
|
|
TrailingCharacters};
|
2014-06-28 08:39:49 -05:00
|
|
|
use std::{f32, f64, io};
|
2014-05-29 21:03:06 -05:00
|
|
|
use std::collections::TreeMap;
|
2013-03-27 02:13:01 -05:00
|
|
|
|
2014-05-29 19:45:07 -05:00
|
|
|
#[deriving(PartialEq, Encodable, Decodable, Show)]
|
2013-03-30 13:08:57 -05:00
|
|
|
enum Animal {
|
|
|
|
Dog,
|
2014-05-22 18:57:53 -05:00
|
|
|
Frog(String, int)
|
2013-03-30 13:08:57 -05:00
|
|
|
}
|
|
|
|
|
2014-05-29 19:45:07 -05:00
|
|
|
#[deriving(PartialEq, Encodable, Decodable, Show)]
|
2013-03-30 15:31:03 -05:00
|
|
|
struct Inner {
|
|
|
|
a: (),
|
|
|
|
b: uint,
|
2014-05-22 18:57:53 -05:00
|
|
|
c: Vec<String>,
|
2013-03-30 15:31:03 -05:00
|
|
|
}
|
|
|
|
|
2014-05-29 19:45:07 -05:00
|
|
|
#[deriving(PartialEq, Encodable, Decodable, Show)]
|
2013-03-30 15:31:03 -05:00
|
|
|
struct Outer {
|
2014-05-04 01:34:26 -05:00
|
|
|
inner: Vec<Inner>,
|
2013-03-30 15:31:03 -05:00
|
|
|
}
|
|
|
|
|
2014-05-22 18:57:53 -05:00
|
|
|
fn mk_object(items: &[(String, Json)]) -> Json {
|
2014-06-28 07:41:40 -05:00
|
|
|
let mut d = TreeMap::new();
|
2012-02-25 18:39:32 -06:00
|
|
|
|
2013-08-03 11:45:23 -05:00
|
|
|
for item in items.iter() {
|
2012-09-24 11:55:42 -05:00
|
|
|
match *item {
|
2013-07-02 14:47:32 -05:00
|
|
|
(ref key, ref value) => { d.insert((*key).clone(), (*value).clone()); },
|
2012-09-24 11:55:42 -05:00
|
|
|
}
|
2012-02-25 18:39:32 -06:00
|
|
|
};
|
|
|
|
|
2013-02-15 01:30:30 -06:00
|
|
|
Object(d)
|
2012-02-25 18:39:32 -06:00
|
|
|
}
|
|
|
|
|
2014-06-28 08:39:49 -05:00
|
|
|
#[test]
|
|
|
|
fn test_from_str_trait() {
|
|
|
|
let s = "null";
|
|
|
|
assert!(::std::from_str::from_str::<Json>(s).unwrap() == from_str(s).unwrap());
|
|
|
|
}
|
|
|
|
|
2012-02-25 18:39:32 -06:00
|
|
|
#[test]
|
|
|
|
fn test_write_null() {
|
2014-06-21 05:39:03 -05:00
|
|
|
assert_eq!(Null.to_string().into_string(), "null".to_string());
|
2014-05-25 05:17:19 -05:00
|
|
|
assert_eq!(Null.to_pretty_str().into_string(), "null".to_string());
|
2012-02-25 18:39:32 -06:00
|
|
|
}
|
|
|
|
|
2013-03-30 13:08:57 -05:00
|
|
|
|
2012-02-25 18:39:32 -06:00
|
|
|
#[test]
|
2012-09-24 11:55:42 -05:00
|
|
|
fn test_write_number() {
|
2014-06-21 05:39:03 -05:00
|
|
|
assert_eq!(Number(3.0).to_string().into_string(), "3".to_string());
|
2014-05-25 05:17:19 -05:00
|
|
|
assert_eq!(Number(3.0).to_pretty_str().into_string(), "3".to_string());
|
2013-03-30 13:08:57 -05:00
|
|
|
|
2014-06-21 05:39:03 -05:00
|
|
|
assert_eq!(Number(3.1).to_string().into_string(), "3.1".to_string());
|
2014-05-25 05:17:19 -05:00
|
|
|
assert_eq!(Number(3.1).to_pretty_str().into_string(), "3.1".to_string());
|
2013-03-30 13:08:57 -05:00
|
|
|
|
2014-06-21 05:39:03 -05:00
|
|
|
assert_eq!(Number(-1.5).to_string().into_string(), "-1.5".to_string());
|
2014-05-25 05:17:19 -05:00
|
|
|
assert_eq!(Number(-1.5).to_pretty_str().into_string(), "-1.5".to_string());
|
2013-03-30 13:08:57 -05:00
|
|
|
|
2014-06-21 05:39:03 -05:00
|
|
|
assert_eq!(Number(0.5).to_string().into_string(), "0.5".to_string());
|
2014-05-25 05:17:19 -05:00
|
|
|
assert_eq!(Number(0.5).to_pretty_str().into_string(), "0.5".to_string());
|
2014-06-25 20:26:41 -05:00
|
|
|
|
2014-06-21 05:39:03 -05:00
|
|
|
assert_eq!(Number(f64::NAN).to_string().into_string(), "null".to_string());
|
2014-06-25 20:26:41 -05:00
|
|
|
assert_eq!(Number(f64::NAN).to_pretty_str().into_string(), "null".to_string());
|
|
|
|
|
2014-06-21 05:39:03 -05:00
|
|
|
assert_eq!(Number(f64::INFINITY).to_string().into_string(), "null".to_string());
|
2014-06-25 20:26:41 -05:00
|
|
|
assert_eq!(Number(f64::INFINITY).to_pretty_str().into_string(), "null".to_string());
|
|
|
|
|
2014-06-21 05:39:03 -05:00
|
|
|
assert_eq!(Number(f64::NEG_INFINITY).to_string().into_string(), "null".to_string());
|
2014-06-25 20:26:41 -05:00
|
|
|
assert_eq!(Number(f64::NEG_INFINITY).to_pretty_str().into_string(), "null".to_string());
|
2012-02-25 18:39:32 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_write_str() {
|
2014-06-21 05:39:03 -05:00
|
|
|
assert_eq!(String("".to_string()).to_string().into_string(), "\"\"".to_string());
|
2014-05-25 05:17:19 -05:00
|
|
|
assert_eq!(String("".to_string()).to_pretty_str().into_string(), "\"\"".to_string());
|
2013-03-30 13:08:57 -05:00
|
|
|
|
2014-06-21 05:39:03 -05:00
|
|
|
assert_eq!(String("foo".to_string()).to_string().into_string(), "\"foo\"".to_string());
|
2014-05-25 05:17:19 -05:00
|
|
|
assert_eq!(String("foo".to_string()).to_pretty_str().into_string(), "\"foo\"".to_string());
|
2012-02-25 18:39:32 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_write_bool() {
|
2014-06-21 05:39:03 -05:00
|
|
|
assert_eq!(Boolean(true).to_string().into_string(), "true".to_string());
|
2014-05-25 05:17:19 -05:00
|
|
|
assert_eq!(Boolean(true).to_pretty_str().into_string(), "true".to_string());
|
2013-03-30 13:08:57 -05:00
|
|
|
|
2014-06-21 05:39:03 -05:00
|
|
|
assert_eq!(Boolean(false).to_string().into_string(), "false".to_string());
|
2014-05-25 05:17:19 -05:00
|
|
|
assert_eq!(Boolean(false).to_pretty_str().into_string(), "false".to_string());
|
2012-02-25 18:39:32 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_write_list() {
|
2014-06-21 05:39:03 -05:00
|
|
|
assert_eq!(List(vec![]).to_string().into_string(), "[]".to_string());
|
2014-05-25 05:17:19 -05:00
|
|
|
assert_eq!(List(vec![]).to_pretty_str().into_string(), "[]".to_string());
|
2013-03-30 13:08:57 -05:00
|
|
|
|
2014-06-21 05:39:03 -05:00
|
|
|
assert_eq!(List(vec![Boolean(true)]).to_string().into_string(), "[true]".to_string());
|
2013-03-26 19:34:49 -05:00
|
|
|
assert_eq!(
|
2014-05-25 05:17:19 -05:00
|
|
|
List(vec![Boolean(true)]).to_pretty_str().into_string(),
|
2014-04-15 20:17:48 -05:00
|
|
|
"\
|
2013-03-26 19:34:49 -05:00
|
|
|
[\n \
|
|
|
|
true\n\
|
2014-05-25 05:17:19 -05:00
|
|
|
]".to_string()
|
2013-03-26 19:34:49 -05:00
|
|
|
);
|
2013-03-30 13:08:57 -05:00
|
|
|
|
2014-05-04 01:34:26 -05:00
|
|
|
let long_test_list = List(vec![
|
2013-03-30 13:08:57 -05:00
|
|
|
Boolean(false),
|
|
|
|
Null,
|
2014-05-25 05:17:19 -05:00
|
|
|
List(vec![String("foo\nbar".to_string()), Number(3.5)])]);
|
2013-08-22 00:32:18 -05:00
|
|
|
|
2014-06-21 05:39:03 -05:00
|
|
|
assert_eq!(long_test_list.to_string().into_string(),
|
2014-05-25 05:17:19 -05:00
|
|
|
"[false,null,[\"foo\\nbar\",3.5]]".to_string());
|
2013-03-26 19:34:49 -05:00
|
|
|
assert_eq!(
|
2014-05-25 05:17:19 -05:00
|
|
|
long_test_list.to_pretty_str().into_string(),
|
2014-04-15 20:17:48 -05:00
|
|
|
"\
|
2013-03-26 19:34:49 -05:00
|
|
|
[\n \
|
|
|
|
false,\n \
|
|
|
|
null,\n \
|
|
|
|
[\n \
|
|
|
|
\"foo\\nbar\",\n \
|
|
|
|
3.5\n \
|
|
|
|
]\n\
|
2014-05-25 05:17:19 -05:00
|
|
|
]".to_string()
|
2013-03-26 19:34:49 -05:00
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2012-02-25 18:39:32 -06:00
|
|
|
#[test]
|
2012-09-24 11:55:42 -05:00
|
|
|
fn test_write_object() {
|
2014-06-21 05:39:03 -05:00
|
|
|
assert_eq!(mk_object([]).to_string().into_string(), "{}".to_string());
|
2014-05-25 05:17:19 -05:00
|
|
|
assert_eq!(mk_object([]).to_pretty_str().into_string(), "{}".to_string());
|
2013-03-30 13:08:57 -05:00
|
|
|
|
2013-03-26 19:23:00 -05:00
|
|
|
assert_eq!(
|
2014-05-14 23:16:44 -05:00
|
|
|
mk_object([
|
2014-05-25 05:17:19 -05:00
|
|
|
("a".to_string(), Boolean(true))
|
2014-06-21 05:39:03 -05:00
|
|
|
]).to_string().into_string(),
|
2014-05-25 05:17:19 -05:00
|
|
|
"{\"a\":true}".to_string()
|
2013-03-26 19:23:00 -05:00
|
|
|
);
|
2013-03-30 13:08:57 -05:00
|
|
|
assert_eq!(
|
2014-05-25 05:17:19 -05:00
|
|
|
mk_object([("a".to_string(), Boolean(true))]).to_pretty_str(),
|
2014-04-15 20:17:48 -05:00
|
|
|
"\
|
2013-03-30 13:08:57 -05:00
|
|
|
{\n \
|
|
|
|
\"a\": true\n\
|
2014-05-25 05:17:19 -05:00
|
|
|
}".to_string()
|
2013-03-30 13:08:57 -05:00
|
|
|
);
|
|
|
|
|
2014-02-15 15:15:03 -06:00
|
|
|
let complex_obj = mk_object([
|
2014-05-25 05:17:19 -05:00
|
|
|
("b".to_string(), List(vec![
|
|
|
|
mk_object([("c".to_string(), String("\x0c\r".to_string()))]),
|
|
|
|
mk_object([("d".to_string(), String("".to_string()))])
|
2013-03-26 19:34:49 -05:00
|
|
|
]))
|
2013-08-22 00:32:18 -05:00
|
|
|
]);
|
|
|
|
|
|
|
|
assert_eq!(
|
2014-06-21 05:39:03 -05:00
|
|
|
complex_obj.to_string().into_string(),
|
2014-04-15 20:17:48 -05:00
|
|
|
"{\
|
2013-03-26 19:34:49 -05:00
|
|
|
\"b\":[\
|
|
|
|
{\"c\":\"\\f\\r\"},\
|
|
|
|
{\"d\":\"\"}\
|
|
|
|
]\
|
2014-05-25 05:17:19 -05:00
|
|
|
}".to_string()
|
2013-03-26 19:34:49 -05:00
|
|
|
);
|
|
|
|
assert_eq!(
|
2014-05-25 05:17:19 -05:00
|
|
|
complex_obj.to_pretty_str().into_string(),
|
2014-04-15 20:17:48 -05:00
|
|
|
"\
|
2013-03-26 19:34:49 -05:00
|
|
|
{\n \
|
|
|
|
\"b\": [\n \
|
|
|
|
{\n \
|
|
|
|
\"c\": \"\\f\\r\"\n \
|
|
|
|
},\n \
|
|
|
|
{\n \
|
|
|
|
\"d\": \"\"\n \
|
|
|
|
}\n \
|
|
|
|
]\n\
|
2014-05-25 05:17:19 -05:00
|
|
|
}".to_string()
|
2013-03-26 19:34:49 -05:00
|
|
|
);
|
2013-03-30 13:08:57 -05:00
|
|
|
|
2013-05-23 11:39:00 -05:00
|
|
|
let a = mk_object([
|
2014-05-25 05:17:19 -05:00
|
|
|
("a".to_string(), Boolean(true)),
|
|
|
|
("b".to_string(), List(vec![
|
|
|
|
mk_object([("c".to_string(), String("\x0c\r".to_string()))]),
|
|
|
|
mk_object([("d".to_string(), String("".to_string()))])
|
2012-06-29 18:26:56 -05:00
|
|
|
]))
|
2012-08-30 18:27:15 -05:00
|
|
|
]);
|
2013-03-30 13:08:57 -05:00
|
|
|
|
2012-09-24 11:55:42 -05:00
|
|
|
// We can't compare the strings directly because the object fields be
|
|
|
|
// printed in a different order.
|
2014-06-21 05:39:03 -05:00
|
|
|
assert_eq!(a.clone(), from_str(a.to_string().as_slice()).unwrap());
|
2014-05-14 23:16:44 -05:00
|
|
|
assert_eq!(a.clone(),
|
|
|
|
from_str(a.to_pretty_str().as_slice()).unwrap());
|
2013-03-26 19:34:49 -05:00
|
|
|
}
|
|
|
|
|
2014-05-22 18:57:53 -05:00
|
|
|
fn with_str_writer(f: |&mut io::Writer|) -> String {
|
2014-01-15 15:25:09 -06:00
|
|
|
use std::io::MemWriter;
|
2013-10-13 20:48:47 -05:00
|
|
|
use std::str;
|
|
|
|
|
2013-11-29 23:26:03 -06:00
|
|
|
let mut m = MemWriter::new();
|
|
|
|
f(&mut m as &mut io::Writer);
|
2014-05-25 05:17:19 -05:00
|
|
|
str::from_utf8(m.unwrap().as_slice()).unwrap().to_string()
|
2013-10-13 20:48:47 -05:00
|
|
|
}
|
|
|
|
|
2013-03-26 19:34:49 -05:00
|
|
|
#[test]
|
2013-03-30 13:08:57 -05:00
|
|
|
fn test_write_enum() {
|
2013-03-26 19:34:49 -05:00
|
|
|
let animal = Dog;
|
2013-03-30 13:08:57 -05:00
|
|
|
assert_eq!(
|
2014-06-28 07:34:58 -05:00
|
|
|
with_str_writer(|writer| {
|
|
|
|
let mut encoder = Encoder::new(writer);
|
2014-03-18 12:58:26 -05:00
|
|
|
animal.encode(&mut encoder).unwrap();
|
2013-11-21 21:20:48 -06:00
|
|
|
}),
|
2014-05-25 05:17:19 -05:00
|
|
|
"\"Dog\"".to_string()
|
2013-03-30 13:08:57 -05:00
|
|
|
);
|
|
|
|
assert_eq!(
|
2014-06-28 07:34:58 -05:00
|
|
|
with_str_writer(|writer| {
|
|
|
|
let mut encoder = PrettyEncoder::new(writer);
|
2014-03-18 12:58:26 -05:00
|
|
|
animal.encode(&mut encoder).unwrap();
|
2013-11-21 21:20:48 -06:00
|
|
|
}),
|
2014-05-25 05:17:19 -05:00
|
|
|
"\"Dog\"".to_string()
|
2013-03-30 13:08:57 -05:00
|
|
|
);
|
2013-03-26 19:34:49 -05:00
|
|
|
|
2014-05-25 05:17:19 -05:00
|
|
|
let animal = Frog("Henry".to_string(), 349);
|
2013-03-26 19:34:49 -05:00
|
|
|
assert_eq!(
|
2014-06-28 07:34:58 -05:00
|
|
|
with_str_writer(|writer| {
|
|
|
|
let mut encoder = Encoder::new(writer);
|
2014-03-18 12:58:26 -05:00
|
|
|
animal.encode(&mut encoder).unwrap();
|
2013-11-21 21:20:48 -06:00
|
|
|
}),
|
2014-05-25 05:17:19 -05:00
|
|
|
"{\"variant\":\"Frog\",\"fields\":[\"Henry\",349]}".to_string()
|
2013-03-30 13:08:57 -05:00
|
|
|
);
|
|
|
|
assert_eq!(
|
2014-06-28 07:34:58 -05:00
|
|
|
with_str_writer(|writer| {
|
|
|
|
let mut encoder = PrettyEncoder::new(writer);
|
2014-03-18 12:58:26 -05:00
|
|
|
animal.encode(&mut encoder).unwrap();
|
2013-11-21 21:20:48 -06:00
|
|
|
}),
|
2014-04-15 20:17:48 -05:00
|
|
|
"\
|
2013-03-26 19:34:49 -05:00
|
|
|
[\n \
|
|
|
|
\"Frog\",\n \
|
2013-03-27 02:14:52 -05:00
|
|
|
\"Henry\",\n \
|
|
|
|
349\n\
|
2014-05-25 05:17:19 -05:00
|
|
|
]".to_string()
|
2013-03-26 19:34:49 -05:00
|
|
|
);
|
2013-02-08 17:36:40 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
2013-03-26 19:23:00 -05:00
|
|
|
fn test_write_some() {
|
2014-05-25 05:17:19 -05:00
|
|
|
let value = Some("jodhpurs".to_string());
|
2014-06-28 07:34:58 -05:00
|
|
|
let s = with_str_writer(|writer| {
|
|
|
|
let mut encoder = Encoder::new(writer);
|
2014-03-18 12:58:26 -05:00
|
|
|
value.encode(&mut encoder).unwrap();
|
2013-11-21 21:20:48 -06:00
|
|
|
});
|
2014-05-25 05:17:19 -05:00
|
|
|
assert_eq!(s, "\"jodhpurs\"".to_string());
|
2013-02-08 17:36:40 -06:00
|
|
|
|
2014-05-25 05:17:19 -05:00
|
|
|
let value = Some("jodhpurs".to_string());
|
2014-06-28 07:34:58 -05:00
|
|
|
let s = with_str_writer(|writer| {
|
|
|
|
let mut encoder = PrettyEncoder::new(writer);
|
2014-03-18 12:58:26 -05:00
|
|
|
value.encode(&mut encoder).unwrap();
|
2013-11-21 21:20:48 -06:00
|
|
|
});
|
2014-05-25 05:17:19 -05:00
|
|
|
assert_eq!(s, "\"jodhpurs\"".to_string());
|
2013-03-26 19:34:49 -05:00
|
|
|
}
|
|
|
|
|
2013-02-08 17:36:40 -06:00
|
|
|
#[test]
|
2013-03-26 19:23:00 -05:00
|
|
|
fn test_write_none() {
|
2014-05-22 18:57:53 -05:00
|
|
|
let value: Option<String> = None;
|
2014-06-28 07:34:58 -05:00
|
|
|
let s = with_str_writer(|writer| {
|
|
|
|
let mut encoder = Encoder::new(writer);
|
2014-03-18 12:58:26 -05:00
|
|
|
value.encode(&mut encoder).unwrap();
|
2013-11-21 21:20:48 -06:00
|
|
|
});
|
2014-05-25 05:17:19 -05:00
|
|
|
assert_eq!(s, "null".to_string());
|
2013-02-07 19:06:26 -06:00
|
|
|
|
2014-06-28 07:34:58 -05:00
|
|
|
let s = with_str_writer(|writer| {
|
|
|
|
let mut encoder = Encoder::new(writer);
|
2014-03-18 12:58:26 -05:00
|
|
|
value.encode(&mut encoder).unwrap();
|
2013-11-21 21:20:48 -06:00
|
|
|
});
|
2014-05-25 05:17:19 -05:00
|
|
|
assert_eq!(s, "null".to_string());
|
2013-03-26 19:34:49 -05:00
|
|
|
}
|
|
|
|
|
2012-01-17 21:05:07 -06:00
|
|
|
#[test]
|
2012-02-25 18:39:32 -06:00
|
|
|
fn test_trailing_characters() {
|
2014-03-30 07:58:02 -05:00
|
|
|
assert_eq!(from_str("nulla"), Err(SyntaxError(TrailingCharacters, 1, 5)));
|
|
|
|
assert_eq!(from_str("truea"), Err(SyntaxError(TrailingCharacters, 1, 5)));
|
|
|
|
assert_eq!(from_str("falsea"), Err(SyntaxError(TrailingCharacters, 1, 6)));
|
|
|
|
assert_eq!(from_str("1a"), Err(SyntaxError(TrailingCharacters, 1, 2)));
|
|
|
|
assert_eq!(from_str("[]a"), Err(SyntaxError(TrailingCharacters, 1, 3)));
|
|
|
|
assert_eq!(from_str("{}a"), Err(SyntaxError(TrailingCharacters, 1, 3)));
|
2012-02-25 18:39:32 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_read_identifiers() {
|
2014-03-30 07:58:02 -05:00
|
|
|
assert_eq!(from_str("n"), Err(SyntaxError(InvalidSyntax, 1, 2)));
|
|
|
|
assert_eq!(from_str("nul"), Err(SyntaxError(InvalidSyntax, 1, 4)));
|
|
|
|
assert_eq!(from_str("t"), Err(SyntaxError(InvalidSyntax, 1, 2)));
|
|
|
|
assert_eq!(from_str("truz"), Err(SyntaxError(InvalidSyntax, 1, 4)));
|
|
|
|
assert_eq!(from_str("f"), Err(SyntaxError(InvalidSyntax, 1, 2)));
|
|
|
|
assert_eq!(from_str("faz"), Err(SyntaxError(InvalidSyntax, 1, 3)));
|
2012-02-25 18:39:32 -06:00
|
|
|
|
2013-05-23 11:39:00 -05:00
|
|
|
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)));
|
2012-01-17 21:05:07 -06:00
|
|
|
}
|
|
|
|
|
2013-03-30 15:31:03 -05:00
|
|
|
#[test]
|
|
|
|
fn test_decode_identifiers() {
|
2014-06-28 08:33:37 -05:00
|
|
|
let v: () = super::decode("null").unwrap();
|
2013-03-30 15:31:03 -05:00
|
|
|
assert_eq!(v, ());
|
|
|
|
|
2014-06-28 08:33:37 -05:00
|
|
|
let v: bool = super::decode("true").unwrap();
|
2013-03-30 15:31:03 -05:00
|
|
|
assert_eq!(v, true);
|
|
|
|
|
2014-06-28 08:33:37 -05:00
|
|
|
let v: bool = super::decode("false").unwrap();
|
2013-03-30 15:31:03 -05:00
|
|
|
assert_eq!(v, false);
|
|
|
|
}
|
|
|
|
|
2012-01-17 21:05:07 -06:00
|
|
|
#[test]
|
2012-09-24 11:55:42 -05:00
|
|
|
fn test_read_number() {
|
2014-03-30 07:58:02 -05:00
|
|
|
assert_eq!(from_str("+"), Err(SyntaxError(InvalidSyntax, 1, 1)));
|
|
|
|
assert_eq!(from_str("."), Err(SyntaxError(InvalidSyntax, 1, 1)));
|
2014-06-25 20:26:41 -05:00
|
|
|
assert_eq!(from_str("NaN"), Err(SyntaxError(InvalidSyntax, 1, 1)));
|
2014-03-30 07:58:02 -05:00
|
|
|
assert_eq!(from_str("-"), Err(SyntaxError(InvalidNumber, 1, 2)));
|
|
|
|
assert_eq!(from_str("00"), Err(SyntaxError(InvalidNumber, 1, 2)));
|
|
|
|
assert_eq!(from_str("1."), Err(SyntaxError(InvalidNumber, 1, 3)));
|
|
|
|
assert_eq!(from_str("1e"), Err(SyntaxError(InvalidNumber, 1, 3)));
|
|
|
|
assert_eq!(from_str("1e+"), Err(SyntaxError(InvalidNumber, 1, 4)));
|
2013-03-06 15:58:02 -06:00
|
|
|
|
2013-09-26 01:26:09 -05:00
|
|
|
assert_eq!(from_str("3"), Ok(Number(3.0)));
|
|
|
|
assert_eq!(from_str("3.1"), Ok(Number(3.1)));
|
|
|
|
assert_eq!(from_str("-1.2"), Ok(Number(-1.2)));
|
|
|
|
assert_eq!(from_str("0.4"), Ok(Number(0.4)));
|
|
|
|
assert_eq!(from_str("0.4e5"), Ok(Number(0.4e5)));
|
|
|
|
assert_eq!(from_str("0.4e+15"), Ok(Number(0.4e15)));
|
|
|
|
assert_eq!(from_str("0.4e-01"), Ok(Number(0.4e-01)));
|
|
|
|
assert_eq!(from_str(" 3 "), Ok(Number(3.0)));
|
2012-01-17 21:05:07 -06:00
|
|
|
}
|
|
|
|
|
2013-03-30 15:31:03 -05:00
|
|
|
#[test]
|
|
|
|
fn test_decode_numbers() {
|
2014-06-28 08:33:37 -05:00
|
|
|
let v: f64 = super::decode("3").unwrap();
|
2013-09-26 01:26:09 -05:00
|
|
|
assert_eq!(v, 3.0);
|
2013-03-30 15:31:03 -05:00
|
|
|
|
2014-06-28 08:33:37 -05:00
|
|
|
let v: f64 = super::decode("3.1").unwrap();
|
2013-09-26 01:26:09 -05:00
|
|
|
assert_eq!(v, 3.1);
|
2013-03-30 15:31:03 -05:00
|
|
|
|
2014-06-28 08:33:37 -05:00
|
|
|
let v: f64 = super::decode("-1.2").unwrap();
|
2013-09-26 01:26:09 -05:00
|
|
|
assert_eq!(v, -1.2);
|
2013-03-30 15:31:03 -05:00
|
|
|
|
2014-06-28 08:33:37 -05:00
|
|
|
let v: f64 = super::decode("0.4").unwrap();
|
2013-09-26 01:26:09 -05:00
|
|
|
assert_eq!(v, 0.4);
|
2013-03-30 15:31:03 -05:00
|
|
|
|
2014-06-28 08:33:37 -05:00
|
|
|
let v: f64 = super::decode("0.4e5").unwrap();
|
2013-09-26 01:26:09 -05:00
|
|
|
assert_eq!(v, 0.4e5);
|
2013-03-30 15:31:03 -05:00
|
|
|
|
2014-06-28 08:33:37 -05:00
|
|
|
let v: f64 = super::decode("0.4e15").unwrap();
|
2013-09-26 01:26:09 -05:00
|
|
|
assert_eq!(v, 0.4e15);
|
2013-03-30 15:31:03 -05:00
|
|
|
|
2014-06-28 08:33:37 -05:00
|
|
|
let v: f64 = super::decode("0.4e-01").unwrap();
|
2013-09-26 01:26:09 -05:00
|
|
|
assert_eq!(v, 0.4e-01);
|
2013-03-30 15:31:03 -05:00
|
|
|
}
|
|
|
|
|
2013-07-10 22:03:10 -05:00
|
|
|
#[test]
|
2012-02-25 18:39:32 -06:00
|
|
|
fn test_read_str() {
|
2014-03-30 07:58:02 -05:00
|
|
|
assert_eq!(from_str("\""), Err(SyntaxError(EOFWhileParsingString, 1, 2)));
|
|
|
|
assert_eq!(from_str("\"lol"), Err(SyntaxError(EOFWhileParsingString, 1, 5)));
|
|
|
|
|
2014-05-25 05:17:19 -05:00
|
|
|
assert_eq!(from_str("\"\""), Ok(String("".to_string())));
|
|
|
|
assert_eq!(from_str("\"foo\""), Ok(String("foo".to_string())));
|
|
|
|
assert_eq!(from_str("\"\\\"\""), Ok(String("\"".to_string())));
|
|
|
|
assert_eq!(from_str("\"\\b\""), Ok(String("\x08".to_string())));
|
|
|
|
assert_eq!(from_str("\"\\n\""), Ok(String("\n".to_string())));
|
|
|
|
assert_eq!(from_str("\"\\r\""), Ok(String("\r".to_string())));
|
|
|
|
assert_eq!(from_str("\"\\t\""), Ok(String("\t".to_string())));
|
|
|
|
assert_eq!(from_str(" \"foo\" "), Ok(String("foo".to_string())));
|
|
|
|
assert_eq!(from_str("\"\\u12ab\""), Ok(String("\u12ab".to_string())));
|
|
|
|
assert_eq!(from_str("\"\\uAB12\""), Ok(String("\uAB12".to_string())));
|
2012-01-17 21:05:07 -06:00
|
|
|
}
|
|
|
|
|
2012-08-30 23:03:19 -05:00
|
|
|
#[test]
|
2013-03-30 15:31:03 -05:00
|
|
|
fn test_decode_str() {
|
2014-04-30 17:55:04 -05:00
|
|
|
let s = [("\"\"", ""),
|
|
|
|
("\"foo\"", "foo"),
|
|
|
|
("\"\\\"\"", "\""),
|
|
|
|
("\"\\b\"", "\x08"),
|
|
|
|
("\"\\n\"", "\n"),
|
|
|
|
("\"\\r\"", "\r"),
|
|
|
|
("\"\\t\"", "\t"),
|
|
|
|
("\"\\u12ab\"", "\u12ab"),
|
|
|
|
("\"\\uAB12\"", "\uAB12")];
|
|
|
|
|
|
|
|
for &(i, o) in s.iter() {
|
2014-06-28 08:33:37 -05:00
|
|
|
let v: String = super::decode(i).unwrap();
|
2014-04-30 17:55:04 -05:00
|
|
|
assert_eq!(v.as_slice(), o);
|
|
|
|
}
|
2012-08-30 23:03:19 -05:00
|
|
|
}
|
|
|
|
|
2012-01-17 21:05:07 -06:00
|
|
|
#[test]
|
2012-02-25 18:39:32 -06:00
|
|
|
fn test_read_list() {
|
2014-03-30 07:58:02 -05:00
|
|
|
assert_eq!(from_str("["), Err(SyntaxError(EOFWhileParsingValue, 1, 2)));
|
|
|
|
assert_eq!(from_str("[1"), Err(SyntaxError(EOFWhileParsingList, 1, 3)));
|
|
|
|
assert_eq!(from_str("[1,"), Err(SyntaxError(EOFWhileParsingValue, 1, 4)));
|
|
|
|
assert_eq!(from_str("[1,]"), Err(SyntaxError(InvalidSyntax, 1, 4)));
|
|
|
|
assert_eq!(from_str("[6 7]"), Err(SyntaxError(InvalidSyntax, 1, 4)));
|
2013-03-06 15:58:02 -06:00
|
|
|
|
2014-05-04 01:34:26 -05:00
|
|
|
assert_eq!(from_str("[]"), Ok(List(vec![])));
|
|
|
|
assert_eq!(from_str("[ ]"), Ok(List(vec![])));
|
|
|
|
assert_eq!(from_str("[true]"), Ok(List(vec![Boolean(true)])));
|
|
|
|
assert_eq!(from_str("[ false ]"), Ok(List(vec![Boolean(false)])));
|
|
|
|
assert_eq!(from_str("[null]"), Ok(List(vec![Null])));
|
2013-05-23 11:39:00 -05:00
|
|
|
assert_eq!(from_str("[3, 1]"),
|
2014-05-04 01:34:26 -05:00
|
|
|
Ok(List(vec![Number(3.0), Number(1.0)])));
|
2013-05-23 11:39:00 -05:00
|
|
|
assert_eq!(from_str("\n[3, 2]\n"),
|
2014-05-04 01:34:26 -05:00
|
|
|
Ok(List(vec![Number(3.0), Number(2.0)])));
|
2013-05-23 11:39:00 -05:00
|
|
|
assert_eq!(from_str("[2, [4, 1]]"),
|
2014-05-04 01:34:26 -05:00
|
|
|
Ok(List(vec![Number(2.0), List(vec![Number(4.0), Number(1.0)])])));
|
2012-01-17 21:05:07 -06:00
|
|
|
}
|
|
|
|
|
2013-03-30 15:31:03 -05:00
|
|
|
#[test]
|
|
|
|
fn test_decode_list() {
|
2014-06-28 08:33:37 -05:00
|
|
|
let v: Vec<()> = super::decode("[]").unwrap();
|
2014-05-04 01:34:26 -05:00
|
|
|
assert_eq!(v, vec![]);
|
2013-03-30 15:31:03 -05:00
|
|
|
|
2014-06-28 08:33:37 -05:00
|
|
|
let v: Vec<()> = super::decode("[null]").unwrap();
|
2014-05-04 01:34:26 -05:00
|
|
|
assert_eq!(v, vec![()]);
|
2013-03-30 15:31:03 -05:00
|
|
|
|
2014-06-28 08:33:37 -05:00
|
|
|
let v: Vec<bool> = super::decode("[true]").unwrap();
|
2014-05-04 01:34:26 -05:00
|
|
|
assert_eq!(v, vec![true]);
|
2013-03-30 15:31:03 -05:00
|
|
|
|
2014-06-28 08:33:37 -05:00
|
|
|
let v: Vec<int> = super::decode("[3, 1]").unwrap();
|
2014-05-04 01:34:26 -05:00
|
|
|
assert_eq!(v, vec![3, 1]);
|
2013-03-30 15:31:03 -05:00
|
|
|
|
2014-06-28 08:33:37 -05:00
|
|
|
let v: Vec<Vec<uint>> = super::decode("[[3], [1, 2]]").unwrap();
|
2014-05-04 01:34:26 -05:00
|
|
|
assert_eq!(v, vec![vec![3], vec![1, 2]]);
|
2013-03-30 15:31:03 -05:00
|
|
|
}
|
|
|
|
|
2012-01-17 21:05:07 -06:00
|
|
|
#[test]
|
2012-09-24 11:55:42 -05:00
|
|
|
fn test_read_object() {
|
2014-03-30 07:58:02 -05:00
|
|
|
assert_eq!(from_str("{"), Err(SyntaxError(EOFWhileParsingObject, 1, 2)));
|
|
|
|
assert_eq!(from_str("{ "), Err(SyntaxError(EOFWhileParsingObject, 1, 3)));
|
|
|
|
assert_eq!(from_str("{1"), Err(SyntaxError(KeyMustBeAString, 1, 2)));
|
|
|
|
assert_eq!(from_str("{ \"a\""), Err(SyntaxError(EOFWhileParsingObject, 1, 6)));
|
|
|
|
assert_eq!(from_str("{\"a\""), Err(SyntaxError(EOFWhileParsingObject, 1, 5)));
|
|
|
|
assert_eq!(from_str("{\"a\" "), Err(SyntaxError(EOFWhileParsingObject, 1, 6)));
|
|
|
|
|
|
|
|
assert_eq!(from_str("{\"a\" 1"), Err(SyntaxError(ExpectedColon, 1, 6)));
|
|
|
|
assert_eq!(from_str("{\"a\":"), Err(SyntaxError(EOFWhileParsingValue, 1, 6)));
|
|
|
|
assert_eq!(from_str("{\"a\":1"), Err(SyntaxError(EOFWhileParsingObject, 1, 7)));
|
|
|
|
assert_eq!(from_str("{\"a\":1 1"), Err(SyntaxError(InvalidSyntax, 1, 8)));
|
|
|
|
assert_eq!(from_str("{\"a\":1,"), Err(SyntaxError(EOFWhileParsingObject, 1, 8)));
|
2013-03-06 15:58:02 -06:00
|
|
|
|
2013-07-26 20:36:51 -05:00
|
|
|
assert_eq!(from_str("{}").unwrap(), mk_object([]));
|
|
|
|
assert_eq!(from_str("{\"a\": 3}").unwrap(),
|
2014-05-25 05:17:19 -05:00
|
|
|
mk_object([("a".to_string(), Number(3.0))]));
|
2013-03-06 15:58:02 -06:00
|
|
|
|
2013-07-26 20:36:51 -05:00
|
|
|
assert_eq!(from_str(
|
|
|
|
"{ \"a\": null, \"b\" : true }").unwrap(),
|
2013-05-23 11:39:00 -05:00
|
|
|
mk_object([
|
2014-05-25 05:17:19 -05:00
|
|
|
("a".to_string(), Null),
|
|
|
|
("b".to_string(), Boolean(true))]));
|
2013-07-26 20:36:51 -05:00
|
|
|
assert_eq!(from_str("\n{ \"a\": null, \"b\" : true }\n").unwrap(),
|
2013-05-23 11:39:00 -05:00
|
|
|
mk_object([
|
2014-05-25 05:17:19 -05:00
|
|
|
("a".to_string(), Null),
|
|
|
|
("b".to_string(), Boolean(true))]));
|
2013-07-26 20:36:51 -05:00
|
|
|
assert_eq!(from_str(
|
|
|
|
"{\"a\" : 1.0 ,\"b\": [ true ]}").unwrap(),
|
2013-05-23 11:39:00 -05:00
|
|
|
mk_object([
|
2014-05-25 05:17:19 -05:00
|
|
|
("a".to_string(), Number(1.0)),
|
|
|
|
("b".to_string(), List(vec![Boolean(true)]))
|
2013-03-06 15:58:02 -06:00
|
|
|
]));
|
2013-07-26 20:36:51 -05:00
|
|
|
assert_eq!(from_str(
|
2014-05-14 23:16:44 -05:00
|
|
|
"{\
|
|
|
|
\"a\": 1.0, \
|
|
|
|
\"b\": [\
|
|
|
|
true,\
|
|
|
|
\"foo\\nbar\", \
|
|
|
|
{ \"c\": {\"d\": null} } \
|
|
|
|
]\
|
|
|
|
}").unwrap(),
|
2013-05-23 11:39:00 -05:00
|
|
|
mk_object([
|
2014-05-25 05:17:19 -05:00
|
|
|
("a".to_string(), Number(1.0)),
|
|
|
|
("b".to_string(), List(vec![
|
2012-08-11 09:08:42 -05:00
|
|
|
Boolean(true),
|
2014-05-25 05:17:19 -05:00
|
|
|
String("foo\nbar".to_string()),
|
2013-05-23 11:39:00 -05:00
|
|
|
mk_object([
|
2014-05-25 05:17:19 -05:00
|
|
|
("c".to_string(), mk_object([("d".to_string(), Null)]))
|
2012-06-29 18:26:56 -05:00
|
|
|
])
|
|
|
|
]))
|
2013-03-06 15:58:02 -06:00
|
|
|
]));
|
2012-01-17 21:05:07 -06:00
|
|
|
}
|
|
|
|
|
2013-03-27 02:13:01 -05:00
|
|
|
#[test]
|
2013-03-30 15:31:03 -05:00
|
|
|
fn test_decode_struct() {
|
2014-04-15 20:17:48 -05:00
|
|
|
let s = "{
|
2013-03-30 15:31:03 -05:00
|
|
|
\"inner\": [
|
|
|
|
{ \"a\": null, \"b\": 2, \"c\": [\"abc\", \"xyz\"] }
|
|
|
|
]
|
2014-05-14 23:16:44 -05:00
|
|
|
}";
|
2014-06-28 08:33:37 -05:00
|
|
|
|
|
|
|
let v: Outer = super::decode(s).unwrap();
|
2013-03-30 15:31:03 -05:00
|
|
|
assert_eq!(
|
|
|
|
v,
|
|
|
|
Outer {
|
2014-05-04 01:34:26 -05:00
|
|
|
inner: vec![
|
2014-05-25 05:17:19 -05:00
|
|
|
Inner { a: (), b: 2, c: vec!["abc".to_string(), "xyz".to_string()] }
|
2013-03-30 15:31:03 -05:00
|
|
|
]
|
|
|
|
}
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2014-06-25 20:26:41 -05:00
|
|
|
#[deriving(Decodable)]
|
|
|
|
struct FloatStruct {
|
|
|
|
f: f64,
|
|
|
|
a: Vec<f64>
|
|
|
|
}
|
|
|
|
#[test]
|
|
|
|
fn test_decode_struct_with_nan() {
|
2014-06-28 08:33:37 -05:00
|
|
|
let s = "{\"f\":null,\"a\":[null,123]}";
|
|
|
|
let obj: FloatStruct = super::decode(s).unwrap();
|
|
|
|
assert!(obj.f.is_nan());
|
|
|
|
assert!(obj.a.get(0).is_nan());
|
|
|
|
assert_eq!(obj.a.get(1), &123f64);
|
2014-06-25 20:26:41 -05:00
|
|
|
}
|
|
|
|
|
2013-03-30 15:31:03 -05:00
|
|
|
#[test]
|
|
|
|
fn test_decode_option() {
|
2014-06-28 08:33:37 -05:00
|
|
|
let value: Option<String> = super::decode("null").unwrap();
|
2013-03-27 02:13:01 -05:00
|
|
|
assert_eq!(value, None);
|
|
|
|
|
2014-06-28 08:33:37 -05:00
|
|
|
let value: Option<String> = super::decode("\"jodhpurs\"").unwrap();
|
2014-05-25 05:17:19 -05:00
|
|
|
assert_eq!(value, Some("jodhpurs".to_string()));
|
2013-03-27 02:13:01 -05:00
|
|
|
}
|
|
|
|
|
2013-03-26 19:42:01 -05:00
|
|
|
#[test]
|
2013-03-30 15:31:03 -05:00
|
|
|
fn test_decode_enum() {
|
2014-06-28 08:33:37 -05:00
|
|
|
let value: Animal = super::decode("\"Dog\"").unwrap();
|
2013-03-26 19:42:01 -05:00
|
|
|
assert_eq!(value, Dog);
|
|
|
|
|
2013-11-29 13:11:52 -06:00
|
|
|
let s = "{\"variant\":\"Frog\",\"fields\":[\"Henry\",349]}";
|
2014-06-28 08:33:37 -05:00
|
|
|
let value: Animal = super::decode(s).unwrap();
|
2014-05-25 05:17:19 -05:00
|
|
|
assert_eq!(value, Frog("Henry".to_string(), 349));
|
2013-03-26 19:42:01 -05:00
|
|
|
}
|
|
|
|
|
2013-03-29 11:04:35 -05:00
|
|
|
#[test]
|
2013-03-30 15:31:03 -05:00
|
|
|
fn test_decode_map() {
|
2014-04-15 20:17:48 -05:00
|
|
|
let s = "{\"a\": \"Dog\", \"b\": {\"variant\":\"Frog\",\
|
2014-05-14 23:16:44 -05:00
|
|
|
\"fields\":[\"Henry\", 349]}}";
|
2014-06-28 08:33:37 -05:00
|
|
|
let mut map: TreeMap<String, Animal> = super::decode(s).unwrap();
|
2013-03-29 11:04:35 -05:00
|
|
|
|
2014-05-25 05:17:19 -05:00
|
|
|
assert_eq!(map.pop(&"a".to_string()), Some(Dog));
|
|
|
|
assert_eq!(map.pop(&"b".to_string()), Some(Frog("Henry".to_string(), 349)));
|
2013-03-29 11:04:35 -05:00
|
|
|
}
|
|
|
|
|
2012-01-17 21:05:07 -06:00
|
|
|
#[test]
|
2012-02-25 18:39:32 -06:00
|
|
|
fn test_multiline_errors() {
|
2013-05-23 11:39:00 -05:00
|
|
|
assert_eq!(from_str("{\n \"foo\":\n \"bar\""),
|
2014-03-30 07:58:02 -05:00
|
|
|
Err(SyntaxError(EOFWhileParsingObject, 3u, 8u)));
|
2012-01-17 21:05:07 -06:00
|
|
|
}
|
2013-11-23 17:17:34 -06:00
|
|
|
|
|
|
|
#[deriving(Decodable)]
|
2014-06-25 20:26:41 -05:00
|
|
|
#[allow(dead_code)]
|
2013-11-23 17:17:34 -06:00
|
|
|
struct DecodeStruct {
|
|
|
|
x: f64,
|
|
|
|
y: bool,
|
2014-05-22 18:57:53 -05:00
|
|
|
z: String,
|
2014-05-04 01:34:26 -05:00
|
|
|
w: Vec<DecodeStruct>
|
2013-11-23 17:17:34 -06:00
|
|
|
}
|
|
|
|
#[deriving(Decodable)]
|
|
|
|
enum DecodeEnum {
|
|
|
|
A(f64),
|
2014-05-22 18:57:53 -05:00
|
|
|
B(String)
|
2013-11-23 17:17:34 -06:00
|
|
|
}
|
2014-04-07 10:40:45 -05:00
|
|
|
fn check_err<T: Decodable<Decoder, DecoderError>>(to_parse: &'static str,
|
|
|
|
expected: DecoderError) {
|
2014-03-18 12:58:26 -05:00
|
|
|
let res: DecodeResult<T> = match from_str(to_parse) {
|
2014-03-30 07:58:02 -05:00
|
|
|
Err(e) => Err(ParseError(e)),
|
2014-03-18 12:58:26 -05:00
|
|
|
Ok(json) => Decodable::decode(&mut Decoder::new(json))
|
|
|
|
};
|
2013-11-23 17:17:34 -06:00
|
|
|
match res {
|
2014-03-18 12:58:26 -05:00
|
|
|
Ok(_) => fail!("`{}` parsed & decoded ok, expecting error `{}`",
|
|
|
|
to_parse, expected),
|
2014-03-30 07:58:02 -05:00
|
|
|
Err(ParseError(e)) => fail!("`{}` is not valid json: {}",
|
2014-03-18 12:58:26 -05:00
|
|
|
to_parse, e),
|
2013-11-23 17:17:34 -06:00
|
|
|
Err(e) => {
|
2014-03-18 12:58:26 -05:00
|
|
|
assert_eq!(e, expected);
|
2013-11-23 17:17:34 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#[test]
|
|
|
|
fn test_decode_errors_struct() {
|
2014-05-25 05:17:19 -05:00
|
|
|
check_err::<DecodeStruct>("[]", ExpectedError("Object".to_string(), "[]".to_string()));
|
2013-11-23 17:17:34 -06:00
|
|
|
check_err::<DecodeStruct>("{\"x\": true, \"y\": true, \"z\": \"\", \"w\": []}",
|
2014-05-25 05:17:19 -05:00
|
|
|
ExpectedError("Number".to_string(), "true".to_string()));
|
2013-11-23 17:17:34 -06:00
|
|
|
check_err::<DecodeStruct>("{\"x\": 1, \"y\": [], \"z\": \"\", \"w\": []}",
|
2014-05-25 05:17:19 -05:00
|
|
|
ExpectedError("Boolean".to_string(), "[]".to_string()));
|
2013-11-23 17:17:34 -06:00
|
|
|
check_err::<DecodeStruct>("{\"x\": 1, \"y\": true, \"z\": {}, \"w\": []}",
|
2014-05-25 05:17:19 -05:00
|
|
|
ExpectedError("String".to_string(), "{}".to_string()));
|
2013-11-23 17:17:34 -06:00
|
|
|
check_err::<DecodeStruct>("{\"x\": 1, \"y\": true, \"z\": \"\", \"w\": null}",
|
2014-05-25 05:17:19 -05:00
|
|
|
ExpectedError("List".to_string(), "null".to_string()));
|
2013-11-23 17:17:34 -06:00
|
|
|
check_err::<DecodeStruct>("{\"x\": 1, \"y\": true, \"z\": \"\"}",
|
2014-05-25 05:17:19 -05:00
|
|
|
MissingFieldError("w".to_string()));
|
2013-11-23 17:17:34 -06:00
|
|
|
}
|
|
|
|
#[test]
|
|
|
|
fn test_decode_errors_enum() {
|
|
|
|
check_err::<DecodeEnum>("{}",
|
2014-05-25 05:17:19 -05:00
|
|
|
MissingFieldError("variant".to_string()));
|
2013-11-23 17:17:34 -06:00
|
|
|
check_err::<DecodeEnum>("{\"variant\": 1}",
|
2014-05-25 05:17:19 -05:00
|
|
|
ExpectedError("String".to_string(), "1".to_string()));
|
2013-11-23 17:17:34 -06:00
|
|
|
check_err::<DecodeEnum>("{\"variant\": \"A\"}",
|
2014-05-25 05:17:19 -05:00
|
|
|
MissingFieldError("fields".to_string()));
|
2013-11-23 17:17:34 -06:00
|
|
|
check_err::<DecodeEnum>("{\"variant\": \"A\", \"fields\": null}",
|
2014-05-25 05:17:19 -05:00
|
|
|
ExpectedError("List".to_string(), "null".to_string()));
|
2013-11-23 17:17:34 -06:00
|
|
|
check_err::<DecodeEnum>("{\"variant\": \"C\", \"fields\": []}",
|
2014-05-25 05:17:19 -05:00
|
|
|
UnknownVariantError("C".to_string()));
|
2013-11-23 17:17:34 -06:00
|
|
|
}
|
2014-03-09 00:30:27 -06:00
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_find(){
|
|
|
|
let json_value = from_str("{\"dog\" : \"cat\"}").unwrap();
|
2014-05-25 05:17:19 -05:00
|
|
|
let found_str = json_value.find(&"dog".to_string());
|
2014-05-01 00:32:13 -05:00
|
|
|
assert!(found_str.is_some() && found_str.unwrap().as_string().unwrap() == "cat");
|
2014-03-09 00:30:27 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_find_path(){
|
|
|
|
let json_value = from_str("{\"dog\":{\"cat\": {\"mouse\" : \"cheese\"}}}").unwrap();
|
2014-05-25 05:17:19 -05:00
|
|
|
let found_str = json_value.find_path(&[&"dog".to_string(),
|
|
|
|
&"cat".to_string(), &"mouse".to_string()]);
|
2014-05-01 00:32:13 -05:00
|
|
|
assert!(found_str.is_some() && found_str.unwrap().as_string().unwrap() == "cheese");
|
2014-03-09 00:30:27 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_search(){
|
|
|
|
let json_value = from_str("{\"dog\":{\"cat\": {\"mouse\" : \"cheese\"}}}").unwrap();
|
2014-05-25 05:17:19 -05:00
|
|
|
let found_str = json_value.search(&"mouse".to_string()).and_then(|j| j.as_string());
|
2014-03-09 00:30:27 -06:00
|
|
|
assert!(found_str.is_some());
|
2014-05-01 00:32:13 -05:00
|
|
|
assert!(found_str.unwrap() == "cheese");
|
2014-03-09 00:30:27 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_is_object(){
|
|
|
|
let json_value = from_str("{}").unwrap();
|
|
|
|
assert!(json_value.is_object());
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_as_object(){
|
|
|
|
let json_value = from_str("{}").unwrap();
|
|
|
|
let json_object = json_value.as_object();
|
|
|
|
assert!(json_object.is_some());
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_is_list(){
|
|
|
|
let json_value = from_str("[1, 2, 3]").unwrap();
|
|
|
|
assert!(json_value.is_list());
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_as_list(){
|
|
|
|
let json_value = from_str("[1, 2, 3]").unwrap();
|
|
|
|
let json_list = json_value.as_list();
|
|
|
|
let expected_length = 3;
|
|
|
|
assert!(json_list.is_some() && json_list.unwrap().len() == expected_length);
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
2014-03-11 22:04:36 -05:00
|
|
|
fn test_is_string(){
|
2014-03-09 00:30:27 -06:00
|
|
|
let json_value = from_str("\"dog\"").unwrap();
|
2014-03-11 22:04:36 -05:00
|
|
|
assert!(json_value.is_string());
|
2014-03-09 00:30:27 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
2014-03-11 22:04:36 -05:00
|
|
|
fn test_as_string(){
|
2014-03-09 00:30:27 -06:00
|
|
|
let json_value = from_str("\"dog\"").unwrap();
|
2014-03-11 22:04:36 -05:00
|
|
|
let json_str = json_value.as_string();
|
2014-05-01 00:32:13 -05:00
|
|
|
let expected_str = "dog";
|
2014-03-09 00:30:27 -06:00
|
|
|
assert_eq!(json_str, Some(expected_str));
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_is_number(){
|
|
|
|
let json_value = from_str("12").unwrap();
|
|
|
|
assert!(json_value.is_number());
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_as_number(){
|
|
|
|
let json_value = from_str("12").unwrap();
|
|
|
|
let json_num = json_value.as_number();
|
|
|
|
let expected_num = 12f64;
|
|
|
|
assert!(json_num.is_some() && json_num.unwrap() == expected_num);
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_is_boolean(){
|
|
|
|
let json_value = from_str("false").unwrap();
|
|
|
|
assert!(json_value.is_boolean());
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_as_boolean(){
|
|
|
|
let json_value = from_str("false").unwrap();
|
|
|
|
let json_bool = json_value.as_boolean();
|
|
|
|
let expected_bool = false;
|
|
|
|
assert!(json_bool.is_some() && json_bool.unwrap() == expected_bool);
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_is_null(){
|
|
|
|
let json_value = from_str("null").unwrap();
|
|
|
|
assert!(json_value.is_null());
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_as_null(){
|
|
|
|
let json_value = from_str("null").unwrap();
|
|
|
|
let json_null = json_value.as_null();
|
|
|
|
let expected_null = ();
|
|
|
|
assert!(json_null.is_some() && json_null.unwrap() == expected_null);
|
|
|
|
}
|
2014-03-17 02:26:36 -05:00
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_encode_hashmap_with_numeric_key() {
|
|
|
|
use std::str::from_utf8;
|
|
|
|
use std::io::Writer;
|
|
|
|
use std::io::MemWriter;
|
2014-05-29 21:03:06 -05:00
|
|
|
use std::collections::HashMap;
|
2014-03-17 02:26:36 -05:00
|
|
|
let mut hm: HashMap<uint, bool> = HashMap::new();
|
|
|
|
hm.insert(1, true);
|
|
|
|
let mut mem_buf = MemWriter::new();
|
|
|
|
{
|
|
|
|
let mut encoder = Encoder::new(&mut mem_buf as &mut io::Writer);
|
2014-03-18 12:58:26 -05:00
|
|
|
hm.encode(&mut encoder).unwrap();
|
2014-03-17 02:26:36 -05:00
|
|
|
}
|
|
|
|
let bytes = mem_buf.unwrap();
|
2014-03-27 00:46:25 -05:00
|
|
|
let json_str = from_utf8(bytes.as_slice()).unwrap();
|
2014-03-17 02:26:36 -05:00
|
|
|
match from_str(json_str) {
|
2014-05-22 13:28:01 -05:00
|
|
|
Err(_) => fail!("Unable to parse json_str: {}", json_str),
|
2014-03-17 02:26:36 -05:00
|
|
|
_ => {} // it parsed and we are good to go
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#[test]
|
|
|
|
fn test_prettyencode_hashmap_with_numeric_key() {
|
|
|
|
use std::str::from_utf8;
|
|
|
|
use std::io::Writer;
|
|
|
|
use std::io::MemWriter;
|
2014-05-29 21:03:06 -05:00
|
|
|
use std::collections::HashMap;
|
2014-03-17 02:26:36 -05:00
|
|
|
let mut hm: HashMap<uint, bool> = HashMap::new();
|
|
|
|
hm.insert(1, true);
|
|
|
|
let mut mem_buf = MemWriter::new();
|
|
|
|
{
|
|
|
|
let mut encoder = PrettyEncoder::new(&mut mem_buf as &mut io::Writer);
|
2014-03-30 07:58:02 -05:00
|
|
|
hm.encode(&mut encoder).unwrap()
|
2014-03-17 02:26:36 -05:00
|
|
|
}
|
|
|
|
let bytes = mem_buf.unwrap();
|
2014-03-27 00:46:25 -05:00
|
|
|
let json_str = from_utf8(bytes.as_slice()).unwrap();
|
2014-03-17 02:26:36 -05:00
|
|
|
match from_str(json_str) {
|
2014-05-22 13:28:01 -05:00
|
|
|
Err(_) => fail!("Unable to parse json_str: {}", json_str),
|
2014-03-17 02:26:36 -05:00
|
|
|
_ => {} // it parsed and we are good to go
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#[test]
|
|
|
|
fn test_hashmap_with_numeric_key_can_handle_double_quote_delimited_key() {
|
2014-05-29 21:03:06 -05:00
|
|
|
use std::collections::HashMap;
|
2014-03-17 02:26:36 -05:00
|
|
|
use Decodable;
|
|
|
|
let json_str = "{\"1\":true}";
|
|
|
|
let json_obj = match from_str(json_str) {
|
2014-05-22 13:28:01 -05:00
|
|
|
Err(_) => fail!("Unable to parse json_str: {}", json_str),
|
2014-03-17 02:26:36 -05:00
|
|
|
Ok(o) => o
|
|
|
|
};
|
|
|
|
let mut decoder = Decoder::new(json_obj);
|
2014-03-18 12:58:26 -05:00
|
|
|
let _hm: HashMap<uint, bool> = Decodable::decode(&mut decoder).unwrap();
|
2014-03-17 02:26:36 -05:00
|
|
|
}
|
2014-03-30 07:58:02 -05:00
|
|
|
|
2014-06-06 12:27:49 -05:00
|
|
|
fn assert_stream_equal(src: &str,
|
|
|
|
expected: Vec<(JsonEvent, Vec<StackElement>)>) {
|
2014-03-30 07:58:02 -05:00
|
|
|
let mut parser = Parser::new(src.chars());
|
|
|
|
let mut i = 0;
|
|
|
|
loop {
|
|
|
|
let evt = match parser.next() {
|
|
|
|
Some(e) => e,
|
|
|
|
None => { break; }
|
|
|
|
};
|
2014-06-06 12:27:49 -05:00
|
|
|
let (ref expected_evt, ref expected_stack) = *expected.get(i);
|
2014-03-30 07:58:02 -05:00
|
|
|
if !parser.stack().is_equal_to(expected_stack.as_slice()) {
|
|
|
|
fail!("Parser stack is not equal to {}", expected_stack);
|
|
|
|
}
|
|
|
|
assert_eq!(&evt, expected_evt);
|
|
|
|
i+=1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#[test]
|
2014-06-06 12:27:49 -05:00
|
|
|
#[ignore(cfg(target_word_size = "32"))] // FIXME(#14064)
|
2014-03-30 07:58:02 -05:00
|
|
|
fn test_streaming_parser() {
|
|
|
|
assert_stream_equal(
|
|
|
|
r#"{ "foo":"bar", "array" : [0, 1, 2,3 ,4,5], "idents":[null,true,false]}"#,
|
2014-06-06 12:27:49 -05:00
|
|
|
vec![
|
|
|
|
(ObjectStart, vec![]),
|
|
|
|
(StringValue("bar".to_string()), vec![Key("foo")]),
|
|
|
|
(ListStart, vec![Key("array")]),
|
|
|
|
(NumberValue(0.0), vec![Key("array"), Index(0)]),
|
|
|
|
(NumberValue(1.0), vec![Key("array"), Index(1)]),
|
|
|
|
(NumberValue(2.0), vec![Key("array"), Index(2)]),
|
|
|
|
(NumberValue(3.0), vec![Key("array"), Index(3)]),
|
|
|
|
(NumberValue(4.0), vec![Key("array"), Index(4)]),
|
|
|
|
(NumberValue(5.0), vec![Key("array"), Index(5)]),
|
|
|
|
(ListEnd, vec![Key("array")]),
|
|
|
|
(ListStart, vec![Key("idents")]),
|
|
|
|
(NullValue, vec![Key("idents"), Index(0)]),
|
|
|
|
(BooleanValue(true), vec![Key("idents"), Index(1)]),
|
|
|
|
(BooleanValue(false), vec![Key("idents"), Index(2)]),
|
|
|
|
(ListEnd, vec![Key("idents")]),
|
|
|
|
(ObjectEnd, vec![]),
|
2014-03-30 07:58:02 -05:00
|
|
|
]
|
|
|
|
);
|
|
|
|
}
|
|
|
|
fn last_event(src: &str) -> JsonEvent {
|
|
|
|
let mut parser = Parser::new(src.chars());
|
|
|
|
let mut evt = NullValue;
|
|
|
|
loop {
|
|
|
|
evt = match parser.next() {
|
|
|
|
Some(e) => e,
|
|
|
|
None => return evt,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#[test]
|
2014-05-13 11:28:26 -05:00
|
|
|
#[ignore(cfg(target_word_size = "32"))] // FIXME(#14064)
|
2014-03-30 07:58:02 -05:00
|
|
|
fn test_read_object_streaming() {
|
|
|
|
assert_eq!(last_event("{ "), Error(SyntaxError(EOFWhileParsingObject, 1, 3)));
|
|
|
|
assert_eq!(last_event("{1"), Error(SyntaxError(KeyMustBeAString, 1, 2)));
|
|
|
|
assert_eq!(last_event("{ \"a\""), Error(SyntaxError(EOFWhileParsingObject, 1, 6)));
|
|
|
|
assert_eq!(last_event("{\"a\""), Error(SyntaxError(EOFWhileParsingObject, 1, 5)));
|
|
|
|
assert_eq!(last_event("{\"a\" "), Error(SyntaxError(EOFWhileParsingObject, 1, 6)));
|
|
|
|
|
|
|
|
assert_eq!(last_event("{\"a\" 1"), Error(SyntaxError(ExpectedColon, 1, 6)));
|
|
|
|
assert_eq!(last_event("{\"a\":"), Error(SyntaxError(EOFWhileParsingValue, 1, 6)));
|
|
|
|
assert_eq!(last_event("{\"a\":1"), Error(SyntaxError(EOFWhileParsingObject, 1, 7)));
|
|
|
|
assert_eq!(last_event("{\"a\":1 1"), Error(SyntaxError(InvalidSyntax, 1, 8)));
|
|
|
|
assert_eq!(last_event("{\"a\":1,"), Error(SyntaxError(EOFWhileParsingObject, 1, 8)));
|
|
|
|
|
|
|
|
assert_stream_equal(
|
|
|
|
"{}",
|
2014-06-06 12:27:49 -05:00
|
|
|
vec![(ObjectStart, vec![]), (ObjectEnd, vec![])]
|
2014-03-30 07:58:02 -05:00
|
|
|
);
|
|
|
|
assert_stream_equal(
|
|
|
|
"{\"a\": 3}",
|
2014-06-06 12:27:49 -05:00
|
|
|
vec![
|
|
|
|
(ObjectStart, vec![]),
|
|
|
|
(NumberValue(3.0), vec![Key("a")]),
|
|
|
|
(ObjectEnd, vec![]),
|
2014-03-30 07:58:02 -05:00
|
|
|
]
|
|
|
|
);
|
|
|
|
assert_stream_equal(
|
|
|
|
"{ \"a\": null, \"b\" : true }",
|
2014-06-06 12:27:49 -05:00
|
|
|
vec![
|
|
|
|
(ObjectStart, vec![]),
|
|
|
|
(NullValue, vec![Key("a")]),
|
|
|
|
(BooleanValue(true), vec![Key("b")]),
|
|
|
|
(ObjectEnd, vec![]),
|
2014-03-30 07:58:02 -05:00
|
|
|
]
|
|
|
|
);
|
|
|
|
assert_stream_equal(
|
|
|
|
"{\"a\" : 1.0 ,\"b\": [ true ]}",
|
2014-06-06 12:27:49 -05:00
|
|
|
vec![
|
|
|
|
(ObjectStart, vec![]),
|
|
|
|
(NumberValue(1.0), vec![Key("a")]),
|
|
|
|
(ListStart, vec![Key("b")]),
|
|
|
|
(BooleanValue(true),vec![Key("b"), Index(0)]),
|
|
|
|
(ListEnd, vec![Key("b")]),
|
|
|
|
(ObjectEnd, vec![]),
|
2014-03-30 07:58:02 -05:00
|
|
|
]
|
|
|
|
);
|
|
|
|
assert_stream_equal(
|
|
|
|
r#"{
|
|
|
|
"a": 1.0,
|
|
|
|
"b": [
|
|
|
|
true,
|
|
|
|
"foo\nbar",
|
|
|
|
{ "c": {"d": null} }
|
|
|
|
]
|
|
|
|
}"#,
|
2014-06-06 12:27:49 -05:00
|
|
|
vec![
|
|
|
|
(ObjectStart, vec![]),
|
|
|
|
(NumberValue(1.0), vec![Key("a")]),
|
|
|
|
(ListStart, vec![Key("b")]),
|
|
|
|
(BooleanValue(true), vec![Key("b"), Index(0)]),
|
|
|
|
(StringValue("foo\nbar".to_string()), vec![Key("b"), Index(1)]),
|
|
|
|
(ObjectStart, vec![Key("b"), Index(2)]),
|
|
|
|
(ObjectStart, vec![Key("b"), Index(2), Key("c")]),
|
|
|
|
(NullValue, vec![Key("b"), Index(2), Key("c"), Key("d")]),
|
|
|
|
(ObjectEnd, vec![Key("b"), Index(2), Key("c")]),
|
|
|
|
(ObjectEnd, vec![Key("b"), Index(2)]),
|
|
|
|
(ListEnd, vec![Key("b")]),
|
|
|
|
(ObjectEnd, vec![]),
|
2014-03-30 07:58:02 -05:00
|
|
|
]
|
|
|
|
);
|
|
|
|
}
|
|
|
|
#[test]
|
2014-05-13 11:28:26 -05:00
|
|
|
#[ignore(cfg(target_word_size = "32"))] // FIXME(#14064)
|
2014-03-30 07:58:02 -05:00
|
|
|
fn test_read_list_streaming() {
|
|
|
|
assert_stream_equal(
|
|
|
|
"[]",
|
2014-06-06 12:27:49 -05:00
|
|
|
vec![
|
|
|
|
(ListStart, vec![]),
|
|
|
|
(ListEnd, vec![]),
|
2014-03-30 07:58:02 -05:00
|
|
|
]
|
|
|
|
);
|
|
|
|
assert_stream_equal(
|
|
|
|
"[ ]",
|
2014-06-06 12:27:49 -05:00
|
|
|
vec![
|
|
|
|
(ListStart, vec![]),
|
|
|
|
(ListEnd, vec![]),
|
2014-03-30 07:58:02 -05:00
|
|
|
]
|
|
|
|
);
|
|
|
|
assert_stream_equal(
|
|
|
|
"[true]",
|
2014-06-06 12:27:49 -05:00
|
|
|
vec![
|
|
|
|
(ListStart, vec![]),
|
|
|
|
(BooleanValue(true), vec![Index(0)]),
|
|
|
|
(ListEnd, vec![]),
|
2014-03-30 07:58:02 -05:00
|
|
|
]
|
|
|
|
);
|
|
|
|
assert_stream_equal(
|
|
|
|
"[ false ]",
|
2014-06-06 12:27:49 -05:00
|
|
|
vec![
|
|
|
|
(ListStart, vec![]),
|
|
|
|
(BooleanValue(false), vec![Index(0)]),
|
|
|
|
(ListEnd, vec![]),
|
2014-03-30 07:58:02 -05:00
|
|
|
]
|
|
|
|
);
|
|
|
|
assert_stream_equal(
|
|
|
|
"[null]",
|
2014-06-06 12:27:49 -05:00
|
|
|
vec![
|
|
|
|
(ListStart, vec![]),
|
|
|
|
(NullValue, vec![Index(0)]),
|
|
|
|
(ListEnd, vec![]),
|
2014-03-30 07:58:02 -05:00
|
|
|
]
|
|
|
|
);
|
|
|
|
assert_stream_equal(
|
|
|
|
"[3, 1]",
|
2014-06-06 12:27:49 -05:00
|
|
|
vec![
|
|
|
|
(ListStart, vec![]),
|
|
|
|
(NumberValue(3.0), vec![Index(0)]),
|
|
|
|
(NumberValue(1.0), vec![Index(1)]),
|
|
|
|
(ListEnd, vec![]),
|
2014-03-30 07:58:02 -05:00
|
|
|
]
|
|
|
|
);
|
|
|
|
assert_stream_equal(
|
|
|
|
"\n[3, 2]\n",
|
2014-06-06 12:27:49 -05:00
|
|
|
vec![
|
|
|
|
(ListStart, vec![]),
|
|
|
|
(NumberValue(3.0), vec![Index(0)]),
|
|
|
|
(NumberValue(2.0), vec![Index(1)]),
|
|
|
|
(ListEnd, vec![]),
|
2014-03-30 07:58:02 -05:00
|
|
|
]
|
|
|
|
);
|
|
|
|
assert_stream_equal(
|
|
|
|
"[2, [4, 1]]",
|
2014-06-06 12:27:49 -05:00
|
|
|
vec![
|
|
|
|
(ListStart, vec![]),
|
|
|
|
(NumberValue(2.0), vec![Index(0)]),
|
|
|
|
(ListStart, vec![Index(1)]),
|
|
|
|
(NumberValue(4.0), vec![Index(1), Index(0)]),
|
|
|
|
(NumberValue(1.0), vec![Index(1), Index(1)]),
|
|
|
|
(ListEnd, vec![Index(1)]),
|
|
|
|
(ListEnd, vec![]),
|
2014-03-30 07:58:02 -05:00
|
|
|
]
|
|
|
|
);
|
|
|
|
|
|
|
|
assert_eq!(last_event("["), Error(SyntaxError(EOFWhileParsingValue, 1, 2)));
|
|
|
|
|
|
|
|
assert_eq!(from_str("["), Err(SyntaxError(EOFWhileParsingValue, 1, 2)));
|
|
|
|
assert_eq!(from_str("[1"), Err(SyntaxError(EOFWhileParsingList, 1, 3)));
|
|
|
|
assert_eq!(from_str("[1,"), Err(SyntaxError(EOFWhileParsingValue, 1, 4)));
|
|
|
|
assert_eq!(from_str("[1,]"), Err(SyntaxError(InvalidSyntax, 1, 4)));
|
|
|
|
assert_eq!(from_str("[6 7]"), Err(SyntaxError(InvalidSyntax, 1, 4)));
|
|
|
|
|
|
|
|
}
|
|
|
|
#[test]
|
|
|
|
fn test_trailing_characters_streaming() {
|
|
|
|
assert_eq!(last_event("nulla"), Error(SyntaxError(TrailingCharacters, 1, 5)));
|
|
|
|
assert_eq!(last_event("truea"), Error(SyntaxError(TrailingCharacters, 1, 5)));
|
|
|
|
assert_eq!(last_event("falsea"), Error(SyntaxError(TrailingCharacters, 1, 6)));
|
|
|
|
assert_eq!(last_event("1a"), Error(SyntaxError(TrailingCharacters, 1, 2)));
|
|
|
|
assert_eq!(last_event("[]a"), Error(SyntaxError(TrailingCharacters, 1, 3)));
|
|
|
|
assert_eq!(last_event("{}a"), Error(SyntaxError(TrailingCharacters, 1, 3)));
|
|
|
|
}
|
|
|
|
#[test]
|
|
|
|
fn test_read_identifiers_streaming() {
|
|
|
|
assert_eq!(Parser::new("null".chars()).next(), Some(NullValue));
|
|
|
|
assert_eq!(Parser::new("true".chars()).next(), Some(BooleanValue(true)));
|
|
|
|
assert_eq!(Parser::new("false".chars()).next(), Some(BooleanValue(false)));
|
|
|
|
|
|
|
|
assert_eq!(last_event("n"), Error(SyntaxError(InvalidSyntax, 1, 2)));
|
|
|
|
assert_eq!(last_event("nul"), Error(SyntaxError(InvalidSyntax, 1, 4)));
|
|
|
|
assert_eq!(last_event("t"), Error(SyntaxError(InvalidSyntax, 1, 2)));
|
|
|
|
assert_eq!(last_event("truz"), Error(SyntaxError(InvalidSyntax, 1, 4)));
|
|
|
|
assert_eq!(last_event("f"), Error(SyntaxError(InvalidSyntax, 1, 2)));
|
|
|
|
assert_eq!(last_event("faz"), Error(SyntaxError(InvalidSyntax, 1, 3)));
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_stack() {
|
|
|
|
let mut stack = Stack::new();
|
|
|
|
|
|
|
|
assert!(stack.is_empty());
|
|
|
|
assert!(stack.len() == 0);
|
|
|
|
assert!(!stack.last_is_index());
|
|
|
|
|
|
|
|
stack.push_index(0);
|
|
|
|
stack.bump_index();
|
|
|
|
|
|
|
|
assert!(stack.len() == 1);
|
|
|
|
assert!(stack.is_equal_to([Index(1)]));
|
|
|
|
assert!(stack.starts_with([Index(1)]));
|
|
|
|
assert!(stack.ends_with([Index(1)]));
|
|
|
|
assert!(stack.last_is_index());
|
|
|
|
assert!(stack.get(0) == Index(1));
|
|
|
|
|
2014-05-25 05:17:19 -05:00
|
|
|
stack.push_key("foo".to_string());
|
2014-03-30 07:58:02 -05:00
|
|
|
|
|
|
|
assert!(stack.len() == 2);
|
|
|
|
assert!(stack.is_equal_to([Index(1), Key("foo")]));
|
|
|
|
assert!(stack.starts_with([Index(1), Key("foo")]));
|
|
|
|
assert!(stack.starts_with([Index(1)]));
|
|
|
|
assert!(stack.ends_with([Index(1), Key("foo")]));
|
|
|
|
assert!(stack.ends_with([Key("foo")]));
|
|
|
|
assert!(!stack.last_is_index());
|
|
|
|
assert!(stack.get(0) == Index(1));
|
|
|
|
assert!(stack.get(1) == Key("foo"));
|
|
|
|
|
2014-05-25 05:17:19 -05:00
|
|
|
stack.push_key("bar".to_string());
|
2014-03-30 07:58:02 -05:00
|
|
|
|
|
|
|
assert!(stack.len() == 3);
|
|
|
|
assert!(stack.is_equal_to([Index(1), Key("foo"), Key("bar")]));
|
|
|
|
assert!(stack.starts_with([Index(1)]));
|
|
|
|
assert!(stack.starts_with([Index(1), Key("foo")]));
|
|
|
|
assert!(stack.starts_with([Index(1), Key("foo"), Key("bar")]));
|
|
|
|
assert!(stack.ends_with([Key("bar")]));
|
|
|
|
assert!(stack.ends_with([Key("foo"), Key("bar")]));
|
|
|
|
assert!(stack.ends_with([Index(1), Key("foo"), Key("bar")]));
|
|
|
|
assert!(!stack.last_is_index());
|
|
|
|
assert!(stack.get(0) == Index(1));
|
|
|
|
assert!(stack.get(1) == Key("foo"));
|
|
|
|
assert!(stack.get(2) == Key("bar"));
|
|
|
|
|
|
|
|
stack.pop();
|
|
|
|
|
|
|
|
assert!(stack.len() == 2);
|
|
|
|
assert!(stack.is_equal_to([Index(1), Key("foo")]));
|
|
|
|
assert!(stack.starts_with([Index(1), Key("foo")]));
|
|
|
|
assert!(stack.starts_with([Index(1)]));
|
|
|
|
assert!(stack.ends_with([Index(1), Key("foo")]));
|
|
|
|
assert!(stack.ends_with([Key("foo")]));
|
|
|
|
assert!(!stack.last_is_index());
|
|
|
|
assert!(stack.get(0) == Index(1));
|
|
|
|
assert!(stack.get(1) == Key("foo"));
|
|
|
|
}
|
|
|
|
|
2014-06-03 10:49:26 -05:00
|
|
|
#[test]
|
|
|
|
fn test_to_json() {
|
2014-05-29 21:03:06 -05:00
|
|
|
use std::collections::{HashMap,TreeMap};
|
2014-06-03 10:49:26 -05:00
|
|
|
use super::ToJson;
|
|
|
|
|
|
|
|
let list2 = List(vec!(Number(1.0_f64), Number(2.0_f64)));
|
|
|
|
let list3 = List(vec!(Number(1.0f64), Number(2.0f64), Number(3.0f64)));
|
|
|
|
let object = {
|
|
|
|
let mut tree_map = TreeMap::new();
|
|
|
|
tree_map.insert("a".to_string(), Number(1.0_f64));
|
|
|
|
tree_map.insert("b".to_string(), Number(2.0_f64));
|
2014-06-28 07:41:40 -05:00
|
|
|
Object(tree_map)
|
2014-06-03 10:49:26 -05:00
|
|
|
};
|
|
|
|
|
|
|
|
assert_eq!(list2.to_json(), list2);
|
|
|
|
assert_eq!(object.to_json(), object);
|
|
|
|
assert_eq!(3_i.to_json(), Number(3.0_f64));
|
|
|
|
assert_eq!(4_i8.to_json(), Number(4.0_f64));
|
|
|
|
assert_eq!(5_i16.to_json(), Number(5.0_f64));
|
|
|
|
assert_eq!(6_i32.to_json(), Number(6.0_f64));
|
|
|
|
assert_eq!(7_i64.to_json(), Number(7.0_f64));
|
|
|
|
assert_eq!(8_u.to_json(), Number(8.0_f64));
|
|
|
|
assert_eq!(9_u8.to_json(), Number(9.0_f64));
|
|
|
|
assert_eq!(10_u16.to_json(), Number(10.0_f64));
|
|
|
|
assert_eq!(11_u32.to_json(), Number(11.0_f64));
|
|
|
|
assert_eq!(12_u64.to_json(), Number(12.0_f64));
|
|
|
|
assert_eq!(13.0_f32.to_json(), Number(13.0_f64));
|
|
|
|
assert_eq!(14.0_f64.to_json(), Number(14.0_f64));
|
|
|
|
assert_eq!(().to_json(), Null);
|
2014-06-25 20:26:41 -05:00
|
|
|
assert_eq!(f32::INFINITY.to_json(), Null);
|
|
|
|
assert_eq!(f64::NAN.to_json(), Null);
|
2014-06-03 10:49:26 -05:00
|
|
|
assert_eq!(true.to_json(), Boolean(true));
|
|
|
|
assert_eq!(false.to_json(), Boolean(false));
|
|
|
|
assert_eq!("abc".to_string().to_json(), String("abc".to_string()));
|
2014-04-21 16:58:52 -05:00
|
|
|
assert_eq!((1i, 2i).to_json(), list2);
|
|
|
|
assert_eq!((1i, 2i, 3i).to_json(), list3);
|
|
|
|
assert_eq!([1i, 2].to_json(), list2);
|
|
|
|
assert_eq!((&[1i, 2, 3]).to_json(), list3);
|
|
|
|
assert_eq!((vec![1i, 2]).to_json(), list2);
|
|
|
|
assert_eq!(vec!(1i, 2i, 3i).to_json(), list3);
|
2014-06-03 10:49:26 -05:00
|
|
|
let mut tree_map = TreeMap::new();
|
2014-04-21 16:58:52 -05:00
|
|
|
tree_map.insert("a".to_string(), 1i);
|
2014-06-03 10:49:26 -05:00
|
|
|
tree_map.insert("b".to_string(), 2);
|
|
|
|
assert_eq!(tree_map.to_json(), object);
|
|
|
|
let mut hash_map = HashMap::new();
|
2014-04-21 16:58:52 -05:00
|
|
|
hash_map.insert("a".to_string(), 1i);
|
2014-06-03 10:49:26 -05:00
|
|
|
hash_map.insert("b".to_string(), 2);
|
|
|
|
assert_eq!(hash_map.to_json(), object);
|
2014-06-27 14:30:25 -05:00
|
|
|
assert_eq!(Some(15i).to_json(), Number(15f64));
|
2014-06-03 10:49:26 -05:00
|
|
|
assert_eq!(None::<int>.to_json(), Null);
|
|
|
|
}
|
|
|
|
|
2014-03-30 07:58:02 -05:00
|
|
|
#[bench]
|
|
|
|
fn bench_streaming_small(b: &mut Bencher) {
|
|
|
|
b.iter( || {
|
|
|
|
let mut parser = Parser::new(
|
|
|
|
r#"{
|
|
|
|
"a": 1.0,
|
|
|
|
"b": [
|
|
|
|
true,
|
|
|
|
"foo\nbar",
|
|
|
|
{ "c": {"d": null} }
|
|
|
|
]
|
|
|
|
}"#.chars()
|
|
|
|
);
|
|
|
|
loop {
|
|
|
|
match parser.next() {
|
|
|
|
None => return,
|
|
|
|
_ => {}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
|
|
|
#[bench]
|
|
|
|
fn bench_small(b: &mut Bencher) {
|
|
|
|
b.iter( || {
|
|
|
|
let _ = from_str(r#"{
|
|
|
|
"a": 1.0,
|
|
|
|
"b": [
|
|
|
|
true,
|
|
|
|
"foo\nbar",
|
|
|
|
{ "c": {"d": null} }
|
|
|
|
]
|
|
|
|
}"#);
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2014-05-22 18:57:53 -05:00
|
|
|
fn big_json() -> String {
|
2014-05-25 05:17:19 -05:00
|
|
|
let mut src = "[\n".to_string();
|
2014-04-21 16:58:52 -05:00
|
|
|
for _ in range(0i, 500) {
|
2014-05-14 23:16:44 -05:00
|
|
|
src.push_str(r#"{ "a": true, "b": null, "c":3.1415, "d": "Hello world", "e": \
|
|
|
|
[1,2,3]},"#);
|
2014-03-30 07:58:02 -05:00
|
|
|
}
|
2014-05-14 23:16:44 -05:00
|
|
|
src.push_str("{}]");
|
2014-03-30 07:58:02 -05:00
|
|
|
return src;
|
|
|
|
}
|
|
|
|
|
|
|
|
#[bench]
|
|
|
|
fn bench_streaming_large(b: &mut Bencher) {
|
|
|
|
let src = big_json();
|
|
|
|
b.iter( || {
|
2014-05-14 23:16:44 -05:00
|
|
|
let mut parser = Parser::new(src.as_slice().chars());
|
2014-03-30 07:58:02 -05:00
|
|
|
loop {
|
|
|
|
match parser.next() {
|
|
|
|
None => return,
|
|
|
|
_ => {}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
|
|
|
#[bench]
|
|
|
|
fn bench_large(b: &mut Bencher) {
|
|
|
|
let src = big_json();
|
2014-05-14 23:16:44 -05:00
|
|
|
b.iter( || { let _ = from_str(src.as_slice()); });
|
2014-03-30 07:58:02 -05:00
|
|
|
}
|
2012-01-17 21:05:07 -06:00
|
|
|
}
|