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 deserialize_with #1174

Closed
andete opened this issue Mar 12, 2018 · 4 comments
Closed

enum variant deserialize_with #1174

andete opened this issue Mar 12, 2018 · 4 comments
Labels

Comments

@andete
Copy link

andete commented Mar 12, 2018

While working on deserializing json data to an enum I wanted to use the enum variant deserialize_with feature.

I first tried it with my own data structure, which fails with "invalid type: unit variant, expected newtype variant".

The tiny program can be found at: https://github.com/andete/blog-code/blob/master/serde_deserialize_enum_1/src/bin/6.rs

To be sure I understood the approach correctly I looked at the serde testsuite and created the following example program based on a testcase in the test suite:

https://github.com/andete/blog-code/blob/master/serde_deserialize_enum_1/src/bin/6a.rs

This one fails differently with: "ExpectedSomeValue, line: 1, column: 1".

I hope I'm misinterpreting the docs and doing something wrong, else perhaps there is an issue with this feature. The testsuite test does not fail however. Maybe it is some issue that only happens when serde is combined with an actual data structure (serde_json in this case) as the testsuite test does not.

@dtolnay
Copy link
Member

dtolnay commented Mar 12, 2018

The deserialize_with applies to the content of the enum variant. The ones you wrote return Result<(), D::Error> because they apply to a unit variant holding no content, (). Written in JSON form the 6a test from the test suite is testing the input {"Unit":0}.

@andete
Copy link
Author

andete commented Mar 12, 2018

Aha, indeed, like that it works. I guess the feature is not really suitable for my original idea, deserializing several different spellings to one unit variant. Guess I'll stick with a Deserialize trait impl.

@dtolnay
Copy link
Member

dtolnay commented Mar 12, 2018

Here is a quick way to use the default Deserialize logic for all the other variants.

use serde::de::{Deserialize, Deserializer, IntoDeserializer};

#[derive(Debug, Deserialize)]
#[serde(rename_all = "lowercase")]
#[serde(remote = "State")]
pub enum State {
    Expansion,
    CivilWar,
    /* ... */
}

impl<'de> Deserialize<'de> for State {
    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
        where D: Deserializer<'de>
    {
        let s = String::deserialize(deserializer)?;
        if s == "civil war" {
            Ok(State::CivilWar)
        } else {
            State::deserialize(s.into_deserializer())
        }
    }
}

@andete
Copy link
Author

andete commented Mar 12, 2018

That's a neat trick. Thanks! Guess my issue is no longer needed.

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

No branches or pull requests

2 participants