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

Deserialize_with on a struct variant with one field does not compile #1215

Closed
dtolnay opened this issue Apr 13, 2018 · 2 comments
Closed

Deserialize_with on a struct variant with one field does not compile #1215

dtolnay opened this issue Apr 13, 2018 · 2 comments

Comments

@dtolnay
Copy link
Member

dtolnay commented Apr 13, 2018

If your struct variant has 0 fields or >1 fields then deserialize_with seems to work.

#[macro_use]
extern crate serde_derive;
extern crate serde;
use serde::Deserializer;

fn de_v<'de, D>(_deserializer: D) -> Result<(String, String), D::Error>
    where D: Deserializer<'de>
{
    unimplemented!()
}

#[derive(Deserialize)]
enum E {
    #[serde(deserialize_with = "de_v")]
    V { a: String, b: String }
}

But if the struct variant has only one field like V { a: String } then neither Result<(String,), D::Error> nor Result<String, D::Error> works as the de_v return type. Either way you get:

error[E0609]: no field `0` on type `std::string::String`
  --> src/main.rs:12:10
   |
12 | #[derive(Deserialize)]
   |          ^^^^^^^^^^^
#[macro_use]
extern crate serde_derive;
extern crate serde;
use serde::Deserializer;

fn de_v<'de, D>(_deserializer: D) -> Result<String, D::Error>
    where D: Deserializer<'de>
{
    unimplemented!()
}

#[derive(Deserialize)]
enum E {
    #[serde(deserialize_with = "de_v")]
    V { a: String }
}

Mentioning @spinda in case you would be interested in tracking this down.

@dtolnay dtolnay added the derive label Apr 13, 2018
@dtolnay
Copy link
Member Author

dtolnay commented Apr 13, 2018

The generated impl looks roughly like this. The problematic line is |__wrap| E::V { a: __wrap.value.0 }.

impl<'de> serde::Deserialize<'de> for E {
    fn deserialize<__D>(__deserializer: __D) -> Result<Self, __D::Error>
    where
        __D: serde::Deserializer<'de>,
    {
        struct __Visitor<'de> {
            marker: PhantomData<E>,
            lifetime: PhantomData<&'de ()>,
        }
        impl<'de> serde::de::Visitor<'de> for __Visitor<'de> {
            type Value = E;
            fn expecting(
                &self,
                formatter: &mut fmt::Formatter,
            ) -> fmt::Result {
                fmt::Formatter::write_str(formatter, "enum E")
            }
            fn visit_enum<__A>(
                self,
                __data: __A,
            ) -> Result<Self::Value, __A::Error>
            where
                __A: serde::de::EnumAccess<'de>,
            {
                match serde::de::EnumAccess::variant(__data)? {
                    (__Field::__field0, __variant) => {
                        struct __DeserializeWith<'de> {
                            value: (String),
                            phantom: PhantomData<E>,
                            lifetime: PhantomData<&'de ()>,
                        }
                        impl<'de> serde::Deserialize<'de> for __DeserializeWith<'de> {
                            fn deserialize<__D>(
                                __deserializer: __D,
                            ) -> Result<Self, __D::Error>
                            where
                                __D: serde::Deserializer<'de>,
                            {
                                Ok(__DeserializeWith {
                                    value: de_v(__deserializer)?,
                                    phantom: PhantomData,
                                    lifetime: PhantomData,
                                })
                            }
                        }
                        Result::map(
                            serde::de::VariantAccess::newtype_variant::<__DeserializeWith<'de>>(
                                __variant,
                            ),
                            { |__wrap| E::V { a: __wrap.value.0 } },
                        )
                    }
                }
            }
        }
        const VARIANTS: &'static [&'static str] = &["V"];
        serde::Deserializer::deserialize_enum(
            __deserializer,
            "E",
            VARIANTS,
            __Visitor {
                marker: PhantomData::<E>,
                lifetime: PhantomData,
            },
        )
    }
}

@dtolnay dtolnay added the bug label Apr 13, 2018
@dtolnay
Copy link
Member Author

dtolnay commented Apr 13, 2018

Fixed in 202c101.

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

No branches or pull requests

1 participant