Reputation: 528
I am writing a deserializer (Vec<u8>
(Raw JSON) to any type T) for a project and trying to use serde for it. Here's my trait which I to decode the data:
pub trait Decode: Sized {
fn try_decode(input: Vec<u8>) -> Result<Self, InternalError>;
}
Since I intend to use #[derive(Deserialize)]
on my structs, I am writing an impl for any type that implements the Deserialize trait with an arbitrary lifetime:
impl<'a, T: Deserialize<'a>> Decode for T {
fn try_decode(input: Vec<u8>) -> Result<Self, InternalError> {
if let Ok(t) = serde_json::from_slice(&input) {
Ok(t)
} else {
Err(Internal::decode("Could not decode"))
}
}
}
But I am getting a lifetime error:
error[E0597]: `input` does not live long enough
--> src/decode.rs:16:47
|
14 | impl<'a, T: Deserialize<'a>> Decode for T {
| -- lifetime `'a` defined here
15 | fn try_decode(input: Vec<u8>) -> Result<Self, InternalError> {
16 | if let Ok(t) = serde_json::from_slice(&input) {
| -----------------------^^^^^^-
| | |
| | borrowed value does not live long enough
| argument requires that `input` is borrowed for `'a`
...
21 | }
| - `input` dropped here while still borrowed
I understand why the compiler is mad at me. Upon checking the implementation of from_slice, I figured it has an associated lifetime. I am sure input is an owned value, but from_slice requires a reference, so here I am returning reference of a value which gets dropped when the function ends, which is clearly incorrect. My question is, is there a way to ensure that the value is borrowed for <'a> lifetime (i.e. the lifetime supplied by the caller of this function). I can't update the trait because it will cause a disaster.
Upvotes: 0
Views: 294
Reputation: 155196
If you want a value that doesn't borrow from the slice, you can use DeserializeOwned
as the trait bound, which has no associated lifetime (and therefore only stores owned values). For example, this compiles:
impl<T: DeserializeOwned> Decode for T {
fn try_decode(input: Vec<u8>) -> Result<Self, InternalError> {
if let Ok(t) = serde_json::from_slice(&input) {
Ok(t)
} else {
todo!()
}
}
}
This is equivalent to using a higher-ranked trait bound with the lower-level Deserialize
trait bound:
impl<T: for<'de> Deserialize<'de>> Decode for T {
// ...
}
Upvotes: 2
Reputation: 528
The correct way to use Deserialize with a lifetime is using Higher Rank Trait Bounds: Specifically telling compiler that this lifetime is valid for all (concerned) lifetimes using the for<'a>
notation. The code will look like this:
impl<T: for<'de> Deserialize<'de>> InputCoercible for T {
// ...trait methods...
}
Upvotes: 1