Your problem can be reduced to this:
struct Reader;
struct Data;
struct Errors<'a>(&'a str);
fn handle_array(stream: &mut Reader) -> Result<Data, Errors> {
for _ in 0..0 {
handle_request(&mut stream)?;
}
unimplemented!();
}
fn handle_request(_stream: &mut Reader) -> Result<Data, Errors> {
unimplemented!()
}
fn main() {}
error[E0597]: `stream` does not live long enough
--> src/main.rs:7:29
|
7 | handle_request(&mut stream)?;
| ^^^^^^ borrowed value does not live long enough
...
11 | }
| - borrowed value only lives until here
|
note: borrowed value must be valid for the anonymous lifetime #1 defined on the function body at 5:1...
--> src/main.rs:5:1
|
5 | / fn handle_array(stream: &mut Reader) -> Result<Data, Errors> {
6 | | for _ in 0..0 {
7 | | handle_request(&mut stream)?;
8 | | }
9 | |
10 | | unimplemented!();
11 | | }
| |_^
In the body of handle_array
, stream
is of type &mut Reader
. However, when calling handle_request
, you take another reference to it, creating a &mut &mut Reader
.
Adding some explicit lifetimes to the code (for educational purposes, this doesn't compile), the code would look kind of like this:
fn handle_array<'stream>(stream: &'stream mut Reader) -> Result<Data, Errors> {
let tmp: &'tmp mut &'stream mut Reader = &mut stream;
if let Err(x) = handle_request(tmp)
handle_request
requires a &mut Reader
, so the compiler inserts some code to align these two types for you. The compiler has to be conservative about how it performs this conversion, so it picks the shorter lifetime:
fn handle_array<'stream>(stream: &'stream mut Reader) -> Result<Data, Errors> {
let tmp: &'tmp mut &'stream mut Reader = &mut stream;
let tmp2: &'tmp mut Reader = tmp;
if let Err(x) = handle_request(tmp2)
The next aspect of the problem is that lifetime elision has kicked in for both functions. Their expanded forms look like:
fn handle_array<'stream>(stream: &'stream mut Reader) -> Result<Data, Errors<'stream>>
fn handle_request<'_stream>(_stream: &_stream mut Reader) -> Result<Data, Errors<'_stream>>
This means that the lifetime of the returned Errors
is tied to the lifetime of the argument, but in your case, the argument to handle_request
has the shorter 'tmp
lifetime, not the lifetime of 'stream
. This shows why you get the compiler error: You are trying to return an Errors
that can only live inside the function (the lifetime of the variable stream
itself), but you are trying to return a reference that needs to live longer.
We can solve this by only passing stream
to handle_request
:
handle_request(stream)?;
Unfortunately, this only changes the error:
error[E0499]: cannot borrow `*stream` as mutable more than once at a time
--> src/main.rs:9:40
|
9 | if let Err(x) = handle_request(stream) {
| ^^^^^^ mutable borrow starts here in previous iteration of loop
...
15 | }
| - mutable borrow ends here
This part is much harder to explain. See:
This is a really rough edge of Rust's right now, but it's getting closer and closer to being fixed! Right now, however, you have two main choices:
Call the function twice
This probably won't work because you can't read from the stream twice, but in other cases it might be useful:
fn handle_array(stream: &mut Reader) -> Result<Data, Errors> {
let mut array = vec![];
for _ in 0..0 {
if handle_request(stream).is_err() {
return handle_request(stream);
}
if let Ok(r) = handle_request(stream) {
array.push(r);
};
}
unimplemented!();
}
Remove the references
Give up on trying to have references in this case for now.
struct Errors(String);
fn handle_array(stream: &mut Reader) -> Result<Data, Errors> {
let mut array = vec![];
for _ in 0..0 {
array.push(handle_request(stream)?);
}
unimplemented!();
}
Which I'd write using iterators for efficiency:
fn handle_array(stream: &mut Reader) -> Result<Data, Errors> {
let array = (0..0)
.map(|_| handle_request(stream))
.collect::<Result<Vec<_>, _>>()?;
unimplemented!();
}
The future?
With the unstable NLL feature and the experimental "Polonius" implementation, this code works:
struct Errors<'a>(&'a str);
fn handle_array(stream: &mut Reader) -> Result<Data, Errors> {
let mut array = vec![];
for _ in (0..0) {
array.push(handle_request(stream)?);
}
unimplemented!();
}
It will just be a while before this is generally available...