aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.travis.yml4
-rw-r--r--Cargo.toml2
-rw-r--r--src/decoder/mod.rs5
-rw-r--r--src/decoder/serde.rs325
-rw-r--r--src/encoder/mod.rs3
-rw-r--r--src/encoder/serde.rs84
-rw-r--r--src/lib.rs1
-rw-r--r--tests/serde.rs487
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:
diff --git a/Cargo.toml b/Cargo.toml
index c3ce3b7..d935053 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -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())))
+ }
+ }
+ }
+}
diff --git a/src/lib.rs b/src/lib.rs
index c974cd0..daf780e 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -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)));
+}