diff --git a/serde2/src/de.rs b/serde2/src/de.rs index 87f122e4..bd6de3b5 100644 --- a/serde2/src/de.rs +++ b/serde2/src/de.rs @@ -25,14 +25,17 @@ pub trait Deserializer { V: Visitor, >(&mut self, visitor: &mut V) -> Result; - /* + /// The `visit_option` method allows a `Deserialize` type to inform the + /// `Deserializer` that it's expecting an optional value. This allows + /// deserializers that encode an optional value as a nullable value to + /// convert the null value into a `None`, and a regular value as + /// `Some(value)`. + #[inline] fn visit_option< - R, - V: Visitor, - >(&mut self, visitor: &mut V) -> Result { + V: Visitor, + >(&mut self, visitor: &mut V) -> Result { self.visit(visitor) } - */ } pub trait Visitor { @@ -152,22 +155,17 @@ pub trait Visitor { self.visit_unit() } - /* - #[inline] - fn visit_enum_unit< + fn visit_none< E: Error, - >(&mut self, _name: &str, _variant: &str) -> Result { - self.visit_unit() - } - */ - - /* - fn visit_option< - V: OptionVisitor, - >(&mut self, _visitor: V) -> Result { + >(&mut self) -> Result { + Err(Error::syntax_error()) + } + + fn visit_some< + S: Deserializer, + >(&mut self, _state: &mut S) -> Result { Err(Error::syntax_error()) } - */ fn visit_seq< V: SeqVisitor, @@ -203,14 +201,6 @@ pub trait Visitor { } } -/* -pub trait OptionVisitor { - fn visit< - T: Deserialize, - >(&mut self) -> Result, E>; -} -*/ - pub trait SeqVisitor { type Error: Error; @@ -476,35 +466,39 @@ impl Deserialize for String { } } -/* /////////////////////////////////////////////////////////////////////////////// +struct OptionVisitor; + impl< - T: Deserialize, - S: Deserializer, - E: Error, -> Deserialize for Option { - fn deserialize(state: &mut S) -> Result, E> { - struct Visitor; + T: Deserialize, +> Visitor for OptionVisitor { + type Value = Option; - impl< - T: Deserialize, - S: Deserializer, - E: Error, - > self::Visitor, E> for Visitor { - fn visit_option< - V: OptionVisitor, - >(&mut self, mut visitor: V) -> Result, E> { - visitor.visit() - } - } + #[inline] + fn visit_none< + E: Error, + >(&mut self) -> Result, E> { + Ok(None) + } - state.visit_option(&mut Visitor) + #[inline] + fn visit_some< + S: Deserializer, + >(&mut self, state: &mut S) -> Result, S::Error> { + Ok(Some(try!(Deserialize::deserialize(state)))) + } +} + +impl Deserialize for Option where T: Deserialize { + fn deserialize< + S: Deserializer, + >(state: &mut S) -> Result, S::Error> { + state.visit_option(&mut OptionVisitor) } } /////////////////////////////////////////////////////////////////////////////// -*/ struct VecVisitor; @@ -668,6 +662,7 @@ impl< mod tests { use super::{Deserialize, Deserializer, Visitor}; use std::collections::BTreeMap; + use std::iter; use std::vec; #[derive(Show)] @@ -689,6 +684,8 @@ mod tests { Str(&'a str), String(String), + Option(bool), + Unit, NamedUnit(&'a str), @@ -707,13 +704,13 @@ mod tests { } struct TokenDeserializer<'a> { - tokens: vec::IntoIter>, + tokens: iter::Peekable, vec::IntoIter>>, } impl<'a> TokenDeserializer<'a> { fn new(tokens: Vec>) -> TokenDeserializer<'a> { TokenDeserializer { - tokens: tokens.into_iter(), + tokens: tokens.into_iter().peekable(), } } } @@ -753,6 +750,8 @@ mod tests { Some(Token::Char(v)) => visitor.visit_char(v), Some(Token::Str(v)) => visitor.visit_str(v), Some(Token::String(v)) => visitor.visit_string(v), + Some(Token::Option(false)) => visitor.visit_none(), + Some(Token::Option(true)) => visitor.visit_some(self), Some(Token::Unit) => visitor.visit_unit(), Some(Token::NamedUnit(name)) => visitor.visit_named_unit(name), Some(Token::SeqStart(len)) => { @@ -792,6 +791,30 @@ mod tests { None => Err(Error::EndOfStreamError), } } + + /// Hook into `Option` deserializing so we can treat `Unit` as a + /// `None`, or a regular value as `Some(value)`. + #[inline] + fn visit_option< + V: Visitor, + >(&mut self, visitor: &mut V) -> Result { + match self.tokens.peek() { + Some(&Token::Option(false)) => { + self.tokens.next(); + visitor.visit_none() + } + Some(&Token::Option(true)) => { + self.tokens.next(); + visitor.visit_some(self) + } + Some(&Token::Unit) => { + self.tokens.next(); + visitor.visit_none() + } + Some(_) => visitor.visit_some(self), + None => Err(Error::EndOfStreamError), + } + } } ////////////////////////////////////////////////////////////////////////// @@ -1294,17 +1317,6 @@ mod tests { ////////////////////////////////////////////////////////////////////////// declare_tests! { - test_unit { - () => vec![Token::Unit], - () => vec![ - Token::SeqStart(0), - Token::SeqEnd, - ], - () => vec![ - Token::NamedSeqStart("Anything", 0), - Token::SeqEnd, - ], - } test_bool { true => vec![Token::Bool(true)], false => vec![Token::Bool(false)], @@ -1351,6 +1363,26 @@ mod tests { "abc".to_string() => vec![Token::String("abc".to_string())], "a".to_string() => vec![Token::Char('a')], } + test_option { + None:: => vec![Token::Unit], + None:: => vec![Token::Option(false)], + Some(1) => vec![Token::I32(1)], + Some(1) => vec![ + Token::Option(true), + Token::I32(1), + ], + } + test_unit { + () => vec![Token::Unit], + () => vec![ + Token::SeqStart(0), + Token::SeqEnd, + ], + () => vec![ + Token::NamedSeqStart("Anything", 0), + Token::SeqEnd, + ], + } test_named_unit { NamedUnit => vec![Token::Unit], NamedUnit => vec![Token::NamedUnit("NamedUnit")], diff --git a/serde2/src/ser.rs b/serde2/src/ser.rs index 5421a9bc..a871b051 100644 --- a/serde2/src/ser.rs +++ b/serde2/src/ser.rs @@ -109,6 +109,12 @@ pub trait Visitor { fn visit_str(&mut self, value: &str) -> Result; + fn visit_none(&mut self) -> Result; + + #[inline] + fn visit_some(&mut self, value: V) -> Result + where V: Serialize; + fn visit_seq(&mut self, visitor: V) -> Result where V: SeqVisitor; @@ -240,6 +246,20 @@ impl Serialize for String { /////////////////////////////////////////////////////////////////////////////// +impl Serialize for Option where T: Serialize { + #[inline] + fn visit< + V: Visitor, + >(&self, visitor: &mut V) -> Result { + match *self { + Some(ref value) => visitor.visit_some(value), + None => visitor.visit_none(), + } + } +} + +/////////////////////////////////////////////////////////////////////////////// + pub struct SeqIteratorVisitor { iter: Iter, first: bool, @@ -306,9 +326,7 @@ impl< } } -impl< - T: Serialize, -> Serialize for BTreeSet { +impl Serialize for BTreeSet where T: Serialize { #[inline] fn visit< V: Visitor, @@ -323,9 +341,7 @@ impl Serialize for HashSet H: Hasher, { #[inline] - fn visit< - V: Visitor, - >(&self, visitor: &mut V) -> Result { + fn visit(&self, visitor: &mut V) -> Result { visitor.visit_seq(SeqIteratorVisitor::new(self.iter())) } } @@ -533,11 +549,11 @@ impl> MapIteratorVisitor { } } -impl< - K: Serialize, - V: Serialize, - Iter: Iterator, -> MapVisitor for MapIteratorVisitor { +impl MapVisitor for MapIteratorVisitor + where K: Serialize, + V: Serialize, + I: Iterator, +{ #[inline] fn visit< V_: Visitor, @@ -808,6 +824,19 @@ mod tests { Ok(()) } + fn visit_none(&mut self) -> Result<(), ()> { + assert_eq!(self.iter.next(), Some(Token::Option(false))); + Ok(()) + } + + fn visit_some(&mut self, value: V) -> Result<(), ()> + where V: Serialize, + { + assert_eq!(self.iter.next(), Some(Token::Option(true))); + value.visit(self) + } + + fn visit_seq(&mut self, visitor: V) -> Result<(), ()> where V: SeqVisitor { @@ -1107,6 +1136,13 @@ mod tests { "abc" => vec![Token::Str("abc")], "abc".to_string() => vec![Token::Str("abc")], } + test_option { + None:: => vec![Token::Option(false)], + Some(1) => vec![ + Token::Option(true), + Token::I32(1), + ], + } test_slice { &[0][..0] => vec![ Token::SeqStart(0),