This commit is contained in:
Alex Crichton 2015-04-02 17:07:26 -07:00
parent 2d49247b92
commit 41563ee01b
7 changed files with 717 additions and 0 deletions

View file

@ -17,9 +17,11 @@ facilitate deserializing and serializing Rust structures.
[dependencies]
rustc-serialize = { optional = true, version = "0.3.0" }
serde = { optional = true, git = "https://github.com/alexcrichton/rust-serde", branch = "tweak-some-impls" }
[features]
default = ["rustc-serialize"]
[dev-dependencies]
rustc-serialize = "0.3"
serde_macros = { git = "https://github.com/alexcrichton/rust-serde", branch = "tweak-some-impls" }

View file

@ -5,6 +5,7 @@ use Value;
use self::DecodeErrorKind::*;
#[cfg(feature = "rustc-serialize")] mod rustc_serialize;
#[cfg(feature = "serde")] mod serde;
/// A structure to transform TOML values into Rust values.
///

152
src/decoder/serde.rs Normal file
View file

@ -0,0 +1,152 @@
use serde::de;
use Value;
use super::{Decoder, DecodeError, DecodeErrorKind};
struct DecodeValue(Value);
struct MapVisitor<I>(I, Option<Value>);
struct SubDecoder(Decoder);
fn se2toml(err: de::value::Error, ty: &'static str) -> DecodeError {
match err {
de::value::Error::SyntaxError => de::Error::syntax_error(),
de::value::Error::EndOfStreamError => de::Error::end_of_stream_error(),
de::value::Error::MissingFieldError(s) => {
DecodeError {
field: Some(s.to_string()),
kind: DecodeErrorKind::ExpectedField(Some(ty)),
}
}
}
}
impl de::Deserializer for Decoder {
type Error = DecodeError;
fn visit<V>(&mut self, mut visitor: V) -> Result<V::Value, DecodeError>
where V: de::Visitor
{
match self.toml.take() {
Some(Value::String(s)) => {
visitor.visit_string(s).map_err(|e| se2toml(e, "string"))
}
Some(Value::Integer(i)) => {
visitor.visit_i64(i).map_err(|e| se2toml(e, "integer"))
}
Some(Value::Float(f)) => {
visitor.visit_f64(f).map_err(|e| se2toml(e, "float"))
}
Some(Value::Boolean(b)) => {
visitor.visit_bool(b).map_err(|e| se2toml(e, "bool"))
}
Some(Value::Datetime(s)) => {
visitor.visit_string(s).map_err(|e| se2toml(e, "date"))
}
Some(Value::Array(a)) => {
let len = a.len();
let iter = a.into_iter().map(DecodeValue);
let e = visitor.visit_seq(de::value::SeqDeserializer::new(iter,
len));
e.map_err(|e| se2toml(e, "array"))
}
Some(Value::Table(t)) => {
visitor.visit_map(MapVisitor(t.into_iter(), None))
}
None => Err(de::Error::end_of_stream_error()),
}
}
fn visit_option<V>(&mut self, mut visitor: V) -> Result<V::Value, DecodeError>
where V: de::Visitor
{
if self.toml.is_none() {
visitor.visit_none()
} else {
visitor.visit_some(self)
}
}
fn visit_seq<V>(&mut self, mut visitor: V) -> Result<V::Value, DecodeError>
where V: de::Visitor,
{
if self.toml.is_none() {
let iter = None::<i32>.into_iter();
let e = visitor.visit_seq(de::value::SeqDeserializer::new(iter, 0));
e.map_err(|e| se2toml(e, "array"))
} else {
self.visit(visitor)
}
}
}
impl de::Error for DecodeError {
fn syntax_error() -> DecodeError {
DecodeError { field: None, kind: DecodeErrorKind::SyntaxError }
}
fn end_of_stream_error() -> DecodeError {
DecodeError { field: None, kind: DecodeErrorKind::EndOfStream }
}
fn missing_field_error(name: &'static str) -> DecodeError {
DecodeError {
field: Some(name.to_string()),
kind: DecodeErrorKind::ExpectedField(None),
}
}
}
impl de::Deserializer for SubDecoder {
type Error = de::value::Error;
fn visit<V>(&mut self, visitor: V) -> Result<V::Value, de::value::Error>
where V: de::Visitor
{
self.0.visit(visitor).map_err(|e| {
match e.kind {
DecodeErrorKind::SyntaxError => de::value::Error::SyntaxError,
DecodeErrorKind::EndOfStream => de::value::Error::EndOfStreamError,
_ => de::value::Error::SyntaxError,
}
})
}
}
impl de::value::ValueDeserializer for DecodeValue {
type Deserializer = SubDecoder;
fn into_deserializer(self) -> SubDecoder {
SubDecoder(Decoder::new(self.0))
}
}
impl<I> de::MapVisitor for MapVisitor<I>
where I: Iterator<Item=(String, Value)>
{
type Error = DecodeError;
fn visit_key<K>(&mut self) -> Result<Option<K>, DecodeError>
where K: de::Deserialize
{
match self.0.next() {
Some((k, v)) => {
self.1 = Some(v);
de::Deserialize::deserialize(&mut Decoder::new(Value::String(k)))
.map(|v| Some(v))
}
None => Ok(None),
}
}
fn visit_value<V>(&mut self) -> Result<V, DecodeError>
where V: de::Deserialize
{
match self.1.take() {
Some(t) => de::Deserialize::deserialize(&mut Decoder::new(t)),
None => Err(de::Error::end_of_stream_error())
}
}
fn end(&mut self) -> Result<(), DecodeError> {
Ok(())
}
}

View file

@ -6,6 +6,7 @@ use std::mem;
use {Value, Table};
#[cfg(feature = "rustc-serialize")] mod rustc_serialize;
#[cfg(feature = "serde")] mod serde;
/// A structure to transform Rust values into TOML values.
///

84
src/encoder/serde.rs Normal file
View file

@ -0,0 +1,84 @@
use serde::ser;
use Value;
use super::{Encoder, Error};
impl ser::Serializer for Encoder {
type Error = Error;
fn visit_bool(&mut self, v: bool) -> Result<(), Error> {
self.emit_value(Value::Boolean(v))
}
fn visit_i64(&mut self, v: i64) -> Result<(), Error> {
self.emit_value(Value::Integer(v))
}
fn visit_u64(&mut self, v: u64) -> Result<(), Error> {
self.visit_i64(v as i64)
}
fn visit_f64(&mut self, v: f64) -> Result<(), Error> {
self.emit_value(Value::Float(v))
}
fn visit_str(&mut self, value: &str) -> Result<(), Error> {
self.emit_value(Value::String(value.to_string()))
}
fn visit_unit(&mut self) -> Result<(), Error> {
Ok(())
}
fn visit_none(&mut self) -> Result<(), Error> {
self.emit_none()
}
fn visit_some<V>(&mut self, value: V) -> Result<(), Error>
where V: ser::Serialize
{
value.serialize(self)
}
fn visit_seq<V>(&mut self, mut visitor: V) -> Result<(), Error>
where V: ser::SeqVisitor
{
self.seq(|me| {
while try!(visitor.visit(me)).is_some() {}
Ok(())
})
}
fn visit_seq_elt<T>(&mut self, value: T) -> Result<(), Error>
where T: ser::Serialize
{
value.serialize(self)
}
fn visit_map<V>(&mut self, mut visitor: V) -> Result<(), Error>
where V: ser::MapVisitor
{
self.table(|me| {
while try!(visitor.visit(me)).is_some() {}
Ok(())
})
}
fn visit_map_elt<K, V>(&mut self, key: K, value: V) -> Result<(), Error>
where K: ser::Serialize, V: ser::Serialize
{
try!(self.table_key(|me| key.serialize(me)));
try!(value.serialize(self));
Ok(())
}
}
impl ser::Serialize for Value {
fn serialize<E>(&self, e: &mut E) -> Result<(), E::Error>
where E: ser::Serializer
{
match *self {
Value::String(ref s) => e.visit_str(s),
Value::Integer(i) => e.visit_i64(i),
Value::Float(f) => e.visit_f64(f),
Value::Boolean(b) => e.visit_bool(b),
Value::Datetime(ref s) => e.visit_str(s),
Value::Array(ref a) => {
e.visit_seq(ser::impls::SeqIteratorVisitor::new(a.iter(),
Some(a.len())))
}
Value::Table(ref t) => {
e.visit_map(ser::impls::MapIteratorVisitor::new(t.iter(),
Some(t.len())))
}
}
}
}

View file

@ -40,6 +40,7 @@
#![cfg_attr(test, deny(warnings))]
#[cfg(feature = "rustc-serialize")] extern crate rustc_serialize;
#[cfg(feature = "serde")] extern crate serde;
use std::collections::BTreeMap;
use std::str::FromStr;

476
tests/serde.rs Normal file
View file

@ -0,0 +1,476 @@
#![cfg(feature = "serde")]
#![feature(custom_derive, plugin)]
#![plugin(serde_macros)]
extern crate serde;
extern crate toml;
use std::collections::{BTreeMap, HashSet};
use serde::{Deserialize, Serialize, Deserializer};
use toml::{Encoder, Decoder, DecodeError};
use toml::Value;
use toml::Value::{Table, Integer, Array, Float};
macro_rules! t {
($e:expr) => (match $e {
Ok(t) => t,
Err(e) => panic!("{} failed with {}", stringify!($e), e),
})
}
macro_rules! encode( ($t:expr) => ({
let mut e = Encoder::new();
t!($t.serialize(&mut e));
e.toml
}) );
macro_rules! decode( ($t:expr) => ({
let mut d = Decoder::new($t);
t!(Deserialize::deserialize(&mut d))
}) );
macro_rules! map( ($($k:ident, $v:expr),*) => ({
let mut _m = BTreeMap::new();
$(_m.insert(stringify!($k).to_string(), $v);)*
_m
}) );
#[test]
fn smoke() {
#[derive(Serialize, Deserialize, PartialEq, Debug)]
struct Foo { a: isize }
let v = Foo { a: 2 };
assert_eq!(encode!(v), map! { a, Integer(2) });
assert_eq!(v, decode!(Table(encode!(v))));
}
#[test]
fn smoke_hyphen() {
#[derive(Serialize, Deserialize, PartialEq, Debug)]
struct Foo { a_b: isize }
let v = Foo { a_b: 2 };
assert_eq!(encode!(v), map! { a_b, Integer(2) });
assert_eq!(v, decode!(Table(encode!(v))));
let mut m = BTreeMap::new();
m.insert("a-b".to_string(), Integer(2));
assert_eq!(v, decode!(Table(encode!(v))));
}
#[test]
fn nested() {
#[derive(Serialize, Deserialize, PartialEq, Debug)]
struct Foo { a: isize, b: Bar }
#[derive(Serialize, Deserialize, PartialEq, Debug)]
struct Bar { a: String }
let v = Foo { a: 2, b: Bar { a: "test".to_string() } };
assert_eq!(encode!(v),
map! {
a, Integer(2),
b, Table(map! {
a, Value::String("test".to_string())
})
});
assert_eq!(v, decode!(Table(encode!(v))));
}
#[test]
fn application_decode_error() {
#[derive(PartialEq, Debug)]
struct Range10(usize);
impl Deserialize for Range10 {
fn deserialize<D: Deserializer>(d: &mut D) -> Result<Range10, D::Error> {
let x: usize = try!(Deserialize::deserialize(d));
if x > 10 {
Err(serde::de::Error::syntax_error())
} else {
Ok(Range10(x))
}
}
}
let mut d_good = Decoder::new(Integer(5));
let mut d_bad1 = Decoder::new(Value::String("not an isize".to_string()));
let mut d_bad2 = Decoder::new(Integer(11));
assert_eq!(Ok(Range10(5)), Deserialize::deserialize(&mut d_good));
let err1: Result<Range10, _> = Deserialize::deserialize(&mut d_bad1);
assert!(err1.is_err());
let err2: Result<Range10, _> = Deserialize::deserialize(&mut d_bad2);
assert!(err2.is_err());
}
#[test]
fn array() {
#[derive(Serialize, Deserialize, PartialEq, Debug)]
struct Foo { a: Vec<isize> }
let v = Foo { a: vec![1, 2, 3, 4] };
assert_eq!(encode!(v),
map! {
a, Array(vec![
Integer(1),
Integer(2),
Integer(3),
Integer(4)
])
});
assert_eq!(v, decode!(Table(encode!(v))));
}
#[test]
fn tuple() {
#[derive(Serialize, Deserialize, PartialEq, Debug)]
struct Foo { a: (isize, isize, isize, isize) }
let v = Foo { a: (1, 2, 3, 4) };
assert_eq!(encode!(v),
map! {
a, Array(vec![
Integer(1),
Integer(2),
Integer(3),
Integer(4)
])
});
assert_eq!(v, decode!(Table(encode!(v))));
}
#[test]
fn inner_structs_with_options() {
#[derive(Serialize, Deserialize, PartialEq, Debug)]
struct Foo {
a: Option<Box<Foo>>,
b: Bar,
}
#[derive(Serialize, Deserialize, PartialEq, Debug)]
struct Bar {
a: String,
b: f64,
}
let v = Foo {
a: Some(Box::new(Foo {
a: None,
b: Bar { a: "foo".to_string(), b: 4.5 },
})),
b: Bar { a: "bar".to_string(), b: 1.0 },
};
assert_eq!(encode!(v),
map! {
a, Table(map! {
b, Table(map! {
a, Value::String("foo".to_string()),
b, Float(4.5)
})
}),
b, Table(map! {
a, Value::String("bar".to_string()),
b, Float(1.0)
})
});
assert_eq!(v, decode!(Table(encode!(v))));
}
#[test]
fn hashmap() {
#[derive(Serialize, Deserialize, PartialEq, Debug)]
struct Foo {
map: BTreeMap<String, isize>,
set: HashSet<char>,
}
let v = Foo {
map: {
let mut m = BTreeMap::new();
m.insert("foo".to_string(), 10);
m.insert("bar".to_string(), 4);
m
},
set: {
let mut s = HashSet::new();
s.insert('a');
s
},
};
assert_eq!(encode!(v),
map! {
map, Table(map! {
foo, Integer(10),
bar, Integer(4)
}),
set, Array(vec![Value::String("a".to_string())])
}
);
assert_eq!(v, decode!(Table(encode!(v))));
}
#[test]
fn tuple_struct() {
#[derive(Serialize, Deserialize, PartialEq, Debug)]
struct Foo(isize, String, f64);
let v = Foo(1, "foo".to_string(), 4.5);
assert_eq!(
encode!(v),
map! {
_field0, Integer(1),
_field1, Value::String("foo".to_string()),
_field2, Float(4.5)
}
);
assert_eq!(v, decode!(Table(encode!(v))));
}
#[test]
fn table_array() {
#[derive(Serialize, Deserialize, PartialEq, Debug)]
struct Foo { a: Vec<Bar>, }
#[derive(Serialize, Deserialize, PartialEq, Debug)]
struct Bar { a: isize }
let v = Foo { a: vec![Bar { a: 1 }, Bar { a: 2 }] };
assert_eq!(
encode!(v),
map! {
a, Array(vec![
Table(map!{ a, Integer(1) }),
Table(map!{ a, Integer(2) }),
])
}
);
assert_eq!(v, decode!(Table(encode!(v))));
}
#[test]
fn type_errors() {
#[derive(Serialize, Deserialize, PartialEq, Debug)]
struct Foo { bar: isize }
let mut d = Decoder::new(Table(map! {
bar, Float(1.0)
}));
let a: Result<Foo, DecodeError> = Deserialize::deserialize(&mut d);
match a {
Ok(..) => panic!("should not have decoded"),
Err(e) => {
assert_eq!(format!("{}", e),
"expected a value of type `integer`, but \
found a value of type `float` for the key `bar`");
}
}
}
#[test]
fn missing_errors() {
#[derive(Serialize, Deserialize, PartialEq, Debug)]
struct Foo { bar: isize }
let mut d = Decoder::new(Table(map! {
}));
let a: Result<Foo, DecodeError> = Deserialize::deserialize(&mut d);
match a {
Ok(..) => panic!("should not have decoded"),
Err(e) => {
assert_eq!(format!("{}", e),
"expected a value of type `integer` for the key `bar`");
}
}
}
#[test]
fn parse_enum() {
#[derive(Serialize, Deserialize, PartialEq, Debug)]
struct Foo { a: E }
#[derive(Serialize, Deserialize, PartialEq, Debug)]
enum E {
Bar(isize),
Baz(f64),
Last(Foo2),
}
#[derive(Serialize, Deserialize, PartialEq, Debug)]
struct Foo2 {
test: String,
}
let v = Foo { a: E::Bar(10) };
assert_eq!(
encode!(v),
map! { a, Integer(10) }
);
assert_eq!(v, decode!(Table(encode!(v))));
let v = Foo { a: E::Baz(10.2) };
assert_eq!(
encode!(v),
map! { a, Float(10.2) }
);
assert_eq!(v, decode!(Table(encode!(v))));
let v = Foo { a: E::Last(Foo2 { test: "test".to_string() }) };
assert_eq!(
encode!(v),
map! { a, Table(map! { test, Value::String("test".to_string()) }) }
);
assert_eq!(v, decode!(Table(encode!(v))));
}
#[test]
fn unused_fields() {
#[derive(Serialize, Deserialize, PartialEq, Debug)]
struct Foo { a: isize }
let v = Foo { a: 2 };
let mut d = Decoder::new(Table(map! {
a, Integer(2),
b, Integer(5)
}));
assert_eq!(v, t!(Deserialize::deserialize(&mut d)));
assert_eq!(d.toml, Some(Table(map! {
b, Integer(5)
})));
}
#[test]
fn unused_fields2() {
#[derive(Serialize, Deserialize, PartialEq, Debug)]
struct Foo { a: Bar }
#[derive(Serialize, Deserialize, PartialEq, Debug)]
struct Bar { a: isize }
let v = Foo { a: Bar { a: 2 } };
let mut d = Decoder::new(Table(map! {
a, Table(map! {
a, Integer(2),
b, Integer(5)
})
}));
assert_eq!(v, t!(Deserialize::deserialize(&mut d)));
assert_eq!(d.toml, Some(Table(map! {
a, Table(map! {
b, Integer(5)
})
})));
}
#[test]
fn unused_fields3() {
#[derive(Serialize, Deserialize, PartialEq, Debug)]
struct Foo { a: Bar }
#[derive(Serialize, Deserialize, PartialEq, Debug)]
struct Bar { a: isize }
let v = Foo { a: Bar { a: 2 } };
let mut d = Decoder::new(Table(map! {
a, Table(map! {
a, Integer(2)
})
}));
assert_eq!(v, t!(Deserialize::deserialize(&mut d)));
assert_eq!(d.toml, None);
}
#[test]
fn unused_fields4() {
#[derive(Serialize, Deserialize, PartialEq, Debug)]
struct Foo { a: BTreeMap<String, String> }
let v = Foo { a: map! { a, "foo".to_string() } };
let mut d = Decoder::new(Table(map! {
a, Table(map! {
a, Value::String("foo".to_string())
})
}));
assert_eq!(v, t!(Deserialize::deserialize(&mut d)));
assert_eq!(d.toml, None);
}
#[test]
fn unused_fields5() {
#[derive(Serialize, Deserialize, PartialEq, Debug)]
struct Foo { a: Vec<String> }
let v = Foo { a: vec!["a".to_string()] };
let mut d = Decoder::new(Table(map! {
a, Array(vec![Value::String("a".to_string())])
}));
assert_eq!(v, t!(Deserialize::deserialize(&mut d)));
assert_eq!(d.toml, None);
}
#[test]
fn unused_fields6() {
#[derive(Serialize, Deserialize, PartialEq, Debug)]
struct Foo { a: Option<Vec<String>> }
let v = Foo { a: Some(vec![]) };
let mut d = Decoder::new(Table(map! {
a, Array(vec![])
}));
assert_eq!(v, t!(Deserialize::deserialize(&mut d)));
assert_eq!(d.toml, None);
}
#[test]
fn unused_fields7() {
#[derive(Serialize, Deserialize, PartialEq, Debug)]
struct Foo { a: Vec<Bar> }
#[derive(Serialize, Deserialize, PartialEq, Debug)]
struct Bar { a: isize }
let v = Foo { a: vec![Bar { a: 1 }] };
let mut d = Decoder::new(Table(map! {
a, Array(vec![Table(map! {
a, Integer(1),
b, Integer(2)
})])
}));
assert_eq!(v, t!(Deserialize::deserialize(&mut d)));
assert_eq!(d.toml, Some(Table(map! {
a, Array(vec![Table(map! {
b, Integer(2)
})])
})));
}
#[test]
fn empty_arrays() {
#[derive(Serialize, Deserialize, PartialEq, Debug)]
struct Foo { a: Vec<Bar> }
#[derive(Serialize, Deserialize, PartialEq, Debug)]
struct Bar;
let v = Foo { a: vec![] };
let mut d = Decoder::new(Table(map! {}));
assert_eq!(v, t!(Deserialize::deserialize(&mut d)));
}
#[test]
fn empty_arrays2() {
#[derive(Serialize, Deserialize, PartialEq, Debug)]
struct Foo { a: Option<Vec<Bar>> }
#[derive(Serialize, Deserialize, PartialEq, Debug)]
struct Bar;
let v = Foo { a: None };
let mut d = Decoder::new(Table(map! {}));
assert_eq!(v, t!(Deserialize::deserialize(&mut d)));
let v = Foo { a: Some(vec![]) };
let mut d = Decoder::new(Table(map! {
a, Array(vec![])
}));
assert_eq!(v, t!(Deserialize::deserialize(&mut d)));
}