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

Comments

2 participants
@andete

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

This comment has been minimized.

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

This comment has been minimized.

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

This comment has been minimized.

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

This comment has been minimized.

andete commented Mar 12, 2018

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

@andete andete closed this Mar 12, 2018

@dtolnay dtolnay added the support label Mar 28, 2018

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