0

A type satisfying MyTrait is supposed to be passed to deserialize_data specified by deserialize_with. Here is my sample code:

use serde::{Deserialize, Deserializer}; // 1.0.117
use serde_json; // 1.0.59

type Item = Result<String, Box<dyn std::error::Error + Send + Sync>>;
pub trait MyTrait {
    fn method(ind: &str) -> Item;
}

#[derive(Deserialize)]
pub struct S<T>
where
    T: MyTrait + ?Sized, // intend to pass a type T satisfying `MyTrait` to function `deserialize_data`,
{
    #[serde(deserialize_with = "deserialize_data")]
    //#[serde(bound( deserialize = "T: MyTrait,  for<'de2> T: Deserialize<'de2>" ))]
    pub data: String,
}

fn deserialize_data<'de, D, T>(d: D) -> Result<String, D::Error>
where
    D: Deserializer<'de>,
{
    let ind = <&str>::deserialize(d).unwrap();
    match T::method(ind) {
        Ok(data) => Ok(data),
        Err(e) => Err(serde::de::Error::custom(format_args!("invalid type."))),
    }
}

struct A;
impl MyTrait for A {
    fn method(_ind: &str) -> Item {
        // to make it simple, return constant
        Ok("method".to_string())
    }
}

fn main() {
    let s = r#"{"data": "string"}"#;
    let ob: S<A> = serde_json::from_str(s).unwrap();
}

The compiler complains:

error[E0392]: parameter `T` is never used
  --> src/main.rs:10:14
   |
10 | pub struct S<T>
   |              ^ unused parameter
   |
   = help: consider removing `T`, referring to it in a field, or using a marker such as `PhantomData`

I do use T, and PhantomData doesn't help much. One of the obvious way may be using struct A and its implemented method as crate or something then importing them. This, unfortunately, doesn't apply to my case, so I seek to pass a struct type to deserialize_data and achieve that.

Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
bruceyuan
  • 421
  • 1
  • 3
  • 8
  • It sounds like your problem would be solved following [How to transform fields during deserialization using Serde?](https://stackoverflow.com/q/46753955/155423) – Shepmaster Nov 30 '20 at 17:51

1 Answers1

2

To get the code to compile, you need to:

  • use T in struct S<T>, for example with PhantomData.
  • explicitly pass T to deserialize_data using the turbofish operator ::<>.
  • add the appropriate trait bounds to the T generic type in deserialize_data(), such as MyTrait.

For example (playground):

#[derive(Deserialize)]
pub struct S<T>
where
    T: MyTrait + ?Sized,
{
    #[serde(deserialize_with = "deserialize_data::<_, T>")]
    pub data: String,
    marker: std::marker::PhantomData<T>,
}

fn deserialize_data<'de, D, T>(d: D) -> Result<String, D::Error>
where
    D: Deserializer<'de>,
    T: MyTrait + ?Sized,
{
    // ...
}
user4815162342
  • 141,790
  • 18
  • 296
  • 355