This repository has been archived by the owner on Mar 25, 2024. It is now read-only.
-
-
Notifications
You must be signed in to change notification settings - Fork 174
Fallback on default enum variant when no tag is present #338
Comments
This was referenced Oct 21, 2022
Here are 2 possible implementations. A conceptually simpler one where we just insert a // [dependencies]
// serde = { version = "1.0.147", features = ["derive"] }
// serde_yaml = "0.9.14"
use serde::{Deserialize, Deserializer};
#[derive(Deserialize, Debug, PartialEq)]
#[serde(remote = "Self")]
enum Enum {
Variant(String),
Other(u32),
Default(String),
}
impl<'de> Deserialize<'de> for Enum {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
let tagged_value = match serde_yaml::Value::deserialize(deserializer)? {
serde_yaml::Value::Tagged(tagged_value) => *tagged_value,
value => serde_yaml::value::TaggedValue {
tag: serde_yaml::value::Tag::new("Default"),
value,
},
};
Enum::deserialize(tagged_value).map_err(serde::de::Error::custom)
}
} or a slightly more verbose one that avoids allocation and supports borrowing: use serde::de::value::{BorrowedStrDeserializer, EnumAccessDeserializer};
use serde::de::{Deserializer, EnumAccess, Visitor};
use serde::Deserialize;
use std::fmt;
use std::marker::PhantomData;
#[derive(Deserialize, Debug, PartialEq)]
#[serde(remote = "Self")]
enum Enum<'a> {
Variant(&'a str),
Other(u32),
Default(&'a str),
}
impl<'de: 'a, 'a> Deserialize<'de> for Enum<'a> {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
struct EnumVisitor<'de>(PhantomData<fn() -> Enum<'de>>);
impl<'de> Visitor<'de> for EnumVisitor<'de> {
type Value = Enum<'de>;
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
formatter.write_str("enum Enum")
}
fn visit_borrowed_str<E>(self, s: &'de str) -> Result<Self::Value, E>
where
E: serde::de::Error,
{
let de = BorrowedStrDeserializer::new(s);
Deserialize::deserialize(de).map(Enum::Default)
}
fn visit_enum<A>(self, data: A) -> Result<Self::Value, A::Error>
where
A: EnumAccess<'de>,
{
let de = EnumAccessDeserializer::new(data);
Enum::deserialize(de)
}
}
deserializer.deserialize_any(EnumVisitor(PhantomData))
}
} |
Thanks a lot, I got it working just fine for my use case with your instructions! As I needed to do serialization as well I had to add to explicitly re-implement impl Serialize for Enum {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer
{
Enum::serialize(self, serializer)
}
} since adding Anyhow, thanks for the help ! 🙏 |
Sign up for free
to subscribe to this conversation on GitHub.
Already have an account?
Sign in.
Hi and thanks for the lib, especially the latest work on YAML tags which it makes it really useable!
I am trying to figure out if there is a way to have a « default » tag applied when none is defined but the expected target type is an enum wanting a tag to be defined.
In code, is there anyway to have this passing ?
I basically want the YAML to be deserialized into an enum, where only some tags are specified, and the others “default” to one of the variants.
Thanks in advance !
The text was updated successfully, but these errors were encountered: