Skip to content

Commit

Permalink
chore: up
Browse files Browse the repository at this point in the history
  • Loading branch information
greenhat616 committed Jan 18, 2025
1 parent 39cfdee commit 27bb9e4
Show file tree
Hide file tree
Showing 4 changed files with 47 additions and 36 deletions.
34 changes: 17 additions & 17 deletions src/de.rs
Original file line number Diff line number Diff line change
Expand Up @@ -436,6 +436,8 @@ struct DeserializerFromEvents<'de, 'document> {
path: Path<'document>,
remaining_depth: u8,
current_enum: Option<CurrentEnum<'document>>,
/// a flag to do a hack to run visitor.visit_map() instead of visitor.visit_enum() when `is_serde_content_newtype` is true.
/// That is required because `visit_enum` is not available in serde internal newtype visitor.
is_serde_content_newtype: bool,
}

Expand Down Expand Up @@ -747,7 +749,8 @@ struct EnumAccess<'de, 'document, 'variant> {
de: &'variant mut DeserializerFromEvents<'de, 'document>,
name: Option<&'static str>,
tag: &'document str,
/// a flag to do a hack to run visitor.visit_map() instead of visitor.visit_enum() when is_serde_content is true
/// a flag to do a hack to run visitor.visit_map() instead of visitor.visit_enum() when `is_serde_content_newtype` is true.
/// That is required because `visit_enum` is not available in serde internal newtype visitor.
has_visited: bool,
}

Expand Down Expand Up @@ -797,22 +800,19 @@ impl<'de> de::MapAccess<'de> for EnumAccess<'de, '_, '_> {
where
V: DeserializeSeed<'de>,
{
let old_serde_content_newtype = mem::replace(&mut self.de.is_serde_content_newtype, true);
let mut visitor = DeserializerFromEvents {
document: self.de.document,
pos: self.de.pos,
jumpcount: self.de.jumpcount,
path: self.de.path,
remaining_depth: self.de.remaining_depth,
current_enum: Some(CurrentEnum {
name: self.name,
tag: self.tag,
}),
is_serde_content_newtype: self.de.is_serde_content_newtype,
};
let result = seed.deserialize(&mut visitor)?;
self.de.is_serde_content_newtype = old_serde_content_newtype;
Ok(result)
let mut de = DeserializerFromEvents {
document: self.de.document,
pos: self.de.pos,
jumpcount: self.de.jumpcount,
path: self.de.path,
remaining_depth: self.de.remaining_depth,
current_enum: Some(CurrentEnum {
name: self.name,
tag: self.tag,
}),
is_serde_content_newtype: true,
};
seed.deserialize(&mut de)
}
}

Expand Down
6 changes: 3 additions & 3 deletions src/value/de.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ use std::fmt;
use std::slice;
use std::vec;

use super::tagged::TaggedValueMapAccess;
use super::tagged::TaggedValueRefAsMapAccess;

impl<'de> Deserialize<'de> for Value {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
Expand Down Expand Up @@ -211,7 +211,7 @@ impl<'de> Deserializer<'de> for Value {
Value::Sequence(v) => visit_sequence(v, visitor),
Value::Mapping(v) => visit_mapping(v, visitor),
Value::Tagged(tagged) if is_serde_value => {
visitor.visit_map(TaggedValueMapAccess::from(*tagged))
visitor.visit_map(TaggedValueRefAsMapAccess::from(*tagged))
}
Value::Tagged(tagged) => visitor.visit_enum(*tagged),
}
Expand Down Expand Up @@ -733,7 +733,7 @@ impl<'de> Deserializer<'de> for &'de Value {
Value::Sequence(v) => visit_sequence_ref(v, visitor),
Value::Mapping(v) => visit_mapping_ref(v, visitor),
Value::Tagged(tagged) if is_serde_content => {
visitor.visit_map(TaggedValueMapAccess::from((**tagged).clone()))
visitor.visit_map(TaggedValueRefAsMapAccess::from(&**tagged))
}
Value::Tagged(tagged) => visitor.visit_enum(&**tagged),
}
Expand Down
34 changes: 23 additions & 11 deletions src/value/tagged.rs
Original file line number Diff line number Diff line change
Expand Up @@ -261,35 +261,47 @@ impl<'de> EnumAccess<'de> for TaggedValue {
}
}

pub struct TaggedValueMapAccess {
inner: Option<TaggedValue>,
/// Represents [`TaggedValue`] as a map accessor.
///
/// A YAML
/// ```yaml
/// !Thing x
/// ```
/// represented as a map with one entry `Thing -> x`.
///
/// When use #[serde(flatten)] or similar newtype pattern,
/// the `visit_enum` is not available by serde internal newtype visitor.
/// So we need to implement a workaround that wrap the `TaggedValue` as a map accessor, which is this.
pub struct TaggedValueRefAsMapAccess<'a> {
inner: Option<&'a TaggedValue>,
}

impl From<TaggedValue> for TaggedValueMapAccess {
fn from(inner: TaggedValue) -> Self {
TaggedValueMapAccess { inner: Some(inner) }
impl<'a> From<&'a TaggedValue> for TaggedValueRefAsMapAccess<'a> {
fn from(inner: &'a TaggedValue) -> Self {
TaggedValueRefAsMapAccess { inner: Some(inner) }
}
}

impl<'de> MapAccess<'de> for TaggedValueMapAccess {
impl<'de> MapAccess<'de> for TaggedValueRefAsMapAccess {
type Error = Error;

fn next_key_seed<K>(&mut self, seed: K) -> Result<Option<K::Value>, Error>
where
K: DeserializeSeed<'de>,
{
if self.inner.is_none() {
return Ok(None);
if let Some(tagged) = self.inner.as_ref() {
let tag = StrDeserializer::<Error>::new(nobang(&tagged.tag.string));
return seed.deserialize(tag).map(Some);
}
let tag = StrDeserializer::<Error>::new(nobang(&self.inner.as_ref().unwrap().tag.string));
seed.deserialize(tag).map(Some)
Ok(None)
}

fn next_value_seed<V>(&mut self, seed: V) -> Result<V::Value, Error>
where
V: DeserializeSeed<'de>,
{
seed.deserialize(self.inner.take().unwrap().value.clone())
let tagged = self.inner.take().expect("`next_key_seed` was not called");
seed.deserialize(tagged.value.clone())
}
}

Expand Down
9 changes: 4 additions & 5 deletions tests/test_de.rs
Original file line number Diff line number Diff line change
Expand Up @@ -264,12 +264,11 @@ fn test_enum_outer_flatten() {
let yaml: &str = indoc! {"
a: !C x
"};
let expected = Outer {
inner: Inner {
a: Enum::C("x".to_owned()),
},
let inner = Inner {
a: Enum::C("x".to_owned()),
};
test_de(yaml, &expected);
test_de(yaml, &inner);
test_de(yaml, &Outer { inner });
let yaml: &str = indoc! {"
a: !C
"};
Expand Down

0 comments on commit 27bb9e4

Please sign in to comment.