Unconstrained type parameter-2

I am trying to implement a custom JSON deserialize function using serde.
The data type I am working with looks like this -

pub enum MarionetteResponse {
    #[serde(deserialize_with = "deserialize_data", serialize_with = "serialize_data")]
    String(String),
}

The JSON value I receive resembles {"value": "foo"} and I wanted to convert it to the following -
MarionetteResponse::String("foo".into())

I have been trying to implement a generic Visitor for this purpose as there will be many more such types-

fn deserialize_data<'de, D, T>(deserializer: D) -> Result<T, D::Error>
where 
    D: Deserializer<'de>,
    T: serde:: de::DeserializeOwned,
{
      #[derive(Deserialize)]
      struct Wrapper<T> {
          value: T,
      }

    struct WrapperVisitor;

    impl<'de, T> Visitor<'de> for WrapperVisitor 
    where
        T: serde::de::DeserializeOwned,
    {
            type Value = Wrapper<T>;

            fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
                formatter.write_str("temporary struct Wrapper")
            }

            fn visit_map<V>(self, mut map: V) -> Result<Wrapper<T>, V::Error>
            where
                V: MapAccess<'de>,
            {
                let mut val = None;
                while let Some(key) = map.next_key()? {
                    match key {
                        "value" => {
                            if val.is_some() {
                                return Err(de::Error::duplicate_field("value"));
                            }
                            val = Some(map.next_value()?);
                        }
                        
                    }
                }
                let value = val.ok_or_else(|| de::Error::missing_field("value"))?;
                Ok(Wrapper {value})
            }
        }

    const FIELD: &'static [&'static str]= &["value"];
    let w = deserializer.deserialize_struct("Wrapper", FIELD, WrapperVisitor).map_err(de::Error::custom)?;
    Ok(w.value)

I am not sure if this is the optimal approach. But, my immediate problem is the error:

|     impl<'de, T> Visitor<'de> for WrapperVisitor 
|                    ^ unconstrained type parameter

Any suggestions to improve upon this approach and remove this error are welcome.
Please find the link to repository if you wish to understand the bigger picture (branch = bmodel) -
https://github.com/andreastt/marionette-rs/commit/e963fc61328e58639624490b753abc3adb2e54ec

Thanks a lot......!

Doesn't WrapperVisitor have to be generic over T itself? You can't have multiple implementations of one trait for one structure, but for your current implementation to be valid for different Ts it must be implemented for each such T with different Value types.

As a matter of fact I did try changing WrapperVisitor to WrapperVisitor<T> and supplying it to the deserialize_struct method also. But that gives rise to another error -

| struct WrapperVisitor<T>;
| ^ unused type parameter
|
= help: consider removing T or using a marker such as std::marker::PhantomData

Of course, the contents of struct must somehow depend on the generic. As this is a zero-sized type, you can simply write it as struct WrapperVisitor<T>(std::marker::PhantomData<T>).

1 Like

Oh right! Thanks a lot.
I got a simpler solution which might not need a visitor. So I will not overcomplicate this anymore... :smiley: I needed to do the following -

let w = Wrapper::deserialize(deserializer)?;
Ok(w.value)

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.