I am writing a Rogue-like in Rust. I have a Player which has a Vec of boxed TimedEffects. A timed effect has an activate(&mut Player) and deactivate(&mut Player) method, and a tick() method that decrements the time remaining. When it goes to zero, the deactivate() method should be called.
pub struct Player {
timed_effects: Vec<Box<TimedEffect>>,
}
Each time the player moves, I need to decrement the time remaining. This is done inside a Player method:
impl Player {
fn regenerate(&mut self) {
self.timed_effects.iter_mut().for_each(|te| te.tick());
for i in 0..self.timed_effects.len() {
if self.timed_effects[i].ticks_remaining() == 0 {
let bte = self.timed_effects.swap_remove(i);
bte.deactivate(self);
}
}
}
}
I originally tried passing the self parameter (&mut Player) to the tick() method of the TimedEffect objects, with logic to invoke deactivate(player) automatically when the time went to zero.
Iterating over the vector constitutes a borrow of (Player) self, which is incompatible with passing the &mut Player parameter to tick(), or even to a separate iteration with .filter.
Instead, as shown, I find myself iterating over a range of integers, extracting the box from the vector into a local variable, and then invoking .deactivate(self) on it.
This is painful.
Given the effects need to have some connection with their victim so the deactivate() method can undo the effect, how should I be architecting these objects so that I don't wind up tangled in this web of dependent borrows?