How to solve mut error

error[E0596]: cannot borrow `self` as mutable, as it is not declared as mutable
  --> src/future/prio_retry.rs:83:33
   |
81 |     fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
   |                  ---- help: consider changing this to be mutable: `mut self`
82 |         loop {
83 |             match Pin::new(&mut self.stream).poll_next(cx) {
   |                                 ^^^^ cannot borrow as mutable

mut error

self is a keyword in Rust, you can't use it as a variable name. Just renaming self might help.

If you wanted to use the self keyword, try writing &mut self instead of self: Pin<&mut Self>.

Apart, some more info about your code and what you are trying to do might help.

That is not what that signature is doing.

You should follow the helpful message in the error you posted:

3 Likes
impl<S> Stream for PrioRetry<S>
where
    S: Stream,
    S::Item: Ord + Clone + Eq,
{
    type Item = S::Item;
    type Error = Error<S::Error>;

    fn poll(&mut self) -> Poll<Option<Self::Item>, Self::Error> {
        loop {
            match self.stream.poll() {
                Ok(Async::NotReady) => {
                    break;
                }
                Ok(Async::Ready(Some(new_item))) => {
                    // check if we currently have a delay item
                    if let Some(ref mut delayed_item) = self.delayed_item {
                        if delayed_item.value < new_item {
                            // we have new item, this one will be yielded instantly
                            self.delayed_item = Some(DelayedItem::new(new_item.clone()));
                            return Ok(Async::Ready(Some(new_item)));
                        } else if delayed_item.value == new_item {
                            // if the current item was requeued, then we will yield it with a backoff
                            delayed_item.exp_backoff(self.delay_duration);
                        }
                    } else {
                        // we have new item, this one will be yielded instantly
                        self.delayed_item = Some(DelayedItem::new(new_item.clone()));
                        return Ok(Async::Ready(Some(new_item)));
                    }
                }
                Ok(Async::Ready(None)) => {
                    return Ok(Async::Ready(None));
                }
                Err(e) => {
                    return Err(Error(Kind::Inner(e)));
                }
            }
        }

        if let Some(ref mut delayed_item) = self.delayed_item {
            if let Some(ref mut delay) = delayed_item.delay {
                match delay.poll() {
                    Ok(Async::NotReady) => {}
                    Ok(Async::Ready(())) => {
                        // we yield a clone, since we need the old copy to check if an item was requeued
                        delayed_item.pause();
                        return Ok(Async::Ready(Some(delayed_item.value.clone())));
                    }
                    Err(e) => {
                        return Err(Error(Kind::Timer(e)));
                    }
                }
            }
        };
        Ok(Async::NotReady)
    }
}

i update this from futures 0.1 to 0.3 can you help me do a more grateful way to impl it?

Really, just following the compiler's suggestion would be enough for this case.

fn poll_next(mut self: Pin<&mut Self>, ..
error[E0502]: cannot borrow `self` as immutable because it is also borrowed as mutable
  --> src/future/prio_retry.rs:96:54
   |
89 |                     if let Some(ref mut delayed_item) = self.delayed_item {
   |                                                         ---- mutable borrow occurs here
...
96 |                             delayed_item.exp_backoff(self.delay_duration);
   |                                          ----------- ^^^^ immutable borrow occurs here
   |                                          |
   |                                          mutable borrow later used by call

but it occurs this error

That's another error :slight_smile:

Since the self is now Poll<&mut Self> not &mut Self, every field access requires .deref() or .deref_mut() method so compiler cannot treat each fields as disjoint borrow. As a workaround you can distruct references of all field at the start of the function and use these variables.

let Self {
    stream,
    delayed_item,
    delay_duration,
    ..
} = &mut **self;
impl<S> PrioRetry<S>
where
    S: Stream + Unpin,
    S::Item: Ord + Clone + Eq,
{
    pub fn new(stream: S, delay_duration: Duration) -> Self {
        Self {
            delay_duration,
            delayed_item: None,
            stream: stream.fuse(),
        }
    }
}

but i have the new function like this

Then remove those two dots if you don't have more fields. The match ergonomics takes place here, so every fields of Self is borrowed - not moved out.

i don't know how to use it.

    fn exp_backoff(&mut self, delay: Duration) {
        let backoff = 2u32.pow(self.attempt) * delay;
        self.delay = Some(delay_until(Instant::now() + backoff));
        self.attempt += 1;
    }

Rust is being pedantic here about order of evaluation. foo.bar(baz) evaluates foo first, baz second.

delayed_item is from self and is mutable, so it has exclusive access to self. So Rust enforces that exclusive "lock" for the call as soon as delayed_item is "evaluated", so when it looks at self.delay_duration, self is already "locked" by delayed_item.

The solution is trivial — cache delay_duration in a variable.

let delay_duration = self.delay_duration;
       if let Some(ref mut delayed_item) = self.delayed_item {
                             delayed_item.exp_backoff(delay_duration); 

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.