]> git.lizzy.rs Git - rust.git/blobdiff - src/libserialize/json.rs
rollup merge of #17355 : gamazeps/issue17210
[rust.git] / src / libserialize / json.rs
index 733bc593922dedf32f399b21240bfee1843823d8..14274ef9f9b04f09ed76fe2f1c68e885b70bfc19 100644 (file)
@@ -28,7 +28,7 @@
 * `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
+* `List`: equivalent to rust's `Vec<T>`, but also allowing objects of different types in the same
 array
 * `Object`: equivalent to rust's `Treemap<String, json::Json>`
 * `Null`
@@ -201,7 +201,7 @@ fn main() {
 use std::mem::{swap, transmute};
 use std::num::{FPNaN, FPInfinite};
 use std::str::ScalarValue;
-use std::string::String;
+use std::string;
 use std::vec::Vec;
 
 use Encodable;
@@ -212,15 +212,15 @@ pub enum Json {
     I64(i64),
     U64(u64),
     F64(f64),
-    String(String),
+    String(string::String),
     Boolean(bool),
-    List(List),
-    Object(Object),
+    List(JsonList),
+    Object(JsonObject),
     Null,
 }
 
-pub type List = Vec<Json>;
-pub type Object = TreeMap<String, Json>;
+pub type JsonList = Vec<Json>;
+pub type JsonObject = TreeMap<string::String, Json>;
 
 /// The errors that can arise while parsing a JSON stream.
 #[deriving(Clone, PartialEq)]
@@ -234,6 +234,7 @@ pub enum ErrorCode {
     KeyMustBeAString,
     ExpectedColon,
     TrailingCharacters,
+    TrailingComma,
     InvalidEscape,
     InvalidUnicodeCodePoint,
     LoneLeadingSurrogateInHexEscape,
@@ -256,10 +257,10 @@ pub enum ParserError {
 #[deriving(Clone, PartialEq, Show)]
 pub enum DecoderError {
     ParseError(ParserError),
-    ExpectedError(String, String),
-    MissingFieldError(String),
-    UnknownVariantError(String),
-    ApplicationError(String)
+    ExpectedError(string::String, string::String),
+    MissingFieldError(string::String),
+    UnknownVariantError(string::String),
+    ApplicationError(string::String)
 }
 
 /// Returns a readable error string for a given error code.
@@ -274,6 +275,7 @@ pub fn error_str(error: ErrorCode) -> &'static str {
         KeyMustBeAString => "key must be a string",
         ExpectedColon => "expected `:`",
         TrailingCharacters => "trailing characters",
+        TrailingComma => "trailing comma",
         InvalidEscape => "invalid escape",
         UnrecognizedHex => "invalid \\u escape (unrecognized hex)",
         NotFourDigit => "invalid \\u escape (not four digits)",
@@ -296,9 +298,9 @@ pub fn decode<T: ::Decodable<Decoder, DecoderError>>(s: &str) -> DecodeResult<T>
 }
 
 /// Shortcut function to encode a `T` into a JSON `String`
-pub fn encode<'a, T: Encodable<Encoder<'a>, io::IoError>>(object: &T) -> String {
+pub fn encode<'a, T: Encodable<Encoder<'a>, io::IoError>>(object: &T) -> string::String {
     let buff = Encoder::buffer_encode(object);
-    String::from_utf8(buff).unwrap()
+    string::String::from_utf8(buff).unwrap()
 }
 
 impl fmt::Show for ErrorCode {
@@ -373,9 +375,9 @@ fn spaces(wr: &mut io::Writer, mut n: uint) -> Result<(), io::IoError> {
     }
 }
 
-fn fmt_number_or_null(v: f64) -> String {
+fn fmt_number_or_null(v: f64) -> string::String {
     match v.classify() {
-        FPNaN | FPInfinite => String::from_str("null"),
+        FPNaN | FPInfinite => string::String::from_str("null"),
         _ => f64::to_str_digits(v, 6u)
     }
 }
@@ -409,7 +411,7 @@ pub fn buffer_encode<T:Encodable<Encoder<'a>, io::IoError>>(object: &T) -> Vec<u
     ///
     /// Note: this function is deprecated. Consider using `json::encode` instead.
     #[deprecated = "Replaced by `json::encode`"]
-    pub fn str_encode<T: Encodable<Encoder<'a>, io::IoError>>(object: &T) -> String {
+    pub fn str_encode<T: Encodable<Encoder<'a>, io::IoError>>(object: &T) -> string::String {
         encode(object)
     }
 }
@@ -875,15 +877,15 @@ pub fn to_pretty_writer(&self, writer: &mut io::Writer) -> EncodeResult {
     }
 
     /// Encodes a json value into a string
-    pub fn to_pretty_str(&self) -> String {
+    pub fn to_pretty_str(&self) -> string::String {
         let mut s = MemWriter::new();
         self.to_pretty_writer(&mut s as &mut io::Writer).unwrap();
-        String::from_utf8(s.unwrap()).unwrap()
+        string::String::from_utf8(s.unwrap()).unwrap()
     }
 
      /// If the Json value is an Object, returns the value associated with the provided key.
     /// Otherwise, returns None.
-    pub fn find<'a>(&'a self, key: &String) -> Option<&'a Json>{
+    pub fn find<'a>(&'a self, key: &string::String) -> Option<&'a Json>{
         match self {
             &Object(ref map) => map.find(key),
             _ => None
@@ -893,7 +895,7 @@ pub fn find<'a>(&'a self, key: &String) -> Option<&'a Json>{
     /// Attempts to get a nested Json Object for each key in `keys`.
     /// If any key is found not to exist, find_path will return None.
     /// Otherwise, it will return the Json value associated with the final key.
-    pub fn find_path<'a>(&'a self, keys: &[&String]) -> Option<&'a Json>{
+    pub fn find_path<'a>(&'a self, keys: &[&string::String]) -> Option<&'a Json>{
         let mut target = self;
         for key in keys.iter() {
             match target.find(*key) {
@@ -907,7 +909,7 @@ pub fn find_path<'a>(&'a self, keys: &[&String]) -> Option<&'a Json>{
     /// 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.
-    pub fn search<'a>(&'a self, key: &String) -> Option<&'a Json> {
+    pub fn search<'a>(&'a self, key: &string::String) -> Option<&'a Json> {
         match self {
             &Object(ref map) => {
                 match map.find(key) {
@@ -935,7 +937,7 @@ pub fn is_object<'a>(&'a self) -> bool {
 
     /// If the Json value is an Object, returns the associated TreeMap.
     /// Returns None otherwise.
-    pub fn as_object<'a>(&'a self) -> Option<&'a Object> {
+    pub fn as_object<'a>(&'a self) -> Option<&'a JsonObject> {
         match self {
             &Object(ref map) => Some(map),
             _ => None
@@ -949,7 +951,7 @@ pub fn is_list<'a>(&'a self) -> bool {
 
     /// If the Json value is a List, returns the associated vector.
     /// Returns None otherwise.
-    pub fn as_list<'a>(&'a self) -> Option<&'a List> {
+    pub fn as_list<'a>(&'a self) -> Option<&'a JsonList> {
         match self {
             &List(ref list) => Some(&*list),
             _ => None
@@ -1073,7 +1075,7 @@ pub enum JsonEvent {
     I64Value(i64),
     U64Value(u64),
     F64Value(f64),
-    StringValue(String),
+    StringValue(string::String),
     NullValue,
     Error(ParserError),
 }
@@ -1081,7 +1083,7 @@ pub enum JsonEvent {
 #[deriving(PartialEq, Show)]
 enum ParserState {
     // Parse a value in a list, true means first element.
-    ParseList(bool),
+    ParseArray(bool),
     // Parse ',' or ']' after an element in a list.
     ParseListComma,
     // Parse a key:value in an object, true means first element.
@@ -1189,7 +1191,7 @@ pub fn top<'l>(&'l self) -> Option<StackElement<'l>> {
     }
 
     // Used by Parser to insert Key elements at the top of the stack.
-    fn push_key(&mut self, key: String) {
+    fn push_key(&mut self, key: string::String) {
         self.stack.push(InternalKey(self.str_buffer.len() as u16, key.len() as u16));
         for c in key.as_bytes().iter() {
             self.str_buffer.push(*c);
@@ -1500,9 +1502,9 @@ fn decode_hex_escape(&mut self) -> Result<u16, ParserError> {
         Ok(n)
     }
 
-    fn parse_str(&mut self) -> Result<String, ParserError> {
+    fn parse_str(&mut self) -> Result<string::String, ParserError> {
         let mut escape = false;
-        let mut res = String::new();
+        let mut res = string::String::new();
 
         loop {
             self.bump();
@@ -1572,7 +1574,7 @@ fn parse(&mut self) -> JsonEvent {
             // The only paths where the loop can spin a new iteration
             // are in the cases ParseListComma and ParseObjectComma if ','
             // is parsed. In these cases the state is set to (respectively)
-            // ParseList(false) and ParseObject(false), which always return,
+            // ParseArray(false) and ParseObject(false), which always return,
             // so there is no risk of getting stuck in an infinite loop.
             // All other paths return before the end of the loop's iteration.
             self.parse_whitespace();
@@ -1581,7 +1583,7 @@ fn parse(&mut self) -> JsonEvent {
                 ParseStart => {
                     return self.parse_start();
                 }
-                ParseList(first) => {
+                ParseArray(first) => {
                     return self.parse_list(first);
                 }
                 ParseListComma => {
@@ -1613,7 +1615,7 @@ fn parse_start(&mut self) -> JsonEvent {
         let val = self.parse_value();
         self.state = match val {
             Error(_) => { ParseFinished }
-            ListStart => { ParseList(true) }
+            ListStart => { ParseArray(true) }
             ObjectStart => { ParseObject(true) }
             _ => { ParseBeforeFinish }
         };
@@ -1645,7 +1647,7 @@ fn parse_list(&mut self, first: bool) -> JsonEvent {
 
         self.state = match val {
             Error(_) => { ParseFinished }
-            ListStart => { ParseList(true) }
+            ListStart => { ParseArray(true) }
             ObjectStart => { ParseObject(true) }
             _ => { ParseListComma }
         };
@@ -1655,7 +1657,7 @@ fn parse_list(&mut self, first: bool) -> JsonEvent {
     fn parse_list_comma_or_end(&mut self) -> Option<JsonEvent> {
         if self.ch_is(',') {
             self.stack.bump_index();
-            self.state = ParseList(false);
+            self.state = ParseArray(false);
             self.bump();
             return None;
         } else if self.ch_is(']') {
@@ -1681,7 +1683,11 @@ fn parse_list_comma_or_end(&mut self) -> Option<JsonEvent> {
     fn parse_object(&mut self, first: bool) -> JsonEvent {
         if self.ch_is('}') {
             if !first {
-                self.stack.pop();
+                if self.stack.is_empty() {
+                    return self.error_event(TrailingComma);
+                } else {
+                    self.stack.pop();
+                }
             }
             if self.stack.is_empty() {
                 self.state = ParseBeforeFinish;
@@ -1722,7 +1728,7 @@ fn parse_object(&mut self, first: bool) -> JsonEvent {
 
         self.state = match val {
             Error(_) => { ParseFinished }
-            ListStart => { ParseList(true) }
+            ListStart => { ParseArray(true) }
             ObjectStart => { ParseObject(true) }
             _ => { ParseObjectComma }
         };
@@ -1824,7 +1830,7 @@ fn build_value(&mut self) -> Result<Json, BuilderError> {
             Some(F64Value(n)) => { Ok(F64(n)) }
             Some(BooleanValue(b)) => { Ok(Boolean(b)) }
             Some(StringValue(ref mut s)) => {
-                let mut temp = String::new();
+                let mut temp = string::String::new();
                 swap(s, &mut temp);
                 Ok(String(temp))
             }
@@ -1843,7 +1849,7 @@ fn build_list(&mut self) -> Result<Json, BuilderError> {
 
         loop {
             if self.token == Some(ListEnd) {
-                return Ok(List(values.move_iter().collect()));
+                return Ok(List(values.into_iter().collect()));
             }
             match self.build_value() {
                 Ok(v) => values.push(v),
@@ -2028,7 +2034,7 @@ fn read_char(&mut self) -> DecodeResult<char> {
         Err(ExpectedError("single character string".to_string(), format!("{}", s)))
     }
 
-    fn read_str(&mut self) -> DecodeResult<String> {
+    fn read_str(&mut self) -> DecodeResult<string::String> {
         debug!("read_str");
         expect!(self.pop(), String)
     }
@@ -2059,7 +2065,7 @@ fn read_enum_variant<T>(&mut self,
                 };
                 match o.pop(&"fields".to_string()) {
                     Some(List(l)) => {
-                        for field in l.move_iter().rev() {
+                        for field in l.into_iter().rev() {
                             self.stack.push(field);
                         }
                     },
@@ -2186,7 +2192,7 @@ fn read_seq<T>(&mut self, f: |&mut Decoder, uint| -> DecodeResult<T>) -> DecodeR
         debug!("read_seq()");
         let list = try!(expect!(self.pop(), List));
         let len = list.len();
-        for v in list.move_iter().rev() {
+        for v in list.into_iter().rev() {
             self.stack.push(v);
         }
         f(self, len)
@@ -2203,7 +2209,7 @@ fn read_map<T>(&mut self, f: |&mut Decoder, uint| -> DecodeResult<T>) -> DecodeR
         debug!("read_map()");
         let obj = try!(expect!(self.pop(), Object));
         let len = obj.len();
-        for (key, value) in obj.move_iter() {
+        for (key, value) in obj.into_iter() {
             self.stack.push(value);
             self.stack.push(String(key));
         }
@@ -2278,7 +2284,7 @@ impl ToJson for bool {
     fn to_json(&self) -> Json { Boolean(*self) }
 }
 
-impl ToJson for String {
+impl ToJson for string::String {
     fn to_json(&self) -> Json { String((*self).clone()) }
 }
 
@@ -2322,7 +2328,7 @@ impl<A: ToJson> ToJson for Vec<A> {
     fn to_json(&self) -> Json { List(self.iter().map(|elt| elt.to_json()).collect()) }
 }
 
-impl<A: ToJson> ToJson for TreeMap<String, A> {
+impl<A: ToJson> ToJson for TreeMap<string::String, A> {
     fn to_json(&self) -> Json {
         let mut d = TreeMap::new();
         for (key, value) in self.iter() {
@@ -2332,7 +2338,7 @@ fn to_json(&self) -> Json {
     }
 }
 
-impl<A: ToJson> ToJson for HashMap<String, A> {
+impl<A: ToJson> ToJson for HashMap<string::String, A> {
     fn to_json(&self) -> Json {
         let mut d = TreeMap::new();
         for (key, value) in self.iter() {
@@ -2369,7 +2375,7 @@ mod tests {
     extern crate test;
     use self::test::Bencher;
     use {Encodable, Decodable};
-    use super::{Encoder, Decoder, Error, Boolean, I64, U64, F64, List, String, Null,
+    use super::{List, Encoder, Decoder, Error, Boolean, I64, U64, F64, String, Null,
                 PrettyEncoder, Object, Json, from_str, ParseError, ExpectedError,
                 MissingFieldError, UnknownVariantError, DecodeResult, DecoderError,
                 JsonEvent, Parser, StackElement,
@@ -2377,9 +2383,10 @@ mod tests {
                 F64Value, StringValue, NullValue, SyntaxError, Key, Index, Stack,
                 InvalidSyntax, InvalidNumber, EOFWhileParsingObject, EOFWhileParsingList,
                 EOFWhileParsingValue, EOFWhileParsingString, KeyMustBeAString, ExpectedColon,
-                TrailingCharacters};
+                TrailingCharacters, TrailingComma};
     use std::{i64, u64, f32, f64, io};
     use std::collections::TreeMap;
+    use std::string;
 
     #[deriving(Decodable, Eq, PartialEq, Show)]
     struct OptionData {
@@ -2411,14 +2418,14 @@ fn test_decode_option_malformed() {
     #[deriving(PartialEq, Encodable, Decodable, Show)]
     enum Animal {
         Dog,
-        Frog(String, int)
+        Frog(string::String, int)
     }
 
     #[deriving(PartialEq, Encodable, Decodable, Show)]
     struct Inner {
         a: (),
         b: uint,
-        c: Vec<String>,
+        c: Vec<string::String>,
     }
 
     #[deriving(PartialEq, Encodable, Decodable, Show)]
@@ -2426,7 +2433,7 @@ struct Outer {
         inner: Vec<Inner>,
     }
 
-    fn mk_object(items: &[(String, Json)]) -> Json {
+    fn mk_object(items: &[(string::String, Json)]) -> Json {
         let mut d = TreeMap::new();
 
         for item in items.iter() {
@@ -2604,7 +2611,7 @@ fn test_write_object() {
                    from_str(a.to_pretty_str().as_slice()).unwrap());
     }
 
-    fn with_str_writer(f: |&mut io::Writer|) -> String {
+    fn with_str_writer(f: |&mut io::Writer|) -> string::String {
         use std::io::MemWriter;
         use std::str;
 
@@ -2672,7 +2679,7 @@ fn test_write_some() {
 
     #[test]
     fn test_write_none() {
-        let value: Option<String> = None;
+        let value: Option<string::String> = None;
         let s = with_str_writer(|writer| {
             let mut encoder = Encoder::new(writer);
             value.encode(&mut encoder).unwrap();
@@ -2819,7 +2826,7 @@ fn test_decode_str() {
                  ("\"\\uAB12\"", "\uAB12")];
 
         for &(i, o) in s.iter() {
-            let v: String = super::decode(i).unwrap();
+            let v: string::String = super::decode(i).unwrap();
             assert_eq!(v.as_slice(), o);
         }
     }
@@ -2953,10 +2960,10 @@ fn test_decode_struct_with_nan() {
 
     #[test]
     fn test_decode_option() {
-        let value: Option<String> = super::decode("null").unwrap();
+        let value: Option<string::String> = super::decode("null").unwrap();
         assert_eq!(value, None);
 
-        let value: Option<String> = super::decode("\"jodhpurs\"").unwrap();
+        let value: Option<string::String> = super::decode("\"jodhpurs\"").unwrap();
         assert_eq!(value, Some("jodhpurs".to_string()));
     }
 
@@ -2974,7 +2981,7 @@ fn test_decode_enum() {
     fn test_decode_map() {
         let s = "{\"a\": \"Dog\", \"b\": {\"variant\":\"Frog\",\
                   \"fields\":[\"Henry\", 349]}}";
-        let mut map: TreeMap<String, Animal> = super::decode(s).unwrap();
+        let mut map: TreeMap<string::String, Animal> = super::decode(s).unwrap();
 
         assert_eq!(map.pop(&"a".to_string()), Some(Dog));
         assert_eq!(map.pop(&"b".to_string()), Some(Frog("Henry".to_string(), 349)));
@@ -2991,13 +2998,13 @@ fn test_multiline_errors() {
     struct DecodeStruct {
         x: f64,
         y: bool,
-        z: String,
+        z: string::String,
         w: Vec<DecodeStruct>
     }
     #[deriving(Decodable)]
     enum DecodeEnum {
         A(f64),
-        B(String)
+        B(string::String)
     }
     fn check_err<T: Decodable<Decoder, DecoderError>>(to_parse: &'static str,
                                                       expected: DecoderError) {
@@ -3379,6 +3386,7 @@ fn last_event(src: &str) -> JsonEvent {
             }
         }
     }
+
     #[test]
     #[ignore(cfg(target_word_size = "32"))] // FIXME(#14064)
     fn test_read_object_streaming() {
@@ -3393,6 +3401,7 @@ fn test_read_object_streaming() {
         assert_eq!(last_event("{\"a\":1"),   Error(SyntaxError(EOFWhileParsingObject, 1, 7)));
         assert_eq!(last_event("{\"a\":1 1"), Error(SyntaxError(InvalidSyntax,         1, 8)));
         assert_eq!(last_event("{\"a\":1,"),  Error(SyntaxError(EOFWhileParsingObject, 1, 8)));
+        assert_eq!(last_event("{\"a\":1,}"), Error(SyntaxError(TrailingComma, 1, 8)));
 
         assert_stream_equal(
             "{}",
@@ -3701,7 +3710,7 @@ fn bench_small(b: &mut Bencher) {
         });
     }
 
-    fn big_json() -> String {
+    fn big_json() -> string::String {
         let mut src = "[\n".to_string();
         for _ in range(0i, 500) {
             src.push_str(r#"{ "a": true, "b": null, "c":3.1415, "d": "Hello world", "e": \