diff options
Diffstat (limited to 'src')
-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 |
5 files changed, 417 insertions, 1 deletions
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; |