Restrict generic type to 'static lifetime

I have been using the following code to send a message and get a response back:

fn send_msg<'a,T,R>(msg :&T) -> R where T: Serialize, for<'d: 'static> R: Deserialize<'d> {
    tx(&serde_json::to_string(msg).unwrap());
    serde_json::from_str(&rx()).unwrap()
}

Playpen example: Rust Playground
Works fine on stable but compiles with a warning:

warning: unnecessary lifetime parameter `'d`
  --> src/main.rs:20:59
   |
20 | fn send_msg<'a,T,R>(msg :&T) -> R where T: Serialize, for<'d: 'static> R: Deserialize<'d> {
   |                                                           ^^^^^^^^^^^
   |
   = help: you can use the `'static` lifetime directly, in place of `'d`

Clear warning only the suggested fix results in a compile error from the borrow checker. So far no problem I kind a excepted the warning for now but recently the beta build that I run started to fail with the following error:

error: lifetime bounds cannot be used in this context
  --> src/main.rs:20:63
   |
20 | fn send_msg<'a,T,R>(msg :&T) -> R where T: Serialize, for<'d: 'static> R: Deserialize<'d> {
   |                                                               ^^^^^^^

warning: unnecessary lifetime parameter `'d`
  --> src/main.rs:20:59
   |
20 | fn send_msg<'a,T,R>(msg :&T) -> R where T: Serialize, for<'d: 'static> R: Deserialize<'d> {
   |                                                           ^^^^^^^^^^^
   |
   = help: you can use the `'static` lifetime directly, in place of `'d`

Unfortunately the suggested fix will not work on stable / beta / nightly.
Can anyone comment on the correct way to restrict the generic type R to objects that de-serialize into objects that don’t have a lifetime?

what happens when you try this?

DeserializeOwned in serde::de - Rust is the trait for that.

1 Like

That will result in the following compile error:

error[E0597]: borrowed value does not live long enough
  --> src/main.rs:24:27
   |
24 |     serde_json::from_str(&rx()).unwrap()
   |                           ^^^^ temporary value does not live long enough
25 | }
   | - temporary value only lives until here
   |
   = note: borrowed value must be valid for the static lifetime...

Unfortunately it seams that the borrow checker is unable to determinate that the de-serialized result will never have a lifetime bound to the input.

DeserializeOwned as sugested by @vitalyd solves the issue.

Btw, for completeness, the way you’d specify the bound with Deserialize is R: for<'de> Deserialize<'de>. This is essentially what DeserializeOwned is. This says it can be deserialized for all lifetimes, including 'static, which means it can’t borrow anything. DeserializeOwned is just a shorter and more to the point name.

Deserializer lifetimes · Serde covers the topic of deserializer lifetimes and trait bounds.

@dtolnay perhaps linking to that section from Deserialize's rustdoc would be helpful. You may also want to mention/link to DeserializeOwned there as well.

For sure. Thanks for pointing that out! I filed serde-rs/serde#1218 to make sure we follow up. I would love a PR! :bookmark:

1 Like