jplatte / serde_html_form

Rust crate for (de-)serialization of `application/x-www-form-urlencoded` data.
MIT License
23 stars 3 forks source link

Doesn't work with untagged enums #20

Closed imbolc closed 5 months ago

imbolc commented 5 months ago
#[derive(serde::Deserialize)]
pub struct Form {
    value: Vec<String>,
}

#[derive(serde::Deserialize)]
#[serde(untagged)]
pub enum EnumForm {
    Form(Form),
}

fn main() {
    // Works
    let _: Form = serde_html_form::from_str("value=&value=abc").unwrap();

    // Error("data did not match any variant of untagged enum EnumForm")
    let _: EnumForm = serde_html_form::from_str("value=&value=abc").unwrap();
}
jplatte commented 5 months ago

This is an instance of https://github.com/serde-rs/serde/issues/1183, just like #18. There's nothing this library can do about it.

What you can do is write a Deserialize impl like this instead of relying on #[serde(untagged)]:

use serde::de::{Deserialize, Deserializer, Error as _};

impl<'de> Deserialize<'de> for EnumForm {
    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
    where
        D: Deserializer<'de>,
    {
        #[derive(Deserialize)]
        struct FormStructRepr {
            #[serde(default)]
            mutually_exclusive_field_a: Vec<String>,
            mutually_exclusive_field_b: Option<u16>,
        }

        let s = FormStructRepr::deserialize(deserializer)?;
        match (s.mutually_exclusive_field_a.is_empty(), s.mutually_exclusive_field_b) {
            (false, None) => Ok(Self::FormA {
                value: s.mutually_exclusive_field_a,
            }),
            (true, Some(b_value)) => Ok(Self::FormB { value: b_value }),
            (false, Some(_)) => Err(D::Error::custom(
                "only one of mutually_exclusive_field_a, mutually_exclusive_field_b may be set",
            )),
            (true, None) => Err(D::Error::custom(
                "one of mutually_exclusive_field_a, mutually_exclusive_field_b must be set",
            )),
        }
    }
}