Generic type that implements DeserializeOwned

Below is a non-functioning code example:

use serde_json::json;

#[derive(Serialize, Deserialize, Clone, Debug)]
pub struct Model<T>
where
    T: DeserializeOwned,
{
    pub id: i32,
    pub info: Option<T>,
}

fn main() {
    #[derive(Serialize, Deserialize, Debug, Clone)]
    struct Info {
        name: String,
    }

    let some_model_1: Model<Info> = serde_json::from_value(json!({
        "id": 43,
        "info": {
            "name": "some_model_name"
        }
    }))
    .unwrap();

    println!("some_model_1: {:#?}", some_model_1);

    let some_model_2: Model<Info> = serde_json::from_value(json!({
        "id": 43
    }))
    .unwrap();

    println!("some_model_2: {:#?}", some_model_2);
}

The error is as follows: cannot satisfy 'T: Deserialize<'de>.

So I have added:

#[serde(deserialize_with = "Option::deserialize")]
pub info: Option<T>,

Now the code compiles, but the missing "info" object for some_model_2 causes an error despite using the Option type:

thread 'main' panicked at 'called 'Result::unwrap()' on an 'Err' value: Error("missing field 'info'", line: 0, column: 0)', src\main.rs:34:6

My last solution was to use a custom function to do the deserialization for the info field:

use serde::{de::DeserializeOwned, Deserialize, Deserializer, Serialize};
use serde_json::{json, Value};

#[derive(Serialize, Deserialize, Clone, Debug)]
pub struct Model<T>
where
    T: DeserializeOwned,
{
    pub id: i32,

    #[serde(deserialize_with = "ok_or_none")]
    pub info: Option<T>,
}

fn ok_or_none<'de, D, T>(deserializer: D) -> Result<Option<T>, D::Error>
where
    D: Deserializer<'de>,
    T: Deserialize<'de>,
{
    let v = Value::deserialize(deserializer)?;
    Ok(T::deserialize(v).ok())
}

fn main() {
    #[derive(Serialize, Deserialize, Debug, Clone)]
    struct Info {
        name: String,
    }

    let some_model_1: Model<Info> = serde_json::from_value(json!({
        "id": 43,
        "info": {
            "name": "some_model_name"
        }
    }))
    .unwrap();

    println!("some_model_1: {:#?}", some_model_1);

    let some_model_2: Model<Info> = serde_json::from_value(json!({
        "id": 43
    }))
    .unwrap();

    println!("some_model_2: {:#?}", some_model_2);
}

This change did not help, the same panic bug remains. The ok_or_none function is not even called.

Below are my dependencies:

serde = { version = "1.0.94", features = ["derive"]  }
serde_json = "1.0.40"

I don't know what else I can do to make this work.

Thank you in advance for your help!


Solution 1:

You don't need to use DeserializeOwned, a plain T is enough, when deriving from serde it will check that your attributes can be serialized/deserialized:

use serde::{Deserialize, Serialize};
use serde_json::json;

#[derive(Serialize, Deserialize, Clone, Debug)]
pub struct Model<T> {
    pub id: i32,
    pub info: Option<T>,
}

fn main() {
    #[derive(Serialize, Deserialize, Debug, Clone)]
    struct Info {
        name: String,
    }

    let some_model_1: Model<Info> = serde_json::from_value(json!({
        "id": 43,
        "info": {
            "name": "some_model_name"
        }
    }))
    .unwrap();

    println!("some_model_1: {:#?}", some_model_1);

    let some_model_2: Model<Info> = serde_json::from_value(json!({
        "id": 43
    }))
    .unwrap();

    println!("some_model_2: {:#?}", some_model_2);
}

Playground