Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Enum variant aliases don't work #502

Open
momvart opened this issue Nov 30, 2023 · 1 comment
Open

Enum variant aliases don't work #502

momvart opened this issue Nov 30, 2023 · 1 comment

Comments

@momvart
Copy link

momvart commented Nov 30, 2023

Here is a failing example demonstrating that enum variant aliases are not taken into account. It also shows a divergence in behavior compared to using serde_json directly.

#[derive(Debug, serde::Deserialize)]
enum TestEnum {
    #[serde(alias = "f")]
    Foo,
    #[serde(alias = "b")]
    Bar,
}

#[derive(Debug, serde::Deserialize)]
struct Wrapper {
    test: TestEnum,
}

let json = r#"{"test": "f"}"#;
let w: Wrapper = serde_json::from_str(json).unwrap();
println!("{:?}", w);
let w: Wrapper = config::Config::builder()
    .add_source(config::File::from_str(json, config::FileFormat::Json))
    .build()
    .unwrap()
    .try_deserialize()
    .unwrap();
println!("{:?}", w);

Output:

Wrapper { t: Foo }
called `Result::unwrap()` on an `Err` value: enum TestEnum does not have variant constructor f
@sunmy2019
Copy link

In config-rs, the variant_seed cannot create a deserializer on enums with unrecognized values.

config-rs/src/de.rs

Lines 279 to 293 in 57fb261

fn variant_seed<V>(self, seed: V) -> Result<(V::Value, Self::Variant)>
where
V: de::DeserializeSeed<'de>,
{
let value = {
let deserializer = match self.value.kind {
ValueKind::String(ref s) => self.variant_deserializer(s),
ValueKind::Table(ref t) => self.table_deserializer(&t),
_ => Err(self.structural_error()),
}?;
seed.deserialize(deserializer)?
};
Ok((value, self))
}

variant_deserializer only allows name with given str.

config-rs/src/de.rs

Lines 244 to 250 in 57fb261

fn variant_deserializer(&self, name: &str) -> Result<StrDeserializer> {
self.variants
.iter()
.find(|&&s| s == name)
.map(|&s| StrDeserializer(s))
.ok_or_else(|| self.no_constructor_error(name))
}


I got a straightforward fix to demostrate this, it is not the best.

diff --git a/src/de.rs b/src/de.rs
index 0e2b8de..4d014e9 100644
--- a/src/de.rs
+++ b/src/de.rs
@@ -313,8 +313,13 @@ impl<'de> de::EnumAccess<'de> for EnumAccess {
                 ValueKind::String(ref s) => self.variant_deserializer(s),
                 ValueKind::Table(ref t) => self.table_deserializer(t),
                 _ => Err(self.structural_error()),
-            }?;
-            seed.deserialize(deserializer)?
+            };
+            if let Ok(deserializer) = deserializer {
+                seed.deserialize(deserializer)?
+            } else {
+                let deserializer = self.value.clone();
+                seed.deserialize(deserializer)?
+            }
         };
 
         Ok((value, self))

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants