-2

I have this code:

use std::sync::atomic::{AtomicIsize, Ordering};

#[derive(Default)]
pub struct Worker {
    work: Vec<u32>,
    progress: AtomicIsize,
}

impl Worker {
    fn do_work(&mut self) {
        self.work.push(0u32);
        self.progress.store(self.progress.load(Ordering::SeqCst) + 1, Ordering::SeqCst);
    }
    fn get_progress(&self) -> isize {
        self.progress.load(Ordering::SeqCst)
    }
}

pub struct Manager<CB: FnMut()> {
    cb: CB
}

impl<CB: FnMut()> Manager<CB> {
    fn do_a_bit_more_work(&mut self) {
        (self.cb)();
    }
}

fn main() {
    let mut worker = Worker::default();

    let mut manager = Manager {
        cb: || worker.do_work()
    };

    while worker.get_progress() < 100 {
        manager.do_a_bit_more_work();
    }
}

That is, I have some manager that calls a callback to do some work. I want the callback to be Worker::do_work() and that function updates the members of Worker so it needs &mut self. However once I pass worker.do_work() to the manager it means worker is mutably borrowed so I can never use it again.

I want to use it again to check progress, and maybe change its behaviour. I can use atomic operations and mutexes and so on to try to make sure it is safe to do so, but how can I tell Rust to allow this without getting the cannot borrow X as immutable because it is also borrowed as mutable error?

I'm guessing it is something to do with Cell or RefCell but I can't work it out.

Timmmm
  • 88,195
  • 71
  • 364
  • 509
  • 1
    please show the work you have done with `Cell` and `RefCell`. There is a lot of documentation on those types in the [std::cell](https://doc.rust-lang.org/std/cell/index.html) docs. – oli_obk Dec 21 '16 at 15:34
  • 2
    The direct answer to your stated question (*How do I tell Rust it is ok to borrow self as immutable when it is already borrowed mutably?*) is: **you don't**. It is inherently unsafe to do so. – Shepmaster Dec 21 '16 at 15:44
  • @ker: I get the idea of `Cell` and `RefCell`, I'm just not sure how best to apply them to this case. The documentation doesn't really help with that. – Timmmm Dec 21 '16 at 15:46
  • A (non-)compilable minimal example that I believe demonstrates the exact error the OP is getting: [playground](https://play.rust-lang.org/?gist=075e10f188f6d73c3be762df52dd8444&version=stable&backtrace=0). Despite the obvious shortcomings of the OP's code, I'd also be curious how to structure things so that the `while` loop becomes possible. – user4815162342 Dec 21 '16 at 15:58
  • @user4815162342: Thanks! I'll add it to the question. – Timmmm Dec 21 '16 at 16:03
  • @Shepmaster: Ok badly worded, but how do make the example work in any case? – Timmmm Dec 21 '16 at 16:03
  • 3
    Example code would be less confusing if it avoided gratuitous use of atomic types in an otherwise mutable data structure. Note that `x.store(x.load() + 1)` is an antipattern that defeats the purpose of atomic in *any* language. – user4815162342 Dec 21 '16 at 16:22
  • Linked: http://stackoverflow.com/questions/41190333/mutable-borrow-of-self-doesnt-change-to-immutable – Stargateur Dec 21 '16 at 16:53
  • @Stargateur: I'm not sure that is the same issue. In this case `player` really is legitimately mutably borrowed since `manager.do_a_bit_more_work()` really does mutate it. – Timmmm Dec 21 '16 at 17:47
  • @Stargateur: Ha that is cheating! You can't create an entirely new `Manager` on each loop. It has some (omitted in the example) state. – Timmmm Dec 21 '16 at 21:48
  • @Stargateur: Well technically `fn main() {}` is equivalent since the code doesn't actually do anything! I think the example is clear enough without being overly complex. – Timmmm Dec 22 '16 at 09:30
  • @Timmmm I don't understand why you want a `Manager` of `Worker`, if after you use `Worker` yourself in the `while`. Why don't you put `Worker` in the `struct` Manager? – Stargateur Dec 22 '16 at 15:09
  • @Stargateur: This is a simplification of my actual code. I think it makes my question clear. – Timmmm Dec 22 '16 at 16:02

1 Answers1

0

Here's the simpler example I'm going to use:

struct Manager<F> {
    cb: F,
}
impl<F> Manager<F>
    where F: FnMut()
{
    fn do_a_bit_more_work(&mut self) { (self.cb)() }
}

struct Worker;
impl Worker {
    fn do_work(&mut self) {}
    fn get_progress(&self) -> u8 { 100 }
}

fn main() {
    let mut worker = Worker;

    let mut manager = Manager {
        cb: || worker.do_work()
    };

    while worker.get_progress() < 100 {
        manager.do_a_bit_more_work();
    }
}

Adding RefCell allows it to compile:

use std::cell::RefCell;

fn main() {
    let worker = RefCell::new(Worker);

    let mut manager = Manager {
        cb: || worker.borrow_mut().do_work()
    };

    while worker.borrow().get_progress() < 100 {
        manager.do_a_bit_more_work();
    }
}

Now the closure borrows an immutable reference of the RefCell<Worker> and checking for an exclusive mutable borrow moves from compile time to runtime.

Of course, RefCell isn't required to solve the problem, but avoiding RefCell does mean you have to look at the problem from a different direction. One solution is instead of keeping the Worker, give it to the Manager. Then borrow it back as needed:

trait DoWork {
    fn do_work(&mut self);
}

struct Manager<T> {
    work: T,
}

impl<T> Manager<T>
    where T: DoWork
{
    fn do_a_bit_more_work(&mut self) {
        self.work.do_work()
    }

    fn inspect<F, U>(&self, mut f: F) -> U
        where F: FnMut(&T) -> U
    {
        f(&self.work)
    }

    // Optionally
    // fn inspect_mut<F, U>(&mut self, mut f: F) -> U
    //    where F: FnMut(&mut T) -> U
    // {
    //     f(&mut self.work)
    // }

    fn into_inner(self) -> T {
        self.work
    }
}

struct Worker;
impl Worker {
    fn get_progress(&self) -> u8 {
        100
    }
}

impl DoWork for Worker {
    fn do_work(&mut self) {}
}

fn main() {
    let worker = Worker;

    let mut manager = Manager { work: worker };

    while manager.inspect(|w| w.get_progress()) < 100 {
        manager.do_a_bit_more_work();
    }

    let worker = manager.into_inner();
}
Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366