I believe I am running into some sort of interior mutability issue:
thread 'main' panicked at 'already borrowed: BorrowMutError', libcore/result.rs:1009:5
stack backtrace:
...
10: <core::cell::RefCell<T>>::borrow_mut
at libcore/cell.rs:885
11: playground::Scheduler::schedule_timing_target
at src/main.rs:84
12: <playground::BootScene as playground::NodeTrait>::enter
at src/main.rs:49
13: playground::main
at src/main.rs:127
...
Basically I create two Rc-RefCell trait objects and put them into a vec. Everything was working fine until I decided to put the vec into a the Scheduler struct and add methods to mutate it using what I believe is interior mutability.
The problem happens when I try to call borrow_mut() on an element from the iterator. From what I have read about vec iterators is that the iterator "borrows-out" the element which means I can't borrow_mut it myself. This seems like a catch-22. This only shows up when I put the vec collection inside my struct "Scheduler". Some how the extra indirection/level causes a borrow some where that I can't see. I wish the backtrace would show a trace of the borrow history so I could see where the mysterious borrow is occurring.
Any ideas?
use std::cell::RefCell;
use std::rc::Rc;
type RefNode = Rc<RefCell<NodeTrait>>;
trait NodeTrait {
fn id(&self) -> usize {
0
}
fn set_id(&mut self, id: usize);
fn paused(&self) -> bool;
fn pause(&mut self, pause: bool);
fn enter(&self, sch: &Scheduler);
fn exit(&self, sch: &Scheduler);
}
// ======================================================
struct BootScene {
id: usize,
paused: bool,
}
impl BootScene {
fn new() -> RefNode {
Rc::new(RefCell::new(Self {
id: 0,
paused: true,
}))
}
}
impl NodeTrait for BootScene {
fn id(&self) -> usize {
self.id
}
fn set_id(&mut self, id: usize) {
self.id = id;
}
fn paused(&self) -> bool {
self.paused
}
fn pause(&mut self, pause: bool) {
self.paused = pause;
}
fn enter(&self, sch: &Scheduler) {
sch.print();
sch.schedule_timing_target(self.id());
println!("---------------------");
sch.print();
}
fn exit(&self, sch: &Scheduler) {
sch.print();
sch.unschedule_timing_target(self.id());
println!("---------------------");
sch.print();
}
}
struct Scheduler {
scenes: Vec<RefNode>,
}
impl Scheduler {
fn new() -> Self {
Self { scenes: Vec::new() }
}
fn register_timing_target(&mut self, target: RefNode) {
self.scenes.push(target);
}
fn schedule_timing_target(&self, target_id: usize) {
for target in &self.scenes {
let mut t = target.borrow_mut(); // <====== BORROW ERROR
if t.id() == target_id {
t.pause(false);
return;
}
}
}
fn unschedule_timing_target(&self, target_id: usize) {
for target in &self.scenes {
if target.borrow().id() == target_id {
target.borrow_mut().pause(true);
return;
}
}
}
fn print(&self) {
let mut c = 0;
for target in &self.scenes {
println!("c: {}", c);
println!(
"id: {}, paused: {}",
target.borrow().id(),
target.borrow().paused()
);
c += 1;
}
println!("###########################");
}
}
fn main() {
let mut sch = Scheduler::new();
let s1 = BootScene::new();
s1.borrow_mut().set_id(1);
sch.register_timing_target(s1.clone());
let s2 = BootScene::new();
s2.borrow_mut().set_id(3);
sch.register_timing_target(s2.clone());
s2.borrow().enter(&sch);
s2.borrow().exit(&sch);
}