Is it possible to implement a trait for any lifetime of &str
when the trait has functions returning Self
?
The closest solution that I have been able to get is the following:
use std::str;
use std::fmt::Display;
pub trait Deserializer<'a>: Sized {
type Error: Display;
fn deserialize(_: &'a [u8]) -> Result<Self, <Self as Deserializer>::Error>;
}
impl<'a: 's, 's> Deserializer<'a> for &'s str {
type Error = str::Utf8Error;
// ↓ returns &str
fn deserialize(bytes: &'a [u8]) -> Result<Self, <Self as Deserializer>::Error> {
str::from_utf8(bytes)
}
}
fn test<'a, D, F>(mut f: F) -> Result<(), <D as Deserializer<'a>>::Error>
where
F: FnMut(D),
D: Deserializer<'a>,
{
let xs: Vec<u8> = vec![0, 1];
f(D::deserialize(&xs[..])?);
Ok(())
}
fn main() {
test(|_: &str| ()).unwrap();
}
The compiler rejects the code because xs
is expected to have a different lifetime:
error[E0597]: `xs` does not live long enough
--> 1.rs:25:23
|
19 | fn test<'a, D, F>(mut f: F) -> Result<(), <D as Deserializer<'a>>::Error>
| -- lifetime `'a` defined here
...
25 | f(D::deserialize(&xs[..])?);
| ----------------^^-----
| | |
| | borrowed value does not live long enough
| argument requires that `xs` is borrowed for `'a`
26 | Ok(())
27 | }
| - `xs` dropped here while still borrowed
error: aborting due to previous error
For more information about this error, try `rustc --explain E0597`.
How can I tell the compiler that the lifetime of the deserialize
result is the same lifetime of its argument?
Trait with no lifetimes
Without lifetime parameters:
pub trait Deserializer: Sized {
type Error: Display;
fn deserialize(_: &[u8]) -> Result<Self, <Self as Deserializer>::Error>;
}
impl Deserializer for &str {
type Error = str::Utf8Error;
fn deserialize(bytes: &[u8]) -> Result<Self, <Self as Deserializer>::Error> {
str::from_utf8(bytes)
}
}
Shows a different error:
error[E0495]: cannot infer an appropriate lifetime for lifetime parameter in function call due to conflicting requirements
--> 2.rs:14:9
|
14 | str::from_utf8(bytes)
| ^^^^^^^^^^^^^^^^^^^^^
|
note: first, the lifetime cannot outlive the anonymous lifetime #1 defined on the method body at 13:5...
--> 2.rs:13:5
|
13 | / fn deserialize(bytes: &[u8]) -> Result<Self, <Self as Deserializer>::Error> {
14 | | str::from_utf8(bytes)
15 | | }
| |_____^
note: ...so that reference does not outlive borrowed content
--> 2.rs:14:24
|
14 | str::from_utf8(bytes)
| ^^^^^
note: but, the lifetime must be valid for the lifetime `'_` as defined on the impl at 10:23...
--> 2.rs:10:23
|
10 | impl Deserializer for &str {
| ^
note: ...so that the expression is assignable
--> 2.rs:14:9
|
14 | str::from_utf8(bytes)
| ^^^^^^^^^^^^^^^^^^^^^
= note: expected `std::result::Result<&str, _>`
found `std::result::Result<&str, _>`
Using unsafe
As an exercise, I tried mem::transmute
, and it works (playground).
pub trait Deserializer: Sized {
type Error: Display;
fn deserialize(_: &[u8]) -> Result<Self, <Self as Deserializer>::Error>;
}
impl Deserializer for &str {
type Error = str::Utf8Error;
fn deserialize(bytes: &[u8]) -> Result<Self, <Self as Deserializer>::Error> {
unsafe { std::mem::transmute(str::from_utf8(bytes)) }
}
}