Problem about borrowing: My timer implementation requires a mutable reference to the timer queue


#1

I think it’s not a rare problem but sorry I cant figure out how to solve it or what keyword to search.
I’m writing a mio tcp server actually but I think my problem is fundamentally a callback object want a mutable reference to a looper. So I make an example with a simple timer queue. So the question is, timer or something can be very flexable and may call some fn of the timer queue but I don’t want to pass the same timer queue all around and mass up the logic of every timer. I’ve tried Rc, RefCell and found the evil is in the very first ‘tq.run();’, tq is mut so there can be no other &mut to it, no matter what boxing struct I use. Am I right? And what’s the best way (or if there are any) to implement such structures?

    use std::boxed::Box;
    use std::thread::sleep;
    use std::time::Duration;

    trait Timer {
        fn fire(&mut self);
    }

    struct TimerQueue {
        timers : Vec<Box<Timer>>,
        new_timers : Vec<Box<Timer>>,
    }

    impl TimerQueue {
        fn new() -> TimerQueue {
            TimerQueue {
                timers : Vec::new(),
                new_timers : Vec::new(),
            }
        }
        fn insert(&mut self, timer : Box<Timer>) {
            self.new_timers.push(timer);
        }
        fn run(&mut self) {
            loop {
                self.timers.append(&mut self.new_timers);
                sleep(Duration::new(1,0));
                for t in self.timers.iter_mut() {
                    t.fire();
                }
            }
        }
    }

    struct ATimer;

    impl Timer for ATimer {
        fn fire(&mut self) {
        //do something
        //problem: I want to insert another timer into the same queue, but how?
        }
    }

    fn main() {
        let mut tq = TimerQueue::new();
        tq.insert(Box::new(ATimer));
        tq.run();
    }

#2

You can pass a struct, wrapping a mutable reference to new_timers, to Timer::fire():


trait Timer {
    fire(&mut self, queue: QueueMut);
}

struct QueueMut<'a>(&'a mut Vec<Box<Timer>>);

impl<'a> QueueMut<'a> {
    fn insert(&mut self, timer: Box<Timer>) {
        self.0.push(timer);
    }
}

// And then in TimerQueue::run():
for t in self.timers.iter_mut() {
    t.fire(QueueMut(&mut self.new_timers));
}

This works because TimerQueue::run() knows that self.timers is the only thing that’s mutably borrowed in that for loop, so self.new_timers is fair game. You already got halfway there with pushing to new_timers so you don’t risk invalidating the iterator over timers.

If you find yourself duplicating a lot of functionality, you can have a public-in-private supertrait which implements the necessary accessors, then an exported trait which implements all other public-facing methods on top of those, and a blanket impl connecting the latter to the former. Playground link