Why isn't the below compilable (double mut borrow)?

I am trying to use a more complex version of the below, and I am unable to compile this simpler version (minimal example).

I am not following what would cause an issue here. Specifically, since the reference from the iter.next is no longer used after *some = Some(a.clone());, I can't figure what causes a double borrow in this case.

Is there a way to achieve this? (specifically, handle one of the variants of the enum differently and ignore it when advancing the streaming-iterator)

(Rust Playground)

use fallible_streaming_iterator::convert;
use fallible_streaming_iterator::FallibleStreamingIterator;

enum A {
    A(Vec<u8>),
    B(Vec<u8>),
}

fn advance<'a, I: FallibleStreamingIterator<Item = A, Error = String>>(
    iter: &'a mut I,
    some: &mut Option<Vec<u8>>,
) -> &'a [u8] {
    match iter.next() {
        Ok(Some(A::A(a))) => {
            *some = Some(a.clone());
            advance(iter, some)
        }
        Ok(Some(A::B(a))) => a,
        _ => todo!(),
    }
}

fn main() {
    let a = A::A(vec![0]);
    let b = A::B(vec![0, 0]);
    let mut iter =
        convert(vec![Result::<_, String>::Ok(&a), Result::<_, String>::Ok(&b)].into_iter());

    let mut maybe_first = None;
    advance(&mut iter, &mut maybe_first);
}

error message:

Compiling playground v0.0.1 (/playground)
error[E0499]: cannot borrow `*iter` as mutable more than once at a time
  --> src/main.rs:16:21
   |
9  |   fn advance<'a, I: FallibleStreamingIterator<Item = A, Error = String>>(
   |              -- lifetime `'a` defined here
...
13 |       match iter.next() {
   |       -     ----------- first mutable borrow occurs here
   |  _____|
   | |
14 | |         Ok(Some(A::A(a))) => {
15 | |             *some = Some(a.clone());
16 | |             advance(iter, some)
   | |                     ^^^^ second mutable borrow occurs here
...  |
19 | |         _ => todo!(),
20 | |     }
   | |_____- returning this value requires that `*iter` is borrowed for `'a`

For more information about this error, try `rustc --explain E0499`.
error: could not compile `playground` due to previous error

Your example code doesn't compile (for reasons unrelated to your problem). Please fix it, and please include the error message in your post.

2 Likes

wops, sorry for that - wrong copy-pasting to here. Also added a link to playground.

The reference returned by .next() borrows iter until the function returns because the reference is returned. Since the advance call happens before the function returns, iter is still borrowed at that point.

The current borrow checker is not clever enough to handle this case where the reference is only conditionally returned.

1 Like