## 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 TestStruct1 {
+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());
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();
}
```
/// 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 {
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 {
}
}
-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,
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 {
// 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, "]}}")
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)
}
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));
}
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,
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, "]")
}
}
if idx != 0 {
try!(write!(self.writer, ",\n"));
}
- try!(write!(self.writer, "{}", spaces(self.indent)));
+ try!(spaces(self.writer, self.indent));
f(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, "}}")
}
}
} 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)
}
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, "]")
}
}
} else {
try!(write!(self.writer, ",\n"));
}
- try!(write!(self.writer, "{}", spaces(self.indent)));
+ try!(spaces(self.writer, self.indent));
f(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, "}}")
}
}
} 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();
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));
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.
/// 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(
/// 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() }
/// 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()
}
#[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(),
"\
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(),
#[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!(
]);
assert_eq!(
- complex_obj.to_str().into_string(),
+ complex_obj.to_string().into_string(),
"{\
\"b\":[\
{\"c\":\"\\f\\r\"},\
// 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());
}
}
}
#[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\": []}",
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);
}