4

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?

4
  • Can you post the exact code that you want to work, and add the error message you are getting? I'm not sure which lines you want to uncomment. Commented Jan 10, 2020 at 18:59
  • Okay. Tried to clarify the non-working attempt to the library code. Commented Jan 10, 2020 at 19:43
  • That helps, thanks! Unfortunately I'm still as mystified as you are... Commented Jan 10, 2020 at 19:47
  • The 1st code proves that you can instantiate X<Main> without Main being Deserialize. No error unless you actually deserialize X<Main> Commented Jan 10, 2020 at 20:26

1 Answer 1

9

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:

Sign up to request clarification or add additional context in comments.

1 Comment

Wow. Thanks. This github discussion with serde author dtolnay also helped to understand why it works like this.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.