mirror of
https://github.com/pezkuwichain/serde.git
synced 2026-04-22 22:58:02 +00:00
Compare commits
25 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 206e19edb4 | |||
| f0c87fbd4c | |||
| c3fe6c9c67 | |||
| e5df4b6653 | |||
| 12cf2f0b0b | |||
| 8d4de2b3db | |||
| e509adcac5 | |||
| eb9c860cb4 | |||
| cf38b8dae5 | |||
| 75af81234f | |||
| 7cc319acca | |||
| 3b44792ff3 | |||
| 678bad241e | |||
| 5b1225cc87 | |||
| 1748831152 | |||
| ed1b476a22 | |||
| 79c59ebae1 | |||
| fd6462f8d1 | |||
| c37f67b0a1 | |||
| 195f7380b5 | |||
| becb8c48e8 | |||
| aa16ecf4d3 | |||
| ddda360fec | |||
| cca72f2dbc | |||
| 5013b37c09 |
+7
-7
@@ -1,17 +1,17 @@
|
||||
[package]
|
||||
name = "serde"
|
||||
version = "0.3.1"
|
||||
version = "0.3.3"
|
||||
authors = ["Erick Tryzelaar <erick.tryzelaar@gmail.com>"]
|
||||
license = "MIT/Apache-2.0"
|
||||
description = "A serialization/deserialization framework"
|
||||
repository = "https://github.com/erickt/rust-serde"
|
||||
description = "A generic serialization/deserialization framework"
|
||||
repository = "https://github.com/serde-rs/serde"
|
||||
documentation = "http://serde-rs.github.io/serde/serde"
|
||||
readme = "README.md"
|
||||
keywords = ["serialization"]
|
||||
|
||||
[dependencies]
|
||||
num = "*"
|
||||
|
||||
[dev-dependencies]
|
||||
rustc-serialize = "*"
|
||||
|
||||
[dev-dependencies.serde_macros]
|
||||
path = "serde_macros/"
|
||||
version = "0.3.1"
|
||||
serde_macros = { version = "*", path = "serde_macros" }
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
Serde Rust Serialization Framework
|
||||
==================================
|
||||
|
||||
[](https://travis-ci.org/erickt/rust-serde)
|
||||
[](https://travis-ci.org/serde-rs/serde)
|
||||
[](https://crates.io/crates/serde)
|
||||
|
||||
Serde is a powerful framework that enables serialization libraries to
|
||||
generically serialize Rust data structures without the overhead of runtime type
|
||||
@@ -9,7 +10,7 @@ information. In many situations, the handshake protocol between serializers and
|
||||
serializees can be completely optimized away, leaving Serde to perform roughly
|
||||
the same speed as a hand written serializer for a specific type.
|
||||
|
||||
Documentation is available at http://erickt.github.io/rust-serde/serde
|
||||
Documentation is available at http://serde-rs.github.io/serde/serde
|
||||
|
||||
Making a Type Serializable
|
||||
==========================
|
||||
@@ -17,9 +18,9 @@ Making a Type Serializable
|
||||
The simplest way to make a type serializable is to use the `serde_macros`
|
||||
syntax extension, which comes with a `#[derive(Serialize, Deserialize)]`
|
||||
annotation, which automatically generates implementations of
|
||||
[Serialize](http://erickt.github.io/rust-serde/serde/ser/trait.Serialize.html)
|
||||
[Serialize](http://serde-rs.github.io/serde/serde/ser/trait.Serialize.html)
|
||||
and
|
||||
[Deserialize](http://erickt.github.io/rust-serde/serde/de/trait.Deserialize.html)
|
||||
[Deserialize](http://serde-rs.github.io/serde/serde/de/trait.Deserialize.html)
|
||||
for the annotated type:
|
||||
|
||||
```rust
|
||||
@@ -38,11 +39,11 @@ struct Point {
|
||||
```
|
||||
|
||||
Serde bundles a high performance JSON serializer and deserializer,
|
||||
[serde::json](http://erickt.github.io/rust-serde/serde/json/index.html),
|
||||
[serde::json](http://serde-rs.github.io/serde/serde/json/index.html),
|
||||
which comes with the helper functions
|
||||
[to_string](http://erickt.github.io/rust-serde/serde/json/ser/fn.to_string.html)
|
||||
[to_string](http://serde-rs.github.io/serde/serde/json/ser/fn.to_string.html)
|
||||
and
|
||||
[from_str](http://erickt.github.io/rust-serde/serde/json/de/fn.from_str.html)
|
||||
[from_str](http://serde-rs.github.io/serde/serde/json/de/fn.from_str.html)
|
||||
that make it easy to go to and from JSON:
|
||||
|
||||
```rust
|
||||
@@ -58,19 +59,19 @@ println!("{}", serialized_point); // prints: {"x":1,"y":2}
|
||||
let deserialize_point: Point = json::from_str(&serialized_point).unwrap();
|
||||
```
|
||||
|
||||
[serde::json](http://erickt.github.io/rust-serde/serde/json/index.html) also
|
||||
[serde::json](http://serde-rs.github.io/serde/serde/json/index.html) also
|
||||
supports a generic
|
||||
[Value](http://erickt.github.io/rust-serde/serde/json/value/enum.Value.html)
|
||||
[Value](http://serde-rs.github.io/serde/serde/json/value/enum.Value.html)
|
||||
type, which can represent any JSON value. Also, any
|
||||
[Serialize](http://erickt.github.io/rust-serde/serde/ser/trait.Serialize.html)
|
||||
[Serialize](http://serde-rs.github.io/serde/serde/ser/trait.Serialize.html)
|
||||
and
|
||||
[Deserialize](http://erickt.github.io/rust-serde/serde/de/trait.Deserialize.html)
|
||||
[Deserialize](http://serde-rs.github.io/serde/serde/de/trait.Deserialize.html)
|
||||
can be converted into a
|
||||
[Value](http://erickt.github.io/rust-serde/serde/json/value/enum.Value.html)
|
||||
[Value](http://serde-rs.github.io/serde/serde/json/value/enum.Value.html)
|
||||
with the methods
|
||||
[to_value](http://erickt.github.io/rust-serde/serde/json/value/fn.to_value.html)
|
||||
[to_value](http://serde-rs.github.io/serde/serde/json/value/fn.to_value.html)
|
||||
and
|
||||
[from_value](http://erickt.github.io/rust-serde/serde/json/value/fn.from_value.html):
|
||||
[from_value](http://serde-rs.github.io/serde/serde/json/value/fn.from_value.html):
|
||||
|
||||
```rust
|
||||
let point = Point { x: 1, y: 2 };
|
||||
@@ -86,9 +87,9 @@ Serialization without Macros
|
||||
|
||||
Under the covers, Serde extensively uses the Visitor pattern to thread state
|
||||
between the
|
||||
[Serializer](http://erickt.github.io/rust-serde/serde/ser/trait.Serializer.html)
|
||||
[Serializer](http://serde-rs.github.io/serde/serde/ser/trait.Serializer.html)
|
||||
and
|
||||
[Serialize](http://erickt.github.io/rust-serde/serde/ser/trait.Serialize.html)
|
||||
[Serialize](http://serde-rs.github.io/serde/serde/ser/trait.Serialize.html)
|
||||
without the two having specific information about each other's concrete type.
|
||||
This has many of the same benefits as frameworks that use runtime type
|
||||
information without the overhead. In fact, when compiling with optimizations,
|
||||
@@ -97,7 +98,7 @@ nearly as fast as a hand written serializer format for a specific type.
|
||||
|
||||
To see it in action, lets look at how a simple type like `i32` is serialized.
|
||||
The
|
||||
[Serializer](http://erickt.github.io/rust-serde/serde/ser/trait.Serializer.html)
|
||||
[Serializer](http://serde-rs.github.io/serde/serde/ser/trait.Serializer.html)
|
||||
is threaded through the type:
|
||||
|
||||
```rust
|
||||
@@ -112,9 +113,9 @@ impl serde::Serialize for i32 {
|
||||
|
||||
As you can see it's pretty simple. More complex types like `BTreeMap` need to
|
||||
pass a
|
||||
[MapVisitor](http://erickt.github.io/rust-serde/serde/ser/trait.MapVisitor.html)
|
||||
[MapVisitor](http://serde-rs.github.io/serde/serde/ser/trait.MapVisitor.html)
|
||||
to the
|
||||
[Serializer](http://erickt.github.io/rust-serde/serde/ser/trait.Serializer.html)
|
||||
[Serializer](http://serde-rs.github.io/serde/serde/ser/trait.Serializer.html)
|
||||
in order to walk through the type:
|
||||
|
||||
```rust
|
||||
@@ -198,18 +199,18 @@ struct PointMapVisitor<'a> {
|
||||
state: u8,
|
||||
}
|
||||
|
||||
impl<'a> serde::ser::MapVisitor for PointMapVisitor {
|
||||
fn visit<S>(&mut self, serializer: &mut S) -> Result<Option(), S::Error>
|
||||
impl<'a> serde::ser::MapVisitor for PointMapVisitor<'a> {
|
||||
fn visit<S>(&mut self, serializer: &mut S) -> Result<Option<()>, S::Error>
|
||||
where S: serde::Serializer
|
||||
{
|
||||
match self.state {
|
||||
0 => {
|
||||
self.state += 1;
|
||||
Ok(Some(try!(serializer.visit_map_elt("x", &self.x)))
|
||||
Ok(Some(try!(serializer.visit_map_elt("x", &self.value.x))))
|
||||
}
|
||||
1 => {
|
||||
self.state += 1;
|
||||
Ok(Some(try!(serializer.visit_map_elt("y", &self.y))))
|
||||
Ok(Some(try!(serializer.visit_map_elt("y", &self.value.y))))
|
||||
}
|
||||
_ => {
|
||||
Ok(None)
|
||||
@@ -224,16 +225,16 @@ Deserialization without Macros
|
||||
|
||||
Deserialization is a little more complicated since there's a bit more error
|
||||
handling that needs to occur. Let's start with the simple `i32`
|
||||
[Deserialize](http://erickt.github.io/rust-serde/serde/de/trait.Deserialize.html)
|
||||
[Deserialize](http://serde-rs.github.io/serde/serde/de/trait.Deserialize.html)
|
||||
implementation. It passes a
|
||||
[Visitor](http://erickt.github.io/rust-serde/serde/de/trait.Visitor.html) to the
|
||||
[Deserializer](http://erickt.github.io/rust-serde/serde/de/trait.Deserializer.html).
|
||||
The [Visitor](http://erickt.github.io/rust-serde/serde/de/trait.Visitor.html)
|
||||
[Visitor](http://serde-rs.github.io/serde/serde/de/trait.Visitor.html) to the
|
||||
[Deserializer](http://serde-rs.github.io/serde/serde/de/trait.Deserializer.html).
|
||||
The [Visitor](http://serde-rs.github.io/serde/serde/de/trait.Visitor.html)
|
||||
can create the `i32` from a variety of different types:
|
||||
|
||||
```rust
|
||||
impl Deserialize for i32 {
|
||||
fn deserialize<D>(deserializer: &mut D) -> Result<$ty, D::Error>
|
||||
fn deserialize<D>(deserializer: &mut D) -> Result<i32, D::Error>
|
||||
where D: serde::Deserializer,
|
||||
{
|
||||
deserializer.visit(I32Visitor)
|
||||
@@ -263,9 +264,9 @@ impl serde::de::Visitor for I32Visitor {
|
||||
|
||||
Since it's possible for this type to get passed an unexpected type, we need a
|
||||
way to error out. This is done by way of the
|
||||
[Error](http://erickt.github.io/rust-serde/serde/de/trait.Error.html) trait,
|
||||
[Error](http://serde-rs.github.io/serde/serde/de/trait.Error.html) trait,
|
||||
which allows a
|
||||
[Deserialize](http://erickt.github.io/rust-serde/serde/de/trait.Deserialize.html)
|
||||
[Deserialize](http://serde-rs.github.io/serde/serde/de/trait.Deserialize.html)
|
||||
to generate an error for a few common error conditions. Here's how it could be used:
|
||||
|
||||
```rust
|
||||
@@ -282,9 +283,9 @@ to generate an error for a few common error conditions. Here's how it could be u
|
||||
```
|
||||
|
||||
Maps follow a similar pattern as before, and use a
|
||||
[MapVisitor](http://erickt.github.io/rust-serde/serde/de/trait.MapVisitor.html)
|
||||
[MapVisitor](http://serde-rs.github.io/serde/serde/de/trait.MapVisitor.html)
|
||||
to walk through the values generated by the
|
||||
[Deserializer](http://erickt.github.io/rust-serde/serde/de/trait.Deserializer.html).
|
||||
[Deserializer](http://serde-rs.github.io/serde/serde/de/trait.Deserializer.html).
|
||||
|
||||
```rust
|
||||
impl<K, V> serde::Deserialize for BTreeMap<K, V>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "serde_macros"
|
||||
version = "0.3.1"
|
||||
version = "0.3.3"
|
||||
authors = ["Erick Tryzelaar <erick.tryzelaar@gmail.com>"]
|
||||
license = "MIT/Apache-2.0"
|
||||
description = "Macros to auto-generate implementations for the serde framework"
|
||||
|
||||
@@ -361,8 +361,8 @@ fn deserialize_item_enum(
|
||||
let variant_arms: Vec<_> = enum_def.variants.iter()
|
||||
.enumerate()
|
||||
.map(|(i, variant)| {
|
||||
let variant_name = builder.expr().path()
|
||||
.id("__Field").id(format!("__field{}", i))
|
||||
let variant_name = builder.pat().enum_()
|
||||
.id("__Field").id(format!("__field{}", i)).build()
|
||||
.build();
|
||||
|
||||
let expr = deserialize_variant(
|
||||
@@ -596,7 +596,7 @@ fn deserialize_struct_visitor(
|
||||
let field_visitor = deserialize_field_visitor(
|
||||
cx,
|
||||
builder,
|
||||
field::struct_field_strs(cx, builder, struct_def),
|
||||
field::struct_field_strs(cx, builder, struct_def, field::Direction::Deserialize),
|
||||
);
|
||||
|
||||
let visit_map_expr = deserialize_map(
|
||||
@@ -639,9 +639,11 @@ fn deserialize_map(
|
||||
let extract_values: Vec<P<ast::Stmt>> = field_names.iter()
|
||||
.zip(struct_def.fields.iter())
|
||||
.map(|(field_name, field)| {
|
||||
let name_str = match field.node.kind {
|
||||
ast::NamedField(name, _) => builder.expr().str(name),
|
||||
ast::UnnamedField(_) => panic!("struct contains unnamed fields"),
|
||||
let rename = field::field_rename(field, &field::Direction::Deserialize);
|
||||
let name_str = match (rename, field.node.kind) {
|
||||
(Some(rename), _) => builder.expr().build_lit(P(rename.clone())),
|
||||
(None, ast::NamedField(name, _)) => builder.expr().str(name),
|
||||
(None, ast::UnnamedField(_)) => panic!("struct contains unnamed fields"),
|
||||
};
|
||||
|
||||
let missing_expr = if field::default_value(field) {
|
||||
|
||||
@@ -5,7 +5,19 @@ use syntax::ptr::P;
|
||||
|
||||
use aster;
|
||||
|
||||
fn field_rename(field: &ast::StructField) -> Option<&ast::Lit> {
|
||||
pub enum Direction {
|
||||
Serialize,
|
||||
Deserialize,
|
||||
}
|
||||
|
||||
pub fn field_rename<'a>(
|
||||
field: &'a ast::StructField,
|
||||
direction: &Direction,
|
||||
) -> Option<&'a ast::Lit> {
|
||||
let dir_attr = match *direction {
|
||||
Direction::Serialize => "rename_serialize",
|
||||
Direction::Deserialize => "rename_deserialize",
|
||||
};
|
||||
field.node.attrs.iter()
|
||||
.find(|sa| {
|
||||
if let ast::MetaList(ref n, _) = sa.node.value.node {
|
||||
@@ -19,7 +31,7 @@ fn field_rename(field: &ast::StructField) -> Option<&ast::Lit> {
|
||||
attr::mark_used(&sa);
|
||||
vals.iter().fold(None, |v, mi| {
|
||||
if let ast::MetaNameValue(ref n, ref lit) = mi.node {
|
||||
if n == &"rename" {
|
||||
if n == &"rename" || n == &dir_attr {
|
||||
Some(lit)
|
||||
} else {
|
||||
v
|
||||
@@ -38,10 +50,11 @@ pub fn struct_field_strs(
|
||||
cx: &ExtCtxt,
|
||||
builder: &aster::AstBuilder,
|
||||
struct_def: &ast::StructDef,
|
||||
direction: Direction,
|
||||
) -> Vec<P<ast::Expr>> {
|
||||
struct_def.fields.iter()
|
||||
.map(|field| {
|
||||
match field_rename(field) {
|
||||
match field_rename(field, &direction) {
|
||||
Some(rename) => builder.expr().build_lit(P(rename.clone())),
|
||||
None => {
|
||||
match field.node.kind {
|
||||
|
||||
@@ -13,7 +13,7 @@ use syntax::ptr::P;
|
||||
|
||||
use aster;
|
||||
|
||||
use field::struct_field_strs;
|
||||
use field::{Direction, struct_field_strs};
|
||||
|
||||
pub fn expand_derive_serialize(
|
||||
cx: &mut ExtCtxt,
|
||||
@@ -517,7 +517,7 @@ fn serialize_struct_visitor<I>(
|
||||
{
|
||||
let len = struct_def.fields.len();
|
||||
|
||||
let key_exprs = struct_field_strs(cx, builder, struct_def);
|
||||
let key_exprs = struct_field_strs(cx, builder, struct_def, Direction::Serialize);
|
||||
|
||||
let arms: Vec<ast::Arm> = key_exprs.iter()
|
||||
.zip(value_exprs)
|
||||
|
||||
+51
@@ -0,0 +1,51 @@
|
||||
use std::io;
|
||||
|
||||
pub struct LineColIterator<Iter: Iterator<Item=io::Result<u8>>> {
|
||||
iter: Iter,
|
||||
line: usize,
|
||||
col: usize,
|
||||
}
|
||||
|
||||
impl<Iter: Iterator<Item=io::Result<u8>>> LineColIterator<Iter> {
|
||||
pub fn new(iter: Iter) -> LineColIterator<Iter> {
|
||||
LineColIterator {
|
||||
iter: iter,
|
||||
line: 1,
|
||||
col: 0,
|
||||
}
|
||||
}
|
||||
|
||||
/// Report the current line inside the iterator.
|
||||
pub fn line(&self) -> usize { self.line }
|
||||
|
||||
/// Report the current column inside the iterator.
|
||||
pub fn col(&self) -> usize { self.col }
|
||||
|
||||
/// Gets a reference to the underlying iterator.
|
||||
pub fn get_ref(&self) -> &Iter { &self.iter }
|
||||
|
||||
/// Gets a mutable reference to the underlying iterator.
|
||||
pub fn get_mut(&self) -> &Iter { &self.iter }
|
||||
|
||||
/// Unwraps this `LineColIterator`, returning the underlying iterator.
|
||||
pub fn into_inner(self) -> Iter { self.iter }
|
||||
}
|
||||
|
||||
impl<Iter: Iterator<Item=io::Result<u8>>> Iterator for LineColIterator<Iter> {
|
||||
type Item = io::Result<u8>;
|
||||
fn next(&mut self) -> Option<io::Result<u8>> {
|
||||
match self.iter.next() {
|
||||
None => None,
|
||||
Some(Ok(b'\n')) => {
|
||||
self.line += 1;
|
||||
self.col = 0;
|
||||
Some(Ok(b'\n'))
|
||||
},
|
||||
Some(Ok(c)) => {
|
||||
self.col += 1;
|
||||
Some(Ok(c))
|
||||
},
|
||||
Some(Err(e)) => Some(Err(e)),
|
||||
}
|
||||
}
|
||||
}
|
||||
+10
-19
@@ -3,13 +3,13 @@ use std::io;
|
||||
use std::str;
|
||||
|
||||
use de;
|
||||
use iter::LineColIterator;
|
||||
|
||||
use super::error::{Error, ErrorCode};
|
||||
|
||||
pub struct Deserializer<Iter> {
|
||||
rdr: Iter,
|
||||
pub struct Deserializer<Iter: Iterator<Item=io::Result<u8>>> {
|
||||
rdr: LineColIterator<Iter>,
|
||||
ch: Option<u8>,
|
||||
line: usize,
|
||||
col: usize,
|
||||
str_buf: Vec<u8>,
|
||||
}
|
||||
|
||||
@@ -20,10 +20,8 @@ impl<Iter> Deserializer<Iter>
|
||||
#[inline]
|
||||
pub fn new(rdr: Iter) -> Result<Deserializer<Iter>, Error> {
|
||||
let mut deserializer = Deserializer {
|
||||
rdr: rdr,
|
||||
rdr: LineColIterator::new(rdr),
|
||||
ch: None,
|
||||
line: 1,
|
||||
col: 0,
|
||||
str_buf: Vec::with_capacity(128),
|
||||
};
|
||||
|
||||
@@ -53,13 +51,6 @@ impl<Iter> Deserializer<Iter>
|
||||
None => None,
|
||||
};
|
||||
|
||||
if self.ch_is(b'\n') {
|
||||
self.line += 1;
|
||||
self.col = 1;
|
||||
} else {
|
||||
self.col += 1;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -73,7 +64,7 @@ impl<Iter> Deserializer<Iter>
|
||||
}
|
||||
|
||||
fn error(&mut self, reason: ErrorCode) -> Error {
|
||||
Error::SyntaxError(reason, self.line, self.col)
|
||||
Error::SyntaxError(reason, self.rdr.line(), self.rdr.col())
|
||||
}
|
||||
|
||||
fn parse_whitespace(&mut self) -> Result<(), Error> {
|
||||
@@ -476,12 +467,12 @@ impl<Iter> de::Deserializer for Deserializer<Iter>
|
||||
}
|
||||
}
|
||||
|
||||
struct SeqVisitor<'a, Iter: 'a> {
|
||||
struct SeqVisitor<'a, Iter: 'a + Iterator<Item=io::Result<u8>>> {
|
||||
de: &'a mut Deserializer<Iter>,
|
||||
first: bool,
|
||||
}
|
||||
|
||||
impl<'a, Iter> SeqVisitor<'a, Iter> {
|
||||
impl<'a, Iter: Iterator<Item=io::Result<u8>>> SeqVisitor<'a, Iter> {
|
||||
fn new(de: &'a mut Deserializer<Iter>) -> Self {
|
||||
SeqVisitor {
|
||||
de: de,
|
||||
@@ -533,12 +524,12 @@ impl<'a, Iter> de::SeqVisitor for SeqVisitor<'a, Iter>
|
||||
}
|
||||
}
|
||||
|
||||
struct MapVisitor<'a, Iter: 'a> {
|
||||
struct MapVisitor<'a, Iter: 'a + Iterator<Item=io::Result<u8>>> {
|
||||
de: &'a mut Deserializer<Iter>,
|
||||
first: bool,
|
||||
}
|
||||
|
||||
impl<'a, Iter> MapVisitor<'a, Iter> {
|
||||
impl<'a, Iter: Iterator<Item=io::Result<u8>>> MapVisitor<'a, Iter> {
|
||||
fn new(de: &'a mut Deserializer<Iter>) -> Self {
|
||||
MapVisitor {
|
||||
de: de,
|
||||
|
||||
+43
-32
@@ -1,5 +1,5 @@
|
||||
use std::io;
|
||||
use std::num::{Float, FpCategory};
|
||||
use std::num::FpCategory;
|
||||
use std::string::FromUtf8Error;
|
||||
|
||||
use ser;
|
||||
@@ -17,11 +17,20 @@ pub struct Serializer<W, F=CompactFormatter> {
|
||||
impl<W> Serializer<W>
|
||||
where W: io::Write,
|
||||
{
|
||||
/// Creates a new JSON visitr whose output will be written to the writer
|
||||
/// specified.
|
||||
/// Creates a new JSON serializer.
|
||||
#[inline]
|
||||
pub fn new(writer: W) -> Serializer<W> {
|
||||
Serializer::new_with_formatter(writer, CompactFormatter)
|
||||
pub fn new(writer: W) -> Self {
|
||||
Serializer::with_formatter(writer, CompactFormatter)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, W> Serializer<W, PrettyFormatter<'a>>
|
||||
where W: io::Write,
|
||||
{
|
||||
/// Creates a new JSON pretty print serializer.
|
||||
#[inline]
|
||||
pub fn pretty(writer: W) -> Self {
|
||||
Serializer::with_formatter(writer, PrettyFormatter::new())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -29,10 +38,10 @@ impl<W, F> Serializer<W, F>
|
||||
where W: io::Write,
|
||||
F: Formatter,
|
||||
{
|
||||
/// Creates a new JSON visitr whose output will be written to the writer
|
||||
/// Creates a new JSON visitor whose output will be written to the writer
|
||||
/// specified.
|
||||
#[inline]
|
||||
pub fn new_with_formatter(writer: W, formatter: F) -> Serializer<W, F> {
|
||||
pub fn with_formatter(writer: W, formatter: F) -> Self {
|
||||
Serializer {
|
||||
writer: writer,
|
||||
formatter: formatter,
|
||||
@@ -295,16 +304,29 @@ impl Formatter for CompactFormatter {
|
||||
}
|
||||
}
|
||||
|
||||
pub struct PrettyFormatter {
|
||||
pub struct PrettyFormatter<'a> {
|
||||
current_indent: usize,
|
||||
indent: usize,
|
||||
indent: &'a [u8],
|
||||
}
|
||||
|
||||
impl Formatter for PrettyFormatter {
|
||||
impl<'a> PrettyFormatter<'a> {
|
||||
fn new() -> Self {
|
||||
PrettyFormatter::with_indent(b" ")
|
||||
}
|
||||
|
||||
fn with_indent(indent: &'a [u8]) -> Self {
|
||||
PrettyFormatter {
|
||||
current_indent: 0,
|
||||
indent: indent,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Formatter for PrettyFormatter<'a> {
|
||||
fn open<W>(&mut self, writer: &mut W, ch: u8) -> io::Result<()>
|
||||
where W: io::Write,
|
||||
{
|
||||
self.current_indent += self.indent;
|
||||
self.current_indent += 1;
|
||||
writer.write_all(&[ch])
|
||||
}
|
||||
|
||||
@@ -317,7 +339,7 @@ impl Formatter for PrettyFormatter {
|
||||
try!(writer.write_all(b",\n"));
|
||||
}
|
||||
|
||||
spaces(writer, self.current_indent)
|
||||
indent(writer, self.current_indent, self.indent)
|
||||
}
|
||||
|
||||
fn colon<W>(&mut self, writer: &mut W) -> io::Result<()>
|
||||
@@ -329,9 +351,9 @@ impl Formatter for PrettyFormatter {
|
||||
fn close<W>(&mut self, writer: &mut W, ch: u8) -> io::Result<()>
|
||||
where W: io::Write,
|
||||
{
|
||||
self.current_indent -= self.indent;
|
||||
self.current_indent -= 1;
|
||||
try!(writer.write(b"\n"));
|
||||
try!(spaces(writer, self.current_indent));
|
||||
try!(indent(writer, self.current_indent, self.indent));
|
||||
|
||||
writer.write_all(&[ch])
|
||||
}
|
||||
@@ -396,7 +418,7 @@ fn fmt_f32_or_null<W>(wr: &mut W, value: f32) -> io::Result<()>
|
||||
match value.classify() {
|
||||
FpCategory::Nan | FpCategory::Infinite => wr.write_all(b"null"),
|
||||
_ => {
|
||||
let s = value.to_string();
|
||||
let s = format!("{:?}", value);
|
||||
try!(wr.write_all(s.as_bytes()));
|
||||
if !s.contains('.') {
|
||||
try!(wr.write_all(b".0"))
|
||||
@@ -412,7 +434,7 @@ fn fmt_f64_or_null<W>(wr: &mut W, value: f64) -> io::Result<()>
|
||||
match value.classify() {
|
||||
FpCategory::Nan | FpCategory::Infinite => wr.write_all(b"null"),
|
||||
_ => {
|
||||
let s = value.to_string();
|
||||
let s = format!("{:?}", value);
|
||||
try!(wr.write_all(s.as_bytes()));
|
||||
if !s.contains('.') {
|
||||
try!(wr.write_all(b".0"))
|
||||
@@ -439,10 +461,7 @@ pub fn to_writer_pretty<W, T>(writer: &mut W, value: &T) -> io::Result<()>
|
||||
where W: io::Write,
|
||||
T: ser::Serialize,
|
||||
{
|
||||
let mut ser = Serializer::new_with_formatter(writer, PrettyFormatter {
|
||||
current_indent: 0,
|
||||
indent: 2,
|
||||
});
|
||||
let mut ser = Serializer::pretty(writer);
|
||||
try!(value.serialize(&mut ser));
|
||||
Ok(())
|
||||
}
|
||||
@@ -489,20 +508,12 @@ pub fn to_string_pretty<T>(value: &T) -> Result<String, FromUtf8Error>
|
||||
String::from_utf8(vec)
|
||||
}
|
||||
|
||||
fn spaces<W>(wr: &mut W, mut n: usize) -> io::Result<()>
|
||||
fn indent<W>(wr: &mut W, n: usize, s: &[u8]) -> io::Result<()>
|
||||
where W: io::Write,
|
||||
{
|
||||
const LEN: usize = 16;
|
||||
const BUF: &'static [u8; LEN] = &[b' '; 16];
|
||||
|
||||
while n >= LEN {
|
||||
try!(wr.write_all(BUF));
|
||||
n -= LEN;
|
||||
for _ in 0 .. n {
|
||||
try!(wr.write_all(s));
|
||||
}
|
||||
|
||||
if n > 0 {
|
||||
wr.write_all(&BUF[..n])
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
+5
-3
@@ -5,13 +5,15 @@
|
||||
//! handshake protocol between serializers and serializees can be completely optimized away,
|
||||
//! leaving serde to perform roughly the same speed as a hand written serializer for a specific
|
||||
//! type.
|
||||
#![doc(html_root_url="http://erickt.github.io/rust-serde")]
|
||||
|
||||
extern crate num;
|
||||
|
||||
pub use ser::{Serialize, Serializer};
|
||||
pub use de::{Deserialize, Deserializer, Error};
|
||||
|
||||
pub mod ser;
|
||||
pub mod de;
|
||||
pub mod json;
|
||||
pub mod bytes;
|
||||
pub mod de;
|
||||
pub mod iter;
|
||||
pub mod json;
|
||||
pub mod ser;
|
||||
|
||||
@@ -20,6 +20,13 @@ struct Rename {
|
||||
a2: i32,
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Serialize, Deserialize)]
|
||||
struct DirectionRename {
|
||||
a1: i32,
|
||||
#[serde(rename_serialize="a3", rename_deserialize="a4")]
|
||||
a2: i32,
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_default() {
|
||||
let deserialized_value: Default = json::from_str(&"{\"a1\":1,\"a2\":2}").unwrap();
|
||||
@@ -38,3 +45,13 @@ fn test_rename() {
|
||||
let deserialized_value: Rename = json::from_str(&serialized_value).unwrap();
|
||||
assert_eq!(value, deserialized_value);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_direction_rename() {
|
||||
let value = DirectionRename { a1: 1, a2: 2 };
|
||||
let serialized_value = json::to_string(&value).unwrap();
|
||||
assert_eq!(serialized_value, "{\"a1\":1,\"a3\":2}");
|
||||
|
||||
let deserialized_value = json::from_str("{\"a1\":1,\"a4\":2}").unwrap();
|
||||
assert_eq!(value, deserialized_value);
|
||||
}
|
||||
|
||||
+50
-27
@@ -1,4 +1,4 @@
|
||||
#![feature(custom_derive, plugin, test)]
|
||||
#![feature(custom_derive, plugin, test, custom_attribute)]
|
||||
#![plugin(serde_macros)]
|
||||
|
||||
extern crate test;
|
||||
@@ -668,8 +668,8 @@ fn test_parse_err<T>(errors: Vec<(&'static str, Error)>)
|
||||
#[test]
|
||||
fn test_parse_null() {
|
||||
test_parse_err::<()>(vec![
|
||||
("n", Error::SyntaxError(ErrorCode::ExpectedSomeIdent, 1, 2)),
|
||||
("nul", Error::SyntaxError(ErrorCode::ExpectedSomeIdent, 1, 4)),
|
||||
("n", Error::SyntaxError(ErrorCode::ExpectedSomeIdent, 1, 1)),
|
||||
("nul", Error::SyntaxError(ErrorCode::ExpectedSomeIdent, 1, 3)),
|
||||
("nulla", Error::SyntaxError(ErrorCode::TrailingCharacters, 1, 5)),
|
||||
]);
|
||||
|
||||
@@ -681,9 +681,9 @@ fn test_parse_null() {
|
||||
#[test]
|
||||
fn test_parse_bool() {
|
||||
test_parse_err::<bool>(vec![
|
||||
("t", Error::SyntaxError(ErrorCode::ExpectedSomeIdent, 1, 2)),
|
||||
("t", Error::SyntaxError(ErrorCode::ExpectedSomeIdent, 1, 1)),
|
||||
("truz", Error::SyntaxError(ErrorCode::ExpectedSomeIdent, 1, 4)),
|
||||
("f", Error::SyntaxError(ErrorCode::ExpectedSomeIdent, 1, 2)),
|
||||
("f", Error::SyntaxError(ErrorCode::ExpectedSomeIdent, 1, 1)),
|
||||
("faz", Error::SyntaxError(ErrorCode::ExpectedSomeIdent, 1, 3)),
|
||||
("truea", Error::SyntaxError(ErrorCode::TrailingCharacters, 1, 5)),
|
||||
("falsea", Error::SyntaxError(ErrorCode::TrailingCharacters, 1, 6)),
|
||||
@@ -702,11 +702,11 @@ fn test_parse_number_errors() {
|
||||
test_parse_err::<f64>(vec![
|
||||
("+", Error::SyntaxError(ErrorCode::ExpectedSomeValue, 1, 1)),
|
||||
(".", Error::SyntaxError(ErrorCode::ExpectedSomeValue, 1, 1)),
|
||||
("-", Error::SyntaxError(ErrorCode::InvalidNumber, 1, 2)),
|
||||
("-", Error::SyntaxError(ErrorCode::InvalidNumber, 1, 1)),
|
||||
("00", Error::SyntaxError(ErrorCode::InvalidNumber, 1, 2)),
|
||||
("1.", Error::SyntaxError(ErrorCode::InvalidNumber, 1, 3)),
|
||||
("1e", Error::SyntaxError(ErrorCode::InvalidNumber, 1, 3)),
|
||||
("1e+", Error::SyntaxError(ErrorCode::InvalidNumber, 1, 4)),
|
||||
("1.", Error::SyntaxError(ErrorCode::InvalidNumber, 1, 2)),
|
||||
("1e", Error::SyntaxError(ErrorCode::InvalidNumber, 1, 2)),
|
||||
("1e+", Error::SyntaxError(ErrorCode::InvalidNumber, 1, 3)),
|
||||
("1a", Error::SyntaxError(ErrorCode::TrailingCharacters, 1, 2)),
|
||||
]);
|
||||
}
|
||||
@@ -745,8 +745,8 @@ fn test_parse_f64() {
|
||||
#[test]
|
||||
fn test_parse_string() {
|
||||
test_parse_err::<String>(vec![
|
||||
("\"", Error::SyntaxError(ErrorCode::EOFWhileParsingString, 1, 2)),
|
||||
("\"lol", Error::SyntaxError(ErrorCode::EOFWhileParsingString, 1, 5)),
|
||||
("\"", Error::SyntaxError(ErrorCode::EOFWhileParsingString, 1, 1)),
|
||||
("\"lol", Error::SyntaxError(ErrorCode::EOFWhileParsingString, 1, 4)),
|
||||
("\"lol\"a", Error::SyntaxError(ErrorCode::TrailingCharacters, 1, 6)),
|
||||
]);
|
||||
|
||||
@@ -767,10 +767,10 @@ fn test_parse_string() {
|
||||
#[test]
|
||||
fn test_parse_list() {
|
||||
test_parse_err::<Vec<f64>>(vec![
|
||||
("[", Error::SyntaxError(ErrorCode::EOFWhileParsingValue, 1, 2)),
|
||||
("[ ", Error::SyntaxError(ErrorCode::EOFWhileParsingValue, 1, 3)),
|
||||
("[1", Error::SyntaxError(ErrorCode::EOFWhileParsingList, 1, 3)),
|
||||
("[1,", Error::SyntaxError(ErrorCode::EOFWhileParsingValue, 1, 4)),
|
||||
("[", Error::SyntaxError(ErrorCode::EOFWhileParsingValue, 1, 1)),
|
||||
("[ ", Error::SyntaxError(ErrorCode::EOFWhileParsingValue, 1, 2)),
|
||||
("[1", Error::SyntaxError(ErrorCode::EOFWhileParsingList, 1, 2)),
|
||||
("[1,", Error::SyntaxError(ErrorCode::EOFWhileParsingValue, 1, 3)),
|
||||
("[1,]", Error::SyntaxError(ErrorCode::ExpectedSomeValue, 1, 4)),
|
||||
("[1 2]", Error::SyntaxError(ErrorCode::ExpectedListCommaOrEnd, 1, 4)),
|
||||
("[]a", Error::SyntaxError(ErrorCode::TrailingCharacters, 1, 3)),
|
||||
@@ -819,17 +819,17 @@ fn test_parse_list() {
|
||||
#[test]
|
||||
fn test_parse_object() {
|
||||
test_parse_err::<BTreeMap<String, u32>>(vec![
|
||||
("{", Error::SyntaxError(ErrorCode::EOFWhileParsingValue, 1, 2)),
|
||||
("{ ", Error::SyntaxError(ErrorCode::EOFWhileParsingValue, 1, 3)),
|
||||
("{", Error::SyntaxError(ErrorCode::EOFWhileParsingValue, 1, 1)),
|
||||
("{ ", Error::SyntaxError(ErrorCode::EOFWhileParsingValue, 1, 2)),
|
||||
("{1", Error::SyntaxError(ErrorCode::KeyMustBeAString, 1, 2)),
|
||||
("{ \"a\"", Error::SyntaxError(ErrorCode::EOFWhileParsingObject, 1, 6)),
|
||||
("{\"a\"", Error::SyntaxError(ErrorCode::EOFWhileParsingObject, 1, 5)),
|
||||
("{\"a\" ", Error::SyntaxError(ErrorCode::EOFWhileParsingObject, 1, 6)),
|
||||
("{ \"a\"", Error::SyntaxError(ErrorCode::EOFWhileParsingObject, 1, 5)),
|
||||
("{\"a\"", Error::SyntaxError(ErrorCode::EOFWhileParsingObject, 1, 4)),
|
||||
("{\"a\" ", Error::SyntaxError(ErrorCode::EOFWhileParsingObject, 1, 5)),
|
||||
("{\"a\" 1", Error::SyntaxError(ErrorCode::ExpectedColon, 1, 6)),
|
||||
("{\"a\":", Error::SyntaxError(ErrorCode::EOFWhileParsingValue, 1, 6)),
|
||||
("{\"a\":1", Error::SyntaxError(ErrorCode::EOFWhileParsingObject, 1, 7)),
|
||||
("{\"a\":", Error::SyntaxError(ErrorCode::EOFWhileParsingValue, 1, 5)),
|
||||
("{\"a\":1", Error::SyntaxError(ErrorCode::EOFWhileParsingObject, 1, 6)),
|
||||
("{\"a\":1 1", Error::SyntaxError(ErrorCode::ExpectedObjectCommaOrEnd, 1, 8)),
|
||||
("{\"a\":1,", Error::SyntaxError(ErrorCode::EOFWhileParsingValue, 1, 8)),
|
||||
("{\"a\":1,", Error::SyntaxError(ErrorCode::EOFWhileParsingValue, 1, 7)),
|
||||
("{}a", Error::SyntaxError(ErrorCode::TrailingCharacters, 1, 3)),
|
||||
]);
|
||||
|
||||
@@ -870,8 +870,8 @@ fn test_parse_object() {
|
||||
#[test]
|
||||
fn test_parse_struct() {
|
||||
test_parse_err::<Outer>(vec![
|
||||
("5", Error::SyntaxError(ErrorCode::ExpectedSomeValue, 1, 2)),
|
||||
("\"hello\"", Error::SyntaxError(ErrorCode::ExpectedSomeValue, 1, 8)),
|
||||
("5", Error::SyntaxError(ErrorCode::ExpectedSomeValue, 1, 1)),
|
||||
("\"hello\"", Error::SyntaxError(ErrorCode::ExpectedSomeValue, 1, 7)),
|
||||
("{\"inner\": true}", Error::SyntaxError(ErrorCode::ExpectedSomeValue, 1, 15)),
|
||||
]);
|
||||
|
||||
@@ -933,7 +933,7 @@ fn test_parse_option() {
|
||||
fn test_parse_enum_errors() {
|
||||
test_parse_err::<Animal>(vec![
|
||||
("{}", Error::SyntaxError(ErrorCode::ExpectedSomeValue, 1, 2)),
|
||||
("{\"Dog\":", Error::SyntaxError(ErrorCode::EOFWhileParsingValue, 1, 8)),
|
||||
("{\"Dog\":", Error::SyntaxError(ErrorCode::EOFWhileParsingValue, 1, 7)),
|
||||
("{\"Dog\":}", Error::SyntaxError(ErrorCode::ExpectedSomeValue, 1, 8)),
|
||||
("{\"unknown\":[]}", Error::SyntaxError(ErrorCode::UnknownField("unknown".to_string()), 1, 11)),
|
||||
("{\"Dog\":{}}", Error::SyntaxError(ErrorCode::ExpectedSomeValue, 1, 9)),
|
||||
@@ -994,7 +994,7 @@ fn test_parse_trailing_whitespace() {
|
||||
#[test]
|
||||
fn test_multiline_errors() {
|
||||
test_parse_err::<BTreeMap<String, String>>(vec![
|
||||
("{\n \"foo\":\n \"bar\"", Error::SyntaxError(ErrorCode::EOFWhileParsingObject, 3, 8)),
|
||||
("{\n \"foo\":\n \"bar\"", Error::SyntaxError(ErrorCode::EOFWhileParsingObject, 3, 6)),
|
||||
]);
|
||||
}
|
||||
|
||||
@@ -1019,3 +1019,26 @@ fn test_missing_field() {
|
||||
))).unwrap();
|
||||
assert_eq!(value, Foo { x: Some(5) });
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_missing_renamed_field() {
|
||||
#[derive(Debug, PartialEq, Deserialize)]
|
||||
struct Foo {
|
||||
#[serde(rename_deserialize="y")]
|
||||
x: Option<u32>,
|
||||
}
|
||||
|
||||
let value: Foo = from_str("{}").unwrap();
|
||||
assert_eq!(value, Foo { x: None });
|
||||
|
||||
let value: Foo = from_str("{\"y\": 5}").unwrap();
|
||||
assert_eq!(value, Foo { x: Some(5) });
|
||||
|
||||
let value: Foo = from_value(Value::Object(treemap!())).unwrap();
|
||||
assert_eq!(value, Foo { x: None });
|
||||
|
||||
let value: Foo = from_value(Value::Object(treemap!(
|
||||
"y".to_string() => Value::I64(5)
|
||||
))).unwrap();
|
||||
assert_eq!(value, Foo { x: Some(5) });
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user