From 41563ee01b4eb3481207a88bbb2e3a54d6e96b2b Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Thu, 2 Apr 2015 17:07:26 -0700 Subject: wip --- src/decoder/mod.rs | 1 + src/decoder/serde.rs | 152 +++++++++++++++++++++++++++++++++++++++++++++++++++ src/encoder/mod.rs | 1 + src/encoder/serde.rs | 84 ++++++++++++++++++++++++++++ src/lib.rs | 1 + 5 files changed, 239 insertions(+) create mode 100644 src/decoder/serde.rs create mode 100644 src/encoder/serde.rs (limited to 'src') diff --git a/src/decoder/mod.rs b/src/decoder/mod.rs index 675e0ca..a3cc29a 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. /// diff --git a/src/decoder/serde.rs b/src/decoder/serde.rs new file mode 100644 index 0000000..6f60892 --- /dev/null +++ b/src/decoder/serde.rs @@ -0,0 +1,152 @@ +use serde::de; +use Value; +use super::{Decoder, DecodeError, DecodeErrorKind}; + +struct DecodeValue(Value); +struct MapVisitor(I, Option); +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(&mut self, mut visitor: V) -> Result + 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(&mut self, mut visitor: V) -> Result + where V: de::Visitor + { + if self.toml.is_none() { + visitor.visit_none() + } else { + visitor.visit_some(self) + } + } + + fn visit_seq(&mut self, mut visitor: V) -> Result + where V: de::Visitor, + { + if self.toml.is_none() { + let iter = None::.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(&mut self, visitor: V) -> Result + 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 de::MapVisitor for MapVisitor + where I: Iterator +{ + type Error = DecodeError; + + fn visit_key(&mut self) -> Result, 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(&mut self) -> Result + 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(()) + } + +} diff --git a/src/encoder/mod.rs b/src/encoder/mod.rs index 21185f4..8137c33 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. /// 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(&mut self, value: V) -> Result<(), Error> + where V: ser::Serialize + { + value.serialize(self) + } + fn visit_seq(&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(&mut self, value: T) -> Result<(), Error> + where T: ser::Serialize + { + value.serialize(self) + } + fn visit_map(&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(&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(&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 0196fbc..81083e6 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; -- cgit v1.2.3