]> git.lizzy.rs Git - rust.git/blobdiff - src/libserialize/json.rs
auto merge of #15999 : Kimundi/rust/fix_folder, r=nikomatsakis
[rust.git] / src / libserialize / json.rs
index 832bc9c4e10cbb2c8f6085a2303aaaa92900e8d2..0752c68f4d0b29d5bb9f107438f9cc1165345608 100644 (file)
 
 ## Using Autoserialization
 
-Create a struct called TestStruct1 and serialize and deserialize it to and from JSON
-using the serialization API, using the derived serialization code.
+Create a struct called `TestStruct` and serialize and deserialize it to and from JSON using the
+serialization API, using the derived serialization code.
 
 ```rust
 extern crate serialize;
 use serialize::json;
 
-#[deriving(Decodable, Encodable)] //generate Decodable, Encodable impl.
-pub struct TestStruct1  {
+// Automatically generate `Decodable` and `Encodable` trait implementations
+#[deriving(Decodable, Encodable)]
+pub struct TestStruct  {
     data_int: u8,
     data_str: String,
     data_vector: Vec<u8>,
 }
 
 fn main() {
-    let object = TestStruct1
-         {data_int: 1, data_str:"toto".to_string(), data_vector:vec![2,3,4,5]};
+    let object = TestStruct {
+        data_int: 1,
+        data_str: "toto".to_string(),
+        data_vector: vec![2,3,4,5],
+    };
 
     // Serialize using `json::encode`
     let encoded = json::encode(&object);
 
     // Deserialize using `json::decode`
-    let decoded: TestStruct1 = json::decode(encoded.as_slice()).unwrap();
+    let decoded: TestStruct = json::decode(encoded.as_slice()).unwrap();
 }
 ```
 
-## Using `ToJson`
+## Using the `ToJson` trait
+
+The examples above use the `ToJson` trait to generate the JSON string, which required
+for custom mappings.
+
+### Simple example of `ToJson` usage
+
+```rust
+extern crate serialize;
+use serialize::json::ToJson;
+use serialize::json;
+
+// A custom data structure
+struct ComplexNum {
+    a: f64,
+    b: f64,
+}
+
+// JSON value representation
+impl ToJson for ComplexNum {
+    fn to_json(&self) -> json::Json {
+        json::String(format!("{}+{}i", self.a, self.b))
+    }
+}
+
+// Only generate `Encodable` trait implementation
+#[deriving(Encodable)]
+pub struct ComplexNumRecord {
+    uid: u8,
+    dsc: String,
+    val: json::Json,
+}
+
+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(),
+    });
+    println!("data: {}", data);
+    // data: {"uid":1,"dsc":"test","val":"0.0001+12.539j"};
+}
+```
 
-This example uses the `ToJson` trait to generate the JSON string.
+### Verbose example of `ToJson` usage
 
 ```rust
+extern crate serialize;
 use std::collections::TreeMap;
 use serialize::json::ToJson;
 use serialize::json;
 
+// Only generate `Decodable` trait implementation
 #[deriving(Decodable)]
-pub struct TestStruct {
+pub struct TestStruct {
     data_int: u8,
     data_str: String,
     data_vector: Vec<u8>,
 }
 
-impl ToJson for TestStruct1 {
-    fn to_json( &self ) -> json::Json {
+// Specify encoding method manually
+impl ToJson for TestStruct {
+    fn to_json(&self) -> json::Json {
         let mut d = TreeMap::new();
+        // 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());
@@ -128,12 +179,16 @@ fn to_json( &self ) -> json::Json {
 
 fn main() {
     // Serialize using `ToJson`
-    let test2 = TestStruct1 {data_int: 1, data_str:"toto".to_string(), data_vector:vec![2,3,4,5]};
-    let tjson: json::Json = test2.to_json();
-    let json_str: String = tjson.to_str();
+    let input_data = TestStruct {
+        data_int: 1,
+        data_str: "toto".to_string(),
+        data_vector: vec![2,3,4,5],
+    };
+    let json_obj: json::Json = input_data.to_json();
+    let json_str: String = json_obj.to_string();
 
     // Deserialize like before
-    let decoded: TestStruct1 = json::decode(json_str.as_slice()).unwrap();
+    let decoded: TestStruct = json::decode(json_str.as_slice()).unwrap();
 }
 ```
 
@@ -240,7 +295,7 @@ 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 {
     let buff = Encoder::buffer_encode(object);
-    str::from_utf8_owned(buff).unwrap()
+    String::from_utf8(buff).unwrap()
 }
 
 impl fmt::Show for ErrorCode {
@@ -256,22 +311,63 @@ fn io_error_to_error(io: io::IoError) -> ParserError {
 pub type EncodeResult = io::IoResult<()>;
 pub type DecodeResult<T> = Result<T, DecoderError>;
 
-fn escape_str(s: &str) -> String {
-    let mut escaped = String::from_str("\"");
-    for c in s.chars() {
-        match c {
-            '"' => escaped.push_str("\\\""),
-            '\\' => escaped.push_str("\\\\"),
-            '\x08' => escaped.push_str("\\b"),
-            '\x0c' => escaped.push_str("\\f"),
-            '\n' => escaped.push_str("\\n"),
-            '\r' => escaped.push_str("\\r"),
-            '\t' => escaped.push_str("\\t"),
-            _ => escaped.push_char(c),
+pub fn escape_bytes(wr: &mut io::Writer, bytes: &[u8]) -> Result<(), io::IoError> {
+    try!(wr.write_str("\""));
+
+    let mut start = 0;
+
+    for (i, byte) in bytes.iter().enumerate() {
+        let escaped = match *byte {
+            b'"' => "\\\"",
+            b'\\' => "\\\\",
+            b'\x08' => "\\b",
+            b'\x0c' => "\\f",
+            b'\n' => "\\n",
+            b'\r' => "\\r",
+            b'\t' => "\\t",
+            _ => { continue; }
+        };
+
+        if start < i {
+            try!(wr.write(bytes.slice(start, i)));
         }
-    };
-    escaped.push_char('"');
-    escaped
+
+        try!(wr.write_str(escaped));
+
+        start = i + 1;
+    }
+
+    if start != bytes.len() {
+        try!(wr.write(bytes.slice_from(start)));
+    }
+
+    wr.write_str("\"")
+}
+
+fn escape_str(writer: &mut io::Writer, v: &str) -> Result<(), io::IoError> {
+    escape_bytes(writer, v.as_bytes())
+}
+
+fn escape_char(writer: &mut io::Writer, v: char) -> Result<(), io::IoError> {
+    let mut buf = [0, .. 4];
+    v.encode_utf8(buf);
+    escape_bytes(writer, buf)
+}
+
+fn spaces(wr: &mut io::Writer, mut n: uint) -> Result<(), io::IoError> {
+    static len: uint = 16;
+    static buf: [u8, ..len] = [b' ', ..len];
+
+    while n >= len {
+        try!(wr.write(buf));
+        n -= len;
+    }
+
+    if n > 0 {
+        wr.write(buf.slice_to(n))
+    } else {
+        Ok(())
+    }
 }
 
 fn fmt_number_or_null(v: f64) -> String {
@@ -281,10 +377,6 @@ fn fmt_number_or_null(v: f64) -> String {
     }
 }
 
-fn spaces(n: uint) -> String {
-    String::from_char(n, ' ')
-}
-
 /// A structure for implementing serialization to JSON.
 pub struct Encoder<'a> {
     writer: &'a mut io::Writer,
@@ -348,10 +440,10 @@ fn emit_f64(&mut self, v: f64) -> EncodeResult {
     fn emit_f32(&mut self, v: f32) -> EncodeResult { self.emit_f64(v as f64) }
 
     fn emit_char(&mut self, v: char) -> EncodeResult {
-        self.emit_str(str::from_char(v).as_slice())
+        escape_char(self.writer, v)
     }
     fn emit_str(&mut self, v: &str) -> EncodeResult {
-        write!(self.writer, "{}", escape_str(v))
+        escape_str(self.writer, v)
     }
 
     fn emit_enum(&mut self, _name: &str, f: |&mut Encoder<'a>| -> EncodeResult) -> EncodeResult {
@@ -367,10 +459,10 @@ fn emit_enum_variant(&mut self,
         // Bunny => "Bunny"
         // Kangaroo(34,"William") => {"variant": "Kangaroo", "fields": [34,"William"]}
         if cnt == 0 {
-            write!(self.writer, "{}", escape_str(name))
+            escape_str(self.writer, name)
         } else {
             try!(write!(self.writer, "{{\"variant\":"));
-            try!(write!(self.writer, "{}", escape_str(name)));
+            try!(escape_str(self.writer, name));
             try!(write!(self.writer, ",\"fields\":["));
             try!(f(self));
             write!(self.writer, "]}}")
@@ -415,7 +507,8 @@ fn emit_struct_field(&mut self,
                          idx: uint,
                          f: |&mut Encoder<'a>| -> EncodeResult) -> EncodeResult {
         if idx != 0 { try!(write!(self.writer, ",")); }
-        try!(write!(self.writer, "{}:", escape_str(name)));
+        try!(escape_str(self.writer, name));
+        try!(write!(self.writer, ":"));
         f(self)
     }
 
@@ -479,8 +572,7 @@ fn emit_map_elt_key(&mut self,
             let mut check_encoder = Encoder::new(&mut buf);
             try!(f(transmute(&mut check_encoder)));
         }
-        let out = str::from_utf8_owned(buf.unwrap()).unwrap();
-        let out = out.as_slice();
+        let out = str::from_utf8(buf.get_ref()).unwrap();
         let needs_wrapping = out.char_at(0) != '"' && out.char_at_reverse(out.len()) != '"';
         if needs_wrapping { try!(write!(self.writer, "\"")); }
         try!(f(self));
@@ -541,10 +633,10 @@ fn emit_f32(&mut self, v: f32) -> EncodeResult {
     }
 
     fn emit_char(&mut self, v: char) -> EncodeResult {
-        self.emit_str(str::from_char(v).as_slice())
+        escape_char(self.writer, v)
     }
     fn emit_str(&mut self, v: &str) -> EncodeResult {
-        write!(self.writer, "{}", escape_str(v))
+        escape_str(self.writer, v)
     }
 
     fn emit_enum(&mut self,
@@ -559,14 +651,18 @@ fn emit_enum_variant(&mut self,
                          cnt: uint,
                          f: |&mut PrettyEncoder<'a>| -> EncodeResult) -> EncodeResult {
         if cnt == 0 {
-            write!(self.writer, "{}", escape_str(name))
+            escape_str(self.writer, name)
         } else {
             self.indent += 2;
-            try!(write!(self.writer, "[\n{}{},\n", spaces(self.indent),
-                          escape_str(name)));
+            try!(write!(self.writer, "[\n"));
+            try!(spaces(self.writer, self.indent));
+            try!(escape_str(self.writer, name));
+            try!(write!(self.writer, ",\n"));
             try!(f(self));
             self.indent -= 2;
-            write!(self.writer, "\n{}]", spaces(self.indent))
+            try!(write!(self.writer, "\n"));
+            try!(spaces(self.writer, self.indent));
+            write!(self.writer, "]")
         }
     }
 
@@ -576,7 +672,7 @@ fn emit_enum_variant_arg(&mut self,
         if idx != 0 {
             try!(write!(self.writer, ",\n"));
         }
-        try!(write!(self.writer, "{}", spaces(self.indent)));
+        try!(spaces(self.writer, self.indent));
         f(self)
     }
 
@@ -607,7 +703,9 @@ fn emit_struct(&mut self,
             self.indent += 2;
             try!(f(self));
             self.indent -= 2;
-            write!(self.writer, "\n{}}}", spaces(self.indent))
+            try!(write!(self.writer, "\n"));
+            try!(spaces(self.writer, self.indent));
+            write!(self.writer, "}}")
         }
     }
 
@@ -620,7 +718,9 @@ fn emit_struct_field(&mut self,
         } else {
             try!(write!(self.writer, ",\n"));
         }
-        try!(write!(self.writer, "{}{}: ", spaces(self.indent), escape_str(name)));
+        try!(spaces(self.writer, self.indent));
+        try!(escape_str(self.writer, name));
+        try!(write!(self.writer, ": "));
         f(self)
     }
 
@@ -665,7 +765,9 @@ fn emit_seq(&mut self,
             self.indent += 2;
             try!(f(self));
             self.indent -= 2;
-            write!(self.writer, "\n{}]", spaces(self.indent))
+            try!(write!(self.writer, "\n"));
+            try!(spaces(self.writer, self.indent));
+            write!(self.writer, "]")
         }
     }
 
@@ -677,7 +779,7 @@ fn emit_seq_elt(&mut self,
         } else {
             try!(write!(self.writer, ",\n"));
         }
-        try!(write!(self.writer, "{}", spaces(self.indent)));
+        try!(spaces(self.writer, self.indent));
         f(self)
     }
 
@@ -691,7 +793,9 @@ fn emit_map(&mut self,
             self.indent += 2;
             try!(f(self));
             self.indent -= 2;
-            write!(self.writer, "\n{}}}", spaces(self.indent))
+            try!(write!(self.writer, "\n"));
+            try!(spaces(self.writer, self.indent));
+            write!(self.writer, "}}")
         }
     }
 
@@ -703,7 +807,7 @@ fn emit_map_elt_key(&mut self,
         } else {
             try!(write!(self.writer, ",\n"));
         }
-        try!(write!(self.writer, "{}", spaces(self.indent)));
+        try!(spaces(self.writer, self.indent));
         // ref #12967, make sure to wrap a key in double quotes,
         // in the event that its of a type that omits them (eg numbers)
         let mut buf = MemWriter::new();
@@ -712,8 +816,7 @@ fn emit_map_elt_key(&mut self,
             let mut check_encoder = PrettyEncoder::new(&mut buf);
             try!(f(transmute(&mut check_encoder)));
         }
-        let out = str::from_utf8_owned(buf.unwrap()).unwrap();
-        let out = out.as_slice();
+        let out = str::from_utf8(buf.get_ref()).unwrap();
         let needs_wrapping = out.char_at(0) != '"' && out.char_at_reverse(out.len()) != '"';
         if needs_wrapping { try!(write!(self.writer, "\"")); }
         try!(f(self));
@@ -760,7 +863,7 @@ pub fn to_pretty_writer(&self, writer: &mut io::Writer) -> EncodeResult {
     pub fn to_pretty_str(&self) -> String {
         let mut s = MemWriter::new();
         self.to_pretty_writer(&mut s as &mut io::Writer).unwrap();
-        str::from_utf8_owned(s.unwrap()).unwrap()
+        String::from_utf8(s.unwrap()).unwrap()
     }
 
      /// If the Json value is an Object, returns the value associated with the provided key.
@@ -967,7 +1070,7 @@ pub fn is_empty(&self) -> bool { self.stack.is_empty() }
     /// lower indices are at the bottom of the stack while higher indices are
     /// at the top.
     pub fn get<'l>(&'l self, idx: uint) -> StackElement<'l> {
-        match *self.stack.get(idx) {
+        match self.stack[idx] {
             InternalIndex(i) => { Index(i) }
             InternalKey(start, size) => {
                 Key(str::from_utf8(
@@ -1118,7 +1221,7 @@ pub fn new(rdr: T) -> Parser<T> {
     /// Provides access to the current position in the logical structure of the
     /// JSON stream.
     pub fn stack<'l>(&'l self) -> &'l Stack {
-        return &'l self.stack;
+        return &self.stack;
     }
 
     fn eof(&self) -> bool { self.ch.is_none() }
@@ -1678,14 +1781,14 @@ fn build_object(&mut self) -> Result<Json, BuilderError> {
 /// Decodes a json value from an `&mut io::Reader`
 pub fn from_reader(rdr: &mut io::Reader) -> Result<Json, BuilderError> {
     let contents = match rdr.read_to_end() {
-        Ok(c) => c,
+        Ok(c)  => c,
         Err(e) => return Err(io_error_to_error(e))
     };
-    let s = match str::from_utf8_owned(contents) {
-        Ok(s) => s,
-        _ => return Err(SyntaxError(NotUtf8, 0, 0))
+    let s = match str::from_utf8(contents.as_slice()) {
+        Some(s) => s,
+        _       => return Err(SyntaxError(NotUtf8, 0, 0))
     };
-    let mut builder = Builder::new(s.as_slice().chars());
+    let mut builder = Builder::new(s.chars());
     builder.build()
 }
 
@@ -2152,59 +2255,59 @@ fn test_from_str_trait() {
 
     #[test]
     fn test_write_null() {
-        assert_eq!(Null.to_str().into_string(), "null".to_string());
+        assert_eq!(Null.to_string().into_string(), "null".to_string());
         assert_eq!(Null.to_pretty_str().into_string(), "null".to_string());
     }
 
 
     #[test]
     fn test_write_number() {
-        assert_eq!(Number(3.0).to_str().into_string(), "3".to_string());
+        assert_eq!(Number(3.0).to_string().into_string(), "3".to_string());
         assert_eq!(Number(3.0).to_pretty_str().into_string(), "3".to_string());
 
-        assert_eq!(Number(3.1).to_str().into_string(), "3.1".to_string());
+        assert_eq!(Number(3.1).to_string().into_string(), "3.1".to_string());
         assert_eq!(Number(3.1).to_pretty_str().into_string(), "3.1".to_string());
 
-        assert_eq!(Number(-1.5).to_str().into_string(), "-1.5".to_string());
+        assert_eq!(Number(-1.5).to_string().into_string(), "-1.5".to_string());
         assert_eq!(Number(-1.5).to_pretty_str().into_string(), "-1.5".to_string());
 
-        assert_eq!(Number(0.5).to_str().into_string(), "0.5".to_string());
+        assert_eq!(Number(0.5).to_string().into_string(), "0.5".to_string());
         assert_eq!(Number(0.5).to_pretty_str().into_string(), "0.5".to_string());
 
-        assert_eq!(Number(f64::NAN).to_str().into_string(), "null".to_string());
+        assert_eq!(Number(f64::NAN).to_string().into_string(), "null".to_string());
         assert_eq!(Number(f64::NAN).to_pretty_str().into_string(), "null".to_string());
 
-        assert_eq!(Number(f64::INFINITY).to_str().into_string(), "null".to_string());
+        assert_eq!(Number(f64::INFINITY).to_string().into_string(), "null".to_string());
         assert_eq!(Number(f64::INFINITY).to_pretty_str().into_string(), "null".to_string());
 
-        assert_eq!(Number(f64::NEG_INFINITY).to_str().into_string(), "null".to_string());
+        assert_eq!(Number(f64::NEG_INFINITY).to_string().into_string(), "null".to_string());
         assert_eq!(Number(f64::NEG_INFINITY).to_pretty_str().into_string(), "null".to_string());
     }
 
     #[test]
     fn test_write_str() {
-        assert_eq!(String("".to_string()).to_str().into_string(), "\"\"".to_string());
+        assert_eq!(String("".to_string()).to_string().into_string(), "\"\"".to_string());
         assert_eq!(String("".to_string()).to_pretty_str().into_string(), "\"\"".to_string());
 
-        assert_eq!(String("foo".to_string()).to_str().into_string(), "\"foo\"".to_string());
+        assert_eq!(String("foo".to_string()).to_string().into_string(), "\"foo\"".to_string());
         assert_eq!(String("foo".to_string()).to_pretty_str().into_string(), "\"foo\"".to_string());
     }
 
     #[test]
     fn test_write_bool() {
-        assert_eq!(Boolean(true).to_str().into_string(), "true".to_string());
+        assert_eq!(Boolean(true).to_string().into_string(), "true".to_string());
         assert_eq!(Boolean(true).to_pretty_str().into_string(), "true".to_string());
 
-        assert_eq!(Boolean(false).to_str().into_string(), "false".to_string());
+        assert_eq!(Boolean(false).to_string().into_string(), "false".to_string());
         assert_eq!(Boolean(false).to_pretty_str().into_string(), "false".to_string());
     }
 
     #[test]
     fn test_write_list() {
-        assert_eq!(List(vec![]).to_str().into_string(), "[]".to_string());
+        assert_eq!(List(vec![]).to_string().into_string(), "[]".to_string());
         assert_eq!(List(vec![]).to_pretty_str().into_string(), "[]".to_string());
 
-        assert_eq!(List(vec![Boolean(true)]).to_str().into_string(), "[true]".to_string());
+        assert_eq!(List(vec![Boolean(true)]).to_string().into_string(), "[true]".to_string());
         assert_eq!(
             List(vec![Boolean(true)]).to_pretty_str().into_string(),
             "\
@@ -2218,7 +2321,7 @@ fn test_write_list() {
             Null,
             List(vec![String("foo\nbar".to_string()), Number(3.5)])]);
 
-        assert_eq!(long_test_list.to_str().into_string(),
+        assert_eq!(long_test_list.to_string().into_string(),
             "[false,null,[\"foo\\nbar\",3.5]]".to_string());
         assert_eq!(
             long_test_list.to_pretty_str().into_string(),
@@ -2236,13 +2339,13 @@ fn test_write_list() {
 
     #[test]
     fn test_write_object() {
-        assert_eq!(mk_object([]).to_str().into_string(), "{}".to_string());
+        assert_eq!(mk_object([]).to_string().into_string(), "{}".to_string());
         assert_eq!(mk_object([]).to_pretty_str().into_string(), "{}".to_string());
 
         assert_eq!(
             mk_object([
                 ("a".to_string(), Boolean(true))
-            ]).to_str().into_string(),
+            ]).to_string().into_string(),
             "{\"a\":true}".to_string()
         );
         assert_eq!(
@@ -2261,7 +2364,7 @@ fn test_write_object() {
             ]);
 
         assert_eq!(
-            complex_obj.to_str().into_string(),
+            complex_obj.to_string().into_string(),
             "{\
                 \"b\":[\
                     {\"c\":\"\\f\\r\"},\
@@ -2294,7 +2397,7 @@ fn test_write_object() {
 
         // We can't compare the strings directly because the object fields be
         // printed in a different order.
-        assert_eq!(a.clone(), from_str(a.to_str().as_slice()).unwrap());
+        assert_eq!(a.clone(), from_str(a.to_string().as_slice()).unwrap());
         assert_eq!(a.clone(),
                    from_str(a.to_pretty_str().as_slice()).unwrap());
     }
@@ -2692,6 +2795,7 @@ fn check_err<T: Decodable<Decoder, DecoderError>>(to_parse: &'static str,
         }
     }
     #[test]
+    #[ignore] // FIXME(#15763)
     fn test_decode_errors_struct() {
         check_err::<DecodeStruct>("[]", ExpectedError("Object".to_string(), "[]".to_string()));
         check_err::<DecodeStruct>("{\"x\": true, \"y\": true, \"z\": \"\", \"w\": []}",
@@ -2887,7 +2991,7 @@ fn assert_stream_equal(src: &str,
                 Some(e) => e,
                 None => { break; }
             };
-            let (ref expected_evt, ref expected_stack) = *expected.get(i);
+            let (ref expected_evt, ref expected_stack) = expected[i];
             if !parser.stack().is_equal_to(expected_stack.as_slice()) {
                 fail!("Parser stack is not equal to {}", expected_stack);
             }