I am trying to implement a binary tree. I want the node data to be separate, because there are many different ways in which this can be implemented, while algorithms on the tree should be generic and independent of how the data is stored.
But I am running into a weird issue with the borrow checker. Basically, when I switch impl<TValue> Display for dyn Tree<TValue> with impl<TValue> Display for TreeNode<TValue>, the problem goes away. But I have no idea why. Why is the Trait causing this issue?
My code is this:
use std::fmt::{Display, Formatter};
struct TreeNode<TValue> {
value: TValue,
left: Option<Box<TreeNode<TValue>>>,
right: Option<Box<TreeNode<TValue>>>,
}
trait Tree<TValue> {
fn value(&self) -> &TValue;
fn left(&self) -> Option<&dyn Tree<TValue>>;
fn right(&self) -> Option<&dyn Tree<TValue>>;
}
impl<TValue> Display for dyn Tree<TValue>
where
TValue: Display,
{
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
f.write_str("(")?;
Display::fmt(self.value(), f)?;
f.write_str(", ")?;
match self.left() {
Some(ref x) => x.fmt(f)?,
None => f.write_str("None")?,
}
f.write_str(", ")?;
match self.right().as_ref() {
Some(x) => x.fmt(f)?,
None => f.write_str("None")?,
}
f.write_str(")")
}
}
impl<TValue> Tree<TValue> for TreeNode<TValue>
where
TValue: Display,
{
fn value(&self) -> &TValue {
&self.value
}
fn left(&self) -> Option<&dyn Tree<TValue>> {
self.left.as_ref().map(|x| &**x as &dyn Tree<TValue>)
}
fn right(&self) -> Option<&dyn Tree<TValue>> {
self.right.as_ref().map(|x| &**x as &dyn Tree<TValue>)
}
}
fn main() {
let tree = Box::new(TreeNode {
value: 1,
left: Some(Box::new(TreeNode {
value: 2,
left: None,
right: None,
})),
right: Some(Box::new(TreeNode {
value: 3,
left: None,
right: None,
})),
}) as Box<dyn Tree<i32>>;
println!("{}", tree);
}
And the compiler prints:
error[E0521]: borrowed data escapes outside of associated function
--> src\main.rs:24:15
|
19 | fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
| -----
| |
| `self` declared here, outside of the associated function body
| `self` is a reference that is only valid in the associated function body
| let's call the lifetime of this reference `'1`
...
24 | match self.left() {
| ^^^^^^^^^^^
| |
| `self` escapes the associated function body here
| argument requires that `'1` must outlive `'static`
To me, this makes no sense. Nothing in the function body captures this value and tries to keep it beyond the scope of this function. Is this some borrow checker limitation?
There are some mental hoops that the compiler has to jump through to reason about your code. Spoilers, the reason is that when you have dyn Tree<TValue> (where you are implementing Display), the lifetime constraining the type defaults to 'static. So when you call x.fmt(f), the x type must be 'static in order to implement the fmt method, and looking backwards means that the self used in self.left() to get x must be 'static as well. But it's not, and thus the error.
The simple fix is to implement Display for dyn Tree<TValue> with any lifetime:
impl<'a, TValue> Display for dyn Tree<TValue> + 'a
Related
I have reduced my actual code to this minimal example:
trait Producer<P> where P: Something {
fn produce(&self) -> Box<P>;
}
struct P1 {}
impl Producer<B1> for P1 {
fn produce(&self) -> Box<B1> {
Box::new(B1 {})
}
}
trait Something {}
trait Borrower<'b> {
type B: std::fmt::Display;
fn borrow(&'b self) -> Self::B;
}
struct B1 {}
impl Something for B1 {}
impl<'b> Borrower<'b> for B1 {
type B = Borrowing1<'b>;
fn borrow(&'b self) -> Self::B {
Borrowing1 { _b: &self }
}
}
struct Borrowing1<'b> {
_b: &'b B1,
}
impl<'b> std::fmt::Display for Borrowing1<'b> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "Borrowing1")
}
}
fn perform<'b, P, B>(producer: P) where P: Producer<B>, B: Something + Borrower<'b> + 'static {
for _ in 0..1 {
let b = producer.produce();
let s = b.borrow().to_string();
eprintln!("{}", s);
}
}
fn main() {
let p1 = P1 {};
perform(p1);
}
I have a Producer type that creates Something. And that something can implement Borrower<'b>, which introduces a lifetime. Then, I want to restrict a function perform to receive producers that produce Something with the trait Borrower<'b>. However, since I can't prevent introducing a lifetime in perform the function thinks that all produced items must live for the entire function execution. Actually, they are static objects that just implement Borrower<'b>. But I struggle finding the correct bounds.
The error message reflects that:
error[E0597]: `*b` does not live long enough
--> src/main.rs:46:17
|
43 | fn perform<'b, P, B>(producer: P) where P: Producer<B>, B: Something + Borrower<'b> + 'static {
| -- lifetime `'b` defined here
...
46 | let s = b.borrow().to_string();
| ^---------
| |
| borrowed value does not live long enough
| argument requires that `*b` is borrowed for `'b`
47 | eprintln!("{}", s);
48 | }
| - `*b` dropped here while still borrowed
Maybe you can help me with that.
This can be solved using higher-rank trait bounds:
You don't have to pass a lifetime to function here. Instead you need to define a lifetime on the go when borrow() is called. Following should solve the issue:
fn perform<P, B>(producer: P)
where
P: Producer<B>,
for<'b> B: Something + Borrower<'b> + 'static,
{
for _ in 0..1 {
let b = producer.produce();
let u = b.borrow();
let s = u.to_string();
eprintln!("{}", s);
}
}
Playground
Higher-rank trait bounds are explained pretty nicely here: How does for<> syntax differ from a regular lifetime bound?
TL;DR
Having problems with lifetime with nested objects. Code is below.
Long Version:
I'm writing a multiplayer game using ggez, and I'm trying to create an abstraction layer for the input (to allow local and remote players play together).
In order to so, I've created an Input trait, and implemented KeyboardInput for local input, which uses ggez keyboard state querying methods.
Now the tricky part: ggez creates Context object at startup, and expects a reference to it in most of the functions that is exposes.
because my KeyboardInput implementation is using ggez input method (specifically, is_key_pressed), it has to pass &Context to this method. However, since the trait itself should be generic, it won't need a Context reference for any other implementation (for example, NetworkInput).
my solution was to add a reference to Context as field in the KeyboardInput struct. However, that caused a lifetime error that I'm still unable to resolve.
I also tried to make the lifetime 'static, but that did not work either.
here is the relevant code:
pub trait Input {
fn get_direction(&self) -> Direction;
}
pub struct KeyboardInput<'a> {
left_key: KeyCode,
right_key: KeyCode,
_ctx: &'a Context
}
impl KeyboardInput<'_> {
pub fn new(_ctx: &Context, left_key: KeyCode, right_key: KeyCode) -> KeyboardInput {
KeyboardInput{
_ctx,
left_key,
right_key
}
}
}
impl Input for KeyboardInput<'_> {
fn get_direction(&self) -> Direction {
if ggez::input::keyboard::is_key_pressed(self._ctx, self.left_key) {
return Direction::Left;
}
if ggez::input::keyboard::is_key_pressed(self._ctx, self.right_key) {
return Direction::Right;
}
Direction::Unchanged
}
}
struct Player {
angle: f32,
pos_x: f32,
pos_y: f32,
input_manager: Box<dyn Input>,
}
impl <'a>MainState {
fn new(ctx: &'a Context) -> GameResult<MainState> {
let kbd_input = KeyboardInput::new(ctx, KeyCode::Left, KeyCode::Right);
let kbd_input = Box::new(kbd_input);
let s = MainState {
last_update: Instant::now(),
players: vec![
Player::new(kbd_input)
]
};
Ok(s)
}
}
pub fn main() -> GameResult {
let cb = ggez::ContextBuilder::new("My game", "ggez");
let (ctx, event_loop) = &mut cb.build()?;
let state = &mut MainState::new(&ctx)?;
event::run(ctx, event_loop, state)
}
and the compiler error:
error[E0495]: cannot infer an appropriate lifetime for lifetime parameter in function call due to conflicting requirements
--> src\main.rs:75:25
|
75 | let kbd_input = KeyboardInput::new(ctx, KeyCode::Left, KeyCode::Right);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
note: first, the lifetime cannot outlive the lifetime `'a` as defined on the impl at 72:7...
--> src\main.rs:72:7
|
72 | impl <'a>MainState {
| ^^
note: ...so that reference does not outlive borrowed content
--> src\main.rs:75:44
|
75 | let kbd_input = KeyboardInput::new(ctx, KeyCode::Left, KeyCode::Right);
| ^^^
= note: but, the lifetime must be valid for the static lifetime...
= note: ...so that the expression is assignable:
expected std::boxed::Box<(dyn input_manager::Input + 'static)>
found std::boxed::Box<dyn input_manager::Input>
This error almost always means that you are trying to store a value in a way where it can exist longer than it's lifetime.
Let's look at a specific piece of code, annotated with explicit types and lifetimes:
impl<'a> MainState {
fn new(ctx: &'a Context) -> GameResult<MainState> {
let kbd_input: KeyboardInput<'a> = KeyboardInput::new(ctx, KeyCode::Left, KeyCode::Right);
let kbd_input: Box<dyn Input + 'a> = Box::new(kbd_input);
let s: MainState = MainState {
last_update: Instant::now(),
players: vec![
Player::new(kbd_input as Box<dyn Input + 'static>)
]
};
Ok(s)
}
}
On line 9, you're trying to assign kbd_input to Box<dyn Input>. But Box<dyn Input> has no explicit lifetime, it is implicitly equivalent to Box<dyn Input + 'static>. So you're trying to assign a value with lifetime 'a to a type with a static lifetime, which is not allowed.
The solution is to explicitly set the lifetime of the trait object type: Box<dyn Input + 'a>. This cascades and means that you'll need to add a lifetime to the MainState struct as well, as it now will contain a type with a non-static lifetime:
struct MainState<'a> {
/* ... */
players: Vec<Box<dyn Input + 'a>>,
}
Chapter 13 of the Rust book (2nd edition) contains an example of a simple calculation cache. Cacher takes the calculation function as a constructor param, and will cache the result - after the first call, it will not invoke the function again, but simply return the cached result:
struct Cacher<T>
where
T: Fn(u32) -> u32,
{
calculation: T,
value: Option<u32>,
}
impl<T> Cacher<T>
where
T: Fn(u32) -> u32,
{
fn new(calculation: T) -> Cacher<T> {
Cacher {
calculation,
value: None,
}
}
fn value(&mut self, arg: u32) -> u32 {
match self.value {
Some(v) => v,
None => {
let v = (self.calculation)(arg);
self.value = Some(v);
v
}
}
}
}
It is very limited, and there are a couple of improvement suggestions in the book, left as an exercise for the reader.
So I'm trying to make it cache multiple values. The Cacher holds a HashMap with result values, instead of just one value. When asked for a value, if it has in the map (cache), return it. Otherwise, calculate it, store it the cache, and then return it.
The cacher takes references, because it doesn't want to own the inputs. When using it (see unit test), I'm borrowing, because the cacher owns the results.
Here's my attempt:
use std::collections::HashMap;
struct Cacher<T>
where
T: Fn(&u32) -> u32,
{
calculation: T,
values: HashMap<u32, u32>,
}
impl<T> Cacher<T>
where
T: Fn(&u32) -> u32,
{
fn new(calculation: T) -> Cacher<T> {
Cacher {
calculation,
values: HashMap::new(),
}
}
fn value(&mut self, arg: u32) -> &u32 {
let values = &mut self.values;
match values.get(&arg) {
Some(v) => &v,
None => {
let v = (self.calculation)(&arg);
values.insert(arg, v);
&values.get(&arg).unwrap()
}
}
}
}
#[test]
fn call_with_different_values() {
let mut c = Cacher::new(|a| a + 1);
let v1 = c.value(1);
assert_eq!(*v1, 2);
let v2 = c.value(2);
assert_eq!(*v2, 3);
}
Compiler output:
22 | fn value(&mut self, arg: u32) -> &u32 {
| - let's call the lifetime of this reference `'1`
23 | let values = &mut self.values;
24 | match values.get(&arg) {
| ------ immutable borrow occurs here
25 | Some(v) => &v,
| -- returning this value requires that `*values` is borrowed for `'1`
...
28 | values.insert(arg, v);
| ^^^^^^^^^^^^^^^^^^^^^ mutable borrow occurs here
I'm borrowing self.values as mutable on line 23. However, when I try to use it on the following line, I get the "immutable borrow" error. How is match values.get(arg) an immutable borrow of values ? Didn't the borrowing already happen ?
There is also the error for line 25. From my understanding of lifetime elision rules, the 3rd one should apply here - we have &mut self as a method parameter, so it's lifetime should be automatically assigned to the return value ?
I do not think that you are going to be happy with that signature:
fn value(&mut self, arg: u32) -> &u32
Without lifetime elision this is read as:
fn value(&'a mut self, arg: u32) -> &'a u32
Even if you implement it correctly this has huge implications. For example you can not call value again as long as old results are still in use. And rightly so, after all nothing is preventing the function body to delete old values from the cache.
Better to follow #hellow advice and make the return type u32.
Another misunderstanding: Just because you borrowed values already, does not mean you cannot borrow from it again.
Now to answer your original question:
The compiler is not lying to you values.get(arg) is indeed an immutable borrow of values. The technical explanation is that the signature of that method call is (simplified) get(&self, k: &Q) -> Option<&V>. So the borrow of self (aka values) is valid as long as &V can still be referenced. &V however needs to be valid for the entire function body at least (so it can be returned). Now you tried to mutably borrow in the None case which means &V never existed in the first place. So if the compiler gets smarter it may allow your code to run, but for now (1.34.0) it isn't.
I'm trying to implement lazy "thunks" in Rust and I just can't figure out how to get my code to pass the borrow checker. The basic idea is that a Thunk<T> can only be in one of two ThunkStates:
Forced which carries its value of type T;
Unforced, which carries a boxed closure that returns a T.
My naïve code goes like this:
pub struct Thunk<T>(ThunkState<T>);
enum ThunkState<T> {
Forced(T),
Unforced(Box<Fn() -> T>),
}
impl<T> Thunk<T> {
pub fn new<F>(f: F) -> Thunk<T>
where
F: Fn() -> T + 'static,
{
Thunk(ThunkState::Unforced(Box::new(f)))
}
pub fn get(&mut self) -> &T {
match self.0 {
ThunkState::Forced(ref t) => &t,
ThunkState::Unforced(ref f) => {
// TROUBLE HERE
self.0 = ThunkState::Forced(f());
self.get()
}
}
}
}
I get the following two compilation errors:
error[E0506]: cannot assign to `self.0` because it is borrowed
--> src/main.rs:21:17
|
19 | ThunkState::Unforced(ref f) => {
| ----- borrow of `self.0` occurs here
20 | // TROUBLE HERE
21 | self.0 = ThunkState::Forced(f());
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ assignment to borrowed `self.0` occurs here
error[E0502]: cannot borrow `*self` as mutable because `self.0.0` is also borrowed as immutable
--> src/main.rs:22:17
|
19 | ThunkState::Unforced(ref f) => {
| ----- immutable borrow occurs here
...
22 | self.get()
| ^^^^ mutable borrow occurs here
23 | }
24 | }
| - immutable borrow ends here
I've gone through various iterations of trying out stuff (e.g., match *self.0, using &mut in the ThunkState patterns, and a few variations), but try as I may, I can't figure out how to fix it.
Am I attempting to do something that doesn't make sense?
If not, what makes this example so tricky, and how do I get it right?
Staring at it a bit more, I've formulated the following hypothesis: the assignment to self.0 would invalidate the f reference in that match branch. Is this right? And if so, then how do I achieve what I'm trying to do—discard the closure after I use it?
Your original code works as-is with non-lexical lifetimes enabled (available in the 2018 edition):
pub struct Thunk<T>(ThunkState<T>);
enum ThunkState<T> {
Forced(T),
Unforced(Box<Fn() -> T>),
}
impl<T> Thunk<T> {
pub fn new<F>(f: F) -> Thunk<T>
where
F: Fn() -> T + 'static,
{
Thunk(ThunkState::Unforced(Box::new(f)))
}
pub fn get(&mut self) -> &T {
match self.0 {
ThunkState::Forced(ref t) => t,
ThunkState::Unforced(ref f) => {
self.0 = ThunkState::Forced(f());
self.get()
}
}
}
}
This is now supported because the tracking of what is borrowed in which match arm is now more precise.
This is indeed a tricky problem, but it is possible. For stuff like this, it's often a good idea to search for helpful functions in the mem module.
I've come up with a solution, but I think that there is still a lot of room for improvement.
pub fn get(&mut self) -> &T {
let mut f = None;
if let ThunkState::Unforced(ref mut f_ref) = self.0 {
f = Some(std::mem::replace(f_ref, unsafe {
std::mem::uninitialized()
}));
}
if let Some(f) = f {
self.0 = ThunkState::Forced(f());
}
match self.0 {
ThunkState::Forced(ref t) => &t,
_ => unreachable!(),
}
}
This compiles fine, at least. The trick is to use mem::replace to get the important value out of self first. Additionally, you can avoid the unsafe by creating some kind of dummy value (like Box::new(|| panic!())).
I found something that semi-works:
pub struct Thunk<T>(ThunkState<T>);
enum ThunkState<T> {
Forced(T),
Unforced(Box<Fn() -> T>),
}
impl<T> Thunk<T> {
pub fn new<F>(f: F) -> Thunk<T>
where
F: Fn() -> T + 'static,
{
Thunk(ThunkState::Unforced(Box::new(f)))
}
pub fn get(&mut self) -> &T {
match self.0 {
ThunkState::Forced(ref t) => &t,
// Don't actually bind a variable to the boxed closure here.
ThunkState::Unforced(_) => {
self.0 = ThunkState::Forced(self.0.compute());
self.get()
}
}
}
}
impl<T> ThunkState<T> {
fn compute(&self) -> T {
match self {
&ThunkState::Unforced(ref f) => f(),
// FIXME: get rid of this panic?
&ThunkState::Forced(_) => panic!("case never used"),
}
}
}
It compiles, but after trying to use this type what I've learned is that I probably need interior mutability.
The problem is that you're trying to do too much (for the sake of avoiding return) within the lexical borrowing context of match self.0 { ... }.
What you can do is:
Move results of calculations performed on values you need to borrow from self.0 into variables defined in an outer scope.
Exit early on paths where those values aren't needed
Consume the values after the match statement
Applied to your example, a solution could be:
pub struct Thunk<T>(ThunkState<T>);
enum ThunkState<T> {
Forced(T),
Unforced(Box<Fn() -> T>),
}
impl<T> Thunk<T> {
pub fn new<F>(f: F) -> Thunk<T>
where
F: Fn() -> T + 'static,
{
Thunk(ThunkState::Unforced(Box::new(f)))
}
pub fn get(&mut self) -> &T {
let func_result: T;
match self.0 {
ThunkState::Forced(ref t) => {
return &t;
}
ThunkState::Unforced(ref f) => {
func_result = f();
}
}
self.0 = ThunkState::Forced(func_result);
self.get()
}
}
Consider this simple protocol implementation:
#[derive(PartialEq, Debug)]
enum Req<'a> {
InputData(&'a [u8]),
Stop,
}
impl<'a> Req<'a> {
fn decode(packet: &'a [u8]) -> Result<Req<'a>, String> {
match packet.first() {
Some(&0x01) => Ok(Req::InputData(&packet[1..])),
Some(&0x02) => Ok(Req::Stop),
_ => Err(format!("invalid request: {:?}", packet)),
}
}
}
#[derive(PartialEq, Debug)]
enum Rep<'a> {
OutputData(&'a [u8]),
StopAck,
}
impl<'a> Rep<'a> {
fn decode(packet: &'a [u8]) -> Result<Rep<'a>, String> {
match packet.first() {
Some(&0x01) => Ok(Rep::OutputData(&packet[1..])),
Some(&0x02) => Ok(Rep::StopAck),
_ => Err(format!("invalid reply: {:?}", packet)),
}
}
}
fn assert_req(packet: Vec<u8>, sample: Req) {
assert_eq!(Req::decode(&packet), Ok(sample));
}
fn assert_rep(packet: Vec<u8>, sample: Rep) {
assert_eq!(Rep::decode(&packet), Ok(sample));
}
fn main() {
assert_req(vec![1, 2, 3], Req::InputData(&[2, 3]));
assert_req(vec![2], Req::Stop);
assert_rep(vec![1, 2, 3], Rep::OutputData(&[2, 3]));
assert_rep(vec![2], Rep::StopAck);
}
playground
This works, but the two functions assert_req and assert_rep have identical code with only a difference in types. It is a good idea to write one generic assert_packet:
trait Decode<'a>: Sized {
fn decode(packet: &'a [u8]) -> Result<Self, String>;
}
#[derive(PartialEq, Debug)]
enum Req<'a> {
InputData(&'a [u8]),
Stop,
}
impl<'a> Decode<'a> for Req<'a> {
fn decode(packet: &'a [u8]) -> Result<Req<'a>, String> {
match packet.first() {
Some(&0x01) => Ok(Req::InputData(&packet[1..])),
Some(&0x02) => Ok(Req::Stop),
_ => Err(format!("invalid request: {:?}", packet)),
}
}
}
#[derive(PartialEq, Debug)]
enum Rep<'a> {
OutputData(&'a [u8]),
StopAck,
}
impl<'a> Decode<'a> for Rep<'a> {
fn decode(packet: &'a [u8]) -> Result<Rep<'a>, String> {
match packet.first() {
Some(&0x01) => Ok(Rep::OutputData(&packet[1..])),
Some(&0x02) => Ok(Rep::StopAck),
_ => Err(format!("invalid reply: {:?}", packet)),
}
}
}
fn assert_packet<'a, T>(packet: Vec<u8>, sample: T)
where
T: Decode<'a> + PartialEq + std::fmt::Debug,
{
assert_eq!(T::decode(&packet), Ok(sample));
}
fn main() {
assert_packet(vec![1, 2, 3], Req::InputData(&[2, 3]));
assert_packet(vec![2], Req::Stop);
assert_packet(vec![1, 2, 3], Rep::OutputData(&[2, 3]));
assert_packet(vec![2], Rep::StopAck);
}
playground
However, this triggers a "does not live long enough" error:
error[E0597]: `packet` does not live long enough
--> src/main.rs:41:27
|
41 | assert_eq!(T::decode(&packet), Ok(sample));
| ^^^^^^ does not live long enough
42 | }
| - borrowed value only lives until here
|
note: borrowed value must be valid for the lifetime 'a as defined on the function body at 37:1...
--> src/main.rs:37:1
|
37 | / fn assert_packet<'a, T>(packet: Vec<u8>, sample: T)
38 | | where
39 | | T: Decode<'a> + PartialEq + std::fmt::Debug,
40 | | {
41 | | assert_eq!(T::decode(&packet), Ok(sample));
42 | | }
| |_^
If I understand correctly, the problem is in the function signature:
fn assert_packet<'a, T>(packet: Vec<u8>, sample: T)
where
T: Decode<'a>
Here, packet is destroyed when the function returns, but the user-provided 'a lifetime parameter says that the lifetime should end somewhere outside the assert_packet function. Is there any right solution? How should the signature look? Maybe higher rank trait bounds could help here?
Why does this compile:
fn assert_req(packet: Vec<u8>, sample: Req) {
assert_eq!(Req::decode(&packet), Ok(sample));
}
while this doesn't?
fn assert_packet<'a, T>(packet: Vec<u8>, sample: T) where T: Decode<'a> + PartialEq + std::fmt::Debug {
assert_eq!(T::decode(&packet), Ok(sample));
}
The difference is that in the first version, the two textual occurrences of Req name two different instances of the Req<'a> struct, with two different lifetimes. The first occurrence, on the sample parameter, is specialized with a lifetime parameter received by the assert_req function. The second occurrence, used to invoke decode, is specialized with the lifetime of the packet parameter itself (which ceases to exist as soon as the function returns). This means that the two arguments to assert_eq! don't have the same type; yet, it compiles because Req<'a> can be coerced to a Req<'b> where 'b is a shorter lifetime than 'a (Req<'a> is a subtype of Req<'b>).
On the other hand, in the second version, both occurrences of T must represent the exact same type. Lifetime parameters are always assumed to represent lifetimes that are longer than the function call, so it's an error to invoke T::decode with a lifetime that is shorter.
Here's a shorter function that exhibits the same problem:
fn decode_packet<'a, T>(packet: Vec<u8>) where T: Decode<'a> {
T::decode(&packet);
}
This function fails to compile:
<anon>:38:16: 38:22 error: `packet` does not live long enough
<anon>:38 T::decode(&packet);
^~~~~~
It's possible to use higher rank trait bounds on this function to make it compile:
fn decode_packet<T>(packet: Vec<u8>) where for<'a> T: Decode<'a> {
T::decode(&packet);
}
However, now we have another problem: we can't invoke this function! If we try to invoke it like this:
fn main() {
decode_packet(vec![1, 2, 3]);
}
We get this error:
<anon>:55:5: 55:18 error: unable to infer enough type information about `_`; type annotations or generic parameter binding required [E0282]
<anon>:55 decode_packet(vec![1, 2, 3]);
^~~~~~~~~~~~~
That's because we didn't specify which implementation of Decode we want to use, and there are no parameters the compiler can use to infer this information.
What if we specify an implementation?
fn main() {
decode_packet::<Req>(vec![1, 2, 3]);
}
We get this error:
<anon>:55:5: 55:25 error: the trait `for<'a> Decode<'a>` is not implemented for the type `Req<'_>` [E0277]
<anon>:55 decode_packet::<Req>(vec![1, 2, 3]);
^~~~~~~~~~~~~~~~~~~~
That doesn't work, because the Req we wrote is actually interpreted as Req<'_>, where '_ is a lifetime inferred by the compiler. This doesn't implement Decode for all possible lifetimes, only for one particular lifetime.
In order to be able to implement your desired function, Rust would have to support higher kinded types. It would then be possible to define a type constructor parameter (instead of a type parameter) on the function. For instance, you'd be able to pass Req or Rep as a type constructor requiring a lifetime parameter to produce a specific Req<'a> type.
It works correctly if you link the lifetimes involved to the input which you'll be referencing, e.g.
fn assert_packet<'a, T>(packet: &'a [u8], sample: T) where T: Decode<'a> ..
(You'll also need to update the tests to pass borrows rather than owned Vecs.)