Add support for option handling

This commit is contained in:
Erick Tryzelaar 2015-01-17 21:58:52 -08:00
parent d38d06a151
commit 73018e4d5d
2 changed files with 138 additions and 70 deletions

View File

@ -25,14 +25,17 @@ pub trait Deserializer {
V: Visitor,
>(&mut self, visitor: &mut V) -> Result<V::Value, Self::Error>;
/*
/// 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<Self, R, E>,
>(&mut self, visitor: &mut V) -> Result<R, S::Error> {
V: Visitor,
>(&mut self, visitor: &mut V) -> Result<V::Value, Self::Error> {
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::Value, E> {
self.visit_unit()
}
*/
/*
fn visit_option<
V: OptionVisitor<S, E>,
>(&mut self, _visitor: V) -> Result<Self::Value, E> {
>(&mut self) -> Result<Self::Value, E> {
Err(Error::syntax_error())
}
fn visit_some<
S: Deserializer,
>(&mut self, _state: &mut S) -> Result<Self::Value, S::Error> {
Err(Error::syntax_error())
}
*/
fn visit_seq<
V: SeqVisitor,
@ -203,14 +201,6 @@ pub trait Visitor {
}
}
/*
pub trait OptionVisitor<S, E> {
fn visit<
T: Deserialize<S, E>,
>(&mut self) -> Result<Option<T>, E>;
}
*/
pub trait SeqVisitor {
type Error: Error;
@ -476,35 +466,39 @@ impl Deserialize for String {
}
}
/*
///////////////////////////////////////////////////////////////////////////////
struct OptionVisitor<T>;
impl<
T: Deserialize<S, E>,
S: Deserializer<E>,
E: Error,
> Deserialize<S, E> for Option<T> {
fn deserialize(state: &mut S) -> Result<Option<T>, E> {
struct Visitor;
T: Deserialize,
> Visitor for OptionVisitor<T> {
type Value = Option<T>;
impl<
T: Deserialize<S, E>,
S: Deserializer<E>,
E: Error,
> self::Visitor<S, Option<T>, E> for Visitor {
fn visit_option<
V: OptionVisitor<S, E>,
>(&mut self, mut visitor: V) -> Result<Option<T>, E> {
visitor.visit()
}
}
#[inline]
fn visit_none<
E: Error,
>(&mut self) -> Result<Option<T>, E> {
Ok(None)
}
state.visit_option(&mut Visitor)
#[inline]
fn visit_some<
S: Deserializer,
>(&mut self, state: &mut S) -> Result<Option<T>, S::Error> {
Ok(Some(try!(Deserialize::deserialize(state))))
}
}
impl<T> Deserialize for Option<T> where T: Deserialize {
fn deserialize<
S: Deserializer,
>(state: &mut S) -> Result<Option<T>, S::Error> {
state.visit_option(&mut OptionVisitor)
}
}
///////////////////////////////////////////////////////////////////////////////
*/
struct VecVisitor<T>;
@ -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<Token<'a>>,
tokens: iter::Peekable<Token<'a>, vec::IntoIter<Token<'a>>>,
}
impl<'a> TokenDeserializer<'a> {
fn new(tokens: Vec<Token<'a>>) -> 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<V::Value, Error> {
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::<i32> => vec![Token::Unit],
None::<i32> => 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")],

View File

@ -109,6 +109,12 @@ pub trait Visitor {
fn visit_str(&mut self, value: &str) -> Result<Self::Value, Self::Error>;
fn visit_none(&mut self) -> Result<Self::Value, Self::Error>;
#[inline]
fn visit_some<V>(&mut self, value: V) -> Result<Self::Value, Self::Error>
where V: Serialize;
fn visit_seq<V>(&mut self, visitor: V) -> Result<Self::Value, Self::Error>
where V: SeqVisitor;
@ -240,6 +246,20 @@ impl Serialize for String {
///////////////////////////////////////////////////////////////////////////////
impl<T> Serialize for Option<T> where T: Serialize {
#[inline]
fn visit<
V: Visitor,
>(&self, visitor: &mut V) -> Result<V::Value, V::Error> {
match *self {
Some(ref value) => visitor.visit_some(value),
None => visitor.visit_none(),
}
}
}
///////////////////////////////////////////////////////////////////////////////
pub struct SeqIteratorVisitor<Iter> {
iter: Iter,
first: bool,
@ -306,9 +326,7 @@ impl<
}
}
impl<
T: Serialize,
> Serialize for BTreeSet<T> {
impl<T> Serialize for BTreeSet<T> where T: Serialize {
#[inline]
fn visit<
V: Visitor,
@ -323,9 +341,7 @@ impl<T, S, H> Serialize for HashSet<T, S>
H: Hasher<Output=u64>,
{
#[inline]
fn visit<
V: Visitor,
>(&self, visitor: &mut V) -> Result<V::Value, V::Error> {
fn visit<V: Visitor>(&self, visitor: &mut V) -> Result<V::Value, V::Error> {
visitor.visit_seq(SeqIteratorVisitor::new(self.iter()))
}
}
@ -533,11 +549,11 @@ impl<K, V, Iter: Iterator<Item=(K, V)>> MapIteratorVisitor<Iter> {
}
}
impl<
K: Serialize,
V: Serialize,
Iter: Iterator<Item=(K, V)>,
> MapVisitor for MapIteratorVisitor<Iter> {
impl<K, V, I> MapVisitor for MapIteratorVisitor<I>
where K: Serialize,
V: Serialize,
I: Iterator<Item=(K, V)>,
{
#[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<V>(&mut self, value: V) -> Result<(), ()>
where V: Serialize,
{
assert_eq!(self.iter.next(), Some(Token::Option(true)));
value.visit(self)
}
fn visit_seq<V>(&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::<i32> => vec![Token::Option(false)],
Some(1) => vec![
Token::Option(true),
Token::I32(1),
],
}
test_slice {
&[0][..0] => vec![
Token::SeqStart(0),