diff options
-rw-r--r-- | .travis.yml | 4 | ||||
-rw-r--r-- | Cargo.toml | 2 | ||||
-rw-r--r-- | src/decoder/mod.rs | 5 | ||||
-rw-r--r-- | src/decoder/serde.rs | 325 | ||||
-rw-r--r-- | src/encoder/mod.rs | 3 | ||||
-rw-r--r-- | src/encoder/serde.rs | 84 | ||||
-rw-r--r-- | src/lib.rs | 1 | ||||
-rw-r--r-- | tests/serde.rs | 487 |
8 files changed, 908 insertions, 3 deletions
diff --git a/.travis.yml b/.travis.yml index 94e4a6f..417e85d 100644 --- a/.travis.yml +++ b/.travis.yml @@ -9,8 +9,8 @@ before_script: script: - cargo build --verbose - cargo build --verbose --no-default-features - - cargo test --verbose - - cargo test --verbose --no-default-features + - cargo build --verbose --features serde --no-default-features + - cargo test --verbose --features serde - rustdoc --test README.md -L target - cargo doc --no-deps after_success: @@ -17,9 +17,11 @@ facilitate deserializing and serializing Rust structures. [dependencies] rustc-serialize = { optional = true, version = "0.3.0" } +serde = { optional = true } [features] default = ["rustc-serialize"] [dev-dependencies] rustc-serialize = "0.3" +serde_macros = "*" diff --git a/src/decoder/mod.rs b/src/decoder/mod.rs index 675e0ca..62de223 100644 --- a/src/decoder/mod.rs +++ b/src/decoder/mod.rs @@ -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. /// @@ -34,6 +35,8 @@ pub enum DecodeErrorKind { ApplicationError(String), /// A field was expected, but none was found. ExpectedField(/* type */ Option<&'static str>), + /// A field was found, but it was not an expected one. + UnknownField, /// A field was found, but it had the wrong type. ExpectedType(/* expected */ &'static str, /* found */ &'static str), /// The nth map key was expected, but none was found. @@ -148,6 +151,7 @@ impl fmt::Display for DecodeError { None => write!(f, "expected a value"), } } + UnknownField => write!(f, "unknown field"), ExpectedType(expected, found) => { fn humanize(s: &str) -> String { if s == "section" { @@ -193,6 +197,7 @@ impl error::Error for DecodeError { match self.kind { ApplicationError(ref s) => &**s, ExpectedField(..) => "expected a field", + UnknownField => "found an unknown field", ExpectedType(..) => "expected a type", ExpectedMapKey(..) => "expected a map key", ExpectedMapElement(..) => "expected a map element", diff --git a/src/decoder/serde.rs b/src/decoder/serde.rs new file mode 100644 index 0000000..b12984d --- /dev/null +++ b/src/decoder/serde.rs @@ -0,0 +1,325 @@ +use serde::de; +use Value; +use super::{Decoder, DecodeError, DecodeErrorKind}; +use std::collections::BTreeMap; + +struct MapVisitor<'a, I> { + iter: I, + toml: &'a mut Option<Value>, + key: Option<String>, + value: Option<Value>, +} + +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)), + } + }, + de::value::Error::UnknownFieldError(s) => { + DecodeError { + field: Some(s.to_string()), + kind: DecodeErrorKind::UnknownField, + } + }, + } +} + +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(); + visitor.visit_seq(SeqDeserializer::new(iter, len, &mut self.toml)) + } + Some(Value::Table(t)) => { + visitor.visit_map(MapVisitor { + iter: t.into_iter(), + toml: &mut self.toml, + key: None, + value: 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) + } + } +} + +struct SeqDeserializer<'a, I> { + iter: I, + len: usize, + toml: &'a mut Option<Value>, +} + +impl<'a, I> SeqDeserializer<'a, I> where I: Iterator<Item=Value> { + fn new(iter: I, len: usize, toml: &'a mut Option<Value>) -> Self { + SeqDeserializer { + iter: iter, + len: len, + toml: toml, + } + } + + fn put_value_back(&mut self, v: Value) { + *self.toml = self.toml.take().or(Some(Value::Array(Vec::new()))); + match self.toml.as_mut().unwrap() { + &mut Value::Array(ref mut a) => { + a.push(v); + }, + _ => unreachable!(), + } + } +} + +impl<'a, I> de::Deserializer for SeqDeserializer<'a, I> + where I: Iterator<Item=Value>, +{ + type Error = DecodeError; + + fn visit<V>(&mut self, mut visitor: V) -> Result<V::Value, DecodeError> + where V: de::Visitor, + { + visitor.visit_seq(self) + } +} + +impl<'a, I> de::SeqVisitor for SeqDeserializer<'a, I> + where I: Iterator<Item=Value> +{ + type Error = DecodeError; + + fn visit<V>(&mut self) -> Result<Option<V>, DecodeError> + where V: de::Deserialize + { + match self.iter.next() { + Some(value) => { + self.len -= 1; + let mut de = Decoder::new(value); + let v = try!(de::Deserialize::deserialize(&mut de)); + if let Some(t) = de.toml { + self.put_value_back(t); + } + Ok(Some(v)) + } + None => Ok(None), + } + } + + fn end(&mut self) -> Result<(), DecodeError> { + if self.len == 0 { + Ok(()) + } else { + Err(de::Error::end_of_stream_error()) + } + } + + fn size_hint(&self) -> (usize, Option<usize>) { + (self.len, Some(self.len)) + } +} + +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), + } + } + fn unknown_field_error(name: &str) -> DecodeError { + DecodeError { + field: Some(name.to_string()), + kind: DecodeErrorKind::UnknownField, + } + } +} + +impl<'a, I> MapVisitor<'a, I> { + fn put_value_back(&mut self, v: Value) { + *self.toml = self.toml.take().or_else(|| { + Some(Value::Table(BTreeMap::new())) + }); + match self.toml.as_mut().unwrap() { + &mut Value::Table(ref mut t) => { + t.insert(self.key.take().unwrap(), v); + }, + _ => unreachable!(), + } + } +} + +impl<'a, I> de::MapVisitor for MapVisitor<'a, I> + where I: Iterator<Item=(String, Value)> +{ + type Error = DecodeError; + + fn visit_key<K>(&mut self) -> Result<Option<K>, DecodeError> + where K: de::Deserialize + { + while let Some((k, v)) = self.iter.next() { + self.key = Some(k.clone()); + let mut dec = Decoder::new(Value::String(k)); + match de::Deserialize::deserialize(&mut dec) { + Ok(val) => { + self.value = Some(v); + return Ok(Some(val)) + } + + // If this was an unknown field, then we put the toml value + // back into the map and keep going. + Err(DecodeError {kind: DecodeErrorKind::UnknownField, ..}) => { + self.put_value_back(v); + } + Err(e) => return Err(e), + } + } + Ok(None) + } + + fn visit_value<V>(&mut self) -> Result<V, DecodeError> + where V: de::Deserialize + { + match self.value.take() { + Some(t) => { + let mut dec = Decoder::new(t); + let v = try!(de::Deserialize::deserialize(&mut dec)); + if let Some(t) = dec.toml { + self.put_value_back(t); + } + Ok(v) + }, + None => Err(de::Error::end_of_stream_error()) + } + } + + fn end(&mut self) -> Result<(), DecodeError> { + Ok(()) + } + + fn missing_field<V>(&mut self, field_name: &'static str) + -> Result<V, DecodeError> where V: de::Deserialize { + // See if the type can deserialize from a unit. + match de::Deserialize::deserialize(&mut UnitDeserializer) { + Err(DecodeError { + kind: DecodeErrorKind::SyntaxError, + field, + }) => Err(DecodeError { + field: field.or(Some(field_name.to_string())), + kind: DecodeErrorKind::ExpectedField(None), + }), + v => v, + } + } +} + +struct UnitDeserializer; + +impl de::Deserializer for UnitDeserializer { + type Error = DecodeError; + + fn visit<V>(&mut self, mut visitor: V) -> Result<V::Value, DecodeError> + where V: de::Visitor, + { + visitor.visit_unit() + } + + fn visit_option<V>(&mut self, mut visitor: V) -> Result<V::Value, DecodeError> + where V: de::Visitor, + { + visitor.visit_none() + } +} + +// Based on https://github.com/serde-rs/serde/blob/199ed417bd6afc2071d17759b8c7e0ab8d0ba4cc/serde_json/src/value.rs#L265 +impl de::Deserialize for Value { + fn deserialize<D>(deserializer: &mut D) -> Result<Value, D::Error> where D: de::Deserializer { + struct ValueVisitor; + + impl de::Visitor for ValueVisitor { + type Value = Value; + + fn visit_bool<E>(&mut self, value: bool) -> Result<Value, E> { + Ok(Value::Boolean(value)) + } + + fn visit_i64<E>(&mut self, value: i64) -> Result<Value, E> { + Ok(Value::Integer(value)) + } + + fn visit_f64<E>(&mut self, value: f64) -> Result<Value, E> { + Ok(Value::Float(value)) + } + + fn visit_str<E>(&mut self, value: &str) -> Result<Value, E> { + Ok(Value::String(value.into())) + } + + fn visit_string<E>(&mut self, value: String) -> Result<Value, E> { + Ok(Value::String(value)) + } + + fn visit_seq<V>(&mut self, visitor: V) -> Result<Value, V::Error> where V: de::SeqVisitor { + let values = try!(de::impls::VecVisitor::new().visit_seq(visitor)); + Ok(Value::Array(values)) + } + + fn visit_map<V>(&mut self, visitor: V) -> Result<Value, V::Error> where V: de::MapVisitor { + let values = try!(de::impls::BTreeMapVisitor::new().visit_map(visitor)); + Ok(Value::Table(values)) + } + } + + deserializer.visit(ValueVisitor) + } +} diff --git a/src/encoder/mod.rs b/src/encoder/mod.rs index 21185f4..35e7212 100644 --- a/src/encoder/mod.rs +++ b/src/encoder/mod.rs @@ -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. /// @@ -170,7 +171,7 @@ pub fn encode<T: ::rustc_serialize::Encodable>(t: &T) -> Value { #[cfg(all(not(feature = "rustc-serialize"), feature = "serde"))] pub fn encode<T: ::serde::Serialize>(t: &T) -> Value { let mut e = Encoder::new(); - t.deserialize(&mut e).unwrap(); + t.serialize(&mut e).unwrap(); Value::Table(e.toml) } diff --git a/src/encoder/serde.rs b/src/encoder/serde.rs new file mode 100644 index 0000000..87a742e --- /dev/null +++ b/src/encoder/serde.rs @@ -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()))) + } + } + } +} @@ -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; diff --git a/tests/serde.rs b/tests/serde.rs new file mode 100644 index 0000000..4c0cc96 --- /dev/null +++ b/tests/serde.rs @@ -0,0 +1,487 @@ +#![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); + #[derive(Serialize, Deserialize, PartialEq, Debug)] + struct Bar { + whee: Foo, + } + + let v = Bar { + whee: Foo(1, "foo".to_string(), 4.5) + }; + assert_eq!( + encode!(v), + map! { + whee, Value::Array(vec![ + Integer(1), + Value::String("foo".to_string()), + 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); + // serde uses FromPrimitive, that's why this works + 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 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) }; + // technically serde is correct here. a single element tuple still is a tuple and therefor + // a sequence + 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))); +} |