At work, I stumbled across the following lifetime issue I just couldn't find a solution for. Maybe someone of you finds one, or can at least tell me that it is currently just not possible? Thank you in advance!
I was implementing some sort of BufRead
trait that allows peeking all stored data. The challenge is, that I want to be generic over the different buffer types that might need to return a varying number of slices. To return all stored data, a Vec<u8>
only ever needs to return one slice, a VecDeque<u8>
sometimes two, and a buffer chain potentially multiple.
My first try was to define this part of the trait the following way:
trait BufRead {
fn peek_all(&self) -> impl Iterator<Item = &[u8]>;
}
This worked, until I wanted to write a helper type that allows reading from a generic iterator over slices. A shortened version of this type might look like this:
struct SlicesReader<'b, I: Iterator<Item = &'b [u8]>> {
iter: I,
}
Now, the issue is: No matter how I define the BufRead
trait, some implementation breaks because of lifetime issues. Either I cannot implement BufRead
for my SlicesReader
, or I cannot implement it for another type like VecDeque<u8>
. I have three different variants, and neither of them works:
Version A (Playground)
trait BufRead {
fn peek_all(&self) -> impl Iterator<Item = &[u8]>;
}
impl BufRead for VecDeque<u8> {
fn peek_all(&self) -> impl Iterator<Item = &[u8]> {
let (front, back) = self.as_slices();
[front, back].into_iter()
}
}
impl<'b, I: Iterator<Item = &'b [u8]> + Clone> BufRead for SlicesReader<'b, I> {
fn peek_all(&self) -> impl Iterator<Item = &[u8]> {
self.iter.clone()
}
}
This version fails with the following error:
error: lifetime may not live long enough
--> src/lib.rs:20:9
|
18 | impl<'b, I: Iterator<Item = &'b [u8]> + Clone> BufRead for SlicesReader<'b, I> {
| -- lifetime `'b` defined here
19 | fn peek_all(&self) -> impl Iterator<Item = &[u8]> {
| - let's call the lifetime of this reference `'1`
20 | self.iter.clone()
| ^^^^^^^^^^^^^^^^^ method was supposed to return data with lifetime `'b` but it is returning data with lifetime `'1`
To be honest, I don't understand this error message. The method is indeed returning data with lifetime 'b
, but the compiler seems to think that the lifetime of the returned iterator is bound to self
.
Version B (Playground)
This time, I was trying it with a GAT whose lifetime is bound to self
.
trait BufRead {
type Peek<'a>: Iterator<Item = &'a [u8]> where Self: 'a;
fn peek_all(&self) -> Self::Peek<'_>;
}
impl BufRead for VecDeque<u8> {
type Peek<'a> = std::array::IntoIter<&'a [u8], 2> where Self: 'a;
fn peek_all(&self) -> Self::Peek<'_> {
let (front, back) = self.as_slices();
[front, back].into_iter()
}
}
impl<'b, I: Iterator<Item = &'b [u8]> + Clone> BufRead for SlicesReader<'b, I> {
type Peek<'a> = I where Self: 'a;
fn peek_all(&self) -> Self::Peek<'_> {
self.iter.clone()
}
}
This version fails with the following error:
error[E0308]: mismatched types
--> src/lib.rs:23:21
|
23 | type Peek<'a> = I where Self: 'a;
| ^ lifetime mismatch
|
= note: expected reference `&'b _`
found reference `&'a _`
note: the lifetime `'a` as defined here...
--> src/lib.rs:23:15
|
23 | type Peek<'a> = I where Self: 'a;
| ^^
note: ...does not necessarily outlive the lifetime `'b` as defined here
--> src/lib.rs:22:6
|
22 | impl<'b, I: Iterator<Item = &'b [u8]> + Clone> BufRead for SlicesReader<'b, I> {
| ^^
For more information about this error, try `rustc --explain E0308`.
I don't really blame the compiler for not being happy with this. I just couldn't find a way to connect I
with the lifetime 'a
of the GAT.
Version C (Playground)
In the last try, I introduced a buffer lifetime for the BufRead
trait. This fixes the SlicesReader
implementation, but breaks VecDeque
.
trait BufRead<'b> {
type Peek: Iterator<Item = &'b [u8]>;
fn peek_all(&self) -> Self::Peek;
}
impl<'b> BufRead<'b> for VecDeque<u8> where Self: 'b {
type Peek = std::array::IntoIter<&'b [u8], 2>;
fn peek_all(&self) -> Self::Peek {
let (front, back) = self.as_slices();
[front, back].into_iter()
}
}
impl<'b, I: Iterator<Item = &'b [u8]> + Clone> BufRead<'b> for SlicesReader<'b, I> {
type Peek = I;
fn peek_all(&self) -> Self::Peek {
self.iter.clone()
}
}
This version fails with the following error:
error: lifetime may not live long enough
--> src/lib.rs:14:9
|
9 | impl<'b> BufRead<'b> for VecDeque<u8> where Self: 'b {
| -- lifetime `'b` defined here
...
12 | fn peek_all(&self) -> Self::Peek {
| - let's call the lifetime of this reference `'1`
13 | let (front, back) = self.as_slices();
14 | [front, back].into_iter()
| ^^^^^^^^^^^^^^^^^^^^^^^^^ method was supposed to return data with lifetime `'b` but it is returning data with lifetime `'1`
Again, I cannot really blame the compiler for this, except that it seems to ignore the Self: 'b
lifetime bound (?)
Do you have an idea on how to fix this? I don't want to resort to returning something like Vec<&[u8]>
. This seems just wasteful, especially since this code needs to run on an embedded microcontroller. Thank you for your time!