简体   繁体   中英

Constraining generic parameter of Rust struct to be Deserialize

I would like to limit a (de)serializable struct to have a generic parameter that is also deserializable. The derive macro Deserialize does not require me to add this constraint, which is nice, but I would like the integration code to get compilation errors even if they never try to deserialize the struct defined in the library.

use failure::Fallible; // 0.1.6
use serde::{Deserialize, Serialize}; // 1.0.104
use serde_json::to_string_pretty; // 1.0.44

#[derive(Deserialize, Serialize)]
struct X<T>
where
    // T: Serialize,
{
    a: u8,
    t: T,
}

type Main<'a> = &'a dyn Fn() -> Fallible<()>;

fn main() -> Fallible<()> {
    let x = X { a: 1, t: false };
    println!("{}", to_string_pretty(&x)?);

    let y: X<bool> = serde_json::from_str(r#"{"a":2,"t":true}"#)?;
    println!("{}", y.t);

    let _z: X<Main> = X { a: 3, t: &main };
    // println!("{}", to_string_pretty(&z)?);

    //let w: X<Main> = serde_json::from_str(r#"{"a":4,"t":NONONO}"#)?;

    Ok(())
}

playground

  • The compilation fails if I uncomment the line with to_string_pretty(&z) , which is good.
  • Even without that line, the compilation fails on the let _z = ... line if I uncomment where T: Serialize . This is great, because it helps the library integrators to spot they are using struct X with a non-serializable type parameter even before they actually start serializing it.

I have tried to add where for<'a> T: serde::de::Deserialize<'a> as a constraint to struct X<T> , but that breaks the build even without anything using X

use serde::{Deserialize, Serialize};

#[derive(Deserialize, Serialize)]
struct X<T>
where
    for<'a> T: serde::de::Deserialize<'a>,
{
    a: u8,
    t: T,
}

playground

Is there a way to phrase this constraint I am looking for?

You need to use #[serde(bound)] to prevent Serde from attempting to automatically determine the bounds on the Deserialize and Serialize implementations:

use serde::{Deserialize, Serialize};

#[derive(Deserialize, Serialize)]
#[serde(bound = "T: Serialize, for<'de2> T: Deserialize<'de2>")]
struct X<T>
where
    T: Serialize,
    for<'de2> T: Deserialize<'de2>,
{
    t: T,
}

struct NotSerializable;

fn main() {
    X { t: true };

    // X { t: NotSerializable }; // Generates compiler error
}

See also:

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM