Merge pull request #787 from 46bit/issue-775

Fix internally tagged enums by implementing ContentDeserializer::deserialize_enum
This commit is contained in:
David Tolnay
2017-02-22 18:23:18 -08:00
committed by GitHub
+258 -4
View File
@@ -58,6 +58,32 @@ pub enum Content {
Map(Vec<(Content, Content)>),
}
impl Content {
fn unexpected(&self) -> Unexpected {
match *self {
Content::Bool(b) => Unexpected::Bool(b),
Content::U8(n) => Unexpected::Unsigned(n as u64),
Content::U16(n) => Unexpected::Unsigned(n as u64),
Content::U32(n) => Unexpected::Unsigned(n as u64),
Content::U64(n) => Unexpected::Unsigned(n),
Content::I8(n) => Unexpected::Signed(n as i64),
Content::I16(n) => Unexpected::Signed(n as i64),
Content::I32(n) => Unexpected::Signed(n as i64),
Content::I64(n) => Unexpected::Signed(n),
Content::F32(f) => Unexpected::Float(f as f64),
Content::F64(f) => Unexpected::Float(f),
Content::Char(c) => Unexpected::Char(c),
Content::String(ref s) => Unexpected::Str(s),
Content::Bytes(ref b) => Unexpected::Bytes(b),
Content::None | Content::Some(_) => Unexpected::Option,
Content::Unit => Unexpected::Unit,
Content::Newtype(_) => Unexpected::NewtypeStruct,
Content::Seq(_) => Unexpected::Seq,
Content::Map(_) => Unexpected::Map,
}
}
}
impl Deserialize for Content {
fn deserialize<D: Deserializer>(deserializer: D) -> Result<Self, D::Error> {
// Untagged and internally tagged enums are only supported in
@@ -607,10 +633,41 @@ impl<E> Deserializer for ContentDeserializer<E>
visitor.visit_newtype_struct(self)
}
fn deserialize_enum<V>(self, _name: &str, _variants: &'static [&'static str], visitor: V) -> Result<V::Value, Self::Error>
where V: Visitor,
{
let (variant, value) = match self.content {
Content::Map(value) => {
let mut iter = value.into_iter();
let (variant, value) = match iter.next() {
Some(v) => v,
None => {
return Err(de::Error::invalid_value(de::Unexpected::Map, &"map with a single key"));
}
};
// enums are encoded in json as maps with a single key:value pair
if iter.next().is_some() {
return Err(de::Error::invalid_value(de::Unexpected::Map, &"map with a single key"));
}
(variant, Some(value))
}
Content::String(variant) => (Content::String(variant), None),
other => {
return Err(de::Error::invalid_type(other.unexpected(), &"string or map"));
}
};
visitor.visit_enum(EnumDeserializer {
variant: variant,
value: value,
err: PhantomData,
})
}
forward_to_deserialize! {
bool u8 u16 u32 u64 i8 i16 i32 i64 f32 f64 char str string unit seq
seq_fixed_size bytes byte_buf map unit_struct tuple_struct struct
struct_field tuple enum ignored_any
struct_field tuple ignored_any
}
}
@@ -624,6 +681,203 @@ impl<E> ContentDeserializer<E> {
}
}
struct EnumDeserializer<E> where E: de::Error {
variant: Content,
value: Option<Content>,
err: PhantomData<E>,
}
impl<E> de::EnumVisitor for EnumDeserializer<E> where E: de::Error {
type Error = E;
type Variant = VariantDeserializer<Self::Error>;
fn visit_variant_seed<V>(self, seed: V) -> Result<(V::Value, VariantDeserializer<E>), Self::Error>
where V: de::DeserializeSeed,
{
let visitor = VariantDeserializer { value: self.value, err: PhantomData, };
seed.deserialize(ContentDeserializer::new(self.variant)).map(|v| (v, visitor))
}
}
struct VariantDeserializer<E> where E: de::Error {
value: Option<Content>,
err: PhantomData<E>,
}
impl<E> de::VariantVisitor for VariantDeserializer<E> where E: de::Error {
type Error = E;
fn visit_unit(self) -> Result<(), E> {
match self.value {
Some(value) => de::Deserialize::deserialize(ContentDeserializer::new(value)),
None => Ok(()),
}
}
fn visit_newtype_seed<T>(self, seed: T) -> Result<T::Value, E>
where T: de::DeserializeSeed
{
match self.value {
Some(value) => seed.deserialize(ContentDeserializer::new(value)),
None => Err(de::Error::invalid_type(de::Unexpected::UnitVariant, &"newtype variant")),
}
}
fn visit_tuple<V>(
self,
_len: usize,
visitor: V
) -> Result<V::Value, Self::Error>
where V: de::Visitor
{
match self.value {
Some(Content::Seq(v)) => {
de::Deserializer::deserialize(SeqDeserializer::new(v), visitor)
}
Some(other) => Err(de::Error::invalid_type(other.unexpected(), &"tuple variant")),
None => Err(de::Error::invalid_type(de::Unexpected::UnitVariant, &"tuple variant"))
}
}
fn visit_struct<V>(
self,
_fields: &'static [&'static str],
visitor: V
) -> Result<V::Value, Self::Error>
where V: de::Visitor
{
match self.value {
Some(Content::Map(v)) => {
de::Deserializer::deserialize(MapDeserializer::new(v), visitor)
}
Some(other) => Err(de::Error::invalid_type(other.unexpected(), &"struct variant")),
_ => Err(de::Error::invalid_type(de::Unexpected::UnitVariant, &"struct variant"))
}
}
}
struct SeqDeserializer<E> where E: de::Error {
iter: <Vec<Content> as IntoIterator>::IntoIter,
err: PhantomData<E>,
}
impl<E> SeqDeserializer<E> where E: de::Error {
fn new(vec: Vec<Content>) -> Self {
SeqDeserializer {
iter: vec.into_iter(),
err: PhantomData,
}
}
}
impl<E> de::Deserializer for SeqDeserializer<E> where E: de::Error {
type Error = E;
#[inline]
fn deserialize<V>(mut self, visitor: V) -> Result<V::Value, Self::Error>
where V: de::Visitor,
{
let len = self.iter.len();
if len == 0 {
visitor.visit_unit()
} else {
let ret = try!(visitor.visit_seq(&mut self));
let remaining = self.iter.len();
if remaining == 0 {
Ok(ret)
} else {
Err(de::Error::invalid_length(len, &"fewer elements in array"))
}
}
}
forward_to_deserialize! {
bool u8 u16 u32 u64 i8 i16 i32 i64 f32 f64 char str string unit option
seq seq_fixed_size bytes byte_buf map unit_struct newtype_struct
tuple_struct struct struct_field tuple enum ignored_any
}
}
impl<E> de::SeqVisitor for SeqDeserializer<E> where E: de::Error {
type Error = E;
fn visit_seed<T>(&mut self, seed: T) -> Result<Option<T::Value>, Self::Error>
where T: de::DeserializeSeed,
{
match self.iter.next() {
Some(value) => seed.deserialize(ContentDeserializer::new(value)).map(Some),
None => Ok(None),
}
}
fn size_hint(&self) -> (usize, Option<usize>) {
self.iter.size_hint()
}
}
struct MapDeserializer<E> where E: de::Error {
iter: <Vec<(Content, Content)> as IntoIterator>::IntoIter,
value: Option<Content>,
err: PhantomData<E>,
}
impl<E> MapDeserializer<E> where E: de::Error {
fn new(map: Vec<(Content, Content)>) -> Self {
MapDeserializer {
iter: map.into_iter(),
value: None,
err: PhantomData,
}
}
}
impl<E> de::MapVisitor for MapDeserializer<E> where E: de::Error {
type Error = E;
fn visit_key_seed<T>(&mut self, seed: T) -> Result<Option<T::Value>, Self::Error>
where T: de::DeserializeSeed,
{
match self.iter.next() {
Some((key, value)) => {
self.value = Some(value);
seed.deserialize(ContentDeserializer::new(key)).map(Some)
}
None => Ok(None),
}
}
fn visit_value_seed<T>(&mut self, seed: T) -> Result<T::Value, Self::Error>
where T: de::DeserializeSeed,
{
match self.value.take() {
Some(value) => seed.deserialize(ContentDeserializer::new(value)),
None => Err(de::Error::custom("value is missing")),
}
}
fn size_hint(&self) -> (usize, Option<usize>) {
self.iter.size_hint()
}
}
impl<E> de::Deserializer for MapDeserializer<E> where E: de::Error {
type Error = E;
#[inline]
fn deserialize<V>(self, visitor: V) -> Result<V::Value, Self::Error>
where V: de::Visitor,
{
visitor.visit_map(self)
}
forward_to_deserialize! {
bool u8 u16 u32 u64 i8 i16 i32 i64 f32 f64 char str string unit option
seq seq_fixed_size bytes byte_buf map unit_struct newtype_struct
tuple_struct struct struct_field tuple enum ignored_any
}
}
/// Not public API.
pub struct ContentRefDeserializer<'a, E> {
content: &'a Content,
@@ -637,7 +891,7 @@ impl<'a, E> Deserializer for ContentRefDeserializer<'a, E>
{
type Error = E;
fn deserialize<V>(self, visitor: V) -> Result<V::Value, Self::Error>
fn deserialize<V>(self, visitor: V) -> Result<V::Value, E>
where V: Visitor
{
match *self.content {
@@ -678,7 +932,7 @@ impl<'a, E> Deserializer for ContentRefDeserializer<'a, E>
}
}
fn deserialize_option<V>(self, visitor: V) -> Result<V::Value, Self::Error>
fn deserialize_option<V>(self, visitor: V) -> Result<V::Value, E>
where V: Visitor
{
match *self.content {
@@ -689,7 +943,7 @@ impl<'a, E> Deserializer for ContentRefDeserializer<'a, E>
}
}
fn deserialize_newtype_struct<V>(self, _name: &str, visitor: V) -> Result<V::Value, Self::Error>
fn deserialize_newtype_struct<V>(self, _name: &str, visitor: V) -> Result<V::Value, E>
where V: Visitor
{
visitor.visit_newtype_struct(self)