2014-06-26 01:26:41 +00:00
|
|
|
// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT
|
2012-12-04 00:48:01 +00: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 23:24:44 +00:00
|
|
|
// Rust JSON serialization library
|
|
|
|
// Copyright (c) 2011 Google Inc.
|
2013-05-31 22:17:22 +00:00
|
|
|
|
2014-03-22 01:05:05 +00:00
|
|
|
#![forbid(non_camel_case_types)]
|
2014-10-27 22:37:07 +00:00
|
|
|
#![allow(missing_docs)]
|
2011-11-07 19:01:28 +00:00
|
|
|
|
2014-11-26 02:17:11 +00:00
|
|
|
//! JSON parsing and serialization
|
|
|
|
//!
|
|
|
|
//! # What is JSON?
|
|
|
|
//!
|
|
|
|
//! JSON (JavaScript Object Notation) is a way to write data in Javascript.
|
|
|
|
//! 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
|
2014-12-23 23:52:09 +00:00
|
|
|
//! * `Object`: equivalent to rust's `BTreeMap<String, json::Json>`
|
2014-11-26 02:17:11 +00:00
|
|
|
//! * `Null`
|
|
|
|
//!
|
|
|
|
//! 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 ({ ... }).
|
2015-01-17 20:44:54 +00:00
|
|
|
//! A simple JSON document encoding a person, their age, address and phone numbers could look like
|
2014-11-26 02:17:11 +00:00
|
|
|
//!
|
|
|
|
//! ```ignore
|
|
|
|
//! {
|
|
|
|
//! "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
|
|
|
|
//!
|
|
|
|
//! Rust provides a mechanism for low boilerplate encoding & decoding of values to and from JSON via
|
|
|
|
//! the serialization API.
|
2014-12-19 06:52:48 +00:00
|
|
|
//! To be able to encode a piece of data, it must implement the `serialize::RustcEncodable` trait.
|
|
|
|
//! To be able to decode a piece of data, it must implement the `serialize::RustcDecodable` trait.
|
2014-11-26 02:17:11 +00:00
|
|
|
//! The Rust compiler provides an annotation to automatically generate the code for these traits:
|
2015-01-04 03:54:18 +00:00
|
|
|
//! `#[derive(RustcDecodable, RustcEncodable)]`
|
2014-11-26 02:17:11 +00: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-12-19 06:52:48 +00:00
|
|
|
//! When using `ToJson` the `RustcEncodable` trait implementation is not mandatory.
|
2014-11-26 02:17:11 +00:00
|
|
|
//!
|
|
|
|
//! # Examples of use
|
|
|
|
//!
|
|
|
|
//! ## Using Autoserialization
|
|
|
|
//!
|
|
|
|
//! Create a struct called `TestStruct` and serialize and deserialize it to and from JSON using the
|
|
|
|
//! serialization API, using the derived serialization code.
|
|
|
|
//!
|
2015-09-20 10:35:08 +00:00
|
|
|
//! ```rust
|
2015-11-03 16:17:57 +00:00
|
|
|
//! # #![feature(rustc_private)]
|
|
|
|
//! extern crate serialize as rustc_serialize; // for the deriving below
|
|
|
|
//! use rustc_serialize::json;
|
2014-11-26 02:17:11 +00:00
|
|
|
//!
|
|
|
|
//! // Automatically generate `Decodable` and `Encodable` trait implementations
|
2015-01-04 03:54:18 +00:00
|
|
|
//! #[derive(RustcDecodable, RustcEncodable)]
|
2014-11-26 02:17:11 +00:00
|
|
|
//! pub struct TestStruct {
|
|
|
|
//! data_int: u8,
|
|
|
|
//! data_str: String,
|
|
|
|
//! data_vector: Vec<u8>,
|
|
|
|
//! }
|
|
|
|
//!
|
|
|
|
//! fn main() {
|
|
|
|
//! let object = TestStruct {
|
|
|
|
//! data_int: 1,
|
2014-11-23 18:32:31 +00:00
|
|
|
//! data_str: "homura".to_string(),
|
2014-11-26 02:17:11 +00:00
|
|
|
//! data_vector: vec![2,3,4,5],
|
|
|
|
//! };
|
|
|
|
//!
|
|
|
|
//! // Serialize using `json::encode`
|
2015-01-23 09:52:58 +00:00
|
|
|
//! let encoded = json::encode(&object).unwrap();
|
2014-11-26 02:17:11 +00:00
|
|
|
//!
|
|
|
|
//! // Deserialize using `json::decode`
|
2015-03-30 16:22:46 +00:00
|
|
|
//! let decoded: TestStruct = json::decode(&encoded[..]).unwrap();
|
2014-11-26 02:17:11 +00:00
|
|
|
//! }
|
|
|
|
//! ```
|
|
|
|
//!
|
|
|
|
//! ## Using the `ToJson` trait
|
|
|
|
//!
|
|
|
|
//! The examples above use the `ToJson` trait to generate the JSON string, which is required
|
|
|
|
//! for custom mappings.
|
|
|
|
//!
|
|
|
|
//! ### Simple example of `ToJson` usage
|
|
|
|
//!
|
2015-09-20 10:35:08 +00:00
|
|
|
//! ```rust
|
2015-11-03 16:17:57 +00:00
|
|
|
//! # #![feature(rustc_private)]
|
2014-11-26 02:17:11 +00:00
|
|
|
//! extern crate serialize;
|
2015-01-04 03:42:21 +00:00
|
|
|
//! use serialize::json::{self, ToJson, Json};
|
2014-11-26 02:17:11 +00:00
|
|
|
//!
|
|
|
|
//! // A custom data structure
|
|
|
|
//! struct ComplexNum {
|
|
|
|
//! a: f64,
|
|
|
|
//! b: f64,
|
|
|
|
//! }
|
|
|
|
//!
|
|
|
|
//! // JSON value representation
|
|
|
|
//! impl ToJson for ComplexNum {
|
2014-11-26 19:00:36 +00:00
|
|
|
//! fn to_json(&self) -> Json {
|
|
|
|
//! Json::String(format!("{}+{}i", self.a, self.b))
|
2014-11-26 02:17:11 +00:00
|
|
|
//! }
|
|
|
|
//! }
|
|
|
|
//!
|
2014-12-19 06:52:48 +00:00
|
|
|
//! // Only generate `RustcEncodable` trait implementation
|
2015-01-04 03:54:18 +00:00
|
|
|
//! #[derive(Encodable)]
|
2014-11-26 02:17:11 +00:00
|
|
|
//! pub struct ComplexNumRecord {
|
|
|
|
//! uid: u8,
|
|
|
|
//! dsc: String,
|
2014-11-26 19:00:36 +00:00
|
|
|
//! val: Json,
|
2014-11-26 02:17:11 +00:00
|
|
|
//! }
|
|
|
|
//!
|
|
|
|
//! fn main() {
|
|
|
|
//! let num = ComplexNum { a: 0.0001, b: 12.539 };
|
|
|
|
//! let data: String = json::encode(&ComplexNumRecord{
|
|
|
|
//! uid: 1,
|
|
|
|
//! dsc: "test".to_string(),
|
|
|
|
//! val: num.to_json(),
|
2015-01-23 09:52:58 +00:00
|
|
|
//! }).unwrap();
|
2014-11-26 02:17:11 +00:00
|
|
|
//! println!("data: {}", data);
|
2015-05-30 15:41:09 +00:00
|
|
|
//! // data: {"uid":1,"dsc":"test","val":"0.0001+12.539i"};
|
2014-11-26 02:17:11 +00:00
|
|
|
//! }
|
|
|
|
//! ```
|
|
|
|
//!
|
|
|
|
//! ### Verbose example of `ToJson` usage
|
|
|
|
//!
|
2015-09-20 10:35:08 +00:00
|
|
|
//! ```rust
|
2015-11-03 16:17:57 +00:00
|
|
|
//! # #![feature(rustc_private)]
|
2014-11-26 02:17:11 +00:00
|
|
|
//! extern crate serialize;
|
2014-12-17 04:09:16 +00:00
|
|
|
//! use std::collections::BTreeMap;
|
2015-01-04 03:42:21 +00:00
|
|
|
//! use serialize::json::{self, Json, ToJson};
|
2014-11-26 02:17:11 +00:00
|
|
|
//!
|
|
|
|
//! // Only generate `Decodable` trait implementation
|
2015-01-04 03:54:18 +00:00
|
|
|
//! #[derive(Decodable)]
|
2014-11-26 02:17:11 +00:00
|
|
|
//! pub struct TestStruct {
|
|
|
|
//! data_int: u8,
|
|
|
|
//! data_str: String,
|
|
|
|
//! data_vector: Vec<u8>,
|
|
|
|
//! }
|
|
|
|
//!
|
|
|
|
//! // Specify encoding method manually
|
|
|
|
//! impl ToJson for TestStruct {
|
2014-11-26 19:00:36 +00:00
|
|
|
//! fn to_json(&self) -> Json {
|
2014-12-17 04:09:16 +00:00
|
|
|
//! let mut d = BTreeMap::new();
|
2014-11-26 02:17:11 +00:00
|
|
|
//! // All standard types implement `to_json()`, so use it
|
|
|
|
//! 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-11-26 19:00:36 +00:00
|
|
|
//! Json::Object(d)
|
2014-11-26 02:17:11 +00:00
|
|
|
//! }
|
|
|
|
//! }
|
|
|
|
//!
|
|
|
|
//! fn main() {
|
|
|
|
//! // Serialize using `ToJson`
|
|
|
|
//! let input_data = TestStruct {
|
|
|
|
//! data_int: 1,
|
2014-11-23 18:32:31 +00:00
|
|
|
//! data_str: "madoka".to_string(),
|
2014-11-26 02:17:11 +00:00
|
|
|
//! data_vector: vec![2,3,4,5],
|
|
|
|
//! };
|
2014-11-26 19:00:36 +00:00
|
|
|
//! let json_obj: Json = input_data.to_json();
|
2014-11-26 02:17:11 +00:00
|
|
|
//! let json_str: String = json_obj.to_string();
|
|
|
|
//!
|
|
|
|
//! // Deserialize like before
|
2015-11-03 16:17:57 +00:00
|
|
|
//! let decoded: TestStruct = json::decode(&json_str).unwrap();
|
2014-11-26 02:17:11 +00:00
|
|
|
//! }
|
|
|
|
//! ```
|
2012-03-08 02:17:30 +00:00
|
|
|
|
2014-11-22 18:48:01 +00:00
|
|
|
use self::JsonEvent::*;
|
|
|
|
use self::ErrorCode::*;
|
|
|
|
use self::ParserError::*;
|
|
|
|
use self::DecoderError::*;
|
2014-11-06 08:05:53 +00:00
|
|
|
use self::ParserState::*;
|
|
|
|
use self::InternalStackElement::*;
|
|
|
|
|
2014-12-17 04:09:16 +00:00
|
|
|
use std::collections::{HashMap, BTreeMap};
|
2015-03-11 22:24:14 +00:00
|
|
|
use std::io::prelude::*;
|
|
|
|
use std::io;
|
2015-03-28 09:23:20 +00:00
|
|
|
use std::mem::swap;
|
2014-12-22 21:50:57 +00:00
|
|
|
use std::num::FpCategory as Fp;
|
2015-03-11 22:24:14 +00:00
|
|
|
use std::ops::Index;
|
2014-12-22 21:50:57 +00:00
|
|
|
use std::str::FromStr;
|
2014-09-11 05:07:49 +00:00
|
|
|
use std::string;
|
2015-04-17 22:32:42 +00:00
|
|
|
use std::{char, f64, fmt, str};
|
2015-03-11 22:24:14 +00:00
|
|
|
use std;
|
2013-03-13 18:29:05 +00:00
|
|
|
|
2014-02-21 22:18:39 +00:00
|
|
|
use Encodable;
|
2011-11-07 19:01:28 +00:00
|
|
|
|
2012-07-04 21:53:12 +00:00
|
|
|
/// Represents a json value
|
2015-01-28 13:34:18 +00:00
|
|
|
#[derive(Clone, PartialEq, PartialOrd, Debug)]
|
2012-09-24 16:55:42 +00:00
|
|
|
pub enum Json {
|
2014-08-07 12:35:06 +00:00
|
|
|
I64(i64),
|
|
|
|
U64(u64),
|
|
|
|
F64(f64),
|
2014-09-11 05:07:49 +00:00
|
|
|
String(string::String),
|
2012-08-11 14:08:42 +00:00
|
|
|
Boolean(bool),
|
2014-11-22 18:48:01 +00:00
|
|
|
Array(self::Array),
|
|
|
|
Object(self::Object),
|
2012-08-11 14:08:42 +00:00
|
|
|
Null,
|
2011-11-07 19:01:28 +00:00
|
|
|
}
|
|
|
|
|
2014-11-22 18:48:01 +00:00
|
|
|
pub type Array = Vec<Json>;
|
2014-12-17 04:09:16 +00:00
|
|
|
pub type Object = BTreeMap<string::String, Json>;
|
2012-09-24 16:55:42 +00:00
|
|
|
|
2014-12-12 18:59:41 +00:00
|
|
|
pub struct PrettyJson<'a> { inner: &'a Json }
|
|
|
|
|
|
|
|
pub struct AsJson<'a, T: 'a> { inner: &'a T }
|
2015-03-26 00:06:52 +00:00
|
|
|
pub struct AsPrettyJson<'a, T: 'a> { inner: &'a T, indent: Option<usize> }
|
2014-12-12 18:59:41 +00:00
|
|
|
|
2014-03-30 12:58:02 +00:00
|
|
|
/// The errors that can arise while parsing a JSON stream.
|
2015-01-28 13:34:18 +00:00
|
|
|
#[derive(Clone, Copy, PartialEq, Debug)]
|
2014-03-30 12:58:02 +00:00
|
|
|
pub enum ErrorCode {
|
|
|
|
InvalidSyntax,
|
|
|
|
InvalidNumber,
|
|
|
|
EOFWhileParsingObject,
|
2014-11-19 18:19:43 +00:00
|
|
|
EOFWhileParsingArray,
|
2014-03-30 12:58:02 +00:00
|
|
|
EOFWhileParsingValue,
|
|
|
|
EOFWhileParsingString,
|
|
|
|
KeyMustBeAString,
|
|
|
|
ExpectedColon,
|
|
|
|
TrailingCharacters,
|
2014-09-15 17:12:15 +00:00
|
|
|
TrailingComma,
|
2014-03-30 12:58:02 +00:00
|
|
|
InvalidEscape,
|
|
|
|
InvalidUnicodeCodePoint,
|
|
|
|
LoneLeadingSurrogateInHexEscape,
|
|
|
|
UnexpectedEndOfHexEscape,
|
|
|
|
UnrecognizedHex,
|
|
|
|
NotFourDigit,
|
|
|
|
NotUtf8,
|
|
|
|
}
|
|
|
|
|
2015-03-11 22:24:14 +00:00
|
|
|
#[derive(Clone, PartialEq, Debug)]
|
2014-03-30 12:58:02 +00:00
|
|
|
pub enum ParserError {
|
2014-03-18 17:58:26 +00:00
|
|
|
/// msg, line, col
|
2015-03-26 00:06:52 +00:00
|
|
|
SyntaxError(ErrorCode, usize, usize),
|
2015-03-11 22:24:14 +00:00
|
|
|
IoError(io::ErrorKind, String),
|
2014-03-30 12:58:02 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Builder and Parser have the same errors.
|
|
|
|
pub type BuilderError = ParserError;
|
|
|
|
|
2015-01-28 13:34:18 +00:00
|
|
|
#[derive(Clone, PartialEq, Debug)]
|
2014-03-30 12:58:02 +00:00
|
|
|
pub enum DecoderError {
|
|
|
|
ParseError(ParserError),
|
2014-09-11 05:07:49 +00:00
|
|
|
ExpectedError(string::String, string::String),
|
|
|
|
MissingFieldError(string::String),
|
|
|
|
UnknownVariantError(string::String),
|
|
|
|
ApplicationError(string::String)
|
2014-03-30 12:58:02 +00:00
|
|
|
}
|
|
|
|
|
2015-03-30 13:40:52 +00:00
|
|
|
#[derive(Copy, Clone, Debug)]
|
2015-01-10 09:14:19 +00:00
|
|
|
pub enum EncoderError {
|
|
|
|
FmtError(fmt::Error),
|
|
|
|
BadHashmapKey,
|
|
|
|
}
|
|
|
|
|
2014-03-30 12:58:02 +00:00
|
|
|
/// Returns a readable error string for a given error code.
|
|
|
|
pub fn error_str(error: ErrorCode) -> &'static str {
|
2014-11-22 18:48:01 +00:00
|
|
|
match error {
|
2014-03-30 12:58:02 +00:00
|
|
|
InvalidSyntax => "invalid syntax",
|
|
|
|
InvalidNumber => "invalid number",
|
|
|
|
EOFWhileParsingObject => "EOF While parsing object",
|
2014-11-19 18:19:43 +00:00
|
|
|
EOFWhileParsingArray => "EOF While parsing array",
|
2014-03-30 12:58:02 +00:00
|
|
|
EOFWhileParsingValue => "EOF While parsing value",
|
|
|
|
EOFWhileParsingString => "EOF While parsing string",
|
|
|
|
KeyMustBeAString => "key must be a string",
|
|
|
|
ExpectedColon => "expected `:`",
|
|
|
|
TrailingCharacters => "trailing characters",
|
2014-09-15 17:12:15 +00:00
|
|
|
TrailingComma => "trailing comma",
|
2014-03-30 12:58:02 +00:00
|
|
|
InvalidEscape => "invalid escape",
|
2014-12-09 22:08:10 +00:00
|
|
|
UnrecognizedHex => "invalid \\u{ esc}ape (unrecognized hex)",
|
|
|
|
NotFourDigit => "invalid \\u{ esc}ape (not four digits)",
|
2014-03-30 12:58:02 +00:00
|
|
|
NotUtf8 => "contents not utf-8",
|
2014-09-02 05:35:58 +00:00
|
|
|
InvalidUnicodeCodePoint => "invalid Unicode code point",
|
2014-03-30 12:58:02 +00:00
|
|
|
LoneLeadingSurrogateInHexEscape => "lone leading surrogate in hex escape",
|
|
|
|
UnexpectedEndOfHexEscape => "unexpected end of hex escape",
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-06-28 13:33:37 +00:00
|
|
|
/// Shortcut function to decode a JSON `&str` into an object
|
2015-01-04 06:24:50 +00:00
|
|
|
pub fn decode<T: ::Decodable>(s: &str) -> DecodeResult<T> {
|
2014-06-28 13:33:37 +00:00
|
|
|
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`
|
2015-01-23 09:52:58 +00:00
|
|
|
pub fn encode<T: ::Encodable>(object: &T) -> Result<string::String, EncoderError> {
|
2014-12-12 18:59:41 +00:00
|
|
|
let mut s = String::new();
|
|
|
|
{
|
|
|
|
let mut encoder = Encoder::new(&mut s);
|
2016-03-23 03:01:37 +00:00
|
|
|
object.encode(&mut encoder)?;
|
2014-12-12 18:59:41 +00:00
|
|
|
}
|
2015-01-23 09:52:58 +00:00
|
|
|
Ok(s)
|
2014-06-28 13:33:37 +00:00
|
|
|
}
|
|
|
|
|
2015-01-20 23:45:07 +00:00
|
|
|
impl fmt::Display for ErrorCode {
|
2014-03-30 12:58:02 +00:00
|
|
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
|
|
error_str(*self).fmt(f)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-03-11 22:24:14 +00:00
|
|
|
fn io_error_to_error(io: io::Error) -> ParserError {
|
|
|
|
IoError(io.kind(), io.to_string())
|
2012-09-24 16:55:42 +00:00
|
|
|
}
|
2012-02-26 00:39:32 +00:00
|
|
|
|
2015-01-20 23:45:07 +00:00
|
|
|
impl fmt::Display for ParserError {
|
|
|
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
|
|
// FIXME this should be a nicer error
|
|
|
|
fmt::Debug::fmt(self, f)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl fmt::Display for DecoderError {
|
|
|
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
|
|
// FIXME this should be a nicer error
|
|
|
|
fmt::Debug::fmt(self, f)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-10-03 21:24:49 +00:00
|
|
|
impl std::error::Error for DecoderError {
|
|
|
|
fn description(&self) -> &str { "decoder error" }
|
2015-01-20 23:45:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
impl fmt::Display for EncoderError {
|
|
|
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
|
|
// FIXME this should be a nicer error
|
|
|
|
fmt::Debug::fmt(self, f)
|
|
|
|
}
|
2014-10-03 21:24:49 +00:00
|
|
|
}
|
|
|
|
|
2015-01-10 09:14:19 +00:00
|
|
|
impl std::error::Error for EncoderError {
|
|
|
|
fn description(&self) -> &str { "encoder error" }
|
|
|
|
}
|
|
|
|
|
2015-03-31 00:56:48 +00:00
|
|
|
impl From<fmt::Error> for EncoderError {
|
|
|
|
fn from(err: fmt::Error) -> EncoderError { EncoderError::FmtError(err) }
|
2015-01-10 09:14:19 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
pub type EncodeResult = Result<(), EncoderError>;
|
2014-03-30 12:58:02 +00:00
|
|
|
pub type DecodeResult<T> = Result<T, DecoderError>;
|
2014-01-30 01:39:12 +00:00
|
|
|
|
2015-02-13 23:56:32 +00:00
|
|
|
fn escape_str(wr: &mut fmt::Write, v: &str) -> EncodeResult {
|
2016-03-23 03:01:37 +00:00
|
|
|
wr.write_str("\"")?;
|
2014-07-04 23:36:49 +00:00
|
|
|
|
|
|
|
let mut start = 0;
|
|
|
|
|
2014-12-12 18:59:41 +00:00
|
|
|
for (i, byte) in v.bytes().enumerate() {
|
|
|
|
let escaped = match byte {
|
2014-07-04 23:36:49 +00:00
|
|
|
b'"' => "\\\"",
|
|
|
|
b'\\' => "\\\\",
|
2014-12-20 23:40:15 +00:00
|
|
|
b'\x00' => "\\u0000",
|
|
|
|
b'\x01' => "\\u0001",
|
|
|
|
b'\x02' => "\\u0002",
|
|
|
|
b'\x03' => "\\u0003",
|
|
|
|
b'\x04' => "\\u0004",
|
|
|
|
b'\x05' => "\\u0005",
|
|
|
|
b'\x06' => "\\u0006",
|
|
|
|
b'\x07' => "\\u0007",
|
2014-07-04 23:36:49 +00:00
|
|
|
b'\x08' => "\\b",
|
2014-12-20 23:40:15 +00:00
|
|
|
b'\t' => "\\t",
|
2014-07-04 23:36:49 +00:00
|
|
|
b'\n' => "\\n",
|
2014-12-20 23:40:15 +00:00
|
|
|
b'\x0b' => "\\u000b",
|
|
|
|
b'\x0c' => "\\f",
|
2014-07-04 23:36:49 +00:00
|
|
|
b'\r' => "\\r",
|
2014-12-20 23:40:15 +00:00
|
|
|
b'\x0e' => "\\u000e",
|
|
|
|
b'\x0f' => "\\u000f",
|
|
|
|
b'\x10' => "\\u0010",
|
|
|
|
b'\x11' => "\\u0011",
|
|
|
|
b'\x12' => "\\u0012",
|
|
|
|
b'\x13' => "\\u0013",
|
|
|
|
b'\x14' => "\\u0014",
|
|
|
|
b'\x15' => "\\u0015",
|
|
|
|
b'\x16' => "\\u0016",
|
|
|
|
b'\x17' => "\\u0017",
|
|
|
|
b'\x18' => "\\u0018",
|
|
|
|
b'\x19' => "\\u0019",
|
|
|
|
b'\x1a' => "\\u001a",
|
|
|
|
b'\x1b' => "\\u001b",
|
|
|
|
b'\x1c' => "\\u001c",
|
|
|
|
b'\x1d' => "\\u001d",
|
|
|
|
b'\x1e' => "\\u001e",
|
|
|
|
b'\x1f' => "\\u001f",
|
|
|
|
b'\x7f' => "\\u007f",
|
2014-07-04 23:36:49 +00:00
|
|
|
_ => { continue; }
|
|
|
|
};
|
|
|
|
|
|
|
|
if start < i {
|
2016-03-23 03:01:37 +00:00
|
|
|
wr.write_str(&v[start..i])?;
|
2011-11-07 19:01:28 +00:00
|
|
|
}
|
2014-07-04 23:36:49 +00:00
|
|
|
|
2016-03-23 03:01:37 +00:00
|
|
|
wr.write_str(escaped)?;
|
2014-07-04 23:36:49 +00:00
|
|
|
|
|
|
|
start = i + 1;
|
2014-07-04 18:08:38 +00:00
|
|
|
}
|
2014-07-04 23:36:49 +00:00
|
|
|
|
2014-12-12 18:59:41 +00:00
|
|
|
if start != v.len() {
|
2016-03-23 03:01:37 +00:00
|
|
|
wr.write_str(&v[start..])?;
|
2014-07-04 23:36:49 +00:00
|
|
|
}
|
|
|
|
|
2016-03-23 03:01:37 +00:00
|
|
|
wr.write_str("\"")?;
|
2015-01-10 09:14:19 +00:00
|
|
|
Ok(())
|
2014-07-04 18:08:38 +00:00
|
|
|
}
|
|
|
|
|
2015-02-13 23:56:32 +00:00
|
|
|
fn escape_char(writer: &mut fmt::Write, v: char) -> EncodeResult {
|
2016-03-11 19:01:46 +00:00
|
|
|
escape_str(writer, unsafe {
|
|
|
|
str::from_utf8_unchecked(v.encode_utf8().as_slice())
|
|
|
|
})
|
2014-07-04 18:08:38 +00:00
|
|
|
}
|
|
|
|
|
2015-03-26 00:06:52 +00:00
|
|
|
fn spaces(wr: &mut fmt::Write, mut n: usize) -> EncodeResult {
|
2014-12-12 18:59:41 +00:00
|
|
|
const BUF: &'static str = " ";
|
2014-10-06 23:33:56 +00:00
|
|
|
|
2014-12-12 18:59:41 +00:00
|
|
|
while n >= BUF.len() {
|
2016-03-23 03:01:37 +00:00
|
|
|
wr.write_str(BUF)?;
|
2014-12-12 18:59:41 +00:00
|
|
|
n -= BUF.len();
|
2014-07-04 23:56:23 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if n > 0 {
|
2016-03-23 03:01:37 +00:00
|
|
|
wr.write_str(&BUF[..n])?;
|
2014-07-04 18:08:38 +00:00
|
|
|
}
|
2015-01-10 09:14:19 +00:00
|
|
|
Ok(())
|
2011-11-07 19:01:28 +00:00
|
|
|
}
|
|
|
|
|
2014-09-11 05:07:49 +00:00
|
|
|
fn fmt_number_or_null(v: f64) -> string::String {
|
2014-06-26 01:26:41 +00:00
|
|
|
match v.classify() {
|
2015-06-08 14:55:35 +00:00
|
|
|
Fp::Nan | Fp::Infinite => string::String::from("null"),
|
2015-04-17 22:32:42 +00:00
|
|
|
_ if v.fract() != 0f64 => v.to_string(),
|
|
|
|
_ => v.to_string() + ".0",
|
2014-06-26 01:26:41 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-05-29 03:11:41 +00:00
|
|
|
/// A structure for implementing serialization to JSON.
|
2013-12-10 07:16:18 +00:00
|
|
|
pub struct Encoder<'a> {
|
2015-02-13 23:56:32 +00:00
|
|
|
writer: &'a mut (fmt::Write+'a),
|
2015-01-10 09:14:19 +00:00
|
|
|
is_emitting_map_key: bool,
|
2012-09-24 16:55:42 +00:00
|
|
|
}
|
|
|
|
|
2013-12-10 07:16:18 +00:00
|
|
|
impl<'a> Encoder<'a> {
|
2013-11-29 19:11:52 +00:00
|
|
|
/// Creates a new JSON encoder whose output will be written to the writer
|
|
|
|
/// specified.
|
2015-02-13 23:56:32 +00:00
|
|
|
pub fn new(writer: &'a mut fmt::Write) -> Encoder<'a> {
|
2015-01-10 09:14:19 +00:00
|
|
|
Encoder { writer: writer, is_emitting_map_key: false, }
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
macro_rules! emit_enquoted_if_mapkey {
|
|
|
|
($enc:ident,$e:expr) => {
|
|
|
|
if $enc.is_emitting_map_key {
|
|
|
|
try!(write!($enc.writer, "\"{}\"", $e));
|
|
|
|
Ok(())
|
|
|
|
} else {
|
|
|
|
try!(write!($enc.writer, "{}", $e));
|
|
|
|
Ok(())
|
|
|
|
}
|
2013-11-29 19:11:52 +00:00
|
|
|
}
|
2012-09-24 16:55:42 +00:00
|
|
|
}
|
|
|
|
|
2015-01-04 06:24:50 +00:00
|
|
|
impl<'a> ::Encoder for Encoder<'a> {
|
2015-01-10 09:14:19 +00:00
|
|
|
type Error = EncoderError;
|
2015-01-04 06:24:50 +00:00
|
|
|
|
2015-01-10 09:14:19 +00:00
|
|
|
fn emit_nil(&mut self) -> EncodeResult {
|
|
|
|
if self.is_emitting_map_key { return Err(EncoderError::BadHashmapKey); }
|
2016-03-23 03:01:37 +00:00
|
|
|
write!(self.writer, "null")?;
|
2015-01-10 09:14:19 +00:00
|
|
|
Ok(())
|
|
|
|
}
|
2013-05-02 00:54:54 +00:00
|
|
|
|
2015-03-26 00:06:52 +00:00
|
|
|
fn emit_uint(&mut self, v: usize) -> EncodeResult { emit_enquoted_if_mapkey!(self, v) }
|
2015-01-10 09:14:19 +00:00
|
|
|
fn emit_u64(&mut self, v: u64) -> EncodeResult { emit_enquoted_if_mapkey!(self, v) }
|
|
|
|
fn emit_u32(&mut self, v: u32) -> EncodeResult { emit_enquoted_if_mapkey!(self, v) }
|
|
|
|
fn emit_u16(&mut self, v: u16) -> EncodeResult { emit_enquoted_if_mapkey!(self, v) }
|
|
|
|
fn emit_u8(&mut self, v: u8) -> EncodeResult { emit_enquoted_if_mapkey!(self, v) }
|
2013-05-02 00:54:54 +00:00
|
|
|
|
2015-03-26 00:06:52 +00:00
|
|
|
fn emit_int(&mut self, v: isize) -> EncodeResult { emit_enquoted_if_mapkey!(self, v) }
|
2015-01-10 09:14:19 +00:00
|
|
|
fn emit_i64(&mut self, v: i64) -> EncodeResult { emit_enquoted_if_mapkey!(self, v) }
|
|
|
|
fn emit_i32(&mut self, v: i32) -> EncodeResult { emit_enquoted_if_mapkey!(self, v) }
|
|
|
|
fn emit_i16(&mut self, v: i16) -> EncodeResult { emit_enquoted_if_mapkey!(self, v) }
|
|
|
|
fn emit_i8(&mut self, v: i8) -> EncodeResult { emit_enquoted_if_mapkey!(self, v) }
|
2013-05-02 00:54:54 +00:00
|
|
|
|
2014-03-18 17:58:26 +00:00
|
|
|
fn emit_bool(&mut self, v: bool) -> EncodeResult {
|
2015-01-10 09:14:19 +00:00
|
|
|
if self.is_emitting_map_key { return Err(EncoderError::BadHashmapKey); }
|
2013-05-02 00:54:54 +00:00
|
|
|
if v {
|
2016-03-23 03:01:37 +00:00
|
|
|
write!(self.writer, "true")?;
|
2013-05-02 00:54:54 +00:00
|
|
|
} else {
|
2016-03-23 03:01:37 +00:00
|
|
|
write!(self.writer, "false")?;
|
2013-05-02 00:54:54 +00:00
|
|
|
}
|
2015-01-10 09:14:19 +00:00
|
|
|
Ok(())
|
2013-05-02 00:54:54 +00:00
|
|
|
}
|
|
|
|
|
2014-03-18 17:58:26 +00:00
|
|
|
fn emit_f64(&mut self, v: f64) -> EncodeResult {
|
2015-01-10 09:14:19 +00:00
|
|
|
emit_enquoted_if_mapkey!(self, fmt_number_or_null(v))
|
2013-10-14 01:48:47 +00:00
|
|
|
}
|
2014-11-23 18:32:31 +00:00
|
|
|
fn emit_f32(&mut self, v: f32) -> EncodeResult {
|
|
|
|
self.emit_f64(v as f64)
|
|
|
|
}
|
2013-05-02 00:54:54 +00:00
|
|
|
|
2014-05-20 00:23:26 +00:00
|
|
|
fn emit_char(&mut self, v: char) -> EncodeResult {
|
2014-07-04 18:08:38 +00:00
|
|
|
escape_char(self.writer, v)
|
2014-05-20 00:23:26 +00:00
|
|
|
}
|
2014-03-18 17:58:26 +00:00
|
|
|
fn emit_str(&mut self, v: &str) -> EncodeResult {
|
2014-07-04 18:08:38 +00:00
|
|
|
escape_str(self.writer, v)
|
2013-10-14 01:48:47 +00:00
|
|
|
}
|
2013-05-02 00:54:54 +00:00
|
|
|
|
2014-12-06 19:30:22 +00:00
|
|
|
fn emit_enum<F>(&mut self, _name: &str, f: F) -> EncodeResult where
|
|
|
|
F: FnOnce(&mut Encoder<'a>) -> EncodeResult,
|
|
|
|
{
|
2014-06-28 12:34:58 +00:00
|
|
|
f(self)
|
|
|
|
}
|
2013-05-02 00:54:54 +00:00
|
|
|
|
2014-12-06 19:30:22 +00:00
|
|
|
fn emit_enum_variant<F>(&mut self,
|
|
|
|
name: &str,
|
2015-03-26 00:06:52 +00:00
|
|
|
_id: usize,
|
|
|
|
cnt: usize,
|
2014-12-06 19:30:22 +00:00
|
|
|
f: F) -> EncodeResult where
|
|
|
|
F: FnOnce(&mut Encoder<'a>) -> EncodeResult,
|
|
|
|
{
|
2014-05-28 16:24:28 +00:00
|
|
|
// enums are encoded as strings or objects
|
|
|
|
// Bunny => "Bunny"
|
|
|
|
// Kangaroo(34,"William") => {"variant": "Kangaroo", "fields": [34,"William"]}
|
|
|
|
if cnt == 0 {
|
2014-07-04 18:08:38 +00:00
|
|
|
escape_str(self.writer, name)
|
2014-05-28 16:24:28 +00:00
|
|
|
} else {
|
2015-01-23 09:52:58 +00:00
|
|
|
if self.is_emitting_map_key { return Err(EncoderError::BadHashmapKey); }
|
2016-03-23 03:01:37 +00:00
|
|
|
write!(self.writer, "{{\"variant\":")?;
|
|
|
|
escape_str(self.writer, name)?;
|
|
|
|
write!(self.writer, ",\"fields\":[")?;
|
|
|
|
f(self)?;
|
|
|
|
write!(self.writer, "]}}")?;
|
2015-01-10 09:14:19 +00:00
|
|
|
Ok(())
|
2014-05-28 16:24:28 +00:00
|
|
|
}
|
|
|
|
}
|
2013-05-02 00:54:54 +00:00
|
|
|
|
2015-03-26 00:06:52 +00:00
|
|
|
fn emit_enum_variant_arg<F>(&mut self, idx: usize, f: F) -> EncodeResult where
|
2014-12-06 19:30:22 +00:00
|
|
|
F: FnOnce(&mut Encoder<'a>) -> EncodeResult,
|
|
|
|
{
|
2015-01-10 09:14:19 +00:00
|
|
|
if self.is_emitting_map_key { return Err(EncoderError::BadHashmapKey); }
|
2013-05-02 00:54:54 +00:00
|
|
|
if idx != 0 {
|
2016-03-23 03:01:37 +00:00
|
|
|
write!(self.writer, ",")?;
|
2013-05-02 00:54:54 +00:00
|
|
|
}
|
2014-03-18 17:58:26 +00:00
|
|
|
f(self)
|
2013-05-02 00:54:54 +00:00
|
|
|
}
|
|
|
|
|
2014-12-06 19:30:22 +00:00
|
|
|
fn emit_enum_struct_variant<F>(&mut self,
|
|
|
|
name: &str,
|
2015-03-26 00:06:52 +00:00
|
|
|
id: usize,
|
|
|
|
cnt: usize,
|
2014-12-06 19:30:22 +00:00
|
|
|
f: F) -> EncodeResult where
|
|
|
|
F: FnOnce(&mut Encoder<'a>) -> EncodeResult,
|
|
|
|
{
|
2015-01-10 09:14:19 +00:00
|
|
|
if self.is_emitting_map_key { return Err(EncoderError::BadHashmapKey); }
|
2013-05-02 00:54:54 +00:00
|
|
|
self.emit_enum_variant(name, id, cnt, f)
|
|
|
|
}
|
|
|
|
|
2014-12-06 19:30:22 +00:00
|
|
|
fn emit_enum_struct_variant_field<F>(&mut self,
|
|
|
|
_: &str,
|
2015-03-26 00:06:52 +00:00
|
|
|
idx: usize,
|
2014-12-06 19:30:22 +00:00
|
|
|
f: F) -> EncodeResult where
|
|
|
|
F: FnOnce(&mut Encoder<'a>) -> EncodeResult,
|
|
|
|
{
|
2015-01-10 09:14:19 +00:00
|
|
|
if self.is_emitting_map_key { return Err(EncoderError::BadHashmapKey); }
|
2013-05-02 00:54:54 +00:00
|
|
|
self.emit_enum_variant_arg(idx, f)
|
|
|
|
}
|
|
|
|
|
2015-03-26 00:06:52 +00:00
|
|
|
fn emit_struct<F>(&mut self, _: &str, _: usize, f: F) -> EncodeResult where
|
2014-12-06 19:30:22 +00:00
|
|
|
F: FnOnce(&mut Encoder<'a>) -> EncodeResult,
|
|
|
|
{
|
2015-01-10 09:14:19 +00:00
|
|
|
if self.is_emitting_map_key { return Err(EncoderError::BadHashmapKey); }
|
2016-03-23 03:01:37 +00:00
|
|
|
write!(self.writer, "{{")?;
|
|
|
|
f(self)?;
|
|
|
|
write!(self.writer, "}}")?;
|
2015-01-10 09:14:19 +00:00
|
|
|
Ok(())
|
2014-05-28 16:24:28 +00:00
|
|
|
}
|
2013-05-02 00:54:54 +00:00
|
|
|
|
2015-03-26 00:06:52 +00:00
|
|
|
fn emit_struct_field<F>(&mut self, name: &str, idx: usize, f: F) -> EncodeResult where
|
2014-12-06 19:30:22 +00:00
|
|
|
F: FnOnce(&mut Encoder<'a>) -> EncodeResult,
|
|
|
|
{
|
2015-01-10 09:14:19 +00:00
|
|
|
if self.is_emitting_map_key { return Err(EncoderError::BadHashmapKey); }
|
2016-03-23 03:01:37 +00:00
|
|
|
if idx != 0 { write!(self.writer, ",")?; }
|
|
|
|
escape_str(self.writer, name)?;
|
|
|
|
write!(self.writer, ":")?;
|
2014-03-18 17:58:26 +00:00
|
|
|
f(self)
|
2013-05-02 00:54:54 +00:00
|
|
|
}
|
|
|
|
|
2015-03-26 00:06:52 +00:00
|
|
|
fn emit_tuple<F>(&mut self, len: usize, f: F) -> EncodeResult where
|
2014-12-06 19:30:22 +00:00
|
|
|
F: FnOnce(&mut Encoder<'a>) -> EncodeResult,
|
|
|
|
{
|
2015-01-10 09:14:19 +00:00
|
|
|
if self.is_emitting_map_key { return Err(EncoderError::BadHashmapKey); }
|
2013-05-02 00:54:54 +00:00
|
|
|
self.emit_seq(len, f)
|
|
|
|
}
|
2015-03-26 00:06:52 +00:00
|
|
|
fn emit_tuple_arg<F>(&mut self, idx: usize, f: F) -> EncodeResult where
|
2014-12-06 19:30:22 +00:00
|
|
|
F: FnOnce(&mut Encoder<'a>) -> EncodeResult,
|
|
|
|
{
|
2015-01-10 09:14:19 +00:00
|
|
|
if self.is_emitting_map_key { return Err(EncoderError::BadHashmapKey); }
|
2013-05-02 00:54:54 +00:00
|
|
|
self.emit_seq_elt(idx, f)
|
|
|
|
}
|
|
|
|
|
2015-03-26 00:06:52 +00:00
|
|
|
fn emit_tuple_struct<F>(&mut self, _name: &str, len: usize, f: F) -> EncodeResult where
|
2014-12-06 19:30:22 +00:00
|
|
|
F: FnOnce(&mut Encoder<'a>) -> EncodeResult,
|
|
|
|
{
|
2015-01-10 09:14:19 +00:00
|
|
|
if self.is_emitting_map_key { return Err(EncoderError::BadHashmapKey); }
|
2013-05-02 00:54:54 +00:00
|
|
|
self.emit_seq(len, f)
|
|
|
|
}
|
2015-03-26 00:06:52 +00:00
|
|
|
fn emit_tuple_struct_arg<F>(&mut self, idx: usize, f: F) -> EncodeResult where
|
2014-12-06 19:30:22 +00:00
|
|
|
F: FnOnce(&mut Encoder<'a>) -> EncodeResult,
|
|
|
|
{
|
2015-01-10 09:14:19 +00:00
|
|
|
if self.is_emitting_map_key { return Err(EncoderError::BadHashmapKey); }
|
2013-05-02 00:54:54 +00:00
|
|
|
self.emit_seq_elt(idx, f)
|
|
|
|
}
|
|
|
|
|
2014-12-06 19:30:22 +00:00
|
|
|
fn emit_option<F>(&mut self, f: F) -> EncodeResult where
|
|
|
|
F: FnOnce(&mut Encoder<'a>) -> EncodeResult,
|
|
|
|
{
|
2015-01-10 09:14:19 +00:00
|
|
|
if self.is_emitting_map_key { return Err(EncoderError::BadHashmapKey); }
|
2014-03-18 17:58:26 +00:00
|
|
|
f(self)
|
|
|
|
}
|
2015-01-10 09:14:19 +00:00
|
|
|
fn emit_option_none(&mut self) -> EncodeResult {
|
|
|
|
if self.is_emitting_map_key { return Err(EncoderError::BadHashmapKey); }
|
|
|
|
self.emit_nil()
|
|
|
|
}
|
2014-12-06 19:30:22 +00:00
|
|
|
fn emit_option_some<F>(&mut self, f: F) -> EncodeResult where
|
|
|
|
F: FnOnce(&mut Encoder<'a>) -> EncodeResult,
|
|
|
|
{
|
2015-01-10 09:14:19 +00:00
|
|
|
if self.is_emitting_map_key { return Err(EncoderError::BadHashmapKey); }
|
2014-03-18 17:58:26 +00:00
|
|
|
f(self)
|
|
|
|
}
|
2013-05-02 00:54:54 +00:00
|
|
|
|
2015-03-26 00:06:52 +00:00
|
|
|
fn emit_seq<F>(&mut self, _len: usize, f: F) -> EncodeResult where
|
2014-12-06 19:30:22 +00:00
|
|
|
F: FnOnce(&mut Encoder<'a>) -> EncodeResult,
|
|
|
|
{
|
2015-01-10 09:14:19 +00:00
|
|
|
if self.is_emitting_map_key { return Err(EncoderError::BadHashmapKey); }
|
2016-03-23 03:01:37 +00:00
|
|
|
write!(self.writer, "[")?;
|
|
|
|
f(self)?;
|
|
|
|
write!(self.writer, "]")?;
|
2015-01-10 09:14:19 +00:00
|
|
|
Ok(())
|
2013-05-02 00:54:54 +00:00
|
|
|
}
|
|
|
|
|
2015-03-26 00:06:52 +00:00
|
|
|
fn emit_seq_elt<F>(&mut self, idx: usize, f: F) -> EncodeResult where
|
2014-12-06 19:30:22 +00:00
|
|
|
F: FnOnce(&mut Encoder<'a>) -> EncodeResult,
|
|
|
|
{
|
2015-01-10 09:14:19 +00:00
|
|
|
if self.is_emitting_map_key { return Err(EncoderError::BadHashmapKey); }
|
2013-05-02 00:54:54 +00:00
|
|
|
if idx != 0 {
|
2016-03-23 03:01:37 +00:00
|
|
|
write!(self.writer, ",")?;
|
2013-05-02 00:54:54 +00:00
|
|
|
}
|
|
|
|
f(self)
|
|
|
|
}
|
|
|
|
|
2015-03-26 00:06:52 +00:00
|
|
|
fn emit_map<F>(&mut self, _len: usize, f: F) -> EncodeResult where
|
2014-12-06 19:30:22 +00:00
|
|
|
F: FnOnce(&mut Encoder<'a>) -> EncodeResult,
|
|
|
|
{
|
2015-01-10 09:14:19 +00:00
|
|
|
if self.is_emitting_map_key { return Err(EncoderError::BadHashmapKey); }
|
2016-03-23 03:01:37 +00:00
|
|
|
write!(self.writer, "{{")?;
|
|
|
|
f(self)?;
|
|
|
|
write!(self.writer, "}}")?;
|
2015-01-10 09:14:19 +00:00
|
|
|
Ok(())
|
2014-05-28 16:24:28 +00:00
|
|
|
}
|
2013-05-02 00:54:54 +00:00
|
|
|
|
2015-03-26 00:06:52 +00:00
|
|
|
fn emit_map_elt_key<F>(&mut self, idx: usize, f: F) -> EncodeResult where
|
2015-01-10 09:14:32 +00:00
|
|
|
F: FnOnce(&mut Encoder<'a>) -> EncodeResult,
|
2014-12-06 19:30:22 +00:00
|
|
|
{
|
2015-01-10 09:14:19 +00:00
|
|
|
if self.is_emitting_map_key { return Err(EncoderError::BadHashmapKey); }
|
2016-03-23 03:01:37 +00:00
|
|
|
if idx != 0 { write!(self.writer, ",")? }
|
2015-01-10 09:14:19 +00:00
|
|
|
self.is_emitting_map_key = true;
|
2016-03-23 03:01:37 +00:00
|
|
|
f(self)?;
|
2015-01-10 09:14:19 +00:00
|
|
|
self.is_emitting_map_key = false;
|
2014-03-18 17:58:26 +00:00
|
|
|
Ok(())
|
2013-05-02 00:54:54 +00:00
|
|
|
}
|
|
|
|
|
2015-03-26 00:06:52 +00:00
|
|
|
fn emit_map_elt_val<F>(&mut self, _idx: usize, f: F) -> EncodeResult where
|
2014-12-06 19:30:22 +00:00
|
|
|
F: FnOnce(&mut Encoder<'a>) -> EncodeResult,
|
|
|
|
{
|
2015-01-10 09:14:19 +00:00
|
|
|
if self.is_emitting_map_key { return Err(EncoderError::BadHashmapKey); }
|
2016-03-23 03:01:37 +00:00
|
|
|
write!(self.writer, ":")?;
|
2013-05-02 00:54:54 +00:00
|
|
|
f(self)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-05-29 03:11:41 +00:00
|
|
|
/// Another encoder for JSON, but prints out human-readable JSON instead of
|
|
|
|
/// compact data
|
2013-12-10 07:16:18 +00:00
|
|
|
pub struct PrettyEncoder<'a> {
|
2015-02-13 23:56:32 +00:00
|
|
|
writer: &'a mut (fmt::Write+'a),
|
2015-03-26 00:06:52 +00:00
|
|
|
curr_indent: usize,
|
|
|
|
indent: usize,
|
2015-01-10 09:14:19 +00:00
|
|
|
is_emitting_map_key: bool,
|
2013-05-04 00:55:53 +00:00
|
|
|
}
|
|
|
|
|
2013-12-10 07:16:18 +00:00
|
|
|
impl<'a> PrettyEncoder<'a> {
|
2013-11-29 19:11:52 +00:00
|
|
|
/// Creates a new encoder whose output will be written to the specified writer
|
2015-02-13 23:56:32 +00:00
|
|
|
pub fn new(writer: &'a mut fmt::Write) -> PrettyEncoder<'a> {
|
2015-01-10 09:14:19 +00:00
|
|
|
PrettyEncoder {
|
|
|
|
writer: writer,
|
|
|
|
curr_indent: 0,
|
|
|
|
indent: 2,
|
|
|
|
is_emitting_map_key: false,
|
|
|
|
}
|
2014-08-21 09:25:24 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/// Set the number of spaces to indent for each level.
|
|
|
|
/// This is safe to set during encoding.
|
2015-03-26 00:06:52 +00:00
|
|
|
pub fn set_indent(&mut self, indent: usize) {
|
2014-08-21 09:25:24 +00:00
|
|
|
// self.indent very well could be 0 so we need to use checked division.
|
2014-11-09 13:11:28 +00:00
|
|
|
let level = self.curr_indent.checked_div(self.indent).unwrap_or(0);
|
2014-08-21 09:25:24 +00:00
|
|
|
self.indent = indent;
|
|
|
|
self.curr_indent = level * self.indent;
|
2013-05-02 00:54:54 +00:00
|
|
|
}
|
2012-09-24 16:55:42 +00:00
|
|
|
}
|
2012-08-30 23:39:56 +00:00
|
|
|
|
2015-01-04 06:24:50 +00:00
|
|
|
impl<'a> ::Encoder for PrettyEncoder<'a> {
|
2015-01-10 09:14:19 +00:00
|
|
|
type Error = EncoderError;
|
2015-01-04 06:24:50 +00:00
|
|
|
|
2015-01-10 09:14:19 +00:00
|
|
|
fn emit_nil(&mut self) -> EncodeResult {
|
|
|
|
if self.is_emitting_map_key { return Err(EncoderError::BadHashmapKey); }
|
2016-03-23 03:01:37 +00:00
|
|
|
write!(self.writer, "null")?;
|
2015-01-10 09:14:19 +00:00
|
|
|
Ok(())
|
|
|
|
}
|
2013-05-02 00:54:54 +00:00
|
|
|
|
2015-03-26 00:06:52 +00:00
|
|
|
fn emit_uint(&mut self, v: usize) -> EncodeResult { emit_enquoted_if_mapkey!(self, v) }
|
2015-01-10 09:14:19 +00:00
|
|
|
fn emit_u64(&mut self, v: u64) -> EncodeResult { emit_enquoted_if_mapkey!(self, v) }
|
|
|
|
fn emit_u32(&mut self, v: u32) -> EncodeResult { emit_enquoted_if_mapkey!(self, v) }
|
|
|
|
fn emit_u16(&mut self, v: u16) -> EncodeResult { emit_enquoted_if_mapkey!(self, v) }
|
|
|
|
fn emit_u8(&mut self, v: u8) -> EncodeResult { emit_enquoted_if_mapkey!(self, v) }
|
2013-05-02 00:54:54 +00:00
|
|
|
|
2015-03-26 00:06:52 +00:00
|
|
|
fn emit_int(&mut self, v: isize) -> EncodeResult { emit_enquoted_if_mapkey!(self, v) }
|
2015-01-10 09:14:19 +00:00
|
|
|
fn emit_i64(&mut self, v: i64) -> EncodeResult { emit_enquoted_if_mapkey!(self, v) }
|
|
|
|
fn emit_i32(&mut self, v: i32) -> EncodeResult { emit_enquoted_if_mapkey!(self, v) }
|
|
|
|
fn emit_i16(&mut self, v: i16) -> EncodeResult { emit_enquoted_if_mapkey!(self, v) }
|
|
|
|
fn emit_i8(&mut self, v: i8) -> EncodeResult { emit_enquoted_if_mapkey!(self, v) }
|
2013-05-02 00:54:54 +00:00
|
|
|
|
2014-03-18 17:58:26 +00:00
|
|
|
fn emit_bool(&mut self, v: bool) -> EncodeResult {
|
2015-01-10 09:14:19 +00:00
|
|
|
if self.is_emitting_map_key { return Err(EncoderError::BadHashmapKey); }
|
2013-05-02 00:54:54 +00:00
|
|
|
if v {
|
2016-03-23 03:01:37 +00:00
|
|
|
write!(self.writer, "true")?;
|
2013-05-02 00:54:54 +00:00
|
|
|
} else {
|
2016-03-23 03:01:37 +00:00
|
|
|
write!(self.writer, "false")?;
|
2013-05-02 00:54:54 +00:00
|
|
|
}
|
2015-01-10 09:14:19 +00:00
|
|
|
Ok(())
|
2013-05-02 00:54:54 +00:00
|
|
|
}
|
|
|
|
|
2014-03-18 17:58:26 +00:00
|
|
|
fn emit_f64(&mut self, v: f64) -> EncodeResult {
|
2015-01-10 09:14:19 +00:00
|
|
|
emit_enquoted_if_mapkey!(self, fmt_number_or_null(v))
|
2013-10-14 01:48:47 +00:00
|
|
|
}
|
2014-05-20 00:23:26 +00:00
|
|
|
fn emit_f32(&mut self, v: f32) -> EncodeResult {
|
|
|
|
self.emit_f64(v as f64)
|
|
|
|
}
|
2013-05-02 00:54:54 +00:00
|
|
|
|
2014-05-20 00:23:26 +00:00
|
|
|
fn emit_char(&mut self, v: char) -> EncodeResult {
|
2014-07-04 18:08:38 +00:00
|
|
|
escape_char(self.writer, v)
|
2014-05-20 00:23:26 +00:00
|
|
|
}
|
2014-03-18 17:58:26 +00:00
|
|
|
fn emit_str(&mut self, v: &str) -> EncodeResult {
|
2014-07-04 18:08:38 +00:00
|
|
|
escape_str(self.writer, v)
|
2014-01-30 01:39:12 +00:00
|
|
|
}
|
2013-05-02 00:54:54 +00:00
|
|
|
|
2014-12-06 19:30:22 +00:00
|
|
|
fn emit_enum<F>(&mut self, _name: &str, f: F) -> EncodeResult where
|
|
|
|
F: FnOnce(&mut PrettyEncoder<'a>) -> EncodeResult,
|
|
|
|
{
|
2013-05-02 00:54:54 +00:00
|
|
|
f(self)
|
|
|
|
}
|
|
|
|
|
2014-12-06 19:30:22 +00:00
|
|
|
fn emit_enum_variant<F>(&mut self,
|
|
|
|
name: &str,
|
2015-03-26 00:06:52 +00:00
|
|
|
_id: usize,
|
|
|
|
cnt: usize,
|
2014-12-06 19:30:22 +00:00
|
|
|
f: F)
|
|
|
|
-> EncodeResult where
|
|
|
|
F: FnOnce(&mut PrettyEncoder<'a>) -> EncodeResult,
|
|
|
|
{
|
2013-05-02 00:54:54 +00:00
|
|
|
if cnt == 0 {
|
2014-07-04 18:08:38 +00:00
|
|
|
escape_str(self.writer, name)
|
2013-05-02 00:54:54 +00:00
|
|
|
} else {
|
2015-01-23 09:52:58 +00:00
|
|
|
if self.is_emitting_map_key { return Err(EncoderError::BadHashmapKey); }
|
2016-03-23 03:01:37 +00:00
|
|
|
write!(self.writer, "{{\n")?;
|
2014-08-21 09:25:24 +00:00
|
|
|
self.curr_indent += self.indent;
|
2016-03-23 03:01:37 +00:00
|
|
|
spaces(self.writer, self.curr_indent)?;
|
|
|
|
write!(self.writer, "\"variant\": ")?;
|
|
|
|
escape_str(self.writer, name)?;
|
|
|
|
write!(self.writer, ",\n")?;
|
|
|
|
spaces(self.writer, self.curr_indent)?;
|
|
|
|
write!(self.writer, "\"fields\": [\n")?;
|
2014-09-29 03:24:35 +00:00
|
|
|
self.curr_indent += self.indent;
|
2016-03-23 03:01:37 +00:00
|
|
|
f(self)?;
|
2014-08-21 09:25:24 +00:00
|
|
|
self.curr_indent -= self.indent;
|
2016-03-23 03:01:37 +00:00
|
|
|
write!(self.writer, "\n")?;
|
|
|
|
spaces(self.writer, self.curr_indent)?;
|
2014-09-29 03:24:35 +00:00
|
|
|
self.curr_indent -= self.indent;
|
2016-03-23 03:01:37 +00:00
|
|
|
write!(self.writer, "]\n")?;
|
|
|
|
spaces(self.writer, self.curr_indent)?;
|
|
|
|
write!(self.writer, "}}")?;
|
2015-01-10 09:14:19 +00:00
|
|
|
Ok(())
|
2013-05-02 00:54:54 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-03-26 00:06:52 +00:00
|
|
|
fn emit_enum_variant_arg<F>(&mut self, idx: usize, f: F) -> EncodeResult where
|
2014-12-06 19:30:22 +00:00
|
|
|
F: FnOnce(&mut PrettyEncoder<'a>) -> EncodeResult,
|
|
|
|
{
|
2015-01-10 09:14:19 +00:00
|
|
|
if self.is_emitting_map_key { return Err(EncoderError::BadHashmapKey); }
|
2013-05-02 00:54:54 +00:00
|
|
|
if idx != 0 {
|
2016-03-23 03:01:37 +00:00
|
|
|
write!(self.writer, ",\n")?;
|
2013-05-02 00:54:54 +00:00
|
|
|
}
|
2016-03-23 03:01:37 +00:00
|
|
|
spaces(self.writer, self.curr_indent)?;
|
2013-05-02 00:54:54 +00:00
|
|
|
f(self)
|
|
|
|
}
|
|
|
|
|
2014-12-06 19:30:22 +00:00
|
|
|
fn emit_enum_struct_variant<F>(&mut self,
|
|
|
|
name: &str,
|
2015-03-26 00:06:52 +00:00
|
|
|
id: usize,
|
|
|
|
cnt: usize,
|
2014-12-06 19:30:22 +00:00
|
|
|
f: F) -> EncodeResult where
|
|
|
|
F: FnOnce(&mut PrettyEncoder<'a>) -> EncodeResult,
|
|
|
|
{
|
2015-01-10 09:14:19 +00:00
|
|
|
if self.is_emitting_map_key { return Err(EncoderError::BadHashmapKey); }
|
2013-05-02 00:54:54 +00:00
|
|
|
self.emit_enum_variant(name, id, cnt, f)
|
|
|
|
}
|
|
|
|
|
2014-12-06 19:30:22 +00:00
|
|
|
fn emit_enum_struct_variant_field<F>(&mut self,
|
|
|
|
_: &str,
|
2015-03-26 00:06:52 +00:00
|
|
|
idx: usize,
|
2014-12-06 19:30:22 +00:00
|
|
|
f: F) -> EncodeResult where
|
|
|
|
F: FnOnce(&mut PrettyEncoder<'a>) -> EncodeResult,
|
|
|
|
{
|
2015-01-10 09:14:19 +00:00
|
|
|
if self.is_emitting_map_key { return Err(EncoderError::BadHashmapKey); }
|
2013-05-02 00:54:54 +00:00
|
|
|
self.emit_enum_variant_arg(idx, f)
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2015-03-26 00:06:52 +00:00
|
|
|
fn emit_struct<F>(&mut self, _: &str, len: usize, f: F) -> EncodeResult where
|
2014-12-06 19:30:22 +00:00
|
|
|
F: FnOnce(&mut PrettyEncoder<'a>) -> EncodeResult,
|
|
|
|
{
|
2015-01-10 09:14:19 +00:00
|
|
|
if self.is_emitting_map_key { return Err(EncoderError::BadHashmapKey); }
|
2014-05-28 16:24:28 +00:00
|
|
|
if len == 0 {
|
2016-03-23 03:01:37 +00:00
|
|
|
write!(self.writer, "{{}}")?;
|
2014-05-28 16:24:28 +00:00
|
|
|
} else {
|
2016-03-23 03:01:37 +00:00
|
|
|
write!(self.writer, "{{")?;
|
2014-08-21 09:25:24 +00:00
|
|
|
self.curr_indent += self.indent;
|
2016-03-23 03:01:37 +00:00
|
|
|
f(self)?;
|
2014-08-21 09:25:24 +00:00
|
|
|
self.curr_indent -= self.indent;
|
2016-03-23 03:01:37 +00:00
|
|
|
write!(self.writer, "\n")?;
|
|
|
|
spaces(self.writer, self.curr_indent)?;
|
|
|
|
write!(self.writer, "}}")?;
|
2014-05-28 16:24:28 +00:00
|
|
|
}
|
2015-01-10 09:14:19 +00:00
|
|
|
Ok(())
|
2014-05-28 16:24:28 +00:00
|
|
|
}
|
2013-05-02 00:54:54 +00:00
|
|
|
|
2015-03-26 00:06:52 +00:00
|
|
|
fn emit_struct_field<F>(&mut self, name: &str, idx: usize, f: F) -> EncodeResult where
|
2014-12-06 19:30:22 +00:00
|
|
|
F: FnOnce(&mut PrettyEncoder<'a>) -> EncodeResult,
|
|
|
|
{
|
2015-01-10 09:14:19 +00:00
|
|
|
if self.is_emitting_map_key { return Err(EncoderError::BadHashmapKey); }
|
2013-05-02 00:54:54 +00:00
|
|
|
if idx == 0 {
|
2016-03-23 03:01:37 +00:00
|
|
|
write!(self.writer, "\n")?;
|
2013-05-02 00:54:54 +00:00
|
|
|
} else {
|
2016-03-23 03:01:37 +00:00
|
|
|
write!(self.writer, ",\n")?;
|
2013-05-02 00:54:54 +00:00
|
|
|
}
|
2016-03-23 03:01:37 +00:00
|
|
|
spaces(self.writer, self.curr_indent)?;
|
|
|
|
escape_str(self.writer, name)?;
|
|
|
|
write!(self.writer, ": ")?;
|
2014-03-18 17:58:26 +00:00
|
|
|
f(self)
|
2013-05-02 00:54:54 +00:00
|
|
|
}
|
|
|
|
|
2015-03-26 00:06:52 +00:00
|
|
|
fn emit_tuple<F>(&mut self, len: usize, f: F) -> EncodeResult where
|
2014-12-06 19:30:22 +00:00
|
|
|
F: FnOnce(&mut PrettyEncoder<'a>) -> EncodeResult,
|
|
|
|
{
|
2015-01-10 09:14:19 +00:00
|
|
|
if self.is_emitting_map_key { return Err(EncoderError::BadHashmapKey); }
|
2013-05-02 00:54:54 +00:00
|
|
|
self.emit_seq(len, f)
|
|
|
|
}
|
2015-03-26 00:06:52 +00:00
|
|
|
fn emit_tuple_arg<F>(&mut self, idx: usize, f: F) -> EncodeResult where
|
2014-12-06 19:30:22 +00:00
|
|
|
F: FnOnce(&mut PrettyEncoder<'a>) -> EncodeResult,
|
|
|
|
{
|
2015-01-10 09:14:19 +00:00
|
|
|
if self.is_emitting_map_key { return Err(EncoderError::BadHashmapKey); }
|
2013-05-02 00:54:54 +00:00
|
|
|
self.emit_seq_elt(idx, f)
|
|
|
|
}
|
|
|
|
|
2015-03-26 00:06:52 +00:00
|
|
|
fn emit_tuple_struct<F>(&mut self, _: &str, len: usize, f: F) -> EncodeResult where
|
2014-12-06 19:30:22 +00:00
|
|
|
F: FnOnce(&mut PrettyEncoder<'a>) -> EncodeResult,
|
|
|
|
{
|
2015-01-10 09:14:19 +00:00
|
|
|
if self.is_emitting_map_key { return Err(EncoderError::BadHashmapKey); }
|
2013-05-02 00:54:54 +00:00
|
|
|
self.emit_seq(len, f)
|
|
|
|
}
|
2015-03-26 00:06:52 +00:00
|
|
|
fn emit_tuple_struct_arg<F>(&mut self, idx: usize, f: F) -> EncodeResult where
|
2014-12-06 19:30:22 +00:00
|
|
|
F: FnOnce(&mut PrettyEncoder<'a>) -> EncodeResult,
|
|
|
|
{
|
2015-01-10 09:14:19 +00:00
|
|
|
if self.is_emitting_map_key { return Err(EncoderError::BadHashmapKey); }
|
2013-05-02 00:54:54 +00:00
|
|
|
self.emit_seq_elt(idx, f)
|
|
|
|
}
|
|
|
|
|
2014-12-06 19:30:22 +00:00
|
|
|
fn emit_option<F>(&mut self, f: F) -> EncodeResult where
|
|
|
|
F: FnOnce(&mut PrettyEncoder<'a>) -> EncodeResult,
|
|
|
|
{
|
2015-01-10 09:14:19 +00:00
|
|
|
if self.is_emitting_map_key { return Err(EncoderError::BadHashmapKey); }
|
2014-03-18 17:58:26 +00:00
|
|
|
f(self)
|
|
|
|
}
|
2015-01-10 09:14:19 +00:00
|
|
|
fn emit_option_none(&mut self) -> EncodeResult {
|
|
|
|
if self.is_emitting_map_key { return Err(EncoderError::BadHashmapKey); }
|
|
|
|
self.emit_nil()
|
|
|
|
}
|
2014-12-06 19:30:22 +00:00
|
|
|
fn emit_option_some<F>(&mut self, f: F) -> EncodeResult where
|
|
|
|
F: FnOnce(&mut PrettyEncoder<'a>) -> EncodeResult,
|
|
|
|
{
|
2015-01-10 09:14:19 +00:00
|
|
|
if self.is_emitting_map_key { return Err(EncoderError::BadHashmapKey); }
|
2014-03-18 17:58:26 +00:00
|
|
|
f(self)
|
|
|
|
}
|
2013-05-02 00:54:54 +00:00
|
|
|
|
2015-03-26 00:06:52 +00:00
|
|
|
fn emit_seq<F>(&mut self, len: usize, f: F) -> EncodeResult where
|
2014-12-06 19:30:22 +00:00
|
|
|
F: FnOnce(&mut PrettyEncoder<'a>) -> EncodeResult,
|
|
|
|
{
|
2015-01-10 09:14:19 +00:00
|
|
|
if self.is_emitting_map_key { return Err(EncoderError::BadHashmapKey); }
|
2013-05-02 00:54:54 +00:00
|
|
|
if len == 0 {
|
2016-03-23 03:01:37 +00:00
|
|
|
write!(self.writer, "[]")?;
|
2013-05-02 00:54:54 +00:00
|
|
|
} else {
|
2016-03-23 03:01:37 +00:00
|
|
|
write!(self.writer, "[")?;
|
2014-08-21 09:25:24 +00:00
|
|
|
self.curr_indent += self.indent;
|
2016-03-23 03:01:37 +00:00
|
|
|
f(self)?;
|
2014-08-21 09:25:24 +00:00
|
|
|
self.curr_indent -= self.indent;
|
2016-03-23 03:01:37 +00:00
|
|
|
write!(self.writer, "\n")?;
|
|
|
|
spaces(self.writer, self.curr_indent)?;
|
|
|
|
write!(self.writer, "]")?;
|
2013-05-02 00:54:54 +00:00
|
|
|
}
|
2015-01-10 09:14:19 +00:00
|
|
|
Ok(())
|
2013-05-02 00:54:54 +00:00
|
|
|
}
|
|
|
|
|
2015-03-26 00:06:52 +00:00
|
|
|
fn emit_seq_elt<F>(&mut self, idx: usize, f: F) -> EncodeResult where
|
2014-12-06 19:30:22 +00:00
|
|
|
F: FnOnce(&mut PrettyEncoder<'a>) -> EncodeResult,
|
|
|
|
{
|
2015-01-10 09:14:19 +00:00
|
|
|
if self.is_emitting_map_key { return Err(EncoderError::BadHashmapKey); }
|
2013-05-02 00:54:54 +00:00
|
|
|
if idx == 0 {
|
2016-03-23 03:01:37 +00:00
|
|
|
write!(self.writer, "\n")?;
|
2013-05-02 00:54:54 +00:00
|
|
|
} else {
|
2016-03-23 03:01:37 +00:00
|
|
|
write!(self.writer, ",\n")?;
|
2013-05-02 00:54:54 +00:00
|
|
|
}
|
2016-03-23 03:01:37 +00:00
|
|
|
spaces(self.writer, self.curr_indent)?;
|
2013-05-02 00:54:54 +00:00
|
|
|
f(self)
|
|
|
|
}
|
|
|
|
|
2015-03-26 00:06:52 +00:00
|
|
|
fn emit_map<F>(&mut self, len: usize, f: F) -> EncodeResult where
|
2014-12-06 19:30:22 +00:00
|
|
|
F: FnOnce(&mut PrettyEncoder<'a>) -> EncodeResult,
|
|
|
|
{
|
2015-01-10 09:14:19 +00:00
|
|
|
if self.is_emitting_map_key { return Err(EncoderError::BadHashmapKey); }
|
2014-05-28 16:24:28 +00:00
|
|
|
if len == 0 {
|
2016-03-23 03:01:37 +00:00
|
|
|
write!(self.writer, "{{}}")?;
|
2014-05-28 16:24:28 +00:00
|
|
|
} else {
|
2016-03-23 03:01:37 +00:00
|
|
|
write!(self.writer, "{{")?;
|
2014-08-21 09:25:24 +00:00
|
|
|
self.curr_indent += self.indent;
|
2016-03-23 03:01:37 +00:00
|
|
|
f(self)?;
|
2014-08-21 09:25:24 +00:00
|
|
|
self.curr_indent -= self.indent;
|
2016-03-23 03:01:37 +00:00
|
|
|
write!(self.writer, "\n")?;
|
|
|
|
spaces(self.writer, self.curr_indent)?;
|
|
|
|
write!(self.writer, "}}")?;
|
2014-05-28 16:24:28 +00:00
|
|
|
}
|
2015-01-10 09:14:19 +00:00
|
|
|
Ok(())
|
2014-05-28 16:24:28 +00:00
|
|
|
}
|
2013-05-02 00:54:54 +00:00
|
|
|
|
2015-03-26 00:06:52 +00:00
|
|
|
fn emit_map_elt_key<F>(&mut self, idx: usize, f: F) -> EncodeResult where
|
2015-01-10 09:14:32 +00:00
|
|
|
F: FnOnce(&mut PrettyEncoder<'a>) -> EncodeResult,
|
2014-12-06 19:30:22 +00:00
|
|
|
{
|
2015-01-10 09:14:19 +00:00
|
|
|
if self.is_emitting_map_key { return Err(EncoderError::BadHashmapKey); }
|
2013-05-02 00:54:54 +00:00
|
|
|
if idx == 0 {
|
2016-03-23 03:01:37 +00:00
|
|
|
write!(self.writer, "\n")?;
|
2013-05-02 00:54:54 +00:00
|
|
|
} else {
|
2016-03-23 03:01:37 +00:00
|
|
|
write!(self.writer, ",\n")?;
|
2013-05-02 00:54:54 +00:00
|
|
|
}
|
2016-03-23 03:01:37 +00:00
|
|
|
spaces(self.writer, self.curr_indent)?;
|
2015-01-10 09:14:19 +00:00
|
|
|
self.is_emitting_map_key = true;
|
2016-03-23 03:01:37 +00:00
|
|
|
f(self)?;
|
2015-01-10 09:14:19 +00:00
|
|
|
self.is_emitting_map_key = false;
|
2014-03-18 17:58:26 +00:00
|
|
|
Ok(())
|
2013-05-02 00:54:54 +00:00
|
|
|
}
|
|
|
|
|
2015-03-26 00:06:52 +00:00
|
|
|
fn emit_map_elt_val<F>(&mut self, _idx: usize, f: F) -> EncodeResult where
|
2014-12-06 19:30:22 +00:00
|
|
|
F: FnOnce(&mut PrettyEncoder<'a>) -> EncodeResult,
|
|
|
|
{
|
2015-01-10 09:14:19 +00:00
|
|
|
if self.is_emitting_map_key { return Err(EncoderError::BadHashmapKey); }
|
2016-03-23 03:01:37 +00:00
|
|
|
write!(self.writer, ": ")?;
|
2014-03-18 17:58:26 +00:00
|
|
|
f(self)
|
2013-05-02 00:54:54 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-01-04 06:24:50 +00:00
|
|
|
impl Encodable for Json {
|
|
|
|
fn encode<E: ::Encoder>(&self, e: &mut E) -> Result<(), E::Error> {
|
2013-05-02 00:54:54 +00:00
|
|
|
match *self {
|
2014-11-22 18:48:01 +00:00
|
|
|
Json::I64(v) => v.encode(e),
|
|
|
|
Json::U64(v) => v.encode(e),
|
|
|
|
Json::F64(v) => v.encode(e),
|
|
|
|
Json::String(ref v) => v.encode(e),
|
|
|
|
Json::Boolean(v) => v.encode(e),
|
|
|
|
Json::Array(ref v) => v.encode(e),
|
|
|
|
Json::Object(ref v) => v.encode(e),
|
|
|
|
Json::Null => e.emit_nil(),
|
2013-05-02 00:54:54 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-12-12 18:59:41 +00:00
|
|
|
/// Create an `AsJson` wrapper which can be used to print a value as JSON
|
|
|
|
/// on-the-fly via `write!`
|
|
|
|
pub fn as_json<T>(t: &T) -> AsJson<T> {
|
|
|
|
AsJson { inner: t }
|
|
|
|
}
|
2012-09-24 16:55:42 +00:00
|
|
|
|
2014-12-12 18:59:41 +00:00
|
|
|
/// Create an `AsPrettyJson` wrapper which can be used to print a value as JSON
|
|
|
|
/// on-the-fly via `write!`
|
|
|
|
pub fn as_pretty_json<T>(t: &T) -> AsPrettyJson<T> {
|
|
|
|
AsPrettyJson { inner: t, indent: None }
|
|
|
|
}
|
2012-06-13 00:20:51 +00:00
|
|
|
|
2014-12-12 18:59:41 +00:00
|
|
|
impl Json {
|
|
|
|
/// Borrow this json object as a pretty object to generate a pretty
|
2015-02-05 12:04:07 +00:00
|
|
|
/// representation for it via `Display`.
|
2014-12-12 18:59:41 +00:00
|
|
|
pub fn pretty(&self) -> PrettyJson {
|
|
|
|
PrettyJson { inner: self }
|
2013-08-22 05:32:18 +00:00
|
|
|
}
|
2014-03-09 06:30:27 +00:00
|
|
|
|
|
|
|
/// If the Json value is an Object, returns the value associated with the provided key.
|
|
|
|
/// Otherwise, returns None.
|
2014-10-30 01:21:37 +00:00
|
|
|
pub fn find<'a>(&'a self, key: &str) -> Option<&'a Json>{
|
2015-09-07 22:36:29 +00:00
|
|
|
match *self {
|
|
|
|
Json::Object(ref map) => map.get(key),
|
2014-10-30 01:21:37 +00:00
|
|
|
_ => None
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-03-09 06:30:27 +00:00
|
|
|
/// Attempts to get a nested Json Object for each key in `keys`.
|
2014-03-12 03:04:36 +00:00
|
|
|
/// If any key is found not to exist, find_path will return None.
|
2014-03-09 06:30:27 +00:00
|
|
|
/// Otherwise, it will return the Json value associated with the final key.
|
2014-11-02 13:27:15 +00:00
|
|
|
pub fn find_path<'a>(&'a self, keys: &[&str]) -> Option<&'a Json>{
|
2014-03-12 03:04:36 +00:00
|
|
|
let mut target = self;
|
2015-01-31 17:20:46 +00:00
|
|
|
for key in keys {
|
2014-03-12 03:04:36 +00:00
|
|
|
match target.find(*key) {
|
|
|
|
Some(t) => { target = t; },
|
|
|
|
None => return None
|
|
|
|
}
|
|
|
|
}
|
|
|
|
Some(target)
|
2014-03-09 06:30:27 +00: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-10-30 01:21:37 +00:00
|
|
|
pub fn search<'a>(&'a self, key: &str) -> Option<&'a Json> {
|
|
|
|
match self {
|
2014-11-22 18:48:01 +00:00
|
|
|
&Json::Object(ref map) => {
|
2014-11-12 23:51:51 +00:00
|
|
|
match map.get(key) {
|
2014-10-30 01:21:37 +00:00
|
|
|
Some(json_value) => Some(json_value),
|
|
|
|
None => {
|
2015-01-31 17:20:46 +00:00
|
|
|
for (_, v) in map {
|
2014-10-30 01:21:37 +00:00
|
|
|
match v.search(key) {
|
|
|
|
x if x.is_some() => return x,
|
|
|
|
_ => ()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
None
|
|
|
|
}
|
|
|
|
}
|
|
|
|
},
|
|
|
|
_ => None
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-03-09 06:30:27 +00:00
|
|
|
/// Returns true if the Json value is an Object. Returns false otherwise.
|
2015-09-07 22:36:29 +00:00
|
|
|
pub fn is_object(&self) -> bool {
|
2014-03-12 03:04:36 +00:00
|
|
|
self.as_object().is_some()
|
2014-03-09 06:30:27 +00:00
|
|
|
}
|
|
|
|
|
2014-12-17 04:09:16 +00:00
|
|
|
/// If the Json value is an Object, returns the associated BTreeMap.
|
2014-03-09 06:30:27 +00:00
|
|
|
/// Returns None otherwise.
|
2015-09-07 22:36:29 +00:00
|
|
|
pub fn as_object(&self) -> Option<&Object> {
|
|
|
|
match *self {
|
|
|
|
Json::Object(ref map) => Some(map),
|
2014-03-09 06:30:27 +00:00
|
|
|
_ => None
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-11-19 19:17:10 +00:00
|
|
|
/// Returns true if the Json value is an Array. Returns false otherwise.
|
2015-09-07 22:36:29 +00:00
|
|
|
pub fn is_array(&self) -> bool {
|
2014-11-19 18:19:43 +00:00
|
|
|
self.as_array().is_some()
|
2014-03-09 06:30:27 +00:00
|
|
|
}
|
|
|
|
|
2014-11-19 19:17:10 +00:00
|
|
|
/// If the Json value is an Array, returns the associated vector.
|
2014-03-09 06:30:27 +00:00
|
|
|
/// Returns None otherwise.
|
2015-09-07 22:36:29 +00:00
|
|
|
pub fn as_array(&self) -> Option<&Array> {
|
|
|
|
match *self {
|
|
|
|
Json::Array(ref array) => Some(&*array),
|
2014-03-09 06:30:27 +00:00
|
|
|
_ => None
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Returns true if the Json value is a String. Returns false otherwise.
|
2015-09-07 22:36:29 +00:00
|
|
|
pub fn is_string(&self) -> bool {
|
2014-03-12 03:04:36 +00:00
|
|
|
self.as_string().is_some()
|
2014-03-09 06:30:27 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/// If the Json value is a String, returns the associated str.
|
|
|
|
/// Returns None otherwise.
|
2015-09-07 22:36:29 +00:00
|
|
|
pub fn as_string(&self) -> Option<&str> {
|
2014-03-09 06:30:27 +00:00
|
|
|
match *self {
|
2015-02-18 19:48:57 +00:00
|
|
|
Json::String(ref s) => Some(&s[..]),
|
2014-03-09 06:30:27 +00:00
|
|
|
_ => None
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Returns true if the Json value is a Number. Returns false otherwise.
|
|
|
|
pub fn is_number(&self) -> bool {
|
2014-08-02 16:54:40 +00:00
|
|
|
match *self {
|
2014-11-22 18:48:01 +00:00
|
|
|
Json::I64(_) | Json::U64(_) | Json::F64(_) => true,
|
2014-08-02 16:54:40 +00:00
|
|
|
_ => false,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Returns true if the Json value is a i64. Returns false otherwise.
|
|
|
|
pub fn is_i64(&self) -> bool {
|
|
|
|
match *self {
|
2014-11-22 18:48:01 +00:00
|
|
|
Json::I64(_) => true,
|
2014-08-07 12:35:06 +00:00
|
|
|
_ => false,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Returns true if the Json value is a u64. Returns false otherwise.
|
|
|
|
pub fn is_u64(&self) -> bool {
|
|
|
|
match *self {
|
2014-11-22 18:48:01 +00:00
|
|
|
Json::U64(_) => true,
|
2014-08-02 16:54:40 +00:00
|
|
|
_ => false,
|
|
|
|
}
|
2014-03-09 06:30:27 +00:00
|
|
|
}
|
|
|
|
|
2014-08-02 16:54:40 +00:00
|
|
|
/// Returns true if the Json value is a f64. Returns false otherwise.
|
|
|
|
pub fn is_f64(&self) -> bool {
|
|
|
|
match *self {
|
2014-11-22 18:48:01 +00:00
|
|
|
Json::F64(_) => true,
|
2014-08-02 16:54:40 +00:00
|
|
|
_ => false,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-08-07 12:35:06 +00:00
|
|
|
/// If the Json value is a number, return or cast it to a i64.
|
2014-03-09 06:30:27 +00:00
|
|
|
/// Returns None otherwise.
|
2014-08-02 16:54:40 +00:00
|
|
|
pub fn as_i64(&self) -> Option<i64> {
|
|
|
|
match *self {
|
2014-11-22 18:48:01 +00:00
|
|
|
Json::I64(n) => Some(n),
|
2015-04-17 22:32:42 +00:00
|
|
|
Json::U64(n) => Some(n as i64),
|
2014-08-07 12:35:06 +00:00
|
|
|
_ => None
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// If the Json value is a number, return or cast it to a u64.
|
|
|
|
/// Returns None otherwise.
|
|
|
|
pub fn as_u64(&self) -> Option<u64> {
|
|
|
|
match *self {
|
2015-04-17 22:32:42 +00:00
|
|
|
Json::I64(n) => Some(n as u64),
|
2014-11-22 18:48:01 +00:00
|
|
|
Json::U64(n) => Some(n),
|
2014-08-02 16:54:40 +00:00
|
|
|
_ => None
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-08-07 12:35:06 +00:00
|
|
|
/// If the Json value is a number, return or cast it to a f64.
|
2014-08-02 16:54:40 +00:00
|
|
|
/// Returns None otherwise.
|
|
|
|
pub fn as_f64(&self) -> Option<f64> {
|
|
|
|
match *self {
|
2015-04-17 22:32:42 +00:00
|
|
|
Json::I64(n) => Some(n as f64),
|
|
|
|
Json::U64(n) => Some(n as f64),
|
2014-11-22 18:48:01 +00:00
|
|
|
Json::F64(n) => Some(n),
|
2014-03-09 06:30:27 +00:00
|
|
|
_ => None
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Returns true if the Json value is a Boolean. Returns false otherwise.
|
|
|
|
pub fn is_boolean(&self) -> bool {
|
2014-03-12 03:04:36 +00:00
|
|
|
self.as_boolean().is_some()
|
2014-03-09 06:30:27 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/// If the Json value is a Boolean, returns the associated bool.
|
|
|
|
/// Returns None otherwise.
|
|
|
|
pub fn as_boolean(&self) -> Option<bool> {
|
2015-09-07 22:36:29 +00:00
|
|
|
match *self {
|
|
|
|
Json::Boolean(b) => Some(b),
|
2014-03-09 06:30:27 +00:00
|
|
|
_ => None
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Returns true if the Json value is a Null. Returns false otherwise.
|
|
|
|
pub fn is_null(&self) -> bool {
|
2014-03-12 03:04:36 +00:00
|
|
|
self.as_null().is_some()
|
2014-03-09 06:30:27 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/// If the Json value is a Null, returns ().
|
|
|
|
/// Returns None otherwise.
|
|
|
|
pub fn as_null(&self) -> Option<()> {
|
2015-09-07 22:36:29 +00:00
|
|
|
match *self {
|
|
|
|
Json::Null => Some(()),
|
2014-03-09 06:30:27 +00:00
|
|
|
_ => None
|
|
|
|
}
|
|
|
|
}
|
2011-11-07 19:01:28 +00:00
|
|
|
}
|
|
|
|
|
2015-03-21 23:33:27 +00:00
|
|
|
impl<'a> Index<&'a str> for Json {
|
|
|
|
type Output = Json;
|
|
|
|
|
|
|
|
fn index(&self, idx: &'a str) -> &Json {
|
|
|
|
self.find(idx).unwrap()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-03-26 00:06:52 +00:00
|
|
|
impl Index<usize> for Json {
|
2015-03-21 23:33:27 +00:00
|
|
|
type Output = Json;
|
|
|
|
|
2016-02-18 01:20:41 +00:00
|
|
|
fn index(&self, idx: usize) -> &Json {
|
2015-09-07 22:36:29 +00:00
|
|
|
match *self {
|
|
|
|
Json::Array(ref v) => &v[idx],
|
2015-03-26 00:06:52 +00:00
|
|
|
_ => panic!("can only index Json with usize if it is an array")
|
2015-03-21 23:33:27 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-03-30 12:58:02 +00:00
|
|
|
/// The output of the streaming parser.
|
2015-01-28 13:34:18 +00:00
|
|
|
#[derive(PartialEq, Clone, Debug)]
|
2014-03-30 12:58:02 +00:00
|
|
|
pub enum JsonEvent {
|
|
|
|
ObjectStart,
|
|
|
|
ObjectEnd,
|
2014-11-19 18:19:43 +00:00
|
|
|
ArrayStart,
|
|
|
|
ArrayEnd,
|
2014-03-30 12:58:02 +00:00
|
|
|
BooleanValue(bool),
|
2014-08-07 12:35:06 +00:00
|
|
|
I64Value(i64),
|
|
|
|
U64Value(u64),
|
|
|
|
F64Value(f64),
|
2014-09-11 05:07:49 +00:00
|
|
|
StringValue(string::String),
|
2014-03-30 12:58:02 +00:00
|
|
|
NullValue,
|
|
|
|
Error(ParserError),
|
|
|
|
}
|
|
|
|
|
2015-01-28 13:34:18 +00:00
|
|
|
#[derive(PartialEq, Debug)]
|
2014-03-30 12:58:02 +00:00
|
|
|
enum ParserState {
|
2014-11-19 19:17:10 +00:00
|
|
|
// Parse a value in an array, true means first element.
|
2014-09-11 05:07:49 +00:00
|
|
|
ParseArray(bool),
|
2014-11-19 19:17:10 +00:00
|
|
|
// Parse ',' or ']' after an element in an array.
|
2014-11-19 18:19:43 +00:00
|
|
|
ParseArrayComma,
|
2014-03-30 12:58:02 +00:00
|
|
|
// 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 17:22:49 +00:00
|
|
|
// Initial state.
|
2014-03-30 12:58:02 +00: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.
|
2015-01-04 04:43:24 +00:00
|
|
|
/// For example, StackElement::Key("foo"), StackElement::Key("bar"),
|
|
|
|
/// StackElement::Index(3) and StackElement::Key("x") are the
|
2014-03-30 12:58:02 +00:00
|
|
|
/// StackElements compositing the stack that represents foo.bar[3].x
|
2015-01-28 13:34:18 +00:00
|
|
|
#[derive(PartialEq, Clone, Debug)]
|
2014-03-30 12:58:02 +00: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.
|
2015-01-28 13:34:18 +00:00
|
|
|
#[derive(PartialEq, Clone, Debug)]
|
2014-03-30 12:58:02 +00:00
|
|
|
enum InternalStackElement {
|
|
|
|
InternalIndex(u32),
|
|
|
|
InternalKey(u16, u16), // start, size
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Stack {
|
|
|
|
pub fn new() -> Stack {
|
2014-06-28 12:34:58 +00:00
|
|
|
Stack { stack: Vec::new(), str_buffer: Vec::new() }
|
2014-03-30 12:58:02 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/// Returns The number of elements in the Stack.
|
2015-03-26 00:06:52 +00:00
|
|
|
pub fn len(&self) -> usize { self.stack.len() }
|
2014-03-30 12:58:02 +00:00
|
|
|
|
2014-06-28 12:34:58 +00:00
|
|
|
/// Returns true if the stack is empty.
|
|
|
|
pub fn is_empty(&self) -> bool { self.stack.is_empty() }
|
2014-03-30 12:58:02 +00: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.
|
2016-02-18 01:20:41 +00:00
|
|
|
pub fn get(&self, idx: usize) -> StackElement {
|
2014-07-14 23:37:25 +00:00
|
|
|
match self.stack[idx] {
|
2015-01-02 00:56:28 +00:00
|
|
|
InternalIndex(i) => StackElement::Index(i),
|
2014-06-28 12:34:58 +00:00
|
|
|
InternalKey(start, size) => {
|
2015-01-02 00:56:28 +00:00
|
|
|
StackElement::Key(str::from_utf8(
|
2015-03-26 00:06:52 +00:00
|
|
|
&self.str_buffer[start as usize .. start as usize + size as usize])
|
2015-01-02 00:56:28 +00:00
|
|
|
.unwrap())
|
2014-06-28 12:34:58 +00:00
|
|
|
}
|
2014-03-30 12:58:02 +00: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; }
|
2015-09-07 22:36:29 +00:00
|
|
|
for (i, r) in rhs.iter().enumerate() {
|
2015-09-07 23:03:01 +00:00
|
|
|
if self.get(i) != *r { return false; }
|
2014-03-30 12:58:02 +00:00
|
|
|
}
|
2015-09-07 22:36:29 +00:00
|
|
|
true
|
2014-03-30 12:58:02 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/// 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; }
|
2015-09-07 22:36:29 +00:00
|
|
|
for (i, r) in rhs.iter().enumerate() {
|
2015-09-07 23:03:01 +00:00
|
|
|
if self.get(i) != *r { return false; }
|
2014-03-30 12:58:02 +00:00
|
|
|
}
|
2015-09-07 22:36:29 +00:00
|
|
|
true
|
2014-03-30 12:58:02 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/// 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();
|
2015-09-07 22:36:29 +00:00
|
|
|
for (i, r) in rhs.iter().enumerate() {
|
2015-09-07 23:03:01 +00:00
|
|
|
if self.get(i + offset) != *r { return false; }
|
2014-03-30 12:58:02 +00:00
|
|
|
}
|
2015-09-07 22:36:29 +00:00
|
|
|
true
|
2014-03-30 12:58:02 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/// Returns the top-most element (if any).
|
2016-02-18 01:20:41 +00:00
|
|
|
pub fn top(&self) -> Option<StackElement> {
|
2015-09-07 22:36:29 +00:00
|
|
|
match self.stack.last() {
|
2014-03-30 12:58:02 +00:00
|
|
|
None => None,
|
2015-01-02 00:56:28 +00:00
|
|
|
Some(&InternalIndex(i)) => Some(StackElement::Index(i)),
|
2014-03-30 12:58:02 +00:00
|
|
|
Some(&InternalKey(start, size)) => {
|
2015-01-02 00:56:28 +00:00
|
|
|
Some(StackElement::Key(str::from_utf8(
|
2015-03-26 00:06:52 +00:00
|
|
|
&self.str_buffer[start as usize .. (start+size) as usize]
|
2014-03-30 12:58:02 +00:00
|
|
|
).unwrap()))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-01-02 00:56:28 +00:00
|
|
|
// Used by Parser to insert StackElement::Key elements at the top of the stack.
|
2014-09-11 05:07:49 +00:00
|
|
|
fn push_key(&mut self, key: string::String) {
|
2014-03-30 12:58:02 +00:00
|
|
|
self.stack.push(InternalKey(self.str_buffer.len() as u16, key.len() as u16));
|
2015-01-31 17:20:46 +00:00
|
|
|
for c in key.as_bytes() {
|
2014-03-30 12:58:02 +00:00
|
|
|
self.str_buffer.push(*c);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-01-02 00:56:28 +00:00
|
|
|
// Used by Parser to insert StackElement::Index elements at the top of the stack.
|
2014-03-30 12:58:02 +00:00
|
|
|
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) => {
|
2015-03-26 00:06:52 +00:00
|
|
|
let new_size = self.str_buffer.len() - sz as usize;
|
2014-06-28 12:34:58 +00:00
|
|
|
self.str_buffer.truncate(new_size);
|
2014-03-30 12:58:02 +00: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 12:34:58 +00:00
|
|
|
InternalIndex(i) => { i + 1 }
|
2014-10-09 19:17:22 +00:00
|
|
|
_ => { panic!(); }
|
2014-03-30 12:58:02 +00:00
|
|
|
};
|
2014-10-23 15:42:21 +00:00
|
|
|
self.stack[len - 1] = InternalIndex(idx);
|
2014-03-30 12:58:02 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// A streaming JSON parser implemented as an iterator of JsonEvent, consuming
|
|
|
|
/// an iterator of char.
|
2013-07-11 03:03:10 +00:00
|
|
|
pub struct Parser<T> {
|
2014-03-27 22:13:35 +00:00
|
|
|
rdr: T,
|
|
|
|
ch: Option<char>,
|
2015-03-26 00:06:52 +00:00
|
|
|
line: usize,
|
|
|
|
col: usize,
|
2014-03-30 12:58:02 +00:00
|
|
|
// We maintain a stack representing where we are in the logical structure
|
|
|
|
// of the JSON stream.
|
|
|
|
stack: Stack,
|
2014-06-08 17:22:49 +00:00
|
|
|
// A state machine is kept to make it possible to interrupt and resume parsing.
|
2014-03-30 12:58:02 +00:00
|
|
|
state: ParserState,
|
|
|
|
}
|
|
|
|
|
2015-01-02 03:45:11 +00:00
|
|
|
impl<T: Iterator<Item=char>> Iterator for Parser<T> {
|
|
|
|
type Item = JsonEvent;
|
|
|
|
|
2014-03-30 12:58:02 +00:00
|
|
|
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));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-09-07 22:36:29 +00:00
|
|
|
Some(self.parse())
|
2014-03-30 12:58:02 +00:00
|
|
|
}
|
2012-08-30 23:39:56 +00:00
|
|
|
}
|
|
|
|
|
2015-01-02 03:45:11 +00:00
|
|
|
impl<T: Iterator<Item=char>> Parser<T> {
|
2014-03-30 12:58:02 +00:00
|
|
|
/// Creates the JSON parser.
|
2013-12-04 03:18:35 +00:00
|
|
|
pub fn new(rdr: T) -> Parser<T> {
|
2013-11-29 19:11:52 +00:00
|
|
|
let mut p = Parser {
|
|
|
|
rdr: rdr,
|
2014-02-06 12:56:52 +00:00
|
|
|
ch: Some('\x00'),
|
2013-11-29 19:11:52 +00:00
|
|
|
line: 1,
|
|
|
|
col: 0,
|
2014-03-30 12:58:02 +00:00
|
|
|
stack: Stack::new(),
|
|
|
|
state: ParseStart,
|
2013-11-29 19:11:52 +00:00
|
|
|
};
|
|
|
|
p.bump();
|
2015-09-07 22:36:29 +00:00
|
|
|
p
|
2013-11-29 19:11:52 +00:00
|
|
|
}
|
2011-11-07 19:01:28 +00:00
|
|
|
|
2014-03-30 12:58:02 +00:00
|
|
|
/// Provides access to the current position in the logical structure of the
|
|
|
|
/// JSON stream.
|
2016-02-18 01:20:41 +00:00
|
|
|
pub fn stack(&self) -> &Stack {
|
2015-09-07 22:36:29 +00:00
|
|
|
&self.stack
|
2012-09-24 16:55:42 +00:00
|
|
|
}
|
2012-07-11 22:00:40 +00:00
|
|
|
|
2014-02-06 12:56:52 +00:00
|
|
|
fn eof(&self) -> bool { self.ch.is_none() }
|
|
|
|
fn ch_or_null(&self) -> char { self.ch.unwrap_or('\x00') }
|
2013-03-24 16:41:19 +00:00
|
|
|
fn bump(&mut self) {
|
2014-02-06 12:56:52 +00:00
|
|
|
self.ch = self.rdr.next();
|
2011-11-07 19:01:28 +00:00
|
|
|
|
2014-02-06 12:56:52 +00:00
|
|
|
if self.ch_is('\n') {
|
2015-01-24 14:39:32 +00:00
|
|
|
self.line += 1;
|
|
|
|
self.col = 1;
|
2013-07-11 03:03:10 +00:00
|
|
|
} else {
|
2015-01-24 14:39:32 +00:00
|
|
|
self.col += 1;
|
2011-11-07 19:01:28 +00:00
|
|
|
}
|
2012-02-26 00:39:32 +00:00
|
|
|
}
|
|
|
|
|
2014-02-06 12:56:52 +00:00
|
|
|
fn next_char(&mut self) -> Option<char> {
|
2012-02-26 00:39:32 +00:00
|
|
|
self.bump();
|
|
|
|
self.ch
|
|
|
|
}
|
2014-02-06 12:56:52 +00:00
|
|
|
fn ch_is(&self, c: char) -> bool {
|
|
|
|
self.ch == Some(c)
|
|
|
|
}
|
2012-02-26 00:39:32 +00:00
|
|
|
|
2015-01-08 00:39:45 +00:00
|
|
|
fn error<U>(&self, reason: ErrorCode) -> Result<U, ParserError> {
|
2014-03-30 12:58:02 +00:00
|
|
|
Err(SyntaxError(reason, self.line, self.col))
|
2012-02-26 00:39:32 +00:00
|
|
|
}
|
|
|
|
|
2013-03-24 16:41:19 +00:00
|
|
|
fn parse_whitespace(&mut self) {
|
2014-02-06 12:56:52 +00:00
|
|
|
while self.ch_is(' ') ||
|
|
|
|
self.ch_is('\n') ||
|
|
|
|
self.ch_is('\t') ||
|
|
|
|
self.ch_is('\r') { self.bump(); }
|
2012-02-26 00:39:32 +00:00
|
|
|
}
|
|
|
|
|
2014-08-02 16:54:40 +00:00
|
|
|
fn parse_number(&mut self) -> JsonEvent {
|
2014-08-07 12:35:06 +00:00
|
|
|
let mut neg = false;
|
2012-02-26 00:39:32 +00:00
|
|
|
|
2014-02-06 12:56:52 +00:00
|
|
|
if self.ch_is('-') {
|
2012-02-26 00:39:32 +00:00
|
|
|
self.bump();
|
2014-08-07 12:35:06 +00:00
|
|
|
neg = true;
|
2011-11-07 19:01:28 +00:00
|
|
|
}
|
2012-02-26 00:39:32 +00:00
|
|
|
|
2014-08-07 12:35:06 +00:00
|
|
|
let res = match self.parse_u64() {
|
2014-08-02 16:54:40 +00:00
|
|
|
Ok(res) => res,
|
|
|
|
Err(e) => { return Error(e); }
|
|
|
|
};
|
2012-02-26 00:39:32 +00:00
|
|
|
|
2014-08-02 16:54:40 +00:00
|
|
|
if self.ch_is('.') || self.ch_is('e') || self.ch_is('E') {
|
|
|
|
let mut res = res as f64;
|
2012-02-26 00:39:32 +00:00
|
|
|
|
2014-08-02 16:54:40 +00:00
|
|
|
if self.ch_is('.') {
|
|
|
|
res = match self.parse_decimal(res) {
|
|
|
|
Ok(res) => res,
|
|
|
|
Err(e) => { return Error(e); }
|
|
|
|
};
|
|
|
|
}
|
2012-02-26 00:39:32 +00:00
|
|
|
|
2014-08-02 16:54:40 +00:00
|
|
|
if self.ch_is('e') || self.ch_is('E') {
|
|
|
|
res = match self.parse_exponent(res) {
|
|
|
|
Ok(res) => res,
|
|
|
|
Err(e) => { return Error(e); }
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2014-08-07 12:35:06 +00:00
|
|
|
if neg {
|
|
|
|
res *= -1.0;
|
|
|
|
}
|
|
|
|
|
|
|
|
F64Value(res)
|
2014-08-02 16:54:40 +00:00
|
|
|
} else {
|
2014-08-07 12:35:06 +00:00
|
|
|
if neg {
|
2015-04-16 14:48:14 +00:00
|
|
|
let res = (res as i64).wrapping_neg();
|
2014-08-07 12:35:06 +00:00
|
|
|
|
|
|
|
// Make sure we didn't underflow.
|
|
|
|
if res > 0 {
|
|
|
|
Error(SyntaxError(InvalidNumber, self.line, self.col))
|
|
|
|
} else {
|
|
|
|
I64Value(res)
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
U64Value(res)
|
|
|
|
}
|
2014-08-02 16:54:40 +00:00
|
|
|
}
|
2011-11-07 19:01:28 +00:00
|
|
|
}
|
|
|
|
|
2014-08-07 12:35:06 +00:00
|
|
|
fn parse_u64(&mut self) -> Result<u64, ParserError> {
|
2015-04-17 22:32:42 +00:00
|
|
|
let mut accum = 0u64;
|
2014-08-07 12:35:06 +00:00
|
|
|
let last_accum = 0; // necessary to detect overflow.
|
2011-11-07 19:01:28 +00:00
|
|
|
|
2014-02-06 12:56:52 +00:00
|
|
|
match self.ch_or_null() {
|
|
|
|
'0' => {
|
|
|
|
self.bump();
|
2012-02-26 00:39:32 +00:00
|
|
|
|
2014-06-26 01:26:41 +00:00
|
|
|
// A leading '0' must be the only digit before the decimal point.
|
2015-09-07 22:36:29 +00:00
|
|
|
if let '0' ... '9' = self.ch_or_null() {
|
|
|
|
return self.error(InvalidNumber)
|
2014-02-06 12:56:52 +00:00
|
|
|
}
|
|
|
|
},
|
2014-09-27 04:13:20 +00:00
|
|
|
'1' ... '9' => {
|
2014-02-06 12:56:52 +00:00
|
|
|
while !self.eof() {
|
|
|
|
match self.ch_or_null() {
|
2014-09-27 04:13:20 +00:00
|
|
|
c @ '0' ... '9' => {
|
2015-02-19 18:21:53 +00:00
|
|
|
accum = accum.wrapping_mul(10);
|
|
|
|
accum = accum.wrapping_add((c as u64) - ('0' as u64));
|
2014-08-07 12:35:06 +00:00
|
|
|
|
|
|
|
// Detect overflow by comparing to the last value.
|
|
|
|
if accum <= last_accum { return self.error(InvalidNumber); }
|
|
|
|
|
2014-02-06 12:56:52 +00:00
|
|
|
self.bump();
|
|
|
|
}
|
|
|
|
_ => break,
|
|
|
|
}
|
2012-02-26 00:39:32 +00:00
|
|
|
}
|
|
|
|
}
|
2014-03-30 12:58:02 +00:00
|
|
|
_ => return self.error(InvalidNumber),
|
2011-11-07 19:01:28 +00:00
|
|
|
}
|
2014-08-07 12:35:06 +00:00
|
|
|
|
|
|
|
Ok(accum)
|
2011-11-07 19:01:28 +00:00
|
|
|
}
|
|
|
|
|
2014-06-28 12:34:58 +00:00
|
|
|
fn parse_decimal(&mut self, mut res: f64) -> Result<f64, ParserError> {
|
2012-02-26 00:39:32 +00:00
|
|
|
self.bump();
|
|
|
|
|
|
|
|
// Make sure a digit follows the decimal place.
|
2014-02-06 12:56:52 +00:00
|
|
|
match self.ch_or_null() {
|
2014-09-27 04:13:20 +00:00
|
|
|
'0' ... '9' => (),
|
2014-03-30 12:58:02 +00:00
|
|
|
_ => return self.error(InvalidNumber)
|
2012-02-26 00:39:32 +00:00
|
|
|
}
|
|
|
|
|
2013-09-26 06:26:09 +00:00
|
|
|
let mut dec = 1.0;
|
2012-02-26 00:39:32 +00:00
|
|
|
while !self.eof() {
|
2014-02-06 12:56:52 +00:00
|
|
|
match self.ch_or_null() {
|
2014-09-27 04:13:20 +00:00
|
|
|
c @ '0' ... '9' => {
|
2014-02-06 12:56:52 +00:00
|
|
|
dec /= 10.0;
|
2015-03-26 00:06:52 +00:00
|
|
|
res += (((c as isize) - ('0' as isize)) as f64) * dec;
|
2014-02-06 12:56:52 +00:00
|
|
|
self.bump();
|
|
|
|
}
|
|
|
|
_ => break,
|
2011-11-07 19:01:28 +00:00
|
|
|
}
|
|
|
|
}
|
2012-02-26 00:39:32 +00:00
|
|
|
|
2012-08-26 23:54:31 +00:00
|
|
|
Ok(res)
|
2011-11-07 19:01:28 +00:00
|
|
|
}
|
|
|
|
|
2014-03-30 12:58:02 +00:00
|
|
|
fn parse_exponent(&mut self, mut res: f64) -> Result<f64, ParserError> {
|
2012-02-26 00:39:32 +00:00
|
|
|
self.bump();
|
|
|
|
|
2015-01-24 14:39:32 +00:00
|
|
|
let mut exp = 0;
|
2012-03-14 18:03:56 +00:00
|
|
|
let mut neg_exp = false;
|
2012-02-26 00:39:32 +00:00
|
|
|
|
2014-02-06 12:56:52 +00:00
|
|
|
if self.ch_is('+') {
|
|
|
|
self.bump();
|
|
|
|
} else if self.ch_is('-') {
|
|
|
|
self.bump();
|
|
|
|
neg_exp = true;
|
2012-02-26 00:39:32 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Make sure a digit follows the exponent place.
|
2014-02-06 12:56:52 +00:00
|
|
|
match self.ch_or_null() {
|
2014-09-27 04:13:20 +00:00
|
|
|
'0' ... '9' => (),
|
2014-03-30 12:58:02 +00:00
|
|
|
_ => return self.error(InvalidNumber)
|
2012-02-26 00:39:32 +00:00
|
|
|
}
|
|
|
|
while !self.eof() {
|
2014-02-06 12:56:52 +00:00
|
|
|
match self.ch_or_null() {
|
2014-09-27 04:13:20 +00:00
|
|
|
c @ '0' ... '9' => {
|
2014-02-06 12:56:52 +00:00
|
|
|
exp *= 10;
|
2015-03-26 00:06:52 +00:00
|
|
|
exp += (c as usize) - ('0' as usize);
|
2012-02-26 00:39:32 +00:00
|
|
|
|
2014-02-06 12:56:52 +00:00
|
|
|
self.bump();
|
|
|
|
}
|
|
|
|
_ => break
|
2012-02-26 00:39:32 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-11-09 22:35:53 +00:00
|
|
|
let exp = 10_f64.powi(exp as i32);
|
2012-02-26 00:39:32 +00:00
|
|
|
if neg_exp {
|
|
|
|
res /= exp;
|
|
|
|
} else {
|
|
|
|
res *= exp;
|
|
|
|
}
|
|
|
|
|
2012-08-26 23:54:31 +00:00
|
|
|
Ok(res)
|
2011-11-07 19:01:28 +00:00
|
|
|
}
|
|
|
|
|
2014-03-30 12:58:02 +00:00
|
|
|
fn decode_hex_escape(&mut self) -> Result<u16, ParserError> {
|
2015-01-24 14:39:32 +00:00
|
|
|
let mut i = 0;
|
2015-03-03 08:42:26 +00:00
|
|
|
let mut n = 0;
|
2014-06-28 12:34:58 +00:00
|
|
|
while i < 4 && !self.eof() {
|
2014-04-11 20:21:19 +00:00
|
|
|
self.bump();
|
|
|
|
n = match self.ch_or_null() {
|
2014-09-27 04:13:20 +00:00
|
|
|
c @ '0' ... '9' => n * 16 + ((c as u16) - ('0' as u16)),
|
2014-06-28 12:34:58 +00:00
|
|
|
'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 12:58:02 +00:00
|
|
|
_ => return self.error(InvalidEscape)
|
2014-04-11 20:21:19 +00:00
|
|
|
};
|
|
|
|
|
2015-01-24 14:39:32 +00:00
|
|
|
i += 1;
|
2014-04-11 20:21:19 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Error out if we didn't parse 4 digits.
|
2014-06-28 12:34:58 +00:00
|
|
|
if i != 4 {
|
2014-03-30 12:58:02 +00:00
|
|
|
return self.error(InvalidEscape);
|
2014-04-11 20:21:19 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
Ok(n)
|
|
|
|
}
|
|
|
|
|
2014-09-11 05:07:49 +00:00
|
|
|
fn parse_str(&mut self) -> Result<string::String, ParserError> {
|
2012-03-14 18:03:56 +00:00
|
|
|
let mut escape = false;
|
2014-09-11 05:07:49 +00:00
|
|
|
let mut res = string::String::new();
|
2012-02-26 00:39:32 +00:00
|
|
|
|
2013-07-11 03:03:10 +00:00
|
|
|
loop {
|
2012-02-26 00:39:32 +00:00
|
|
|
self.bump();
|
2013-07-11 03:03:10 +00:00
|
|
|
if self.eof() {
|
2014-03-30 12:58:02 +00:00
|
|
|
return self.error(EOFWhileParsingString);
|
2013-07-11 03:03:10 +00:00
|
|
|
}
|
2012-02-26 00:39:32 +00:00
|
|
|
|
2014-01-19 08:21:14 +00:00
|
|
|
if escape {
|
2014-02-06 12:56:52 +00:00
|
|
|
match self.ch_or_null() {
|
2014-09-22 15:28:35 +00:00
|
|
|
'"' => res.push('"'),
|
|
|
|
'\\' => res.push('\\'),
|
|
|
|
'/' => res.push('/'),
|
|
|
|
'b' => res.push('\x08'),
|
|
|
|
'f' => res.push('\x0c'),
|
|
|
|
'n' => res.push('\n'),
|
|
|
|
'r' => res.push('\r'),
|
|
|
|
't' => res.push('\t'),
|
2016-03-23 03:01:37 +00:00
|
|
|
'u' => match self.decode_hex_escape()? {
|
2014-09-27 04:13:20 +00:00
|
|
|
0xDC00 ... 0xDFFF => {
|
|
|
|
return self.error(LoneLeadingSurrogateInHexEscape)
|
|
|
|
}
|
2014-04-11 20:21:19 +00:00
|
|
|
|
|
|
|
// Non-BMP characters are encoded as a sequence of
|
|
|
|
// two hex escapes, representing UTF-16 surrogates.
|
2014-09-27 04:13:20 +00:00
|
|
|
n1 @ 0xD800 ... 0xDBFF => {
|
2014-06-28 12:34:58 +00:00
|
|
|
match (self.next_char(), self.next_char()) {
|
2014-04-11 20:21:19 +00:00
|
|
|
(Some('\\'), Some('u')) => (),
|
2014-03-30 12:58:02 +00:00
|
|
|
_ => return self.error(UnexpectedEndOfHexEscape),
|
2014-04-11 20:21:19 +00:00
|
|
|
}
|
2014-02-06 12:56:52 +00:00
|
|
|
|
2016-03-23 03:01:37 +00:00
|
|
|
let n2 = self.decode_hex_escape()?;
|
2015-08-13 16:39:46 +00:00
|
|
|
if n2 < 0xDC00 || n2 > 0xDFFF {
|
|
|
|
return self.error(LoneLeadingSurrogateInHexEscape)
|
2014-04-11 20:21:19 +00:00
|
|
|
}
|
2015-08-13 16:39:46 +00:00
|
|
|
let c = (((n1 - 0xD800) as u32) << 10 |
|
|
|
|
(n2 - 0xDC00) as u32) + 0x1_0000;
|
|
|
|
res.push(char::from_u32(c).unwrap());
|
2014-02-06 12:56:52 +00:00
|
|
|
}
|
|
|
|
|
2014-04-11 20:21:19 +00:00
|
|
|
n => match char::from_u32(n as u32) {
|
2014-09-22 15:28:35 +00:00
|
|
|
Some(c) => res.push(c),
|
2014-03-30 12:58:02 +00:00
|
|
|
None => return self.error(InvalidUnicodeCodePoint),
|
2014-04-11 20:21:19 +00:00
|
|
|
},
|
|
|
|
},
|
2014-03-30 12:58:02 +00:00
|
|
|
_ => return self.error(InvalidEscape),
|
2012-02-26 00:39:32 +00:00
|
|
|
}
|
|
|
|
escape = false;
|
2014-02-06 12:56:52 +00:00
|
|
|
} else if self.ch_is('\\') {
|
2012-02-26 00:39:32 +00:00
|
|
|
escape = true;
|
|
|
|
} else {
|
2014-02-06 12:56:52 +00:00
|
|
|
match self.ch {
|
2014-04-02 23:54:22 +00:00
|
|
|
Some('"') => {
|
|
|
|
self.bump();
|
2014-05-15 04:16:44 +00:00
|
|
|
return Ok(res);
|
2014-04-02 23:54:22 +00:00
|
|
|
},
|
2014-09-22 15:28:35 +00:00
|
|
|
Some(c) => res.push(c),
|
2014-02-06 12:56:52 +00:00
|
|
|
None => unreachable!()
|
2012-02-26 00:39:32 +00:00
|
|
|
}
|
2011-11-07 19:01:28 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-03-30 12:58:02 +00: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
|
2015-03-26 00:06:52 +00:00
|
|
|
// stream isize the form of a stack that can be queried by the user using the
|
2014-03-30 12:58:02 +00:00
|
|
|
// stack() method.
|
|
|
|
fn parse(&mut self) -> JsonEvent {
|
|
|
|
loop {
|
|
|
|
// The only paths where the loop can spin a new iteration
|
2014-11-19 18:19:43 +00:00
|
|
|
// are in the cases ParseArrayComma and ParseObjectComma if ','
|
2014-03-30 12:58:02 +00:00
|
|
|
// is parsed. In these cases the state is set to (respectively)
|
2014-09-11 05:07:49 +00:00
|
|
|
// ParseArray(false) and ParseObject(false), which always return,
|
2014-03-30 12:58:02 +00:00
|
|
|
// 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-26 00:39:32 +00:00
|
|
|
|
2014-03-30 12:58:02 +00:00
|
|
|
match self.state {
|
|
|
|
ParseStart => {
|
|
|
|
return self.parse_start();
|
|
|
|
}
|
2014-09-11 05:07:49 +00:00
|
|
|
ParseArray(first) => {
|
2014-11-19 18:19:43 +00:00
|
|
|
return self.parse_array(first);
|
2014-03-30 12:58:02 +00:00
|
|
|
}
|
2014-11-19 18:19:43 +00:00
|
|
|
ParseArrayComma => {
|
|
|
|
match self.parse_array_comma_or_end() {
|
2014-03-30 12:58:02 +00:00
|
|
|
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 {
|
2014-11-23 17:08:11 +00:00
|
|
|
Error(_) => ParseFinished,
|
|
|
|
ArrayStart => ParseArray(true),
|
|
|
|
ObjectStart => ParseObject(true),
|
|
|
|
_ => ParseBeforeFinish,
|
2014-03-30 12:58:02 +00:00
|
|
|
};
|
2015-09-07 22:36:29 +00:00
|
|
|
val
|
2014-03-30 12:58:02 +00:00
|
|
|
}
|
2012-02-26 00:39:32 +00:00
|
|
|
|
2014-11-19 18:19:43 +00:00
|
|
|
fn parse_array(&mut self, first: bool) -> JsonEvent {
|
2014-02-06 12:56:52 +00:00
|
|
|
if self.ch_is(']') {
|
2014-03-30 12:58:02 +00:00
|
|
|
if !first {
|
2014-11-23 17:08:11 +00:00
|
|
|
self.error_event(InvalidSyntax)
|
2014-03-30 12:58:02 +00:00
|
|
|
} else {
|
2014-11-23 17:08:11 +00:00
|
|
|
self.state = if self.stack.is_empty() {
|
|
|
|
ParseBeforeFinish
|
|
|
|
} else if self.stack.last_is_index() {
|
2014-11-19 18:19:43 +00:00
|
|
|
ParseArrayComma
|
2014-03-30 12:58:02 +00:00
|
|
|
} else {
|
|
|
|
ParseObjectComma
|
2014-11-23 17:08:11 +00:00
|
|
|
};
|
|
|
|
self.bump();
|
|
|
|
ArrayEnd
|
2014-03-30 12:58:02 +00:00
|
|
|
}
|
2014-11-23 17:08:11 +00:00
|
|
|
} else {
|
|
|
|
if first {
|
|
|
|
self.stack.push_index(0);
|
|
|
|
}
|
|
|
|
let val = self.parse_value();
|
|
|
|
self.state = match val {
|
|
|
|
Error(_) => ParseFinished,
|
|
|
|
ArrayStart => ParseArray(true),
|
|
|
|
ObjectStart => ParseObject(true),
|
|
|
|
_ => ParseArrayComma,
|
|
|
|
};
|
|
|
|
val
|
2012-02-26 00:39:32 +00:00
|
|
|
}
|
2014-03-30 12:58:02 +00:00
|
|
|
}
|
2012-02-26 00:39:32 +00:00
|
|
|
|
2014-11-19 18:19:43 +00:00
|
|
|
fn parse_array_comma_or_end(&mut self) -> Option<JsonEvent> {
|
2014-03-30 12:58:02 +00:00
|
|
|
if self.ch_is(',') {
|
|
|
|
self.stack.bump_index();
|
2014-09-11 05:07:49 +00:00
|
|
|
self.state = ParseArray(false);
|
2014-03-30 12:58:02 +00:00
|
|
|
self.bump();
|
2014-11-23 17:08:11 +00:00
|
|
|
None
|
2014-03-30 12:58:02 +00:00
|
|
|
} else if self.ch_is(']') {
|
|
|
|
self.stack.pop();
|
2014-11-23 17:08:11 +00:00
|
|
|
self.state = if self.stack.is_empty() {
|
|
|
|
ParseBeforeFinish
|
|
|
|
} else if self.stack.last_is_index() {
|
|
|
|
ParseArrayComma
|
2014-02-06 12:56:52 +00:00
|
|
|
} else {
|
2014-11-23 17:08:11 +00:00
|
|
|
ParseObjectComma
|
|
|
|
};
|
2014-03-30 12:58:02 +00:00
|
|
|
self.bump();
|
2014-11-23 17:08:11 +00:00
|
|
|
Some(ArrayEnd)
|
2014-03-30 12:58:02 +00:00
|
|
|
} else if self.eof() {
|
2014-11-23 17:08:11 +00:00
|
|
|
Some(self.error_event(EOFWhileParsingArray))
|
2014-03-30 12:58:02 +00:00
|
|
|
} else {
|
2014-11-23 17:08:11 +00:00
|
|
|
Some(self.error_event(InvalidSyntax))
|
2014-03-30 12:58:02 +00:00
|
|
|
}
|
2011-11-07 19:01:28 +00:00
|
|
|
}
|
|
|
|
|
2014-03-30 12:58:02 +00:00
|
|
|
fn parse_object(&mut self, first: bool) -> JsonEvent {
|
|
|
|
if self.ch_is('}') {
|
|
|
|
if !first {
|
2014-09-15 17:12:15 +00:00
|
|
|
if self.stack.is_empty() {
|
|
|
|
return self.error_event(TrailingComma);
|
|
|
|
} else {
|
|
|
|
self.stack.pop();
|
|
|
|
}
|
2014-03-30 12:58:02 +00:00
|
|
|
}
|
2014-11-23 17:08:11 +00:00
|
|
|
self.state = if self.stack.is_empty() {
|
|
|
|
ParseBeforeFinish
|
|
|
|
} else if self.stack.last_is_index() {
|
|
|
|
ParseArrayComma
|
2014-03-30 12:58:02 +00:00
|
|
|
} else {
|
2014-11-23 17:08:11 +00:00
|
|
|
ParseObjectComma
|
|
|
|
};
|
2014-03-30 12:58:02 +00:00
|
|
|
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() {
|
2014-11-23 17:08:11 +00:00
|
|
|
Ok(s) => s,
|
2014-03-30 12:58:02 +00:00
|
|
|
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-26 00:39:32 +00:00
|
|
|
self.bump();
|
|
|
|
self.parse_whitespace();
|
|
|
|
|
2014-03-30 12:58:02 +00:00
|
|
|
let val = self.parse_value();
|
2012-02-26 00:39:32 +00:00
|
|
|
|
2014-03-30 12:58:02 +00:00
|
|
|
self.state = match val {
|
2014-11-23 17:08:11 +00:00
|
|
|
Error(_) => ParseFinished,
|
|
|
|
ArrayStart => ParseArray(true),
|
|
|
|
ObjectStart => ParseObject(true),
|
|
|
|
_ => ParseObjectComma,
|
2014-03-30 12:58:02 +00:00
|
|
|
};
|
2015-09-07 22:36:29 +00:00
|
|
|
val
|
2014-03-30 12:58:02 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
fn parse_object_end(&mut self) -> JsonEvent {
|
2014-02-06 12:56:52 +00:00
|
|
|
if self.ch_is('}') {
|
2014-11-23 17:08:11 +00:00
|
|
|
self.state = if self.stack.is_empty() {
|
|
|
|
ParseBeforeFinish
|
|
|
|
} else if self.stack.last_is_index() {
|
|
|
|
ParseArrayComma
|
2014-03-30 12:58:02 +00:00
|
|
|
} else {
|
2014-11-23 17:08:11 +00:00
|
|
|
ParseObjectComma
|
|
|
|
};
|
2014-03-30 12:58:02 +00:00
|
|
|
self.bump();
|
2014-06-28 12:34:58 +00:00
|
|
|
ObjectEnd
|
2014-03-30 12:58:02 +00:00
|
|
|
} else if self.eof() {
|
2014-06-28 12:34:58 +00:00
|
|
|
self.error_event(EOFWhileParsingObject)
|
2014-03-30 12:58:02 +00:00
|
|
|
} else {
|
2014-06-28 12:34:58 +00:00
|
|
|
self.error_event(InvalidSyntax)
|
2012-02-26 00:39:32 +00:00
|
|
|
}
|
2014-03-30 12:58:02 +00:00
|
|
|
}
|
2012-02-26 00:39:32 +00:00
|
|
|
|
2014-03-30 12:58:02 +00:00
|
|
|
fn parse_value(&mut self) -> JsonEvent {
|
|
|
|
if self.eof() { return self.error_event(EOFWhileParsingValue); }
|
|
|
|
match self.ch_or_null() {
|
2014-06-28 12:34:58 +00:00
|
|
|
'n' => { self.parse_ident("ull", NullValue) }
|
|
|
|
't' => { self.parse_ident("rue", BooleanValue(true)) }
|
|
|
|
'f' => { self.parse_ident("alse", BooleanValue(false)) }
|
2014-09-27 04:13:20 +00:00
|
|
|
'0' ... '9' | '-' => self.parse_number(),
|
2014-06-28 12:34:58 +00:00
|
|
|
'"' => match self.parse_str() {
|
2014-03-30 12:58:02 +00:00
|
|
|
Ok(s) => StringValue(s),
|
|
|
|
Err(e) => Error(e),
|
|
|
|
},
|
|
|
|
'[' => {
|
|
|
|
self.bump();
|
2014-11-19 18:19:43 +00:00
|
|
|
ArrayStart
|
2014-03-30 12:58:02 +00:00
|
|
|
}
|
|
|
|
'{' => {
|
|
|
|
self.bump();
|
2014-06-28 12:34:58 +00:00
|
|
|
ObjectStart
|
2012-02-26 00:39:32 +00:00
|
|
|
}
|
2014-06-28 12:34:58 +00:00
|
|
|
_ => { self.error_event(InvalidSyntax) }
|
2014-03-30 12:58:02 +00:00
|
|
|
}
|
|
|
|
}
|
2012-02-26 00:39:32 +00:00
|
|
|
|
2014-03-30 12:58:02 +00: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-26 00:39:32 +00:00
|
|
|
|
2014-03-30 12:58:02 +00:00
|
|
|
fn error_event(&mut self, reason: ErrorCode) -> JsonEvent {
|
|
|
|
self.state = ParseFinished;
|
|
|
|
Error(SyntaxError(reason, self.line, self.col))
|
|
|
|
}
|
|
|
|
}
|
2012-02-26 00:39:32 +00:00
|
|
|
|
2014-03-30 12:58:02 +00: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-26 00:39:32 +00:00
|
|
|
|
2015-01-02 03:45:11 +00:00
|
|
|
impl<T: Iterator<Item=char>> Builder<T> {
|
2014-03-30 12:58:02 +00:00
|
|
|
/// Create a JSON Builder.
|
|
|
|
pub fn new(src: T) -> Builder<T> {
|
2014-06-28 12:34:58 +00:00
|
|
|
Builder { parser: Parser::new(src), token: None, }
|
2014-03-30 12:58:02 +00: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 => {}
|
2015-03-11 22:24:14 +00:00
|
|
|
Some(Error(ref e)) => { return Err(e.clone()); }
|
2014-12-20 08:09:35 +00:00
|
|
|
ref tok => { panic!("unexpected token {:?}", tok.clone()); }
|
2014-03-30 12:58:02 +00:00
|
|
|
}
|
2014-06-28 12:34:58 +00:00
|
|
|
result
|
2014-03-30 12:58:02 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
fn bump(&mut self) {
|
|
|
|
self.token = self.parser.next();
|
|
|
|
}
|
|
|
|
|
|
|
|
fn build_value(&mut self) -> Result<Json, BuilderError> {
|
2015-09-07 22:36:29 +00:00
|
|
|
match self.token {
|
2014-11-22 18:48:01 +00:00
|
|
|
Some(NullValue) => Ok(Json::Null),
|
|
|
|
Some(I64Value(n)) => Ok(Json::I64(n)),
|
|
|
|
Some(U64Value(n)) => Ok(Json::U64(n)),
|
|
|
|
Some(F64Value(n)) => Ok(Json::F64(n)),
|
|
|
|
Some(BooleanValue(b)) => Ok(Json::Boolean(b)),
|
2014-03-30 12:58:02 +00:00
|
|
|
Some(StringValue(ref mut s)) => {
|
2014-09-11 05:07:49 +00:00
|
|
|
let mut temp = string::String::new();
|
2014-03-30 12:58:02 +00:00
|
|
|
swap(s, &mut temp);
|
2014-11-22 18:48:01 +00:00
|
|
|
Ok(Json::String(temp))
|
2012-02-26 00:39:32 +00:00
|
|
|
}
|
2015-03-11 22:24:14 +00:00
|
|
|
Some(Error(ref e)) => Err(e.clone()),
|
2014-11-23 17:08:11 +00:00
|
|
|
Some(ArrayStart) => self.build_array(),
|
|
|
|
Some(ObjectStart) => self.build_object(),
|
|
|
|
Some(ObjectEnd) => self.parser.error(InvalidSyntax),
|
|
|
|
Some(ArrayEnd) => self.parser.error(InvalidSyntax),
|
|
|
|
None => self.parser.error(EOFWhileParsingValue),
|
2014-03-30 12:58:02 +00:00
|
|
|
}
|
|
|
|
}
|
2012-02-26 00:39:32 +00:00
|
|
|
|
2014-11-19 18:19:43 +00:00
|
|
|
fn build_array(&mut self) -> Result<Json, BuilderError> {
|
2014-03-30 12:58:02 +00:00
|
|
|
self.bump();
|
|
|
|
let mut values = Vec::new();
|
|
|
|
|
|
|
|
loop {
|
2014-11-19 18:19:43 +00:00
|
|
|
if self.token == Some(ArrayEnd) {
|
2014-11-22 18:48:01 +00:00
|
|
|
return Ok(Json::Array(values.into_iter().collect()));
|
2014-03-30 12:58:02 +00:00
|
|
|
}
|
|
|
|
match self.build_value() {
|
|
|
|
Ok(v) => values.push(v),
|
|
|
|
Err(e) => { return Err(e) }
|
2012-02-26 00:39:32 +00:00
|
|
|
}
|
2014-03-30 12:58:02 +00:00
|
|
|
self.bump();
|
2012-02-26 00:39:32 +00:00
|
|
|
}
|
2014-03-30 12:58:02 +00:00
|
|
|
}
|
2012-02-26 00:39:32 +00:00
|
|
|
|
2014-03-30 12:58:02 +00:00
|
|
|
fn build_object(&mut self) -> Result<Json, BuilderError> {
|
|
|
|
self.bump();
|
|
|
|
|
2014-12-17 04:09:16 +00:00
|
|
|
let mut values = BTreeMap::new();
|
2014-03-30 12:58:02 +00:00
|
|
|
|
2014-06-28 12:34:58 +00:00
|
|
|
loop {
|
2014-03-30 12:58:02 +00:00
|
|
|
match self.token {
|
2014-11-22 18:48:01 +00:00
|
|
|
Some(ObjectEnd) => { return Ok(Json::Object(values)); }
|
2015-03-11 22:24:14 +00:00
|
|
|
Some(Error(ref e)) => { return Err(e.clone()); }
|
2014-03-30 12:58:02 +00:00
|
|
|
None => { break; }
|
|
|
|
_ => {}
|
|
|
|
}
|
|
|
|
let key = match self.parser.stack().top() {
|
2015-09-07 22:36:29 +00:00
|
|
|
Some(StackElement::Key(k)) => { k.to_owned() }
|
2014-10-09 19:17:22 +00:00
|
|
|
_ => { panic!("invalid state"); }
|
2014-03-30 12:58:02 +00:00
|
|
|
};
|
|
|
|
match self.build_value() {
|
|
|
|
Ok(value) => { values.insert(key, value); }
|
|
|
|
Err(e) => { return Err(e); }
|
|
|
|
}
|
|
|
|
self.bump();
|
|
|
|
}
|
2015-09-07 22:36:29 +00:00
|
|
|
self.parser.error(EOFWhileParsingObject)
|
2011-12-21 20:36:43 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-04-21 02:01:20 +00:00
|
|
|
/// Decodes a json value from an `&mut io::Read`
|
2015-03-11 22:24:14 +00:00
|
|
|
pub fn from_reader(rdr: &mut Read) -> Result<Json, BuilderError> {
|
|
|
|
let mut contents = Vec::new();
|
|
|
|
match rdr.read_to_end(&mut contents) {
|
2014-06-30 14:41:30 +00:00
|
|
|
Ok(c) => c,
|
2014-03-30 12:58:02 +00:00
|
|
|
Err(e) => return Err(io_error_to_error(e))
|
2014-01-30 01:39:12 +00:00
|
|
|
};
|
2015-02-02 02:53:25 +00:00
|
|
|
let s = match str::from_utf8(&contents).ok() {
|
2014-06-30 14:41:30 +00:00
|
|
|
Some(s) => s,
|
|
|
|
_ => return Err(SyntaxError(NotUtf8, 0, 0))
|
2014-01-30 01:39:12 +00:00
|
|
|
};
|
2014-06-30 14:41:30 +00:00
|
|
|
let mut builder = Builder::new(s.chars());
|
2014-03-30 12:58:02 +00:00
|
|
|
builder.build()
|
2011-11-07 19:01:28 +00:00
|
|
|
}
|
|
|
|
|
2012-12-18 03:31:04 +00:00
|
|
|
/// Decodes a json value from a string
|
2014-03-30 12:58:02 +00:00
|
|
|
pub fn from_str(s: &str) -> Result<Json, BuilderError> {
|
|
|
|
let mut builder = Builder::new(s.chars());
|
2014-06-28 12:34:58 +00:00
|
|
|
builder.build()
|
2012-02-26 00:39:32 +00:00
|
|
|
}
|
|
|
|
|
2013-05-29 03:11:41 +00:00
|
|
|
/// A structure to decode JSON to values in rust.
|
2013-05-04 00:55:53 +00:00
|
|
|
pub struct Decoder {
|
2014-04-17 22:59:07 +00:00
|
|
|
stack: Vec<Json>,
|
2013-05-04 00:55:53 +00:00
|
|
|
}
|
|
|
|
|
2013-11-29 19:11:52 +00:00
|
|
|
impl Decoder {
|
|
|
|
/// Creates a new decoder instance for decoding the specified JSON value.
|
2013-12-04 03:18:35 +00:00
|
|
|
pub fn new(json: Json) -> Decoder {
|
2014-06-28 12:34:58 +00:00
|
|
|
Decoder { stack: vec![json] }
|
2013-05-02 00:54:54 +00:00
|
|
|
}
|
2012-09-24 16:55:42 +00:00
|
|
|
}
|
|
|
|
|
2013-11-23 23:17:34 +00:00
|
|
|
impl Decoder {
|
2014-03-18 17:58:26 +00:00
|
|
|
fn pop(&mut self) -> Json {
|
|
|
|
self.stack.pop().unwrap()
|
2013-11-23 23:17:34 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-11-14 17:18:10 +00:00
|
|
|
macro_rules! expect {
|
2014-03-18 17:58:26 +00:00
|
|
|
($e:expr, Null) => ({
|
|
|
|
match $e {
|
2014-11-22 18:48:01 +00:00
|
|
|
Json::Null => Ok(()),
|
2015-09-07 22:36:29 +00:00
|
|
|
other => Err(ExpectedError("Null".to_owned(),
|
2015-01-07 00:16:35 +00:00
|
|
|
format!("{}", other)))
|
2014-03-18 17:58:26 +00:00
|
|
|
}
|
|
|
|
});
|
|
|
|
($e:expr, $t:ident) => ({
|
|
|
|
match $e {
|
2014-11-22 18:48:01 +00:00
|
|
|
Json::$t(v) => Ok(v),
|
2014-05-15 04:16:44 +00:00
|
|
|
other => {
|
2015-09-07 22:36:29 +00:00
|
|
|
Err(ExpectedError(stringify!($t).to_owned(),
|
2015-01-07 00:16:35 +00:00
|
|
|
format!("{}", other)))
|
2014-05-15 04:16:44 +00:00
|
|
|
}
|
2013-05-02 00:54:54 +00:00
|
|
|
}
|
2014-03-18 17:58:26 +00:00
|
|
|
})
|
2014-11-14 17:18:10 +00:00
|
|
|
}
|
2014-03-18 17:58:26 +00:00
|
|
|
|
2014-08-07 12:35:06 +00:00
|
|
|
macro_rules! read_primitive {
|
|
|
|
($name:ident, $ty:ty) => {
|
|
|
|
fn $name(&mut self) -> DecodeResult<$ty> {
|
|
|
|
match self.pop() {
|
2015-04-17 22:32:42 +00:00
|
|
|
Json::I64(f) => Ok(f as $ty),
|
|
|
|
Json::U64(f) => Ok(f as $ty),
|
2015-09-07 22:36:29 +00:00
|
|
|
Json::F64(f) => Err(ExpectedError("Integer".to_owned(), format!("{}", f))),
|
2015-03-26 00:06:52 +00:00
|
|
|
// re: #12967.. a type w/ numeric keys (ie HashMap<usize, V> etc)
|
2014-11-23 18:32:31 +00:00
|
|
|
// is going to have a string here, as per JSON spec.
|
2015-01-28 06:52:32 +00:00
|
|
|
Json::String(s) => match s.parse().ok() {
|
2014-11-23 18:32:31 +00:00
|
|
|
Some(f) => Ok(f),
|
2015-09-07 22:36:29 +00:00
|
|
|
None => Err(ExpectedError("Number".to_owned(), s)),
|
2014-08-07 12:35:06 +00:00
|
|
|
},
|
2015-09-07 22:36:29 +00:00
|
|
|
value => Err(ExpectedError("Number".to_owned(), format!("{}", value))),
|
2014-08-07 12:35:06 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-01-04 06:24:50 +00:00
|
|
|
impl ::Decoder for Decoder {
|
|
|
|
type Error = DecoderError;
|
|
|
|
|
2014-03-18 17:58:26 +00:00
|
|
|
fn read_nil(&mut self) -> DecodeResult<()> {
|
2014-06-28 12:34:58 +00:00
|
|
|
expect!(self.pop(), Null)
|
2013-05-02 00:54:54 +00:00
|
|
|
}
|
|
|
|
|
2015-03-26 00:06:52 +00:00
|
|
|
read_primitive! { read_uint, usize }
|
2014-11-14 17:18:10 +00:00
|
|
|
read_primitive! { read_u8, u8 }
|
|
|
|
read_primitive! { read_u16, u16 }
|
|
|
|
read_primitive! { read_u32, u32 }
|
|
|
|
read_primitive! { read_u64, u64 }
|
2015-03-26 00:06:52 +00:00
|
|
|
read_primitive! { read_int, isize }
|
2014-11-14 17:18:10 +00:00
|
|
|
read_primitive! { read_i8, i8 }
|
|
|
|
read_primitive! { read_i16, i16 }
|
|
|
|
read_primitive! { read_i32, i32 }
|
|
|
|
read_primitive! { read_i64, i64 }
|
2013-05-02 00:54:54 +00:00
|
|
|
|
2014-08-07 12:35:06 +00:00
|
|
|
fn read_f32(&mut self) -> DecodeResult<f32> { self.read_f64().map(|x| x as f32) }
|
2013-05-02 00:54:54 +00:00
|
|
|
|
2014-03-18 17:58:26 +00:00
|
|
|
fn read_f64(&mut self) -> DecodeResult<f64> {
|
|
|
|
match self.pop() {
|
2014-11-22 18:48:01 +00:00
|
|
|
Json::I64(f) => Ok(f as f64),
|
|
|
|
Json::U64(f) => Ok(f as f64),
|
|
|
|
Json::F64(f) => Ok(f),
|
|
|
|
Json::String(s) => {
|
2015-03-26 00:06:52 +00:00
|
|
|
// re: #12967.. a type w/ numeric keys (ie HashMap<usize, V> etc)
|
2014-06-28 12:34:58 +00:00
|
|
|
// is going to have a string here, as per JSON spec.
|
2015-01-28 06:52:32 +00:00
|
|
|
match s.parse().ok() {
|
2014-08-19 20:35:16 +00:00
|
|
|
Some(f) => Ok(f),
|
2015-09-07 22:36:29 +00:00
|
|
|
None => Err(ExpectedError("Number".to_owned(), s)),
|
2014-08-19 20:35:16 +00:00
|
|
|
}
|
2014-03-17 07:26:36 +00:00
|
|
|
},
|
2014-11-22 18:48:01 +00:00
|
|
|
Json::Null => Ok(f64::NAN),
|
2015-09-07 22:36:29 +00:00
|
|
|
value => Err(ExpectedError("Number".to_owned(), format!("{}", value)))
|
2013-05-02 00:54:54 +00:00
|
|
|
}
|
|
|
|
}
|
2014-03-18 16:04:23 +00:00
|
|
|
|
2014-08-07 12:35:06 +00:00
|
|
|
fn read_bool(&mut self) -> DecodeResult<bool> {
|
|
|
|
expect!(self.pop(), Boolean)
|
|
|
|
}
|
2013-05-02 00:54:54 +00:00
|
|
|
|
2014-03-18 17:58:26 +00:00
|
|
|
fn read_char(&mut self) -> DecodeResult<char> {
|
2016-03-23 03:01:37 +00:00
|
|
|
let s = self.read_str()?;
|
2013-11-23 23:17:34 +00:00
|
|
|
{
|
2014-11-27 19:28:51 +00:00
|
|
|
let mut it = s.chars();
|
2013-11-23 23:17:34 +00:00
|
|
|
match (it.next(), it.next()) {
|
|
|
|
// exactly one character
|
2014-03-18 17:58:26 +00:00
|
|
|
(Some(c), None) => return Ok(c),
|
2013-11-23 23:17:34 +00:00
|
|
|
_ => ()
|
|
|
|
}
|
|
|
|
}
|
2015-09-07 22:36:29 +00:00
|
|
|
Err(ExpectedError("single character string".to_owned(), format!("{}", s)))
|
2013-05-02 00:54:54 +00:00
|
|
|
}
|
|
|
|
|
2014-09-11 05:07:49 +00:00
|
|
|
fn read_str(&mut self) -> DecodeResult<string::String> {
|
2014-06-28 12:34:58 +00:00
|
|
|
expect!(self.pop(), String)
|
2013-05-02 00:54:54 +00:00
|
|
|
}
|
|
|
|
|
2014-12-18 15:02:25 +00:00
|
|
|
fn read_enum<T, F>(&mut self, _name: &str, f: F) -> DecodeResult<T> where
|
2014-12-06 19:30:22 +00:00
|
|
|
F: FnOnce(&mut Decoder) -> DecodeResult<T>,
|
|
|
|
{
|
2013-05-02 00:54:54 +00:00
|
|
|
f(self)
|
|
|
|
}
|
|
|
|
|
2014-12-15 17:06:06 +00:00
|
|
|
fn read_enum_variant<T, F>(&mut self, names: &[&str],
|
|
|
|
mut f: F) -> DecodeResult<T>
|
2015-03-26 00:06:52 +00:00
|
|
|
where F: FnMut(&mut Decoder, usize) -> DecodeResult<T>,
|
2014-12-06 19:30:22 +00:00
|
|
|
{
|
2014-03-18 17:58:26 +00:00
|
|
|
let name = match self.pop() {
|
2014-11-22 18:48:01 +00:00
|
|
|
Json::String(s) => s,
|
|
|
|
Json::Object(mut o) => {
|
2015-09-07 22:36:29 +00:00
|
|
|
let n = match o.remove(&"variant".to_owned()) {
|
2014-11-22 18:48:01 +00:00
|
|
|
Some(Json::String(s)) => s,
|
2014-05-15 04:16:44 +00:00
|
|
|
Some(val) => {
|
2015-09-07 22:36:29 +00:00
|
|
|
return Err(ExpectedError("String".to_owned(), format!("{}", val)))
|
2014-05-15 04:16:44 +00:00
|
|
|
}
|
|
|
|
None => {
|
2015-09-07 22:36:29 +00:00
|
|
|
return Err(MissingFieldError("variant".to_owned()))
|
2014-05-15 04:16:44 +00:00
|
|
|
}
|
2013-08-10 00:05:24 +00:00
|
|
|
};
|
2014-12-11 03:46:38 +00:00
|
|
|
match o.remove(&"fields".to_string()) {
|
2014-11-22 18:48:01 +00:00
|
|
|
Some(Json::Array(l)) => {
|
2014-09-15 03:27:36 +00:00
|
|
|
for field in l.into_iter().rev() {
|
2014-06-28 12:34:58 +00:00
|
|
|
self.stack.push(field);
|
2013-08-10 00:05:24 +00:00
|
|
|
}
|
|
|
|
},
|
2014-05-15 04:16:44 +00:00
|
|
|
Some(val) => {
|
2015-09-07 22:36:29 +00:00
|
|
|
return Err(ExpectedError("Array".to_owned(), format!("{}", val)))
|
2014-05-15 04:16:44 +00:00
|
|
|
}
|
|
|
|
None => {
|
2015-09-07 22:36:29 +00:00
|
|
|
return Err(MissingFieldError("fields".to_owned()))
|
2014-05-15 04:16:44 +00:00
|
|
|
}
|
2013-05-02 00:54:54 +00:00
|
|
|
}
|
2013-08-10 00:05:24 +00:00
|
|
|
n
|
2013-05-02 00:54:54 +00:00
|
|
|
}
|
2014-05-15 04:16:44 +00:00
|
|
|
json => {
|
2015-09-07 22:36:29 +00:00
|
|
|
return Err(ExpectedError("String or Object".to_owned(), format!("{}", json)))
|
2014-05-15 04:16:44 +00:00
|
|
|
}
|
2013-05-02 00:54:54 +00:00
|
|
|
};
|
2015-02-18 19:48:57 +00:00
|
|
|
let idx = match names.iter().position(|n| *n == &name[..]) {
|
2013-05-02 00:54:54 +00:00
|
|
|
Some(idx) => idx,
|
2014-03-18 17:58:26 +00:00
|
|
|
None => return Err(UnknownVariantError(name))
|
2013-05-02 00:54:54 +00:00
|
|
|
};
|
|
|
|
f(self, idx)
|
|
|
|
}
|
|
|
|
|
2015-03-26 00:06:52 +00:00
|
|
|
fn read_enum_variant_arg<T, F>(&mut self, _idx: usize, f: F) -> DecodeResult<T> where
|
2014-12-06 19:30:22 +00:00
|
|
|
F: FnOnce(&mut Decoder) -> DecodeResult<T>,
|
|
|
|
{
|
2013-05-02 00:54:54 +00:00
|
|
|
f(self)
|
|
|
|
}
|
|
|
|
|
2014-12-06 19:30:22 +00:00
|
|
|
fn read_enum_struct_variant<T, F>(&mut self, names: &[&str], f: F) -> DecodeResult<T> where
|
2015-03-26 00:06:52 +00:00
|
|
|
F: FnMut(&mut Decoder, usize) -> DecodeResult<T>,
|
2014-12-06 19:30:22 +00:00
|
|
|
{
|
2013-05-02 00:54:54 +00:00
|
|
|
self.read_enum_variant(names, f)
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2014-12-06 19:30:22 +00:00
|
|
|
fn read_enum_struct_variant_field<T, F>(&mut self,
|
2014-12-18 15:02:25 +00:00
|
|
|
_name: &str,
|
2015-03-26 00:06:52 +00:00
|
|
|
idx: usize,
|
2014-12-06 19:30:22 +00:00
|
|
|
f: F)
|
|
|
|
-> DecodeResult<T> where
|
|
|
|
F: FnOnce(&mut Decoder) -> DecodeResult<T>,
|
|
|
|
{
|
2013-05-02 00:54:54 +00:00
|
|
|
self.read_enum_variant_arg(idx, f)
|
|
|
|
}
|
|
|
|
|
2015-03-26 00:06:52 +00:00
|
|
|
fn read_struct<T, F>(&mut self, _name: &str, _len: usize, f: F) -> DecodeResult<T> where
|
2014-12-06 19:30:22 +00:00
|
|
|
F: FnOnce(&mut Decoder) -> DecodeResult<T>,
|
|
|
|
{
|
2016-03-23 03:01:37 +00:00
|
|
|
let value = f(self)?;
|
2014-03-18 17:58:26 +00:00
|
|
|
self.pop();
|
|
|
|
Ok(value)
|
2013-05-02 00:54:54 +00:00
|
|
|
}
|
|
|
|
|
2014-12-06 19:30:22 +00:00
|
|
|
fn read_struct_field<T, F>(&mut self,
|
|
|
|
name: &str,
|
2015-03-26 00:06:52 +00:00
|
|
|
_idx: usize,
|
2014-12-06 19:30:22 +00:00
|
|
|
f: F)
|
|
|
|
-> DecodeResult<T> where
|
|
|
|
F: FnOnce(&mut Decoder) -> DecodeResult<T>,
|
|
|
|
{
|
2016-03-23 03:01:37 +00:00
|
|
|
let mut obj = expect!(self.pop(), Object)?;
|
2014-03-18 17:58:26 +00:00
|
|
|
|
2014-11-06 17:25:16 +00:00
|
|
|
let value = match obj.remove(&name.to_string()) {
|
2014-09-09 05:28:59 +00:00
|
|
|
None => {
|
|
|
|
// Add a Null and try to parse it as an Option<_>
|
|
|
|
// to get None as a default value.
|
2014-11-22 18:48:01 +00:00
|
|
|
self.stack.push(Json::Null);
|
2014-09-09 05:28:59 +00:00
|
|
|
match f(self) {
|
|
|
|
Ok(x) => x,
|
|
|
|
Err(_) => return Err(MissingFieldError(name.to_string())),
|
|
|
|
}
|
|
|
|
},
|
2014-03-18 17:58:26 +00:00
|
|
|
Some(json) => {
|
|
|
|
self.stack.push(json);
|
2016-03-23 03:01:37 +00:00
|
|
|
f(self)?
|
2013-05-02 00:54:54 +00:00
|
|
|
}
|
2014-03-18 17:58:26 +00:00
|
|
|
};
|
2014-11-22 18:48:01 +00:00
|
|
|
self.stack.push(Json::Object(obj));
|
2014-03-18 17:58:26 +00:00
|
|
|
Ok(value)
|
2013-05-02 00:54:54 +00:00
|
|
|
}
|
|
|
|
|
2015-03-26 00:06:52 +00:00
|
|
|
fn read_tuple<T, F>(&mut self, tuple_len: usize, f: F) -> DecodeResult<T> where
|
2014-12-06 19:30:22 +00:00
|
|
|
F: FnOnce(&mut Decoder) -> DecodeResult<T>,
|
|
|
|
{
|
|
|
|
self.read_seq(move |d, len| {
|
2014-10-25 16:29:41 +00:00
|
|
|
if len == tuple_len {
|
|
|
|
f(d)
|
|
|
|
} else {
|
|
|
|
Err(ExpectedError(format!("Tuple{}", tuple_len), format!("Tuple{}", len)))
|
|
|
|
}
|
libserialize: tuple-arity should be provided to `Decoder::read_tuple`
Currently `Decoder` implementations are not provided the tuple arity as
a parameter to `read_tuple`. This forces all encoder/decoder combos to
serialize the arity along with the elements. Tuple-arity is always known
statically at the decode site, because it is part of the type of the
tuple, so it could instead be provided as an argument to `read_tuple`,
as it is to `read_struct`.
The upside to this is that serialized tuples could become smaller in
encoder/decoder implementations which choose not to serialize type
(arity) information. For example, @TyOverby's
[binary-encode](https://github.com/TyOverby/binary-encode) format is
currently forced to serialize the tuple-arity along with every tuple,
despite the information being statically known at the decode site.
A downside to this change is that the tuple-arity of serialized tuples
can no longer be automatically checked during deserialization. However,
for formats which do serialize the tuple-arity, either explicitly (rbml)
or implicitly (json), this check can be added to the `read_tuple` method.
The signature of `Deserialize::read_tuple` and
`Deserialize::read_tuple_struct` are changed, and thus binary
backwards-compatibility is broken. This change does *not* force
serialization formats to change, and thus does not break decoding values
serialized prior to this change.
[breaking-change]
2014-09-27 21:19:19 +00:00
|
|
|
})
|
2013-05-02 00:54:54 +00:00
|
|
|
}
|
|
|
|
|
2015-03-26 00:06:52 +00:00
|
|
|
fn read_tuple_arg<T, F>(&mut self, idx: usize, f: F) -> DecodeResult<T> where
|
2014-12-06 19:30:22 +00:00
|
|
|
F: FnOnce(&mut Decoder) -> DecodeResult<T>,
|
|
|
|
{
|
2013-05-02 00:54:54 +00:00
|
|
|
self.read_seq_elt(idx, f)
|
|
|
|
}
|
|
|
|
|
2014-12-06 19:30:22 +00:00
|
|
|
fn read_tuple_struct<T, F>(&mut self,
|
2014-12-18 15:02:25 +00:00
|
|
|
_name: &str,
|
2015-03-26 00:06:52 +00:00
|
|
|
len: usize,
|
2014-12-06 19:30:22 +00:00
|
|
|
f: F)
|
|
|
|
-> DecodeResult<T> where
|
|
|
|
F: FnOnce(&mut Decoder) -> DecodeResult<T>,
|
|
|
|
{
|
libserialize: tuple-arity should be provided to `Decoder::read_tuple`
Currently `Decoder` implementations are not provided the tuple arity as
a parameter to `read_tuple`. This forces all encoder/decoder combos to
serialize the arity along with the elements. Tuple-arity is always known
statically at the decode site, because it is part of the type of the
tuple, so it could instead be provided as an argument to `read_tuple`,
as it is to `read_struct`.
The upside to this is that serialized tuples could become smaller in
encoder/decoder implementations which choose not to serialize type
(arity) information. For example, @TyOverby's
[binary-encode](https://github.com/TyOverby/binary-encode) format is
currently forced to serialize the tuple-arity along with every tuple,
despite the information being statically known at the decode site.
A downside to this change is that the tuple-arity of serialized tuples
can no longer be automatically checked during deserialization. However,
for formats which do serialize the tuple-arity, either explicitly (rbml)
or implicitly (json), this check can be added to the `read_tuple` method.
The signature of `Deserialize::read_tuple` and
`Deserialize::read_tuple_struct` are changed, and thus binary
backwards-compatibility is broken. This change does *not* force
serialization formats to change, and thus does not break decoding values
serialized prior to this change.
[breaking-change]
2014-09-27 21:19:19 +00:00
|
|
|
self.read_tuple(len, f)
|
2013-05-02 00:54:54 +00:00
|
|
|
}
|
|
|
|
|
2014-12-06 19:30:22 +00:00
|
|
|
fn read_tuple_struct_arg<T, F>(&mut self,
|
2015-03-26 00:06:52 +00:00
|
|
|
idx: usize,
|
2014-12-06 19:30:22 +00:00
|
|
|
f: F)
|
|
|
|
-> DecodeResult<T> where
|
|
|
|
F: FnOnce(&mut Decoder) -> DecodeResult<T>,
|
|
|
|
{
|
2013-05-02 00:54:54 +00:00
|
|
|
self.read_tuple_arg(idx, f)
|
|
|
|
}
|
|
|
|
|
2014-12-15 17:06:06 +00:00
|
|
|
fn read_option<T, F>(&mut self, mut f: F) -> DecodeResult<T> where
|
|
|
|
F: FnMut(&mut Decoder, bool) -> DecodeResult<T>,
|
2014-12-06 19:30:22 +00:00
|
|
|
{
|
2014-03-18 17:58:26 +00:00
|
|
|
match self.pop() {
|
2014-11-22 18:48:01 +00:00
|
|
|
Json::Null => f(self, false),
|
2013-05-02 00:54:54 +00:00
|
|
|
value => { self.stack.push(value); f(self, true) }
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-12-06 19:30:22 +00:00
|
|
|
fn read_seq<T, F>(&mut self, f: F) -> DecodeResult<T> where
|
2015-03-26 00:06:52 +00:00
|
|
|
F: FnOnce(&mut Decoder, usize) -> DecodeResult<T>,
|
2014-12-06 19:30:22 +00:00
|
|
|
{
|
2016-03-23 03:01:37 +00:00
|
|
|
let array = expect!(self.pop(), Array)?;
|
2014-11-19 18:19:43 +00:00
|
|
|
let len = array.len();
|
|
|
|
for v in array.into_iter().rev() {
|
2014-03-18 17:58:26 +00:00
|
|
|
self.stack.push(v);
|
|
|
|
}
|
2013-05-02 00:54:54 +00:00
|
|
|
f(self, len)
|
|
|
|
}
|
|
|
|
|
2015-03-26 00:06:52 +00:00
|
|
|
fn read_seq_elt<T, F>(&mut self, _idx: usize, f: F) -> DecodeResult<T> where
|
2014-12-06 19:30:22 +00:00
|
|
|
F: FnOnce(&mut Decoder) -> DecodeResult<T>,
|
|
|
|
{
|
2013-05-02 00:54:54 +00:00
|
|
|
f(self)
|
|
|
|
}
|
|
|
|
|
2014-12-06 19:30:22 +00:00
|
|
|
fn read_map<T, F>(&mut self, f: F) -> DecodeResult<T> where
|
2015-03-26 00:06:52 +00:00
|
|
|
F: FnOnce(&mut Decoder, usize) -> DecodeResult<T>,
|
2014-12-06 19:30:22 +00:00
|
|
|
{
|
2016-03-23 03:01:37 +00:00
|
|
|
let obj = expect!(self.pop(), Object)?;
|
2014-03-18 17:58:26 +00:00
|
|
|
let len = obj.len();
|
2015-02-01 01:03:04 +00:00
|
|
|
for (key, value) in obj {
|
2014-03-18 17:58:26 +00:00
|
|
|
self.stack.push(value);
|
2014-11-22 18:48:01 +00:00
|
|
|
self.stack.push(Json::String(key));
|
2014-03-18 17:58:26 +00:00
|
|
|
}
|
2013-05-02 00:54:54 +00:00
|
|
|
f(self, len)
|
|
|
|
}
|
|
|
|
|
2015-03-26 00:06:52 +00:00
|
|
|
fn read_map_elt_key<T, F>(&mut self, _idx: usize, f: F) -> DecodeResult<T> where
|
2014-12-06 19:30:22 +00:00
|
|
|
F: FnOnce(&mut Decoder) -> DecodeResult<T>,
|
|
|
|
{
|
2013-05-02 00:54:54 +00:00
|
|
|
f(self)
|
|
|
|
}
|
|
|
|
|
2015-03-26 00:06:52 +00:00
|
|
|
fn read_map_elt_val<T, F>(&mut self, _idx: usize, f: F) -> DecodeResult<T> where
|
2014-12-06 19:30:22 +00:00
|
|
|
F: FnOnce(&mut Decoder) -> DecodeResult<T>,
|
|
|
|
{
|
2013-05-02 00:54:54 +00:00
|
|
|
f(self)
|
|
|
|
}
|
2014-07-31 02:35:32 +00:00
|
|
|
|
|
|
|
fn error(&mut self, err: &str) -> DecoderError {
|
|
|
|
ApplicationError(err.to_string())
|
|
|
|
}
|
2013-05-02 00:54:54 +00:00
|
|
|
}
|
|
|
|
|
2013-05-29 03:11:41 +00:00
|
|
|
/// A trait for converting values to JSON
|
2015-01-05 02:39:02 +00:00
|
|
|
pub trait ToJson {
|
2013-05-29 03:11:41 +00:00
|
|
|
/// Converts the value of `self` to an instance of JSON
|
|
|
|
fn to_json(&self) -> Json;
|
|
|
|
}
|
2012-05-28 19:10:32 +00:00
|
|
|
|
2014-11-14 17:18:10 +00:00
|
|
|
macro_rules! to_json_impl_i64 {
|
2014-08-07 12:35:06 +00:00
|
|
|
($($t:ty), +) => (
|
|
|
|
$(impl ToJson for $t {
|
Add trivial cast lints.
This permits all coercions to be performed in casts, but adds lints to warn in those cases.
Part of this patch moves cast checking to a later stage of type checking. We acquire obligations to check casts as part of type checking where we previously checked them. Once we have type checked a function or module, then we check any cast obligations which have been acquired. That means we have more type information available to check casts (this was crucial to making coercions work properly in place of some casts), but it means that casts cannot feed input into type inference.
[breaking change]
* Adds two new lints for trivial casts and trivial numeric casts, these are warn by default, but can cause errors if you build with warnings as errors. Previously, trivial numeric casts and casts to trait objects were allowed.
* The unused casts lint has gone.
* Interactions between casting and type inference have changed in subtle ways. Two ways this might manifest are:
- You may need to 'direct' casts more with extra type information, for example, in some cases where `foo as _ as T` succeeded, you may now need to specify the type for `_`
- Casts do not influence inference of integer types. E.g., the following used to type check:
```
let x = 42;
let y = &x as *const u32;
```
Because the cast would inform inference that `x` must have type `u32`. This no longer applies and the compiler will fallback to `i32` for `x` and thus there will be a type error in the cast. The solution is to add more type information:
```
let x: u32 = 42;
let y = &x as *const u32;
```
2015-03-20 04:15:27 +00:00
|
|
|
fn to_json(&self) -> Json {
|
|
|
|
Json::I64(*self as i64)
|
|
|
|
}
|
2014-08-07 12:35:06 +00:00
|
|
|
})+
|
|
|
|
)
|
2014-11-14 17:18:10 +00:00
|
|
|
}
|
2014-08-07 12:35:06 +00:00
|
|
|
|
2015-03-26 00:06:52 +00:00
|
|
|
to_json_impl_i64! { isize, i8, i16, i32, i64 }
|
2014-08-07 12:35:06 +00:00
|
|
|
|
2014-11-14 17:18:10 +00:00
|
|
|
macro_rules! to_json_impl_u64 {
|
2014-06-28 12:34:58 +00:00
|
|
|
($($t:ty), +) => (
|
|
|
|
$(impl ToJson for $t {
|
Add trivial cast lints.
This permits all coercions to be performed in casts, but adds lints to warn in those cases.
Part of this patch moves cast checking to a later stage of type checking. We acquire obligations to check casts as part of type checking where we previously checked them. Once we have type checked a function or module, then we check any cast obligations which have been acquired. That means we have more type information available to check casts (this was crucial to making coercions work properly in place of some casts), but it means that casts cannot feed input into type inference.
[breaking change]
* Adds two new lints for trivial casts and trivial numeric casts, these are warn by default, but can cause errors if you build with warnings as errors. Previously, trivial numeric casts and casts to trait objects were allowed.
* The unused casts lint has gone.
* Interactions between casting and type inference have changed in subtle ways. Two ways this might manifest are:
- You may need to 'direct' casts more with extra type information, for example, in some cases where `foo as _ as T` succeeded, you may now need to specify the type for `_`
- Casts do not influence inference of integer types. E.g., the following used to type check:
```
let x = 42;
let y = &x as *const u32;
```
Because the cast would inform inference that `x` must have type `u32`. This no longer applies and the compiler will fallback to `i32` for `x` and thus there will be a type error in the cast. The solution is to add more type information:
```
let x: u32 = 42;
let y = &x as *const u32;
```
2015-03-20 04:15:27 +00:00
|
|
|
fn to_json(&self) -> Json {
|
|
|
|
Json::U64(*self as u64)
|
|
|
|
}
|
2014-06-28 12:34:58 +00:00
|
|
|
})+
|
|
|
|
)
|
2014-11-14 17:18:10 +00:00
|
|
|
}
|
2012-05-28 19:10:32 +00:00
|
|
|
|
2015-03-26 00:06:52 +00:00
|
|
|
to_json_impl_u64! { usize, u8, u16, u32, u64 }
|
2012-05-28 19:10:32 +00:00
|
|
|
|
2014-06-28 12:34:58 +00:00
|
|
|
impl ToJson for Json {
|
|
|
|
fn to_json(&self) -> Json { self.clone() }
|
2012-05-28 19:10:32 +00:00
|
|
|
}
|
|
|
|
|
2013-02-14 19:47:00 +00:00
|
|
|
impl ToJson for f32 {
|
2014-06-26 01:26:41 +00:00
|
|
|
fn to_json(&self) -> Json { (*self as f64).to_json() }
|
2012-05-28 19:10:32 +00:00
|
|
|
}
|
|
|
|
|
2013-02-14 19:47:00 +00:00
|
|
|
impl ToJson for f64 {
|
2014-06-26 01:26:41 +00:00
|
|
|
fn to_json(&self) -> Json {
|
|
|
|
match self.classify() {
|
2014-12-22 21:50:57 +00:00
|
|
|
Fp::Nan | Fp::Infinite => Json::Null,
|
2014-11-22 18:48:01 +00:00
|
|
|
_ => Json::F64(*self)
|
2014-06-26 01:26:41 +00:00
|
|
|
}
|
|
|
|
}
|
2012-05-28 19:10:32 +00:00
|
|
|
}
|
|
|
|
|
2013-02-14 19:47:00 +00:00
|
|
|
impl ToJson for () {
|
2014-11-22 18:48:01 +00:00
|
|
|
fn to_json(&self) -> Json { Json::Null }
|
2012-05-28 19:10:32 +00:00
|
|
|
}
|
|
|
|
|
2013-02-14 19:47:00 +00:00
|
|
|
impl ToJson for bool {
|
2014-11-22 18:48:01 +00:00
|
|
|
fn to_json(&self) -> Json { Json::Boolean(*self) }
|
2012-05-28 19:10:32 +00:00
|
|
|
}
|
|
|
|
|
2014-11-14 08:38:55 +00:00
|
|
|
impl ToJson for str {
|
2014-12-11 03:46:38 +00:00
|
|
|
fn to_json(&self) -> Json { Json::String(self.to_string()) }
|
2014-11-14 08:38:55 +00:00
|
|
|
}
|
|
|
|
|
2014-09-11 05:07:49 +00:00
|
|
|
impl ToJson for string::String {
|
2014-11-22 18:48:01 +00:00
|
|
|
fn to_json(&self) -> Json { Json::String((*self).clone()) }
|
2014-04-30 22:55:04 +00:00
|
|
|
}
|
|
|
|
|
2014-06-29 09:33:45 +00: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]
|
2014-07-18 12:45:17 +00:00
|
|
|
#[allow(non_snake_case)]
|
2014-06-29 09:33:45 +00:00
|
|
|
fn to_json(&self) -> Json {
|
|
|
|
match *self {
|
2014-11-22 18:48:01 +00:00
|
|
|
($(ref $tyvar),*,) => Json::Array(vec![$($tyvar.to_json()),*])
|
2014-06-29 09:33:45 +00:00
|
|
|
}
|
2014-06-28 12:34:58 +00:00
|
|
|
}
|
2012-08-02 22:42:56 +00:00
|
|
|
}
|
2012-05-28 19:10:32 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-06-29 09:33:45 +00: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 19:10:32 +00:00
|
|
|
|
2014-11-06 16:25:09 +00:00
|
|
|
impl<A: ToJson> ToJson for [A] {
|
2014-11-22 18:48:01 +00:00
|
|
|
fn to_json(&self) -> Json { Json::Array(self.iter().map(|elt| elt.to_json()).collect()) }
|
2014-06-03 15:49:26 +00:00
|
|
|
}
|
|
|
|
|
2014-06-28 12:34:58 +00:00
|
|
|
impl<A: ToJson> ToJson for Vec<A> {
|
2014-11-22 18:48:01 +00:00
|
|
|
fn to_json(&self) -> Json { Json::Array(self.iter().map(|elt| elt.to_json()).collect()) }
|
2014-05-02 07:02:15 +00:00
|
|
|
}
|
|
|
|
|
2014-12-17 04:09:16 +00:00
|
|
|
impl<A: ToJson> ToJson for BTreeMap<string::String, A> {
|
2013-03-08 02:11:09 +00:00
|
|
|
fn to_json(&self) -> Json {
|
2014-12-17 04:09:16 +00:00
|
|
|
let mut d = BTreeMap::new();
|
2015-01-31 17:20:46 +00:00
|
|
|
for (key, value) in self {
|
2013-07-02 19:47:32 +00:00
|
|
|
d.insert((*key).clone(), value.to_json());
|
2012-09-24 16:55:42 +00:00
|
|
|
}
|
2014-11-22 18:48:01 +00:00
|
|
|
Json::Object(d)
|
2012-09-24 16:55:42 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-09-11 05:07:49 +00:00
|
|
|
impl<A: ToJson> ToJson for HashMap<string::String, A> {
|
2013-07-08 23:21:09 +00:00
|
|
|
fn to_json(&self) -> Json {
|
2014-12-17 04:09:16 +00:00
|
|
|
let mut d = BTreeMap::new();
|
2015-01-31 17:20:46 +00:00
|
|
|
for (key, value) in self {
|
2013-07-02 19:47:32 +00:00
|
|
|
d.insert((*key).clone(), value.to_json());
|
2013-07-08 23:21:09 +00:00
|
|
|
}
|
2014-11-22 18:48:01 +00:00
|
|
|
Json::Object(d)
|
2013-07-08 23:21:09 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-02-21 01:07:17 +00:00
|
|
|
impl<A:ToJson> ToJson for Option<A> {
|
2013-03-08 02:11:09 +00:00
|
|
|
fn to_json(&self) -> Json {
|
|
|
|
match *self {
|
2014-11-22 18:48:01 +00:00
|
|
|
None => Json::Null,
|
2014-06-28 12:34:58 +00:00
|
|
|
Some(ref value) => value.to_json()
|
2012-05-28 19:10:32 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-12-12 18:59:41 +00:00
|
|
|
struct FormatShim<'a, 'b: 'a> {
|
|
|
|
inner: &'a mut fmt::Formatter<'b>,
|
|
|
|
}
|
|
|
|
|
2015-02-13 23:56:32 +00:00
|
|
|
impl<'a, 'b> fmt::Write for FormatShim<'a, 'b> {
|
2014-12-12 18:59:41 +00:00
|
|
|
fn write_str(&mut self, s: &str) -> fmt::Result {
|
2015-01-10 09:13:11 +00:00
|
|
|
match self.inner.write_str(s) {
|
|
|
|
Ok(_) => Ok(()),
|
|
|
|
Err(_) => Err(fmt::Error)
|
|
|
|
}
|
2014-12-12 18:59:41 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-01-20 23:45:07 +00:00
|
|
|
impl fmt::Display for Json {
|
2013-08-22 05:32:18 +00:00
|
|
|
/// Encodes a json value into a string
|
2014-02-20 02:56:33 +00:00
|
|
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
2014-12-12 18:59:41 +00:00
|
|
|
let mut shim = FormatShim { inner: f };
|
|
|
|
let mut encoder = Encoder::new(&mut shim);
|
2015-01-10 09:13:11 +00:00
|
|
|
match self.encode(&mut encoder) {
|
|
|
|
Ok(_) => Ok(()),
|
|
|
|
Err(_) => Err(fmt::Error)
|
|
|
|
}
|
2014-12-12 18:59:41 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-01-20 23:45:07 +00:00
|
|
|
impl<'a> fmt::Display for PrettyJson<'a> {
|
2014-12-12 18:59:41 +00:00
|
|
|
/// Encodes a json value into a string
|
|
|
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
|
|
let mut shim = FormatShim { inner: f };
|
|
|
|
let mut encoder = PrettyEncoder::new(&mut shim);
|
2015-01-10 09:13:11 +00:00
|
|
|
match self.inner.encode(&mut encoder) {
|
|
|
|
Ok(_) => Ok(()),
|
|
|
|
Err(_) => Err(fmt::Error)
|
|
|
|
}
|
2014-12-12 18:59:41 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-01-20 23:45:07 +00:00
|
|
|
impl<'a, T: Encodable> fmt::Display for AsJson<'a, T> {
|
2014-12-12 18:59:41 +00:00
|
|
|
/// Encodes a json value into a string
|
|
|
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
|
|
let mut shim = FormatShim { inner: f };
|
|
|
|
let mut encoder = Encoder::new(&mut shim);
|
2015-01-10 09:13:11 +00:00
|
|
|
match self.inner.encode(&mut encoder) {
|
|
|
|
Ok(_) => Ok(()),
|
|
|
|
Err(_) => Err(fmt::Error)
|
|
|
|
}
|
2014-12-12 18:59:41 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<'a, T> AsPrettyJson<'a, T> {
|
|
|
|
/// Set the indentation level for the emitted JSON
|
2015-03-26 00:06:52 +00:00
|
|
|
pub fn indent(mut self, indent: usize) -> AsPrettyJson<'a, T> {
|
2014-12-12 18:59:41 +00:00
|
|
|
self.indent = Some(indent);
|
|
|
|
self
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-01-20 23:45:07 +00:00
|
|
|
impl<'a, T: Encodable> fmt::Display for AsPrettyJson<'a, T> {
|
2014-12-12 18:59:41 +00:00
|
|
|
/// Encodes a json value into a string
|
|
|
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
|
|
let mut shim = FormatShim { inner: f };
|
|
|
|
let mut encoder = PrettyEncoder::new(&mut shim);
|
|
|
|
match self.indent {
|
|
|
|
Some(n) => encoder.set_indent(n),
|
|
|
|
None => {}
|
|
|
|
}
|
2015-01-10 09:13:11 +00:00
|
|
|
match self.inner.encode(&mut encoder) {
|
|
|
|
Ok(_) => Ok(()),
|
|
|
|
Err(_) => Err(fmt::Error)
|
|
|
|
}
|
2013-08-22 05:32:18 +00:00
|
|
|
}
|
2012-05-28 19:10:32 +00:00
|
|
|
}
|
|
|
|
|
2014-11-15 04:52:00 +00:00
|
|
|
impl FromStr for Json {
|
2015-01-28 06:52:32 +00:00
|
|
|
type Err = BuilderError;
|
|
|
|
fn from_str(s: &str) -> Result<Json, BuilderError> {
|
|
|
|
from_str(s)
|
2014-06-28 13:39:49 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-01-18 03:05:07 +00:00
|
|
|
#[cfg(test)]
|
|
|
|
mod tests {
|
2014-03-30 12:58:02 +00:00
|
|
|
extern crate test;
|
2014-11-06 08:05:53 +00:00
|
|
|
use self::Animal::*;
|
2014-03-30 12:58:02 +00:00
|
|
|
use self::test::Bencher;
|
2014-02-21 22:18:39 +00:00
|
|
|
use {Encodable, Decodable};
|
2014-11-22 18:48:01 +00:00
|
|
|
use super::Json::*;
|
|
|
|
use super::ErrorCode::*;
|
|
|
|
use super::ParserError::*;
|
|
|
|
use super::DecoderError::*;
|
|
|
|
use super::JsonEvent::*;
|
2014-12-12 18:59:41 +00:00
|
|
|
use super::{Json, from_str, DecodeResult, DecoderError, JsonEvent, Parser,
|
2015-01-10 09:14:38 +00:00
|
|
|
StackElement, Stack, Decoder, Encoder, EncoderError};
|
2015-01-27 03:56:50 +00:00
|
|
|
use std::{i64, u64, f32, f64};
|
2015-04-10 18:39:53 +00:00
|
|
|
use std::io::prelude::*;
|
2014-12-17 04:09:16 +00:00
|
|
|
use std::collections::BTreeMap;
|
2014-09-11 05:07:49 +00:00
|
|
|
use std::string;
|
2013-03-27 07:13:01 +00:00
|
|
|
|
2015-01-28 13:34:18 +00:00
|
|
|
#[derive(RustcDecodable, Eq, PartialEq, Debug)]
|
2014-09-09 05:28:59 +00:00
|
|
|
struct OptionData {
|
2015-03-26 00:06:52 +00:00
|
|
|
opt: Option<usize>,
|
2014-09-09 05:28:59 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_decode_option_none() {
|
|
|
|
let s ="{}";
|
|
|
|
let obj: OptionData = super::decode(s).unwrap();
|
|
|
|
assert_eq!(obj, OptionData { opt: None });
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_decode_option_some() {
|
|
|
|
let s = "{ \"opt\": 10 }";
|
|
|
|
let obj: OptionData = super::decode(s).unwrap();
|
2015-01-24 14:39:32 +00:00
|
|
|
assert_eq!(obj, OptionData { opt: Some(10) });
|
2014-09-09 05:28:59 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_decode_option_malformed() {
|
|
|
|
check_err::<OptionData>("{ \"opt\": [] }",
|
2014-12-11 03:46:38 +00:00
|
|
|
ExpectedError("Number".to_string(), "[]".to_string()));
|
2014-09-09 05:28:59 +00:00
|
|
|
check_err::<OptionData>("{ \"opt\": false }",
|
2014-12-11 03:46:38 +00:00
|
|
|
ExpectedError("Number".to_string(), "false".to_string()));
|
2014-09-09 05:28:59 +00:00
|
|
|
}
|
|
|
|
|
2015-01-28 13:34:18 +00:00
|
|
|
#[derive(PartialEq, RustcEncodable, RustcDecodable, Debug)]
|
2013-03-30 18:08:57 +00:00
|
|
|
enum Animal {
|
|
|
|
Dog,
|
2015-03-26 00:06:52 +00:00
|
|
|
Frog(string::String, isize)
|
2013-03-30 18:08:57 +00:00
|
|
|
}
|
|
|
|
|
2015-01-28 13:34:18 +00:00
|
|
|
#[derive(PartialEq, RustcEncodable, RustcDecodable, Debug)]
|
2013-03-30 20:31:03 +00:00
|
|
|
struct Inner {
|
|
|
|
a: (),
|
2015-03-26 00:06:52 +00:00
|
|
|
b: usize,
|
2014-09-11 05:07:49 +00:00
|
|
|
c: Vec<string::String>,
|
2013-03-30 20:31:03 +00:00
|
|
|
}
|
|
|
|
|
2015-01-28 13:34:18 +00:00
|
|
|
#[derive(PartialEq, RustcEncodable, RustcDecodable, Debug)]
|
2013-03-30 20:31:03 +00:00
|
|
|
struct Outer {
|
2014-05-04 06:34:26 +00:00
|
|
|
inner: Vec<Inner>,
|
2013-03-30 20:31:03 +00:00
|
|
|
}
|
|
|
|
|
2014-09-11 05:07:49 +00:00
|
|
|
fn mk_object(items: &[(string::String, Json)]) -> Json {
|
2014-12-17 04:09:16 +00:00
|
|
|
let mut d = BTreeMap::new();
|
2012-02-26 00:39:32 +00:00
|
|
|
|
2015-01-31 17:20:46 +00:00
|
|
|
for item in items {
|
2012-09-24 16:55:42 +00:00
|
|
|
match *item {
|
2013-07-02 19:47:32 +00:00
|
|
|
(ref key, ref value) => { d.insert((*key).clone(), (*value).clone()); },
|
2012-09-24 16:55:42 +00:00
|
|
|
}
|
2012-02-26 00:39:32 +00:00
|
|
|
};
|
|
|
|
|
2013-02-15 07:30:30 +00:00
|
|
|
Object(d)
|
2012-02-26 00:39:32 +00:00
|
|
|
}
|
|
|
|
|
2014-06-28 13:39:49 +00:00
|
|
|
#[test]
|
|
|
|
fn test_from_str_trait() {
|
|
|
|
let s = "null";
|
2014-12-28 18:51:00 +00:00
|
|
|
assert!(s.parse::<Json>().unwrap() == s.parse().unwrap());
|
2014-06-28 13:39:49 +00:00
|
|
|
}
|
|
|
|
|
2012-02-26 00:39:32 +00:00
|
|
|
#[test]
|
|
|
|
fn test_write_null() {
|
2014-11-23 18:32:31 +00:00
|
|
|
assert_eq!(Null.to_string(), "null");
|
2014-12-12 18:59:41 +00:00
|
|
|
assert_eq!(Null.pretty().to_string(), "null");
|
2012-02-26 00:39:32 +00:00
|
|
|
}
|
|
|
|
|
2014-08-02 16:54:40 +00:00
|
|
|
#[test]
|
|
|
|
fn test_write_i64() {
|
2014-11-23 18:32:31 +00:00
|
|
|
assert_eq!(U64(0).to_string(), "0");
|
2014-12-12 18:59:41 +00:00
|
|
|
assert_eq!(U64(0).pretty().to_string(), "0");
|
2014-08-02 16:54:40 +00:00
|
|
|
|
2014-11-23 18:32:31 +00:00
|
|
|
assert_eq!(U64(1234).to_string(), "1234");
|
2014-12-12 18:59:41 +00:00
|
|
|
assert_eq!(U64(1234).pretty().to_string(), "1234");
|
2014-08-02 16:54:40 +00:00
|
|
|
|
2014-11-23 18:32:31 +00:00
|
|
|
assert_eq!(I64(-5678).to_string(), "-5678");
|
2014-12-12 18:59:41 +00:00
|
|
|
assert_eq!(I64(-5678).pretty().to_string(), "-5678");
|
2014-11-23 17:22:30 +00:00
|
|
|
|
|
|
|
assert_eq!(U64(7650007200025252000).to_string(), "7650007200025252000");
|
2014-12-12 18:59:41 +00:00
|
|
|
assert_eq!(U64(7650007200025252000).pretty().to_string(), "7650007200025252000");
|
2014-08-02 16:54:40 +00:00
|
|
|
}
|
2013-03-30 18:08:57 +00:00
|
|
|
|
2012-02-26 00:39:32 +00:00
|
|
|
#[test]
|
2014-08-02 16:54:40 +00:00
|
|
|
fn test_write_f64() {
|
2014-11-23 18:32:31 +00:00
|
|
|
assert_eq!(F64(3.0).to_string(), "3.0");
|
2014-12-12 18:59:41 +00:00
|
|
|
assert_eq!(F64(3.0).pretty().to_string(), "3.0");
|
2013-03-30 18:08:57 +00:00
|
|
|
|
2014-11-23 18:32:31 +00:00
|
|
|
assert_eq!(F64(3.1).to_string(), "3.1");
|
2014-12-12 18:59:41 +00:00
|
|
|
assert_eq!(F64(3.1).pretty().to_string(), "3.1");
|
2013-03-30 18:08:57 +00:00
|
|
|
|
2014-11-23 18:32:31 +00:00
|
|
|
assert_eq!(F64(-1.5).to_string(), "-1.5");
|
2014-12-12 18:59:41 +00:00
|
|
|
assert_eq!(F64(-1.5).pretty().to_string(), "-1.5");
|
2013-03-30 18:08:57 +00:00
|
|
|
|
2014-11-23 18:32:31 +00:00
|
|
|
assert_eq!(F64(0.5).to_string(), "0.5");
|
2014-12-12 18:59:41 +00:00
|
|
|
assert_eq!(F64(0.5).pretty().to_string(), "0.5");
|
2014-06-26 01:26:41 +00:00
|
|
|
|
2014-11-23 18:32:31 +00:00
|
|
|
assert_eq!(F64(f64::NAN).to_string(), "null");
|
2014-12-12 18:59:41 +00:00
|
|
|
assert_eq!(F64(f64::NAN).pretty().to_string(), "null");
|
2014-06-26 01:26:41 +00:00
|
|
|
|
2014-11-23 18:32:31 +00:00
|
|
|
assert_eq!(F64(f64::INFINITY).to_string(), "null");
|
2014-12-12 18:59:41 +00:00
|
|
|
assert_eq!(F64(f64::INFINITY).pretty().to_string(), "null");
|
2014-06-26 01:26:41 +00:00
|
|
|
|
2014-11-23 18:32:31 +00:00
|
|
|
assert_eq!(F64(f64::NEG_INFINITY).to_string(), "null");
|
2014-12-12 18:59:41 +00:00
|
|
|
assert_eq!(F64(f64::NEG_INFINITY).pretty().to_string(), "null");
|
2012-02-26 00:39:32 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_write_str() {
|
2014-12-11 03:46:38 +00:00
|
|
|
assert_eq!(String("".to_string()).to_string(), "\"\"");
|
2014-12-12 18:59:41 +00:00
|
|
|
assert_eq!(String("".to_string()).pretty().to_string(), "\"\"");
|
2013-03-30 18:08:57 +00:00
|
|
|
|
2014-12-11 03:46:38 +00:00
|
|
|
assert_eq!(String("homura".to_string()).to_string(), "\"homura\"");
|
2014-12-12 18:59:41 +00:00
|
|
|
assert_eq!(String("madoka".to_string()).pretty().to_string(), "\"madoka\"");
|
2012-02-26 00:39:32 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_write_bool() {
|
2014-11-23 18:32:31 +00:00
|
|
|
assert_eq!(Boolean(true).to_string(), "true");
|
2014-12-12 18:59:41 +00:00
|
|
|
assert_eq!(Boolean(true).pretty().to_string(), "true");
|
2013-03-30 18:08:57 +00:00
|
|
|
|
2014-11-23 18:32:31 +00:00
|
|
|
assert_eq!(Boolean(false).to_string(), "false");
|
2014-12-12 18:59:41 +00:00
|
|
|
assert_eq!(Boolean(false).pretty().to_string(), "false");
|
2012-02-26 00:39:32 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
2014-11-19 18:19:43 +00:00
|
|
|
fn test_write_array() {
|
2014-11-23 18:32:31 +00:00
|
|
|
assert_eq!(Array(vec![]).to_string(), "[]");
|
2014-12-12 18:59:41 +00:00
|
|
|
assert_eq!(Array(vec![]).pretty().to_string(), "[]");
|
2013-03-30 18:08:57 +00:00
|
|
|
|
2014-11-23 18:32:31 +00:00
|
|
|
assert_eq!(Array(vec![Boolean(true)]).to_string(), "[true]");
|
2013-03-27 00:34:49 +00:00
|
|
|
assert_eq!(
|
2014-12-12 18:59:41 +00:00
|
|
|
Array(vec![Boolean(true)]).pretty().to_string(),
|
2014-04-16 01:17:48 +00:00
|
|
|
"\
|
2013-03-27 00:34:49 +00:00
|
|
|
[\n \
|
|
|
|
true\n\
|
2014-11-28 00:36:41 +00:00
|
|
|
]"
|
2013-03-27 00:34:49 +00:00
|
|
|
);
|
2013-03-30 18:08:57 +00:00
|
|
|
|
2014-11-19 18:19:43 +00:00
|
|
|
let long_test_array = Array(vec![
|
2013-03-30 18:08:57 +00:00
|
|
|
Boolean(false),
|
|
|
|
Null,
|
2014-12-11 03:46:38 +00:00
|
|
|
Array(vec![String("foo\nbar".to_string()), F64(3.5)])]);
|
2013-08-22 05:32:18 +00:00
|
|
|
|
2014-11-23 18:32:31 +00:00
|
|
|
assert_eq!(long_test_array.to_string(),
|
2014-11-28 00:36:41 +00:00
|
|
|
"[false,null,[\"foo\\nbar\",3.5]]");
|
2013-03-27 00:34:49 +00:00
|
|
|
assert_eq!(
|
2014-12-12 18:59:41 +00:00
|
|
|
long_test_array.pretty().to_string(),
|
2014-04-16 01:17:48 +00:00
|
|
|
"\
|
2013-03-27 00:34:49 +00:00
|
|
|
[\n \
|
|
|
|
false,\n \
|
|
|
|
null,\n \
|
|
|
|
[\n \
|
|
|
|
\"foo\\nbar\",\n \
|
|
|
|
3.5\n \
|
|
|
|
]\n\
|
2014-11-28 00:36:41 +00:00
|
|
|
]"
|
2013-03-27 00:34:49 +00:00
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2012-02-26 00:39:32 +00:00
|
|
|
#[test]
|
2012-09-24 16:55:42 +00:00
|
|
|
fn test_write_object() {
|
2014-11-23 18:32:31 +00:00
|
|
|
assert_eq!(mk_object(&[]).to_string(), "{}");
|
2014-12-12 18:59:41 +00:00
|
|
|
assert_eq!(mk_object(&[]).pretty().to_string(), "{}");
|
2013-03-30 18:08:57 +00:00
|
|
|
|
2013-03-27 00:23:00 +00:00
|
|
|
assert_eq!(
|
2014-11-17 08:39:01 +00:00
|
|
|
mk_object(&[
|
2014-12-11 03:46:38 +00:00
|
|
|
("a".to_string(), Boolean(true))
|
2014-11-23 18:32:31 +00:00
|
|
|
]).to_string(),
|
2014-11-28 00:36:41 +00:00
|
|
|
"{\"a\":true}"
|
2013-03-27 00:23:00 +00:00
|
|
|
);
|
2013-03-30 18:08:57 +00:00
|
|
|
assert_eq!(
|
2014-12-12 18:59:41 +00:00
|
|
|
mk_object(&[("a".to_string(), Boolean(true))]).pretty().to_string(),
|
2014-04-16 01:17:48 +00:00
|
|
|
"\
|
2013-03-30 18:08:57 +00:00
|
|
|
{\n \
|
|
|
|
\"a\": true\n\
|
2014-11-28 00:36:41 +00:00
|
|
|
}"
|
2013-03-30 18:08:57 +00:00
|
|
|
);
|
|
|
|
|
2014-11-17 08:39:01 +00:00
|
|
|
let complex_obj = mk_object(&[
|
2014-12-11 03:46:38 +00:00
|
|
|
("b".to_string(), Array(vec![
|
|
|
|
mk_object(&[("c".to_string(), String("\x0c\r".to_string()))]),
|
|
|
|
mk_object(&[("d".to_string(), String("".to_string()))])
|
2013-03-27 00:34:49 +00:00
|
|
|
]))
|
2013-08-22 05:32:18 +00:00
|
|
|
]);
|
|
|
|
|
|
|
|
assert_eq!(
|
2014-11-23 18:32:31 +00:00
|
|
|
complex_obj.to_string(),
|
2014-04-16 01:17:48 +00:00
|
|
|
"{\
|
2013-03-27 00:34:49 +00:00
|
|
|
\"b\":[\
|
|
|
|
{\"c\":\"\\f\\r\"},\
|
|
|
|
{\"d\":\"\"}\
|
|
|
|
]\
|
2014-11-28 00:36:41 +00:00
|
|
|
}"
|
2013-03-27 00:34:49 +00:00
|
|
|
);
|
|
|
|
assert_eq!(
|
2014-12-12 18:59:41 +00:00
|
|
|
complex_obj.pretty().to_string(),
|
2014-04-16 01:17:48 +00:00
|
|
|
"\
|
2013-03-27 00:34:49 +00:00
|
|
|
{\n \
|
|
|
|
\"b\": [\n \
|
|
|
|
{\n \
|
|
|
|
\"c\": \"\\f\\r\"\n \
|
|
|
|
},\n \
|
|
|
|
{\n \
|
|
|
|
\"d\": \"\"\n \
|
|
|
|
}\n \
|
|
|
|
]\n\
|
2014-11-28 00:36:41 +00:00
|
|
|
}"
|
2013-03-27 00:34:49 +00:00
|
|
|
);
|
2013-03-30 18:08:57 +00:00
|
|
|
|
2014-11-17 08:39:01 +00:00
|
|
|
let a = mk_object(&[
|
2014-12-11 03:46:38 +00:00
|
|
|
("a".to_string(), Boolean(true)),
|
|
|
|
("b".to_string(), Array(vec![
|
|
|
|
mk_object(&[("c".to_string(), String("\x0c\r".to_string()))]),
|
|
|
|
mk_object(&[("d".to_string(), String("".to_string()))])
|
2012-06-29 23:26:56 +00:00
|
|
|
]))
|
2012-08-30 23:27:15 +00:00
|
|
|
]);
|
2013-03-30 18:08:57 +00:00
|
|
|
|
2012-09-24 16:55:42 +00:00
|
|
|
// We can't compare the strings directly because the object fields be
|
|
|
|
// printed in a different order.
|
2014-12-12 18:59:41 +00:00
|
|
|
assert_eq!(a.clone(), a.to_string().parse().unwrap());
|
|
|
|
assert_eq!(a.clone(), a.pretty().to_string().parse().unwrap());
|
2013-10-14 01:48:47 +00:00
|
|
|
}
|
|
|
|
|
2013-03-27 00:34:49 +00:00
|
|
|
#[test]
|
2013-03-30 18:08:57 +00:00
|
|
|
fn test_write_enum() {
|
2013-03-27 00:34:49 +00:00
|
|
|
let animal = Dog;
|
2013-03-30 18:08:57 +00:00
|
|
|
assert_eq!(
|
2014-12-12 18:59:41 +00:00
|
|
|
format!("{}", super::as_json(&animal)),
|
2014-11-28 00:36:41 +00:00
|
|
|
"\"Dog\""
|
2013-03-30 18:08:57 +00:00
|
|
|
);
|
|
|
|
assert_eq!(
|
2014-12-12 18:59:41 +00:00
|
|
|
format!("{}", super::as_pretty_json(&animal)),
|
2014-11-28 00:36:41 +00:00
|
|
|
"\"Dog\""
|
2013-03-30 18:08:57 +00:00
|
|
|
);
|
2013-03-27 00:34:49 +00:00
|
|
|
|
2014-12-11 03:46:38 +00:00
|
|
|
let animal = Frog("Henry".to_string(), 349);
|
2013-03-27 00:34:49 +00:00
|
|
|
assert_eq!(
|
2014-12-12 18:59:41 +00:00
|
|
|
format!("{}", super::as_json(&animal)),
|
2014-11-28 00:36:41 +00:00
|
|
|
"{\"variant\":\"Frog\",\"fields\":[\"Henry\",349]}"
|
2013-03-30 18:08:57 +00:00
|
|
|
);
|
|
|
|
assert_eq!(
|
2014-12-12 18:59:41 +00:00
|
|
|
format!("{}", super::as_pretty_json(&animal)),
|
2014-09-29 03:24:35 +00:00
|
|
|
"{\n \
|
|
|
|
\"variant\": \"Frog\",\n \
|
|
|
|
\"fields\": [\n \
|
|
|
|
\"Henry\",\n \
|
|
|
|
349\n \
|
|
|
|
]\n\
|
2014-11-28 00:36:41 +00:00
|
|
|
}"
|
2013-03-27 00:34:49 +00:00
|
|
|
);
|
2013-02-08 23:36:40 +00:00
|
|
|
}
|
|
|
|
|
2014-11-14 17:18:10 +00:00
|
|
|
macro_rules! check_encoder_for_simple {
|
2014-12-12 02:34:01 +00:00
|
|
|
($value:expr, $expected:expr) => ({
|
2014-12-12 18:59:41 +00:00
|
|
|
let s = format!("{}", super::as_json(&$value));
|
2014-12-12 02:34:01 +00:00
|
|
|
assert_eq!(s, $expected);
|
|
|
|
|
2014-12-12 18:59:41 +00:00
|
|
|
let s = format!("{}", super::as_pretty_json(&$value));
|
2014-12-12 02:34:01 +00:00
|
|
|
assert_eq!(s, $expected);
|
|
|
|
})
|
2014-11-14 17:18:10 +00:00
|
|
|
}
|
2014-12-12 02:34:01 +00:00
|
|
|
|
2013-02-08 23:36:40 +00:00
|
|
|
#[test]
|
2013-03-27 00:23:00 +00:00
|
|
|
fn test_write_some() {
|
2014-12-12 02:34:01 +00:00
|
|
|
check_encoder_for_simple!(Some("jodhpurs".to_string()), "\"jodhpurs\"");
|
2013-03-27 00:34:49 +00:00
|
|
|
}
|
|
|
|
|
2013-02-08 23:36:40 +00:00
|
|
|
#[test]
|
2013-03-27 00:23:00 +00:00
|
|
|
fn test_write_none() {
|
2014-12-12 02:34:01 +00:00
|
|
|
check_encoder_for_simple!(None::<string::String>, "null");
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_write_char() {
|
|
|
|
check_encoder_for_simple!('a', "\"a\"");
|
|
|
|
check_encoder_for_simple!('\t', "\"\\t\"");
|
2014-12-20 23:04:39 +00:00
|
|
|
check_encoder_for_simple!('\u{0000}', "\"\\u0000\"");
|
|
|
|
check_encoder_for_simple!('\u{001b}', "\"\\u001b\"");
|
|
|
|
check_encoder_for_simple!('\u{007f}', "\"\\u007f\"");
|
2014-12-18 08:33:20 +00:00
|
|
|
check_encoder_for_simple!('\u{00a0}', "\"\u{00a0}\"");
|
|
|
|
check_encoder_for_simple!('\u{abcd}', "\"\u{abcd}\"");
|
|
|
|
check_encoder_for_simple!('\u{10ffff}', "\"\u{10ffff}\"");
|
2013-03-27 00:34:49 +00:00
|
|
|
}
|
|
|
|
|
2012-01-18 03:05:07 +00:00
|
|
|
#[test]
|
2012-02-26 00:39:32 +00:00
|
|
|
fn test_trailing_characters() {
|
2014-03-30 12:58:02 +00: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-26 00:39:32 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_read_identifiers() {
|
2014-03-30 12:58:02 +00: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-26 00:39:32 +00:00
|
|
|
|
2013-05-23 16:39:00 +00: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-18 03:05:07 +00:00
|
|
|
}
|
|
|
|
|
2013-03-30 20:31:03 +00:00
|
|
|
#[test]
|
|
|
|
fn test_decode_identifiers() {
|
2014-06-28 13:33:37 +00:00
|
|
|
let v: () = super::decode("null").unwrap();
|
2013-03-30 20:31:03 +00:00
|
|
|
assert_eq!(v, ());
|
|
|
|
|
2014-06-28 13:33:37 +00:00
|
|
|
let v: bool = super::decode("true").unwrap();
|
2013-03-30 20:31:03 +00:00
|
|
|
assert_eq!(v, true);
|
|
|
|
|
2014-06-28 13:33:37 +00:00
|
|
|
let v: bool = super::decode("false").unwrap();
|
2013-03-30 20:31:03 +00:00
|
|
|
assert_eq!(v, false);
|
|
|
|
}
|
|
|
|
|
2012-01-18 03:05:07 +00:00
|
|
|
#[test]
|
2012-09-24 16:55:42 +00:00
|
|
|
fn test_read_number() {
|
2014-03-30 12:58:02 +00:00
|
|
|
assert_eq!(from_str("+"), Err(SyntaxError(InvalidSyntax, 1, 1)));
|
|
|
|
assert_eq!(from_str("."), Err(SyntaxError(InvalidSyntax, 1, 1)));
|
2014-06-26 01:26:41 +00:00
|
|
|
assert_eq!(from_str("NaN"), Err(SyntaxError(InvalidSyntax, 1, 1)));
|
2014-03-30 12:58:02 +00: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 21:58:02 +00:00
|
|
|
|
2014-08-07 12:35:06 +00:00
|
|
|
assert_eq!(from_str("18446744073709551616"), Err(SyntaxError(InvalidNumber, 1, 20)));
|
|
|
|
assert_eq!(from_str("-9223372036854775809"), Err(SyntaxError(InvalidNumber, 1, 21)));
|
|
|
|
|
|
|
|
assert_eq!(from_str("3"), Ok(U64(3)));
|
|
|
|
assert_eq!(from_str("3.1"), Ok(F64(3.1)));
|
|
|
|
assert_eq!(from_str("-1.2"), Ok(F64(-1.2)));
|
|
|
|
assert_eq!(from_str("0.4"), Ok(F64(0.4)));
|
|
|
|
assert_eq!(from_str("0.4e5"), Ok(F64(0.4e5)));
|
|
|
|
assert_eq!(from_str("0.4e+15"), Ok(F64(0.4e15)));
|
|
|
|
assert_eq!(from_str("0.4e-01"), Ok(F64(0.4e-01)));
|
|
|
|
assert_eq!(from_str(" 3 "), Ok(U64(3)));
|
|
|
|
|
|
|
|
assert_eq!(from_str("-9223372036854775808"), Ok(I64(i64::MIN)));
|
|
|
|
assert_eq!(from_str("9223372036854775807"), Ok(U64(i64::MAX as u64)));
|
|
|
|
assert_eq!(from_str("18446744073709551615"), Ok(U64(u64::MAX)));
|
2012-01-18 03:05:07 +00:00
|
|
|
}
|
|
|
|
|
2013-03-30 20:31:03 +00:00
|
|
|
#[test]
|
|
|
|
fn test_decode_numbers() {
|
2014-06-28 13:33:37 +00:00
|
|
|
let v: f64 = super::decode("3").unwrap();
|
2013-09-26 06:26:09 +00:00
|
|
|
assert_eq!(v, 3.0);
|
2013-03-30 20:31:03 +00:00
|
|
|
|
2014-06-28 13:33:37 +00:00
|
|
|
let v: f64 = super::decode("3.1").unwrap();
|
2013-09-26 06:26:09 +00:00
|
|
|
assert_eq!(v, 3.1);
|
2013-03-30 20:31:03 +00:00
|
|
|
|
2014-06-28 13:33:37 +00:00
|
|
|
let v: f64 = super::decode("-1.2").unwrap();
|
2013-09-26 06:26:09 +00:00
|
|
|
assert_eq!(v, -1.2);
|
2013-03-30 20:31:03 +00:00
|
|
|
|
2014-06-28 13:33:37 +00:00
|
|
|
let v: f64 = super::decode("0.4").unwrap();
|
2013-09-26 06:26:09 +00:00
|
|
|
assert_eq!(v, 0.4);
|
2013-03-30 20:31:03 +00:00
|
|
|
|
2014-06-28 13:33:37 +00:00
|
|
|
let v: f64 = super::decode("0.4e5").unwrap();
|
2013-09-26 06:26:09 +00:00
|
|
|
assert_eq!(v, 0.4e5);
|
2013-03-30 20:31:03 +00:00
|
|
|
|
2014-06-28 13:33:37 +00:00
|
|
|
let v: f64 = super::decode("0.4e15").unwrap();
|
2013-09-26 06:26:09 +00:00
|
|
|
assert_eq!(v, 0.4e15);
|
2013-03-30 20:31:03 +00:00
|
|
|
|
2014-06-28 13:33:37 +00:00
|
|
|
let v: f64 = super::decode("0.4e-01").unwrap();
|
2013-09-26 06:26:09 +00:00
|
|
|
assert_eq!(v, 0.4e-01);
|
2014-08-07 12:35:06 +00:00
|
|
|
|
|
|
|
let v: u64 = super::decode("0").unwrap();
|
|
|
|
assert_eq!(v, 0);
|
|
|
|
|
|
|
|
let v: u64 = super::decode("18446744073709551615").unwrap();
|
|
|
|
assert_eq!(v, u64::MAX);
|
|
|
|
|
|
|
|
let v: i64 = super::decode("-9223372036854775808").unwrap();
|
|
|
|
assert_eq!(v, i64::MIN);
|
|
|
|
|
|
|
|
let v: i64 = super::decode("9223372036854775807").unwrap();
|
|
|
|
assert_eq!(v, i64::MAX);
|
2014-11-23 18:00:10 +00:00
|
|
|
|
2015-04-19 17:47:38 +00:00
|
|
|
let res: DecodeResult<i64> = super::decode("765.25");
|
2015-01-07 00:16:35 +00:00
|
|
|
assert_eq!(res, Err(ExpectedError("Integer".to_string(),
|
2015-04-19 17:47:38 +00:00
|
|
|
"765.25".to_string())));
|
2013-03-30 20:31:03 +00:00
|
|
|
}
|
|
|
|
|
2013-07-11 03:03:10 +00:00
|
|
|
#[test]
|
2012-02-26 00:39:32 +00:00
|
|
|
fn test_read_str() {
|
2014-03-30 12:58:02 +00:00
|
|
|
assert_eq!(from_str("\""), Err(SyntaxError(EOFWhileParsingString, 1, 2)));
|
|
|
|
assert_eq!(from_str("\"lol"), Err(SyntaxError(EOFWhileParsingString, 1, 5)));
|
|
|
|
|
2014-12-11 03:46:38 +00: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("\u{12ab}".to_string())));
|
|
|
|
assert_eq!(from_str("\"\\uAB12\""), Ok(String("\u{AB12}".to_string())));
|
2012-01-18 03:05:07 +00:00
|
|
|
}
|
|
|
|
|
2012-08-31 04:03:19 +00:00
|
|
|
#[test]
|
2013-03-30 20:31:03 +00:00
|
|
|
fn test_decode_str() {
|
2014-04-30 22:55:04 +00:00
|
|
|
let s = [("\"\"", ""),
|
|
|
|
("\"foo\"", "foo"),
|
|
|
|
("\"\\\"\"", "\""),
|
|
|
|
("\"\\b\"", "\x08"),
|
|
|
|
("\"\\n\"", "\n"),
|
|
|
|
("\"\\r\"", "\r"),
|
|
|
|
("\"\\t\"", "\t"),
|
2014-12-09 22:08:10 +00:00
|
|
|
("\"\\u12ab\"", "\u{12ab}"),
|
|
|
|
("\"\\uAB12\"", "\u{AB12}")];
|
2014-04-30 22:55:04 +00:00
|
|
|
|
2015-01-31 17:20:46 +00:00
|
|
|
for &(i, o) in &s {
|
2014-09-11 05:07:49 +00:00
|
|
|
let v: string::String = super::decode(i).unwrap();
|
2014-11-27 19:28:51 +00:00
|
|
|
assert_eq!(v, o);
|
2014-04-30 22:55:04 +00:00
|
|
|
}
|
2012-08-31 04:03:19 +00:00
|
|
|
}
|
|
|
|
|
2012-01-18 03:05:07 +00:00
|
|
|
#[test]
|
2014-11-19 18:19:43 +00:00
|
|
|
fn test_read_array() {
|
2014-03-30 12:58:02 +00:00
|
|
|
assert_eq!(from_str("["), Err(SyntaxError(EOFWhileParsingValue, 1, 2)));
|
2014-11-19 18:19:43 +00:00
|
|
|
assert_eq!(from_str("[1"), Err(SyntaxError(EOFWhileParsingArray, 1, 3)));
|
2014-03-30 12:58:02 +00:00
|
|
|
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 21:58:02 +00:00
|
|
|
|
2014-11-19 18:19:43 +00:00
|
|
|
assert_eq!(from_str("[]"), Ok(Array(vec![])));
|
|
|
|
assert_eq!(from_str("[ ]"), Ok(Array(vec![])));
|
|
|
|
assert_eq!(from_str("[true]"), Ok(Array(vec![Boolean(true)])));
|
|
|
|
assert_eq!(from_str("[ false ]"), Ok(Array(vec![Boolean(false)])));
|
|
|
|
assert_eq!(from_str("[null]"), Ok(Array(vec![Null])));
|
2013-05-23 16:39:00 +00:00
|
|
|
assert_eq!(from_str("[3, 1]"),
|
2014-11-19 18:19:43 +00:00
|
|
|
Ok(Array(vec![U64(3), U64(1)])));
|
2013-05-23 16:39:00 +00:00
|
|
|
assert_eq!(from_str("\n[3, 2]\n"),
|
2014-11-19 18:19:43 +00:00
|
|
|
Ok(Array(vec![U64(3), U64(2)])));
|
2013-05-23 16:39:00 +00:00
|
|
|
assert_eq!(from_str("[2, [4, 1]]"),
|
2014-11-19 18:19:43 +00:00
|
|
|
Ok(Array(vec![U64(2), Array(vec![U64(4), U64(1)])])));
|
2012-01-18 03:05:07 +00:00
|
|
|
}
|
|
|
|
|
2013-03-30 20:31:03 +00:00
|
|
|
#[test]
|
2014-11-19 18:19:43 +00:00
|
|
|
fn test_decode_array() {
|
2014-06-28 13:33:37 +00:00
|
|
|
let v: Vec<()> = super::decode("[]").unwrap();
|
2015-02-24 18:15:45 +00:00
|
|
|
assert_eq!(v, []);
|
2013-03-30 20:31:03 +00:00
|
|
|
|
2014-06-28 13:33:37 +00:00
|
|
|
let v: Vec<()> = super::decode("[null]").unwrap();
|
2015-02-24 18:15:45 +00:00
|
|
|
assert_eq!(v, [()]);
|
2013-03-30 20:31:03 +00:00
|
|
|
|
2014-06-28 13:33:37 +00:00
|
|
|
let v: Vec<bool> = super::decode("[true]").unwrap();
|
2015-02-24 18:15:45 +00:00
|
|
|
assert_eq!(v, [true]);
|
2013-03-30 20:31:03 +00:00
|
|
|
|
2015-03-26 00:06:52 +00:00
|
|
|
let v: Vec<isize> = super::decode("[3, 1]").unwrap();
|
2015-02-24 18:15:45 +00:00
|
|
|
assert_eq!(v, [3, 1]);
|
2013-03-30 20:31:03 +00:00
|
|
|
|
2015-03-26 00:06:52 +00:00
|
|
|
let v: Vec<Vec<usize>> = super::decode("[[3], [1, 2]]").unwrap();
|
2015-02-24 18:15:45 +00:00
|
|
|
assert_eq!(v, [vec![3], vec![1, 2]]);
|
2013-03-30 20:31:03 +00:00
|
|
|
}
|
|
|
|
|
libserialize: tuple-arity should be provided to `Decoder::read_tuple`
Currently `Decoder` implementations are not provided the tuple arity as
a parameter to `read_tuple`. This forces all encoder/decoder combos to
serialize the arity along with the elements. Tuple-arity is always known
statically at the decode site, because it is part of the type of the
tuple, so it could instead be provided as an argument to `read_tuple`,
as it is to `read_struct`.
The upside to this is that serialized tuples could become smaller in
encoder/decoder implementations which choose not to serialize type
(arity) information. For example, @TyOverby's
[binary-encode](https://github.com/TyOverby/binary-encode) format is
currently forced to serialize the tuple-arity along with every tuple,
despite the information being statically known at the decode site.
A downside to this change is that the tuple-arity of serialized tuples
can no longer be automatically checked during deserialization. However,
for formats which do serialize the tuple-arity, either explicitly (rbml)
or implicitly (json), this check can be added to the `read_tuple` method.
The signature of `Deserialize::read_tuple` and
`Deserialize::read_tuple_struct` are changed, and thus binary
backwards-compatibility is broken. This change does *not* force
serialization formats to change, and thus does not break decoding values
serialized prior to this change.
[breaking-change]
2014-09-27 21:19:19 +00:00
|
|
|
#[test]
|
|
|
|
fn test_decode_tuple() {
|
2015-03-26 00:06:52 +00:00
|
|
|
let t: (usize, usize, usize) = super::decode("[1, 2, 3]").unwrap();
|
2015-01-24 14:39:32 +00:00
|
|
|
assert_eq!(t, (1, 2, 3));
|
libserialize: tuple-arity should be provided to `Decoder::read_tuple`
Currently `Decoder` implementations are not provided the tuple arity as
a parameter to `read_tuple`. This forces all encoder/decoder combos to
serialize the arity along with the elements. Tuple-arity is always known
statically at the decode site, because it is part of the type of the
tuple, so it could instead be provided as an argument to `read_tuple`,
as it is to `read_struct`.
The upside to this is that serialized tuples could become smaller in
encoder/decoder implementations which choose not to serialize type
(arity) information. For example, @TyOverby's
[binary-encode](https://github.com/TyOverby/binary-encode) format is
currently forced to serialize the tuple-arity along with every tuple,
despite the information being statically known at the decode site.
A downside to this change is that the tuple-arity of serialized tuples
can no longer be automatically checked during deserialization. However,
for formats which do serialize the tuple-arity, either explicitly (rbml)
or implicitly (json), this check can be added to the `read_tuple` method.
The signature of `Deserialize::read_tuple` and
`Deserialize::read_tuple_struct` are changed, and thus binary
backwards-compatibility is broken. This change does *not* force
serialization formats to change, and thus does not break decoding values
serialized prior to this change.
[breaking-change]
2014-09-27 21:19:19 +00:00
|
|
|
|
2015-03-26 00:06:52 +00:00
|
|
|
let t: (usize, string::String) = super::decode("[1, \"two\"]").unwrap();
|
2015-01-24 14:39:32 +00:00
|
|
|
assert_eq!(t, (1, "two".to_string()));
|
libserialize: tuple-arity should be provided to `Decoder::read_tuple`
Currently `Decoder` implementations are not provided the tuple arity as
a parameter to `read_tuple`. This forces all encoder/decoder combos to
serialize the arity along with the elements. Tuple-arity is always known
statically at the decode site, because it is part of the type of the
tuple, so it could instead be provided as an argument to `read_tuple`,
as it is to `read_struct`.
The upside to this is that serialized tuples could become smaller in
encoder/decoder implementations which choose not to serialize type
(arity) information. For example, @TyOverby's
[binary-encode](https://github.com/TyOverby/binary-encode) format is
currently forced to serialize the tuple-arity along with every tuple,
despite the information being statically known at the decode site.
A downside to this change is that the tuple-arity of serialized tuples
can no longer be automatically checked during deserialization. However,
for formats which do serialize the tuple-arity, either explicitly (rbml)
or implicitly (json), this check can be added to the `read_tuple` method.
The signature of `Deserialize::read_tuple` and
`Deserialize::read_tuple_struct` are changed, and thus binary
backwards-compatibility is broken. This change does *not* force
serialization formats to change, and thus does not break decoding values
serialized prior to this change.
[breaking-change]
2014-09-27 21:19:19 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_decode_tuple_malformed_types() {
|
2015-03-26 00:06:52 +00:00
|
|
|
assert!(super::decode::<(usize, string::String)>("[1, 2]").is_err());
|
libserialize: tuple-arity should be provided to `Decoder::read_tuple`
Currently `Decoder` implementations are not provided the tuple arity as
a parameter to `read_tuple`. This forces all encoder/decoder combos to
serialize the arity along with the elements. Tuple-arity is always known
statically at the decode site, because it is part of the type of the
tuple, so it could instead be provided as an argument to `read_tuple`,
as it is to `read_struct`.
The upside to this is that serialized tuples could become smaller in
encoder/decoder implementations which choose not to serialize type
(arity) information. For example, @TyOverby's
[binary-encode](https://github.com/TyOverby/binary-encode) format is
currently forced to serialize the tuple-arity along with every tuple,
despite the information being statically known at the decode site.
A downside to this change is that the tuple-arity of serialized tuples
can no longer be automatically checked during deserialization. However,
for formats which do serialize the tuple-arity, either explicitly (rbml)
or implicitly (json), this check can be added to the `read_tuple` method.
The signature of `Deserialize::read_tuple` and
`Deserialize::read_tuple_struct` are changed, and thus binary
backwards-compatibility is broken. This change does *not* force
serialization formats to change, and thus does not break decoding values
serialized prior to this change.
[breaking-change]
2014-09-27 21:19:19 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_decode_tuple_malformed_length() {
|
2015-03-26 00:06:52 +00:00
|
|
|
assert!(super::decode::<(usize, usize)>("[1, 2, 3]").is_err());
|
libserialize: tuple-arity should be provided to `Decoder::read_tuple`
Currently `Decoder` implementations are not provided the tuple arity as
a parameter to `read_tuple`. This forces all encoder/decoder combos to
serialize the arity along with the elements. Tuple-arity is always known
statically at the decode site, because it is part of the type of the
tuple, so it could instead be provided as an argument to `read_tuple`,
as it is to `read_struct`.
The upside to this is that serialized tuples could become smaller in
encoder/decoder implementations which choose not to serialize type
(arity) information. For example, @TyOverby's
[binary-encode](https://github.com/TyOverby/binary-encode) format is
currently forced to serialize the tuple-arity along with every tuple,
despite the information being statically known at the decode site.
A downside to this change is that the tuple-arity of serialized tuples
can no longer be automatically checked during deserialization. However,
for formats which do serialize the tuple-arity, either explicitly (rbml)
or implicitly (json), this check can be added to the `read_tuple` method.
The signature of `Deserialize::read_tuple` and
`Deserialize::read_tuple_struct` are changed, and thus binary
backwards-compatibility is broken. This change does *not* force
serialization formats to change, and thus does not break decoding values
serialized prior to this change.
[breaking-change]
2014-09-27 21:19:19 +00:00
|
|
|
}
|
|
|
|
|
2012-01-18 03:05:07 +00:00
|
|
|
#[test]
|
2012-09-24 16:55:42 +00:00
|
|
|
fn test_read_object() {
|
2014-03-30 12:58:02 +00: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 21:58:02 +00:00
|
|
|
|
2014-11-17 08:39:01 +00:00
|
|
|
assert_eq!(from_str("{}").unwrap(), mk_object(&[]));
|
2013-07-27 01:36:51 +00:00
|
|
|
assert_eq!(from_str("{\"a\": 3}").unwrap(),
|
2014-12-11 03:46:38 +00:00
|
|
|
mk_object(&[("a".to_string(), U64(3))]));
|
2013-03-06 21:58:02 +00:00
|
|
|
|
2013-07-27 01:36:51 +00:00
|
|
|
assert_eq!(from_str(
|
|
|
|
"{ \"a\": null, \"b\" : true }").unwrap(),
|
2014-11-17 08:39:01 +00:00
|
|
|
mk_object(&[
|
2014-12-11 03:46:38 +00:00
|
|
|
("a".to_string(), Null),
|
|
|
|
("b".to_string(), Boolean(true))]));
|
2013-07-27 01:36:51 +00:00
|
|
|
assert_eq!(from_str("\n{ \"a\": null, \"b\" : true }\n").unwrap(),
|
2014-11-17 08:39:01 +00:00
|
|
|
mk_object(&[
|
2014-12-11 03:46:38 +00:00
|
|
|
("a".to_string(), Null),
|
|
|
|
("b".to_string(), Boolean(true))]));
|
2013-07-27 01:36:51 +00:00
|
|
|
assert_eq!(from_str(
|
|
|
|
"{\"a\" : 1.0 ,\"b\": [ true ]}").unwrap(),
|
2014-11-17 08:39:01 +00:00
|
|
|
mk_object(&[
|
2014-12-11 03:46:38 +00:00
|
|
|
("a".to_string(), F64(1.0)),
|
|
|
|
("b".to_string(), Array(vec![Boolean(true)]))
|
2013-03-06 21:58:02 +00:00
|
|
|
]));
|
2013-07-27 01:36:51 +00:00
|
|
|
assert_eq!(from_str(
|
2014-05-15 04:16:44 +00:00
|
|
|
"{\
|
|
|
|
\"a\": 1.0, \
|
|
|
|
\"b\": [\
|
|
|
|
true,\
|
|
|
|
\"foo\\nbar\", \
|
|
|
|
{ \"c\": {\"d\": null} } \
|
|
|
|
]\
|
|
|
|
}").unwrap(),
|
2014-11-17 08:39:01 +00:00
|
|
|
mk_object(&[
|
2014-12-11 03:46:38 +00:00
|
|
|
("a".to_string(), F64(1.0)),
|
|
|
|
("b".to_string(), Array(vec![
|
2012-08-11 14:08:42 +00:00
|
|
|
Boolean(true),
|
2014-12-11 03:46:38 +00:00
|
|
|
String("foo\nbar".to_string()),
|
2014-11-17 08:39:01 +00:00
|
|
|
mk_object(&[
|
2014-12-11 03:46:38 +00:00
|
|
|
("c".to_string(), mk_object(&[("d".to_string(), Null)]))
|
2012-06-29 23:26:56 +00:00
|
|
|
])
|
|
|
|
]))
|
2013-03-06 21:58:02 +00:00
|
|
|
]));
|
2012-01-18 03:05:07 +00:00
|
|
|
}
|
|
|
|
|
2013-03-27 07:13:01 +00:00
|
|
|
#[test]
|
2013-03-30 20:31:03 +00:00
|
|
|
fn test_decode_struct() {
|
2014-04-16 01:17:48 +00:00
|
|
|
let s = "{
|
2013-03-30 20:31:03 +00:00
|
|
|
\"inner\": [
|
|
|
|
{ \"a\": null, \"b\": 2, \"c\": [\"abc\", \"xyz\"] }
|
|
|
|
]
|
2014-05-15 04:16:44 +00:00
|
|
|
}";
|
2014-06-28 13:33:37 +00:00
|
|
|
|
|
|
|
let v: Outer = super::decode(s).unwrap();
|
2013-03-30 20:31:03 +00:00
|
|
|
assert_eq!(
|
|
|
|
v,
|
|
|
|
Outer {
|
2014-05-04 06:34:26 +00:00
|
|
|
inner: vec![
|
2014-12-11 03:46:38 +00:00
|
|
|
Inner { a: (), b: 2, c: vec!["abc".to_string(), "xyz".to_string()] }
|
2013-03-30 20:31:03 +00:00
|
|
|
]
|
|
|
|
}
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2015-01-04 03:54:18 +00:00
|
|
|
#[derive(RustcDecodable)]
|
2014-06-26 01:26:41 +00:00
|
|
|
struct FloatStruct {
|
|
|
|
f: f64,
|
|
|
|
a: Vec<f64>
|
|
|
|
}
|
|
|
|
#[test]
|
|
|
|
fn test_decode_struct_with_nan() {
|
2014-06-28 13:33:37 +00:00
|
|
|
let s = "{\"f\":null,\"a\":[null,123]}";
|
|
|
|
let obj: FloatStruct = super::decode(s).unwrap();
|
|
|
|
assert!(obj.f.is_nan());
|
2014-10-05 10:11:17 +00:00
|
|
|
assert!(obj.a[0].is_nan());
|
|
|
|
assert_eq!(obj.a[1], 123f64);
|
2014-06-26 01:26:41 +00:00
|
|
|
}
|
|
|
|
|
2013-03-30 20:31:03 +00:00
|
|
|
#[test]
|
|
|
|
fn test_decode_option() {
|
2014-09-11 05:07:49 +00:00
|
|
|
let value: Option<string::String> = super::decode("null").unwrap();
|
2013-03-27 07:13:01 +00:00
|
|
|
assert_eq!(value, None);
|
|
|
|
|
2014-09-11 05:07:49 +00:00
|
|
|
let value: Option<string::String> = super::decode("\"jodhpurs\"").unwrap();
|
2014-12-11 03:46:38 +00:00
|
|
|
assert_eq!(value, Some("jodhpurs".to_string()));
|
2013-03-27 07:13:01 +00:00
|
|
|
}
|
|
|
|
|
2013-03-27 00:42:01 +00:00
|
|
|
#[test]
|
2013-03-30 20:31:03 +00:00
|
|
|
fn test_decode_enum() {
|
2014-06-28 13:33:37 +00:00
|
|
|
let value: Animal = super::decode("\"Dog\"").unwrap();
|
2013-03-27 00:42:01 +00:00
|
|
|
assert_eq!(value, Dog);
|
|
|
|
|
2013-11-29 19:11:52 +00:00
|
|
|
let s = "{\"variant\":\"Frog\",\"fields\":[\"Henry\",349]}";
|
2014-06-28 13:33:37 +00:00
|
|
|
let value: Animal = super::decode(s).unwrap();
|
2014-12-11 03:46:38 +00:00
|
|
|
assert_eq!(value, Frog("Henry".to_string(), 349));
|
2013-03-27 00:42:01 +00:00
|
|
|
}
|
|
|
|
|
2013-03-29 16:04:35 +00:00
|
|
|
#[test]
|
2013-03-30 20:31:03 +00:00
|
|
|
fn test_decode_map() {
|
2014-04-16 01:17:48 +00:00
|
|
|
let s = "{\"a\": \"Dog\", \"b\": {\"variant\":\"Frog\",\
|
2014-05-15 04:16:44 +00:00
|
|
|
\"fields\":[\"Henry\", 349]}}";
|
2014-12-17 04:09:16 +00:00
|
|
|
let mut map: BTreeMap<string::String, Animal> = super::decode(s).unwrap();
|
2013-03-29 16:04:35 +00:00
|
|
|
|
2014-12-11 03:46:38 +00:00
|
|
|
assert_eq!(map.remove(&"a".to_string()), Some(Dog));
|
|
|
|
assert_eq!(map.remove(&"b".to_string()), Some(Frog("Henry".to_string(), 349)));
|
2013-03-29 16:04:35 +00:00
|
|
|
}
|
|
|
|
|
2012-01-18 03:05:07 +00:00
|
|
|
#[test]
|
2012-02-26 00:39:32 +00:00
|
|
|
fn test_multiline_errors() {
|
2013-05-23 16:39:00 +00:00
|
|
|
assert_eq!(from_str("{\n \"foo\":\n \"bar\""),
|
2015-01-24 14:39:32 +00:00
|
|
|
Err(SyntaxError(EOFWhileParsingObject, 3, 8)));
|
2012-01-18 03:05:07 +00:00
|
|
|
}
|
2013-11-23 23:17:34 +00:00
|
|
|
|
2015-01-04 03:54:18 +00:00
|
|
|
#[derive(RustcDecodable)]
|
2014-06-26 01:26:41 +00:00
|
|
|
#[allow(dead_code)]
|
2013-11-23 23:17:34 +00:00
|
|
|
struct DecodeStruct {
|
|
|
|
x: f64,
|
|
|
|
y: bool,
|
2014-09-11 05:07:49 +00:00
|
|
|
z: string::String,
|
2014-05-04 06:34:26 +00:00
|
|
|
w: Vec<DecodeStruct>
|
2013-11-23 23:17:34 +00:00
|
|
|
}
|
2015-01-04 03:54:18 +00:00
|
|
|
#[derive(RustcDecodable)]
|
2013-11-23 23:17:34 +00:00
|
|
|
enum DecodeEnum {
|
|
|
|
A(f64),
|
2014-09-11 05:07:49 +00:00
|
|
|
B(string::String)
|
2013-11-23 23:17:34 +00:00
|
|
|
}
|
2015-01-04 06:24:50 +00:00
|
|
|
fn check_err<T: Decodable>(to_parse: &'static str, expected: DecoderError) {
|
2014-03-18 17:58:26 +00:00
|
|
|
let res: DecodeResult<T> = match from_str(to_parse) {
|
2014-03-30 12:58:02 +00:00
|
|
|
Err(e) => Err(ParseError(e)),
|
2014-03-18 17:58:26 +00:00
|
|
|
Ok(json) => Decodable::decode(&mut Decoder::new(json))
|
|
|
|
};
|
2013-11-23 23:17:34 +00:00
|
|
|
match res {
|
2014-12-20 08:09:35 +00:00
|
|
|
Ok(_) => panic!("`{:?}` parsed & decoded ok, expecting error `{:?}`",
|
2014-03-18 17:58:26 +00:00
|
|
|
to_parse, expected),
|
2014-12-20 08:09:35 +00:00
|
|
|
Err(ParseError(e)) => panic!("`{:?}` is not valid json: {:?}",
|
2014-03-18 17:58:26 +00:00
|
|
|
to_parse, e),
|
2013-11-23 23:17:34 +00:00
|
|
|
Err(e) => {
|
2014-03-18 17:58:26 +00:00
|
|
|
assert_eq!(e, expected);
|
2013-11-23 23:17:34 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#[test]
|
|
|
|
fn test_decode_errors_struct() {
|
2014-12-11 03:46:38 +00:00
|
|
|
check_err::<DecodeStruct>("[]", ExpectedError("Object".to_string(), "[]".to_string()));
|
2013-11-23 23:17:34 +00:00
|
|
|
check_err::<DecodeStruct>("{\"x\": true, \"y\": true, \"z\": \"\", \"w\": []}",
|
2014-12-11 03:46:38 +00:00
|
|
|
ExpectedError("Number".to_string(), "true".to_string()));
|
2013-11-23 23:17:34 +00:00
|
|
|
check_err::<DecodeStruct>("{\"x\": 1, \"y\": [], \"z\": \"\", \"w\": []}",
|
2014-12-11 03:46:38 +00:00
|
|
|
ExpectedError("Boolean".to_string(), "[]".to_string()));
|
2013-11-23 23:17:34 +00:00
|
|
|
check_err::<DecodeStruct>("{\"x\": 1, \"y\": true, \"z\": {}, \"w\": []}",
|
2014-12-11 03:46:38 +00:00
|
|
|
ExpectedError("String".to_string(), "{}".to_string()));
|
2013-11-23 23:17:34 +00:00
|
|
|
check_err::<DecodeStruct>("{\"x\": 1, \"y\": true, \"z\": \"\", \"w\": null}",
|
2014-12-11 03:46:38 +00:00
|
|
|
ExpectedError("Array".to_string(), "null".to_string()));
|
2013-11-23 23:17:34 +00:00
|
|
|
check_err::<DecodeStruct>("{\"x\": 1, \"y\": true, \"z\": \"\"}",
|
2014-12-11 03:46:38 +00:00
|
|
|
MissingFieldError("w".to_string()));
|
2013-11-23 23:17:34 +00:00
|
|
|
}
|
|
|
|
#[test]
|
|
|
|
fn test_decode_errors_enum() {
|
|
|
|
check_err::<DecodeEnum>("{}",
|
2014-12-11 03:46:38 +00:00
|
|
|
MissingFieldError("variant".to_string()));
|
2013-11-23 23:17:34 +00:00
|
|
|
check_err::<DecodeEnum>("{\"variant\": 1}",
|
2014-12-11 03:46:38 +00:00
|
|
|
ExpectedError("String".to_string(), "1".to_string()));
|
2013-11-23 23:17:34 +00:00
|
|
|
check_err::<DecodeEnum>("{\"variant\": \"A\"}",
|
2014-12-11 03:46:38 +00:00
|
|
|
MissingFieldError("fields".to_string()));
|
2013-11-23 23:17:34 +00:00
|
|
|
check_err::<DecodeEnum>("{\"variant\": \"A\", \"fields\": null}",
|
2014-12-11 03:46:38 +00:00
|
|
|
ExpectedError("Array".to_string(), "null".to_string()));
|
2013-11-23 23:17:34 +00:00
|
|
|
check_err::<DecodeEnum>("{\"variant\": \"C\", \"fields\": []}",
|
2014-12-11 03:46:38 +00:00
|
|
|
UnknownVariantError("C".to_string()));
|
2013-11-23 23:17:34 +00:00
|
|
|
}
|
2014-03-09 06:30:27 +00:00
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_find(){
|
|
|
|
let json_value = from_str("{\"dog\" : \"cat\"}").unwrap();
|
2014-11-02 13:27:15 +00:00
|
|
|
let found_str = json_value.find("dog");
|
|
|
|
assert!(found_str.unwrap().as_string().unwrap() == "cat");
|
2014-03-09 06:30:27 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_find_path(){
|
|
|
|
let json_value = from_str("{\"dog\":{\"cat\": {\"mouse\" : \"cheese\"}}}").unwrap();
|
2014-11-02 13:27:15 +00:00
|
|
|
let found_str = json_value.find_path(&["dog", "cat", "mouse"]);
|
|
|
|
assert!(found_str.unwrap().as_string().unwrap() == "cheese");
|
2014-03-09 06:30:27 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_search(){
|
|
|
|
let json_value = from_str("{\"dog\":{\"cat\": {\"mouse\" : \"cheese\"}}}").unwrap();
|
2014-11-02 13:27:15 +00:00
|
|
|
let found_str = json_value.search("mouse").and_then(|j| j.as_string());
|
2014-05-01 05:32:13 +00:00
|
|
|
assert!(found_str.unwrap() == "cheese");
|
2014-03-09 06:30:27 +00:00
|
|
|
}
|
|
|
|
|
2014-11-02 13:27:15 +00:00
|
|
|
#[test]
|
|
|
|
fn test_index(){
|
|
|
|
let json_value = from_str("{\"animals\":[\"dog\",\"cat\",\"mouse\"]}").unwrap();
|
2014-11-19 18:19:43 +00:00
|
|
|
let ref array = json_value["animals"];
|
|
|
|
assert_eq!(array[0].as_string().unwrap(), "dog");
|
|
|
|
assert_eq!(array[1].as_string().unwrap(), "cat");
|
|
|
|
assert_eq!(array[2].as_string().unwrap(), "mouse");
|
2014-11-02 13:27:15 +00:00
|
|
|
}
|
|
|
|
|
2014-03-09 06:30:27 +00: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]
|
2014-11-19 18:19:43 +00:00
|
|
|
fn test_is_array(){
|
2014-03-09 06:30:27 +00:00
|
|
|
let json_value = from_str("[1, 2, 3]").unwrap();
|
2014-11-19 18:19:43 +00:00
|
|
|
assert!(json_value.is_array());
|
2014-03-09 06:30:27 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
2014-11-19 18:19:43 +00:00
|
|
|
fn test_as_array(){
|
2014-03-09 06:30:27 +00:00
|
|
|
let json_value = from_str("[1, 2, 3]").unwrap();
|
2014-11-19 18:19:43 +00:00
|
|
|
let json_array = json_value.as_array();
|
2014-03-09 06:30:27 +00:00
|
|
|
let expected_length = 3;
|
2014-11-19 18:19:43 +00:00
|
|
|
assert!(json_array.is_some() && json_array.unwrap().len() == expected_length);
|
2014-03-09 06:30:27 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
2014-03-12 03:04:36 +00:00
|
|
|
fn test_is_string(){
|
2014-03-09 06:30:27 +00:00
|
|
|
let json_value = from_str("\"dog\"").unwrap();
|
2014-03-12 03:04:36 +00:00
|
|
|
assert!(json_value.is_string());
|
2014-03-09 06:30:27 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
2014-03-12 03:04:36 +00:00
|
|
|
fn test_as_string(){
|
2014-03-09 06:30:27 +00:00
|
|
|
let json_value = from_str("\"dog\"").unwrap();
|
2014-03-12 03:04:36 +00:00
|
|
|
let json_str = json_value.as_string();
|
2014-05-01 05:32:13 +00:00
|
|
|
let expected_str = "dog";
|
2014-03-09 06:30:27 +00: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]
|
2014-08-02 16:54:40 +00:00
|
|
|
fn test_is_i64(){
|
2014-08-07 12:35:06 +00:00
|
|
|
let json_value = from_str("-12").unwrap();
|
2014-08-02 16:54:40 +00:00
|
|
|
assert!(json_value.is_i64());
|
|
|
|
|
2014-08-07 12:35:06 +00:00
|
|
|
let json_value = from_str("12").unwrap();
|
|
|
|
assert!(!json_value.is_i64());
|
|
|
|
|
2014-08-02 16:54:40 +00:00
|
|
|
let json_value = from_str("12.0").unwrap();
|
|
|
|
assert!(!json_value.is_i64());
|
|
|
|
}
|
|
|
|
|
2014-08-07 12:35:06 +00:00
|
|
|
#[test]
|
|
|
|
fn test_is_u64(){
|
|
|
|
let json_value = from_str("12").unwrap();
|
|
|
|
assert!(json_value.is_u64());
|
|
|
|
|
|
|
|
let json_value = from_str("-12").unwrap();
|
|
|
|
assert!(!json_value.is_u64());
|
|
|
|
|
|
|
|
let json_value = from_str("12.0").unwrap();
|
|
|
|
assert!(!json_value.is_u64());
|
|
|
|
}
|
|
|
|
|
2014-08-02 16:54:40 +00:00
|
|
|
#[test]
|
|
|
|
fn test_is_f64(){
|
2014-03-09 06:30:27 +00:00
|
|
|
let json_value = from_str("12").unwrap();
|
2014-08-02 16:54:40 +00:00
|
|
|
assert!(!json_value.is_f64());
|
|
|
|
|
2014-08-07 12:35:06 +00:00
|
|
|
let json_value = from_str("-12").unwrap();
|
|
|
|
assert!(!json_value.is_f64());
|
|
|
|
|
2014-08-02 16:54:40 +00:00
|
|
|
let json_value = from_str("12.0").unwrap();
|
|
|
|
assert!(json_value.is_f64());
|
2014-08-07 12:35:06 +00:00
|
|
|
|
|
|
|
let json_value = from_str("-12.0").unwrap();
|
|
|
|
assert!(json_value.is_f64());
|
2014-08-02 16:54:40 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_as_i64(){
|
2014-08-07 12:35:06 +00:00
|
|
|
let json_value = from_str("-12").unwrap();
|
2014-08-02 16:54:40 +00:00
|
|
|
let json_num = json_value.as_i64();
|
2014-08-07 12:35:06 +00:00
|
|
|
assert_eq!(json_num, Some(-12));
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_as_u64(){
|
|
|
|
let json_value = from_str("12").unwrap();
|
|
|
|
let json_num = json_value.as_u64();
|
2014-08-02 16:54:40 +00:00
|
|
|
assert_eq!(json_num, Some(12));
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_as_f64(){
|
|
|
|
let json_value = from_str("12.0").unwrap();
|
|
|
|
let json_num = json_value.as_f64();
|
|
|
|
assert_eq!(json_num, Some(12f64));
|
2014-03-09 06:30:27 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
#[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 07:26:36 +00:00
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_encode_hashmap_with_numeric_key() {
|
|
|
|
use std::str::from_utf8;
|
2014-05-30 02:03:06 +00:00
|
|
|
use std::collections::HashMap;
|
2015-03-26 00:06:52 +00:00
|
|
|
let mut hm: HashMap<usize, bool> = HashMap::new();
|
2014-03-17 07:26:36 +00:00
|
|
|
hm.insert(1, true);
|
2014-11-11 21:01:29 +00:00
|
|
|
let mut mem_buf = Vec::new();
|
2014-12-12 18:59:41 +00:00
|
|
|
write!(&mut mem_buf, "{}", super::as_pretty_json(&hm)).unwrap();
|
2015-02-18 19:48:57 +00:00
|
|
|
let json_str = from_utf8(&mem_buf[..]).unwrap();
|
2014-03-17 07:26:36 +00:00
|
|
|
match from_str(json_str) {
|
2014-12-20 08:09:35 +00:00
|
|
|
Err(_) => panic!("Unable to parse json_str: {:?}", json_str),
|
2014-03-17 07:26:36 +00:00
|
|
|
_ => {} // it parsed and we are good to go
|
|
|
|
}
|
|
|
|
}
|
2014-08-19 20:35:16 +00:00
|
|
|
|
2014-03-17 07:26:36 +00:00
|
|
|
#[test]
|
|
|
|
fn test_prettyencode_hashmap_with_numeric_key() {
|
|
|
|
use std::str::from_utf8;
|
2014-05-30 02:03:06 +00:00
|
|
|
use std::collections::HashMap;
|
2015-03-26 00:06:52 +00:00
|
|
|
let mut hm: HashMap<usize, bool> = HashMap::new();
|
2014-03-17 07:26:36 +00:00
|
|
|
hm.insert(1, true);
|
2014-11-11 21:01:29 +00:00
|
|
|
let mut mem_buf = Vec::new();
|
2014-12-12 18:59:41 +00:00
|
|
|
write!(&mut mem_buf, "{}", super::as_pretty_json(&hm)).unwrap();
|
2015-02-18 19:48:57 +00:00
|
|
|
let json_str = from_utf8(&mem_buf[..]).unwrap();
|
2014-03-17 07:26:36 +00:00
|
|
|
match from_str(json_str) {
|
2014-12-20 08:09:35 +00:00
|
|
|
Err(_) => panic!("Unable to parse json_str: {:?}", json_str),
|
2014-03-17 07:26:36 +00:00
|
|
|
_ => {} // it parsed and we are good to go
|
|
|
|
}
|
|
|
|
}
|
2014-08-19 20:35:16 +00:00
|
|
|
|
2014-08-21 09:25:24 +00:00
|
|
|
#[test]
|
|
|
|
fn test_prettyencoder_indent_level_param() {
|
|
|
|
use std::str::from_utf8;
|
2014-12-17 04:09:16 +00:00
|
|
|
use std::collections::BTreeMap;
|
2014-08-21 09:25:24 +00:00
|
|
|
|
2014-12-17 04:09:16 +00:00
|
|
|
let mut tree = BTreeMap::new();
|
2014-08-21 09:25:24 +00:00
|
|
|
|
2014-12-11 03:46:38 +00:00
|
|
|
tree.insert("hello".to_string(), String("guten tag".to_string()));
|
|
|
|
tree.insert("goodbye".to_string(), String("sayonara".to_string()));
|
2014-08-21 09:25:24 +00:00
|
|
|
|
2014-11-19 18:19:43 +00:00
|
|
|
let json = Array(
|
2014-08-21 09:25:24 +00:00
|
|
|
// The following layout below should look a lot like
|
|
|
|
// the pretty-printed JSON (indent * x)
|
|
|
|
vec!
|
|
|
|
( // 0x
|
2014-12-11 03:46:38 +00:00
|
|
|
String("greetings".to_string()), // 1x
|
2014-08-21 09:25:24 +00:00
|
|
|
Object(tree), // 1x + 2x + 2x + 1x
|
|
|
|
) // 0x
|
2014-11-19 18:19:43 +00:00
|
|
|
// End JSON array (7 lines)
|
2014-08-21 09:25:24 +00:00
|
|
|
);
|
|
|
|
|
|
|
|
// Helper function for counting indents
|
2015-03-26 00:06:52 +00:00
|
|
|
fn indents(source: &str) -> usize {
|
2014-12-12 18:59:41 +00:00
|
|
|
let trimmed = source.trim_left_matches(' ');
|
2014-08-21 09:25:24 +00:00
|
|
|
source.len() - trimmed.len()
|
|
|
|
}
|
|
|
|
|
|
|
|
// Test up to 4 spaces of indents (more?)
|
2015-01-24 14:39:32 +00:00
|
|
|
for i in 0..4 {
|
2014-11-11 21:01:29 +00:00
|
|
|
let mut writer = Vec::new();
|
2014-12-12 18:59:41 +00:00
|
|
|
write!(&mut writer, "{}",
|
|
|
|
super::as_pretty_json(&json).indent(i)).unwrap();
|
2014-08-21 09:25:24 +00:00
|
|
|
|
2015-02-18 19:48:57 +00:00
|
|
|
let printed = from_utf8(&writer[..]).unwrap();
|
2014-08-21 09:25:24 +00:00
|
|
|
|
|
|
|
// Check for indents at each line
|
|
|
|
let lines: Vec<&str> = printed.lines().collect();
|
|
|
|
assert_eq!(lines.len(), 7); // JSON should be 7 lines
|
|
|
|
|
|
|
|
assert_eq!(indents(lines[0]), 0 * i); // [
|
|
|
|
assert_eq!(indents(lines[1]), 1 * i); // "greetings",
|
|
|
|
assert_eq!(indents(lines[2]), 1 * i); // {
|
|
|
|
assert_eq!(indents(lines[3]), 2 * i); // "hello": "guten tag",
|
|
|
|
assert_eq!(indents(lines[4]), 2 * i); // "goodbye": "sayonara"
|
|
|
|
assert_eq!(indents(lines[5]), 1 * i); // },
|
|
|
|
assert_eq!(indents(lines[6]), 0 * i); // ]
|
|
|
|
|
|
|
|
// Finally, test that the pretty-printed JSON is valid
|
|
|
|
from_str(printed).ok().expect("Pretty-printed JSON is invalid!");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-01-23 09:52:58 +00:00
|
|
|
#[test]
|
|
|
|
fn test_hashmap_with_enum_key() {
|
|
|
|
use std::collections::HashMap;
|
|
|
|
use json;
|
2015-02-05 12:04:07 +00:00
|
|
|
#[derive(RustcEncodable, Eq, Hash, PartialEq, RustcDecodable, Debug)]
|
2015-01-23 09:52:58 +00:00
|
|
|
enum Enum {
|
|
|
|
Foo,
|
|
|
|
#[allow(dead_code)]
|
|
|
|
Bar,
|
|
|
|
}
|
|
|
|
let mut map = HashMap::new();
|
|
|
|
map.insert(Enum::Foo, 0);
|
|
|
|
let result = json::encode(&map).unwrap();
|
2015-02-18 19:48:57 +00:00
|
|
|
assert_eq!(&result[..], r#"{"Foo":0}"#);
|
2015-02-02 02:53:25 +00:00
|
|
|
let decoded: HashMap<Enum, _> = json::decode(&result).unwrap();
|
2015-01-23 09:52:58 +00:00
|
|
|
assert_eq!(map, decoded);
|
|
|
|
}
|
|
|
|
|
2014-03-17 07:26:36 +00:00
|
|
|
#[test]
|
|
|
|
fn test_hashmap_with_numeric_key_can_handle_double_quote_delimited_key() {
|
2014-05-30 02:03:06 +00:00
|
|
|
use std::collections::HashMap;
|
2014-03-17 07:26:36 +00:00
|
|
|
use Decodable;
|
|
|
|
let json_str = "{\"1\":true}";
|
|
|
|
let json_obj = match from_str(json_str) {
|
2014-12-20 08:09:35 +00:00
|
|
|
Err(_) => panic!("Unable to parse json_str: {:?}", json_str),
|
2014-03-17 07:26:36 +00:00
|
|
|
Ok(o) => o
|
|
|
|
};
|
|
|
|
let mut decoder = Decoder::new(json_obj);
|
2015-03-26 00:06:52 +00:00
|
|
|
let _hm: HashMap<usize, bool> = Decodable::decode(&mut decoder).unwrap();
|
2014-03-17 07:26:36 +00:00
|
|
|
}
|
2014-03-30 12:58:02 +00:00
|
|
|
|
2014-08-19 20:35:16 +00:00
|
|
|
#[test]
|
|
|
|
fn test_hashmap_with_numeric_key_will_error_with_string_keys() {
|
|
|
|
use std::collections::HashMap;
|
|
|
|
use Decodable;
|
|
|
|
let json_str = "{\"a\":true}";
|
|
|
|
let json_obj = match from_str(json_str) {
|
2014-12-20 08:09:35 +00:00
|
|
|
Err(_) => panic!("Unable to parse json_str: {:?}", json_str),
|
2014-08-19 20:35:16 +00:00
|
|
|
Ok(o) => o
|
|
|
|
};
|
|
|
|
let mut decoder = Decoder::new(json_obj);
|
2015-03-26 00:06:52 +00:00
|
|
|
let result: Result<HashMap<usize, bool>, DecoderError> = Decodable::decode(&mut decoder);
|
2014-12-11 03:46:38 +00:00
|
|
|
assert_eq!(result, Err(ExpectedError("Number".to_string(), "a".to_string())));
|
2014-08-19 20:35:16 +00:00
|
|
|
}
|
|
|
|
|
2014-06-06 17:27:49 +00:00
|
|
|
fn assert_stream_equal(src: &str,
|
|
|
|
expected: Vec<(JsonEvent, Vec<StackElement>)>) {
|
2014-03-30 12:58:02 +00:00
|
|
|
let mut parser = Parser::new(src.chars());
|
|
|
|
let mut i = 0;
|
|
|
|
loop {
|
|
|
|
let evt = match parser.next() {
|
|
|
|
Some(e) => e,
|
|
|
|
None => { break; }
|
|
|
|
};
|
2014-07-25 14:20:55 +00:00
|
|
|
let (ref expected_evt, ref expected_stack) = expected[i];
|
2015-02-02 02:53:25 +00:00
|
|
|
if !parser.stack().is_equal_to(expected_stack) {
|
2014-12-20 08:09:35 +00:00
|
|
|
panic!("Parser stack is not equal to {:?}", expected_stack);
|
2014-03-30 12:58:02 +00:00
|
|
|
}
|
|
|
|
assert_eq!(&evt, expected_evt);
|
|
|
|
i+=1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#[test]
|
2015-01-07 04:26:55 +00:00
|
|
|
#[cfg_attr(target_pointer_width = "32", ignore)] // FIXME(#14064)
|
2014-03-30 12:58:02 +00:00
|
|
|
fn test_streaming_parser() {
|
|
|
|
assert_stream_equal(
|
2014-08-02 16:54:40 +00:00
|
|
|
r#"{ "foo":"bar", "array" : [0, 1, 2, 3, 4, 5], "idents":[null,true,false]}"#,
|
2014-06-06 17:27:49 +00:00
|
|
|
vec![
|
|
|
|
(ObjectStart, vec![]),
|
2015-01-02 00:56:28 +00:00
|
|
|
(StringValue("bar".to_string()), vec![StackElement::Key("foo")]),
|
|
|
|
(ArrayStart, vec![StackElement::Key("array")]),
|
|
|
|
(U64Value(0), vec![StackElement::Key("array"), StackElement::Index(0)]),
|
|
|
|
(U64Value(1), vec![StackElement::Key("array"), StackElement::Index(1)]),
|
|
|
|
(U64Value(2), vec![StackElement::Key("array"), StackElement::Index(2)]),
|
|
|
|
(U64Value(3), vec![StackElement::Key("array"), StackElement::Index(3)]),
|
|
|
|
(U64Value(4), vec![StackElement::Key("array"), StackElement::Index(4)]),
|
|
|
|
(U64Value(5), vec![StackElement::Key("array"), StackElement::Index(5)]),
|
|
|
|
(ArrayEnd, vec![StackElement::Key("array")]),
|
|
|
|
(ArrayStart, vec![StackElement::Key("idents")]),
|
2015-01-04 04:43:24 +00:00
|
|
|
(NullValue, vec![StackElement::Key("idents"),
|
|
|
|
StackElement::Index(0)]),
|
|
|
|
(BooleanValue(true), vec![StackElement::Key("idents"),
|
|
|
|
StackElement::Index(1)]),
|
|
|
|
(BooleanValue(false), vec![StackElement::Key("idents"),
|
|
|
|
StackElement::Index(2)]),
|
2015-01-02 00:56:28 +00:00
|
|
|
(ArrayEnd, vec![StackElement::Key("idents")]),
|
2014-06-06 17:27:49 +00:00
|
|
|
(ObjectEnd, vec![]),
|
2014-03-30 12:58:02 +00: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,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2014-09-15 17:12:15 +00:00
|
|
|
|
2014-03-30 12:58:02 +00:00
|
|
|
#[test]
|
2015-01-07 04:26:55 +00:00
|
|
|
#[cfg_attr(target_pointer_width = "32", ignore)] // FIXME(#14064)
|
2014-03-30 12:58:02 +00: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)));
|
2014-09-15 17:12:15 +00:00
|
|
|
assert_eq!(last_event("{\"a\":1,}"), Error(SyntaxError(TrailingComma, 1, 8)));
|
2014-03-30 12:58:02 +00:00
|
|
|
|
|
|
|
assert_stream_equal(
|
|
|
|
"{}",
|
2014-06-06 17:27:49 +00:00
|
|
|
vec![(ObjectStart, vec![]), (ObjectEnd, vec![])]
|
2014-03-30 12:58:02 +00:00
|
|
|
);
|
|
|
|
assert_stream_equal(
|
|
|
|
"{\"a\": 3}",
|
2014-06-06 17:27:49 +00:00
|
|
|
vec![
|
|
|
|
(ObjectStart, vec![]),
|
2015-01-02 00:56:28 +00:00
|
|
|
(U64Value(3), vec![StackElement::Key("a")]),
|
2014-06-06 17:27:49 +00:00
|
|
|
(ObjectEnd, vec![]),
|
2014-03-30 12:58:02 +00:00
|
|
|
]
|
|
|
|
);
|
|
|
|
assert_stream_equal(
|
|
|
|
"{ \"a\": null, \"b\" : true }",
|
2014-06-06 17:27:49 +00:00
|
|
|
vec![
|
|
|
|
(ObjectStart, vec![]),
|
2015-01-02 00:56:28 +00:00
|
|
|
(NullValue, vec![StackElement::Key("a")]),
|
|
|
|
(BooleanValue(true), vec![StackElement::Key("b")]),
|
2014-06-06 17:27:49 +00:00
|
|
|
(ObjectEnd, vec![]),
|
2014-03-30 12:58:02 +00:00
|
|
|
]
|
|
|
|
);
|
|
|
|
assert_stream_equal(
|
|
|
|
"{\"a\" : 1.0 ,\"b\": [ true ]}",
|
2014-06-06 17:27:49 +00:00
|
|
|
vec![
|
|
|
|
(ObjectStart, vec![]),
|
2015-01-02 00:56:28 +00:00
|
|
|
(F64Value(1.0), vec![StackElement::Key("a")]),
|
|
|
|
(ArrayStart, vec![StackElement::Key("b")]),
|
|
|
|
(BooleanValue(true),vec![StackElement::Key("b"), StackElement::Index(0)]),
|
|
|
|
(ArrayEnd, vec![StackElement::Key("b")]),
|
2014-06-06 17:27:49 +00:00
|
|
|
(ObjectEnd, vec![]),
|
2014-03-30 12:58:02 +00:00
|
|
|
]
|
|
|
|
);
|
|
|
|
assert_stream_equal(
|
|
|
|
r#"{
|
|
|
|
"a": 1.0,
|
|
|
|
"b": [
|
|
|
|
true,
|
|
|
|
"foo\nbar",
|
|
|
|
{ "c": {"d": null} }
|
|
|
|
]
|
|
|
|
}"#,
|
2014-06-06 17:27:49 +00:00
|
|
|
vec![
|
|
|
|
(ObjectStart, vec![]),
|
2015-01-02 00:56:28 +00:00
|
|
|
(F64Value(1.0), vec![StackElement::Key("a")]),
|
|
|
|
(ArrayStart, vec![StackElement::Key("b")]),
|
2015-01-04 04:43:24 +00:00
|
|
|
(BooleanValue(true), vec![StackElement::Key("b"),
|
|
|
|
StackElement::Index(0)]),
|
|
|
|
(StringValue("foo\nbar".to_string()), vec![StackElement::Key("b"),
|
|
|
|
StackElement::Index(1)]),
|
|
|
|
(ObjectStart, vec![StackElement::Key("b"),
|
|
|
|
StackElement::Index(2)]),
|
|
|
|
(ObjectStart, vec![StackElement::Key("b"),
|
|
|
|
StackElement::Index(2),
|
|
|
|
StackElement::Key("c")]),
|
|
|
|
(NullValue, vec![StackElement::Key("b"),
|
|
|
|
StackElement::Index(2),
|
|
|
|
StackElement::Key("c"),
|
|
|
|
StackElement::Key("d")]),
|
|
|
|
(ObjectEnd, vec![StackElement::Key("b"),
|
|
|
|
StackElement::Index(2),
|
|
|
|
StackElement::Key("c")]),
|
|
|
|
(ObjectEnd, vec![StackElement::Key("b"),
|
|
|
|
StackElement::Index(2)]),
|
2015-01-02 00:56:28 +00:00
|
|
|
(ArrayEnd, vec![StackElement::Key("b")]),
|
2014-06-06 17:27:49 +00:00
|
|
|
(ObjectEnd, vec![]),
|
2014-03-30 12:58:02 +00:00
|
|
|
]
|
|
|
|
);
|
|
|
|
}
|
|
|
|
#[test]
|
2015-01-07 04:26:55 +00:00
|
|
|
#[cfg_attr(target_pointer_width = "32", ignore)] // FIXME(#14064)
|
2014-11-19 18:19:43 +00:00
|
|
|
fn test_read_array_streaming() {
|
2014-03-30 12:58:02 +00:00
|
|
|
assert_stream_equal(
|
|
|
|
"[]",
|
2014-06-06 17:27:49 +00:00
|
|
|
vec![
|
2014-11-19 18:19:43 +00:00
|
|
|
(ArrayStart, vec![]),
|
|
|
|
(ArrayEnd, vec![]),
|
2014-03-30 12:58:02 +00:00
|
|
|
]
|
|
|
|
);
|
|
|
|
assert_stream_equal(
|
|
|
|
"[ ]",
|
2014-06-06 17:27:49 +00:00
|
|
|
vec![
|
2014-11-19 18:19:43 +00:00
|
|
|
(ArrayStart, vec![]),
|
|
|
|
(ArrayEnd, vec![]),
|
2014-03-30 12:58:02 +00:00
|
|
|
]
|
|
|
|
);
|
|
|
|
assert_stream_equal(
|
|
|
|
"[true]",
|
2014-06-06 17:27:49 +00:00
|
|
|
vec![
|
2014-11-19 18:19:43 +00:00
|
|
|
(ArrayStart, vec![]),
|
2015-01-02 00:56:28 +00:00
|
|
|
(BooleanValue(true), vec![StackElement::Index(0)]),
|
2014-11-19 18:19:43 +00:00
|
|
|
(ArrayEnd, vec![]),
|
2014-03-30 12:58:02 +00:00
|
|
|
]
|
|
|
|
);
|
|
|
|
assert_stream_equal(
|
|
|
|
"[ false ]",
|
2014-06-06 17:27:49 +00:00
|
|
|
vec![
|
2014-11-19 18:19:43 +00:00
|
|
|
(ArrayStart, vec![]),
|
2015-01-02 00:56:28 +00:00
|
|
|
(BooleanValue(false), vec![StackElement::Index(0)]),
|
2014-11-19 18:19:43 +00:00
|
|
|
(ArrayEnd, vec![]),
|
2014-03-30 12:58:02 +00:00
|
|
|
]
|
|
|
|
);
|
|
|
|
assert_stream_equal(
|
|
|
|
"[null]",
|
2014-06-06 17:27:49 +00:00
|
|
|
vec![
|
2014-11-19 18:19:43 +00:00
|
|
|
(ArrayStart, vec![]),
|
2015-01-02 00:56:28 +00:00
|
|
|
(NullValue, vec![StackElement::Index(0)]),
|
2014-11-19 18:19:43 +00:00
|
|
|
(ArrayEnd, vec![]),
|
2014-03-30 12:58:02 +00:00
|
|
|
]
|
|
|
|
);
|
|
|
|
assert_stream_equal(
|
|
|
|
"[3, 1]",
|
2014-06-06 17:27:49 +00:00
|
|
|
vec![
|
2014-11-19 18:19:43 +00:00
|
|
|
(ArrayStart, vec![]),
|
2015-01-02 00:56:28 +00:00
|
|
|
(U64Value(3), vec![StackElement::Index(0)]),
|
|
|
|
(U64Value(1), vec![StackElement::Index(1)]),
|
2014-11-19 18:19:43 +00:00
|
|
|
(ArrayEnd, vec![]),
|
2014-03-30 12:58:02 +00:00
|
|
|
]
|
|
|
|
);
|
|
|
|
assert_stream_equal(
|
|
|
|
"\n[3, 2]\n",
|
2014-06-06 17:27:49 +00:00
|
|
|
vec![
|
2014-11-19 18:19:43 +00:00
|
|
|
(ArrayStart, vec![]),
|
2015-01-02 00:56:28 +00:00
|
|
|
(U64Value(3), vec![StackElement::Index(0)]),
|
|
|
|
(U64Value(2), vec![StackElement::Index(1)]),
|
2014-11-19 18:19:43 +00:00
|
|
|
(ArrayEnd, vec![]),
|
2014-03-30 12:58:02 +00:00
|
|
|
]
|
|
|
|
);
|
|
|
|
assert_stream_equal(
|
|
|
|
"[2, [4, 1]]",
|
2014-06-06 17:27:49 +00:00
|
|
|
vec![
|
2014-11-19 18:19:43 +00:00
|
|
|
(ArrayStart, vec![]),
|
2015-01-02 00:56:28 +00:00
|
|
|
(U64Value(2), vec![StackElement::Index(0)]),
|
|
|
|
(ArrayStart, vec![StackElement::Index(1)]),
|
|
|
|
(U64Value(4), vec![StackElement::Index(1), StackElement::Index(0)]),
|
|
|
|
(U64Value(1), vec![StackElement::Index(1), StackElement::Index(1)]),
|
|
|
|
(ArrayEnd, vec![StackElement::Index(1)]),
|
2014-11-19 18:19:43 +00:00
|
|
|
(ArrayEnd, vec![]),
|
2014-03-30 12:58:02 +00:00
|
|
|
]
|
|
|
|
);
|
|
|
|
|
|
|
|
assert_eq!(last_event("["), Error(SyntaxError(EOFWhileParsingValue, 1, 2)));
|
|
|
|
|
|
|
|
assert_eq!(from_str("["), Err(SyntaxError(EOFWhileParsingValue, 1, 2)));
|
2014-11-19 18:19:43 +00:00
|
|
|
assert_eq!(from_str("[1"), Err(SyntaxError(EOFWhileParsingArray, 1, 3)));
|
2014-03-30 12:58:02 +00:00
|
|
|
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());
|
2015-03-24 23:53:34 +00:00
|
|
|
assert!(stack.is_empty());
|
2014-03-30 12:58:02 +00:00
|
|
|
assert!(!stack.last_is_index());
|
|
|
|
|
|
|
|
stack.push_index(0);
|
|
|
|
stack.bump_index();
|
|
|
|
|
|
|
|
assert!(stack.len() == 1);
|
2015-01-02 00:56:28 +00:00
|
|
|
assert!(stack.is_equal_to(&[StackElement::Index(1)]));
|
|
|
|
assert!(stack.starts_with(&[StackElement::Index(1)]));
|
|
|
|
assert!(stack.ends_with(&[StackElement::Index(1)]));
|
2014-03-30 12:58:02 +00:00
|
|
|
assert!(stack.last_is_index());
|
2015-01-02 00:56:28 +00:00
|
|
|
assert!(stack.get(0) == StackElement::Index(1));
|
2014-03-30 12:58:02 +00:00
|
|
|
|
2014-12-11 03:46:38 +00:00
|
|
|
stack.push_key("foo".to_string());
|
2014-03-30 12:58:02 +00:00
|
|
|
|
|
|
|
assert!(stack.len() == 2);
|
2015-01-02 00:56:28 +00:00
|
|
|
assert!(stack.is_equal_to(&[StackElement::Index(1), StackElement::Key("foo")]));
|
|
|
|
assert!(stack.starts_with(&[StackElement::Index(1), StackElement::Key("foo")]));
|
|
|
|
assert!(stack.starts_with(&[StackElement::Index(1)]));
|
|
|
|
assert!(stack.ends_with(&[StackElement::Index(1), StackElement::Key("foo")]));
|
|
|
|
assert!(stack.ends_with(&[StackElement::Key("foo")]));
|
2014-03-30 12:58:02 +00:00
|
|
|
assert!(!stack.last_is_index());
|
2015-01-02 00:56:28 +00:00
|
|
|
assert!(stack.get(0) == StackElement::Index(1));
|
|
|
|
assert!(stack.get(1) == StackElement::Key("foo"));
|
2014-03-30 12:58:02 +00:00
|
|
|
|
2014-12-11 03:46:38 +00:00
|
|
|
stack.push_key("bar".to_string());
|
2014-03-30 12:58:02 +00:00
|
|
|
|
|
|
|
assert!(stack.len() == 3);
|
2015-01-04 04:43:24 +00:00
|
|
|
assert!(stack.is_equal_to(&[StackElement::Index(1),
|
|
|
|
StackElement::Key("foo"),
|
|
|
|
StackElement::Key("bar")]));
|
2015-01-02 00:56:28 +00:00
|
|
|
assert!(stack.starts_with(&[StackElement::Index(1)]));
|
|
|
|
assert!(stack.starts_with(&[StackElement::Index(1), StackElement::Key("foo")]));
|
2015-01-04 04:43:24 +00:00
|
|
|
assert!(stack.starts_with(&[StackElement::Index(1),
|
|
|
|
StackElement::Key("foo"),
|
|
|
|
StackElement::Key("bar")]));
|
2015-01-02 00:56:28 +00:00
|
|
|
assert!(stack.ends_with(&[StackElement::Key("bar")]));
|
|
|
|
assert!(stack.ends_with(&[StackElement::Key("foo"), StackElement::Key("bar")]));
|
2015-01-04 04:43:24 +00:00
|
|
|
assert!(stack.ends_with(&[StackElement::Index(1),
|
|
|
|
StackElement::Key("foo"),
|
|
|
|
StackElement::Key("bar")]));
|
2014-03-30 12:58:02 +00:00
|
|
|
assert!(!stack.last_is_index());
|
2015-01-02 00:56:28 +00:00
|
|
|
assert!(stack.get(0) == StackElement::Index(1));
|
|
|
|
assert!(stack.get(1) == StackElement::Key("foo"));
|
|
|
|
assert!(stack.get(2) == StackElement::Key("bar"));
|
2014-03-30 12:58:02 +00:00
|
|
|
|
|
|
|
stack.pop();
|
|
|
|
|
|
|
|
assert!(stack.len() == 2);
|
2015-01-02 00:56:28 +00:00
|
|
|
assert!(stack.is_equal_to(&[StackElement::Index(1), StackElement::Key("foo")]));
|
|
|
|
assert!(stack.starts_with(&[StackElement::Index(1), StackElement::Key("foo")]));
|
|
|
|
assert!(stack.starts_with(&[StackElement::Index(1)]));
|
|
|
|
assert!(stack.ends_with(&[StackElement::Index(1), StackElement::Key("foo")]));
|
|
|
|
assert!(stack.ends_with(&[StackElement::Key("foo")]));
|
2014-03-30 12:58:02 +00:00
|
|
|
assert!(!stack.last_is_index());
|
2015-01-02 00:56:28 +00:00
|
|
|
assert!(stack.get(0) == StackElement::Index(1));
|
|
|
|
assert!(stack.get(1) == StackElement::Key("foo"));
|
2014-03-30 12:58:02 +00:00
|
|
|
}
|
|
|
|
|
2014-06-03 15:49:26 +00:00
|
|
|
#[test]
|
|
|
|
fn test_to_json() {
|
2014-12-17 04:09:16 +00:00
|
|
|
use std::collections::{HashMap,BTreeMap};
|
2014-06-03 15:49:26 +00:00
|
|
|
use super::ToJson;
|
|
|
|
|
2014-11-19 18:19:43 +00:00
|
|
|
let array2 = Array(vec!(U64(1), U64(2)));
|
|
|
|
let array3 = Array(vec!(U64(1), U64(2), U64(3)));
|
2014-06-03 15:49:26 +00:00
|
|
|
let object = {
|
2014-12-17 04:09:16 +00:00
|
|
|
let mut tree_map = BTreeMap::new();
|
2014-12-28 18:51:00 +00:00
|
|
|
tree_map.insert("a".to_string(), U64(1));
|
|
|
|
tree_map.insert("b".to_string(), U64(2));
|
2014-06-28 12:41:40 +00:00
|
|
|
Object(tree_map)
|
2014-06-03 15:49:26 +00:00
|
|
|
};
|
|
|
|
|
2014-11-19 18:19:43 +00:00
|
|
|
assert_eq!(array2.to_json(), array2);
|
2014-06-03 15:49:26 +00:00
|
|
|
assert_eq!(object.to_json(), object);
|
2015-02-17 14:48:01 +00:00
|
|
|
assert_eq!(3_isize.to_json(), I64(3));
|
2014-08-07 12:35:06 +00:00
|
|
|
assert_eq!(4_i8.to_json(), I64(4));
|
|
|
|
assert_eq!(5_i16.to_json(), I64(5));
|
|
|
|
assert_eq!(6_i32.to_json(), I64(6));
|
|
|
|
assert_eq!(7_i64.to_json(), I64(7));
|
2015-02-17 14:48:01 +00:00
|
|
|
assert_eq!(8_usize.to_json(), U64(8));
|
2014-08-07 12:35:06 +00:00
|
|
|
assert_eq!(9_u8.to_json(), U64(9));
|
|
|
|
assert_eq!(10_u16.to_json(), U64(10));
|
|
|
|
assert_eq!(11_u32.to_json(), U64(11));
|
|
|
|
assert_eq!(12_u64.to_json(), U64(12));
|
|
|
|
assert_eq!(13.0_f32.to_json(), F64(13.0_f64));
|
|
|
|
assert_eq!(14.0_f64.to_json(), F64(14.0_f64));
|
2014-06-03 15:49:26 +00:00
|
|
|
assert_eq!(().to_json(), Null);
|
2014-06-26 01:26:41 +00:00
|
|
|
assert_eq!(f32::INFINITY.to_json(), Null);
|
|
|
|
assert_eq!(f64::NAN.to_json(), Null);
|
2014-06-03 15:49:26 +00:00
|
|
|
assert_eq!(true.to_json(), Boolean(true));
|
|
|
|
assert_eq!(false.to_json(), Boolean(false));
|
2014-12-11 03:46:38 +00:00
|
|
|
assert_eq!("abc".to_json(), String("abc".to_string()));
|
|
|
|
assert_eq!("abc".to_string().to_json(), String("abc".to_string()));
|
2015-02-17 14:48:01 +00:00
|
|
|
assert_eq!((1_usize, 2_usize).to_json(), array2);
|
|
|
|
assert_eq!((1_usize, 2_usize, 3_usize).to_json(), array3);
|
|
|
|
assert_eq!([1_usize, 2_usize].to_json(), array2);
|
|
|
|
assert_eq!((&[1_usize, 2_usize, 3_usize]).to_json(), array3);
|
|
|
|
assert_eq!((vec![1_usize, 2_usize]).to_json(), array2);
|
|
|
|
assert_eq!(vec!(1_usize, 2_usize, 3_usize).to_json(), array3);
|
2014-12-17 04:09:16 +00:00
|
|
|
let mut tree_map = BTreeMap::new();
|
2015-02-17 14:48:01 +00:00
|
|
|
tree_map.insert("a".to_string(), 1 as usize);
|
2014-12-28 18:51:00 +00:00
|
|
|
tree_map.insert("b".to_string(), 2);
|
2014-06-03 15:49:26 +00:00
|
|
|
assert_eq!(tree_map.to_json(), object);
|
|
|
|
let mut hash_map = HashMap::new();
|
2015-02-17 14:48:01 +00:00
|
|
|
hash_map.insert("a".to_string(), 1 as usize);
|
2014-12-11 03:46:38 +00:00
|
|
|
hash_map.insert("b".to_string(), 2);
|
2014-06-03 15:49:26 +00:00
|
|
|
assert_eq!(hash_map.to_json(), object);
|
2015-01-25 21:05:03 +00:00
|
|
|
assert_eq!(Some(15).to_json(), I64(15));
|
2015-02-17 14:48:01 +00:00
|
|
|
assert_eq!(Some(15 as usize).to_json(), U64(15));
|
2015-03-26 00:06:52 +00:00
|
|
|
assert_eq!(None::<isize>.to_json(), Null);
|
2014-06-03 15:49:26 +00:00
|
|
|
}
|
|
|
|
|
2015-01-10 09:14:38 +00:00
|
|
|
#[test]
|
|
|
|
fn test_encode_hashmap_with_arbitrary_key() {
|
|
|
|
use std::collections::HashMap;
|
|
|
|
#[derive(PartialEq, Eq, Hash, RustcEncodable)]
|
2015-03-26 00:06:52 +00:00
|
|
|
struct ArbitraryType(usize);
|
2015-01-10 09:14:38 +00:00
|
|
|
let mut hm: HashMap<ArbitraryType, bool> = HashMap::new();
|
|
|
|
hm.insert(ArbitraryType(1), true);
|
std: Stabilize the std::fmt module
This commit performs a final stabilization pass over the std::fmt module,
marking all necessary APIs as stable. One of the more interesting aspects of
this module is that it exposes a good deal of its runtime representation to the
outside world in order for `format_args!` to be able to construct the format
strings. Instead of hacking the compiler to assume that these items are stable,
this commit instead lays out a story for the stabilization and evolution of
these APIs.
There are three primary details used by the `format_args!` macro:
1. `Arguments` - an opaque package of a "compiled format string". This structure
is passed around and the `write` function is the source of truth for
transforming a compiled format string into a string at runtime. This must be
able to be constructed in stable code.
2. `Argument` - an opaque structure representing an argument to a format string.
This is *almost* a trait object as it's just a pointer/function pair, but due
to the function originating from one of many traits, it's not actually a
trait object. Like `Arguments`, this must be constructed from stable code.
3. `fmt::rt` - this module contains the runtime type definitions primarily for
the `rt::Argument` structure. Whenever an argument is formatted with
nonstandard flags, a corresponding `rt::Argument` is generated describing how
the argument is being formatted. This can be used to construct an
`Arguments`.
The primary interface to `std::fmt` is the `Arguments` structure, and as such
this type name is stabilize as-is today. It is expected for libraries to pass
around an `Arguments` structure to represent a pending formatted computation.
The remaining portions are largely "cruft" which would rather not be stabilized,
but due to the stability checks they must be. As a result, almost all pieces
have been renamed to represent that they are "version 1" of the formatting
representation. The theory is that at a later date if we change the
representation of these types we can add new definitions called "version 2" and
corresponding constructors for `Arguments`.
One of the other remaining large questions about the fmt module were how the
pending I/O reform would affect the signatures of methods in the module. Due to
[RFC 526][rfc], however, the writers of fmt are now incompatible with the
writers of io, so this question has largely been solved. As a result the
interfaces are largely stabilized as-is today.
[rfc]: https://github.com/rust-lang/rfcs/blob/master/text/0526-fmt-text-writer.md
Specifically, the following changes were made:
* The contents of `fmt::rt` were all moved under `fmt::rt::v1`
* `fmt::rt` is stable
* `fmt::rt::v1` is stable
* `Error` is stable
* `Writer` is stable
* `Writer::write_str` is stable
* `Writer::write_fmt` is stable
* `Formatter` is stable
* `Argument` has been renamed to `ArgumentV1` and is stable
* `ArgumentV1::new` is stable
* `ArgumentV1::from_uint` is stable
* `Arguments::new_v1` is stable (renamed from `new`)
* `Arguments::new_v1_formatted` is stable (renamed from `with_placeholders`)
* All formatting traits are now stable, as well as the `fmt` method.
* `fmt::write` is stable
* `fmt::format` is stable
* `Formatter::pad_integral` is stable
* `Formatter::pad` is stable
* `Formatter::write_str` is stable
* `Formatter::write_fmt` is stable
* Some assorted top level items which were only used by `format_args!` were
removed in favor of static functions on `ArgumentV1` as well.
* The formatting-flag-accessing methods remain unstable
Within the contents of the `fmt::rt::v1` module, the following actions were
taken:
* Reexports of all enum variants were removed
* All prefixes on enum variants were removed
* A few miscellaneous enum variants were renamed
* Otherwise all structs, fields, and variants were marked stable.
In addition to these actions in the `std::fmt` module, many implementations of
`Show` and `String` were stabilized as well.
In some other modules:
* `ToString` is now stable
* `ToString::to_string` is now stable
* `Vec` no longer implements `fmt::Writer` (this has moved to `String`)
This is a breaking change due to all of the changes to the `fmt::rt` module, but
this likely will not have much impact on existing programs.
Closes #20661
[breaking-change]
2015-01-13 23:42:53 +00:00
|
|
|
let mut mem_buf = string::String::new();
|
|
|
|
let mut encoder = Encoder::new(&mut mem_buf);
|
2015-01-10 09:14:38 +00:00
|
|
|
let result = hm.encode(&mut encoder);
|
2015-01-20 23:45:07 +00:00
|
|
|
match result.err().unwrap() {
|
2015-01-10 09:14:38 +00:00
|
|
|
EncoderError::BadHashmapKey => (),
|
|
|
|
_ => panic!("expected bad hash map key")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-03-30 12:58:02 +00: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-09-11 05:07:49 +00:00
|
|
|
fn big_json() -> string::String {
|
2014-12-11 03:46:38 +00:00
|
|
|
let mut src = "[\n".to_string();
|
2015-01-25 21:05:03 +00:00
|
|
|
for _ in 0..500 {
|
2014-05-15 04:16:44 +00:00
|
|
|
src.push_str(r#"{ "a": true, "b": null, "c":3.1415, "d": "Hello world", "e": \
|
|
|
|
[1,2,3]},"#);
|
2014-03-30 12:58:02 +00:00
|
|
|
}
|
2014-05-15 04:16:44 +00:00
|
|
|
src.push_str("{}]");
|
2014-03-30 12:58:02 +00:00
|
|
|
return src;
|
|
|
|
}
|
|
|
|
|
|
|
|
#[bench]
|
|
|
|
fn bench_streaming_large(b: &mut Bencher) {
|
|
|
|
let src = big_json();
|
|
|
|
b.iter( || {
|
2014-11-27 19:28:51 +00:00
|
|
|
let mut parser = Parser::new(src.chars());
|
2014-03-30 12:58:02 +00:00
|
|
|
loop {
|
|
|
|
match parser.next() {
|
|
|
|
None => return,
|
|
|
|
_ => {}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
|
|
|
#[bench]
|
|
|
|
fn bench_large(b: &mut Bencher) {
|
|
|
|
let src = big_json();
|
2015-02-02 02:53:25 +00:00
|
|
|
b.iter( || { let _ = from_str(&src); });
|
2014-03-30 12:58:02 +00:00
|
|
|
}
|
2012-01-18 03:05:07 +00:00
|
|
|
}
|