I'm building a GUI and I want to store all used textures in one place, but I have to add new textures while older textures are already immutably borrowed.
let (cat, mouse, dog) = (42, 360, 420); // example values
let mut container = vec![cat, mouse]; // new container
let foo = &container[0]; // now container is immutably borrowed
container.push(dog); // error: mutable borrow
Is there any kind of existing structure that allows something like this,
or can I implement something like this using raw pointers?
The absolute easiest thing is to introduce shared ownership:
use std::rc::Rc;
fn main() {
let (cat, mouse, dog) = (42, 360, 420);
let mut container = vec![Rc::new(cat), Rc::new(mouse)];
let foo = container[0].clone();
container.push(Rc::new(dog));
}
Now container
and foo
jointly own cat
.
Is there any kind of existing structure that allows something like this,
Yes, but there are always tradeoffs. Above, we used Rc
to share ownership, which involves a reference counter.
Another potential solution is to use an arena:
extern crate typed_arena;
use typed_arena::Arena;
fn main() {
let container = Arena::new();
let cat = container.alloc(42);
let mouse = container.alloc(360);
let dog = container.alloc(420);
}
This isn't indexable, you cannot take ownership of the value again, and you cannot remove a value.
Being able to remove things from the collection always makes invalidating references dangerous.
can I implement something like this using raw pointers
Almost certainly. Will you get it right is always the tricky point.
but I have to add new textures while older textures are already immutably borrowed
Many times, you don't have to do any such thing. For example, you can split up your logic into phases. You have two containers; one that people take references into, and another to collect new values. At the end of the phase, you combine the two collections into one. You have to ensure that no references are used after the end of the phase, of course.