How can I mutate the contents of an optional Vec? - rust

I'm trying to learn rust with egui, and I'm trying to make a list of checkboxes.
struct Checkbox {
check: bool,
text: String
}
Eventually, the borrow checker doesn't like this code:
// There is a parameter &mut self
// self.header: Option<Vec<Checkbox>>
if let Some(header) = &self.header {
for i in 0..header.len() - 1 {
ui.checkbox(&mut header[i].check, header[i].text);
}
}
The compiler says cannot borrow '*header' as mutable, as it is behind a '&' reference in the for loop (ui.checkbox line), which kind of makes sense, but I'm not sure what the workaround is. I get the same error if I use for head in header.into_iter() {. And, of course, I tried using let Some(header) = self.header, but that gives cannot move out of 'self.header.0' which is behind a mutable reference.

You need to borrow it mutably:
let Some(header) = &mut self.header

Related

allocating data structures while making the borrow checker happy (second try)

As a follow up to my question from yesterday (allocating data structures while making the borrow checker happy),
here is a simplified case. I would like to create a data structure and return both it and a reference to it. The following code does not compile:
fn create() -> (String, &str) {
let s = String::new();
let r = &s;
return (s,r);
}
fn f() {
let (s,r) = create();
do_something(r);
}
If I restructure my code as follows, everything works fine:
fn create<'a>(s : &'a String) -> &'a str {
let r = &s;
return r;
}
fn f() {
let s = String::new();
let r = create(&s);
do_something(r);
}
Unfortunately, in some cases structuring the code as in the first example is much preferable. Is there some way to make rust accept the first version?
Since both versions of the code do exactly the same thing, there shouldn't be any problems with safety. The question is just whether rust's type system is powerful enough to express it.
The Rust rules on references are that an object can either have
any amount of immutable references,
or exactly one mutable reference.
In other words, you cannot have an immutable reference and a mutable reference to the same object at the same time. Since the object counts as a mutable reference to itself, you cannot modify the object while an immutable reference to the object is present.
This is why your first piece of code does not compile. When you return (String, &str), String contains a mutable reference to a byte array, and &str contains an immutable reference to the same byte array. It violates the borrow checker rules.
However, you may ask, how does the second piece of code work? It works because you never attempt to modify s. If you modify s after r is created, then it will fail to compile:
fn f() {
let mut s = String::new();
let r = &s;
s += "modified"; // ERROR: cannot borrow `s` as mutable because it is also borrowed as immutable
do_something(r);
}
You shouldn't need to return a data structure and a reference to itself. Simply invoke the reference when it is necessary, rather than storing it in a variable. This will make sure that the borrow checker doesn't complain about references colliding.
fn f() {
let s = String::new();
// If a function takes &str, passing &String will be implicitly converted to &str
do_something(&s);
s += "modified"; // Perfectly fine, will still compile
do_something_else(&s);
}
If you want to learn more about why the &String => &str conversion works, see the std::convert::AsRef trait.
I found a solution: use a raw pointer instead of a reference. The following code works:
fn create() -> (String, *const u8) {
let s = String::new();
let r = s.as_ptr();
return (s,r);
}
fn f() {
let (s,r) = create();
do_something(r);
}

Cannot borrow as immutable because it is also borrowed as mutable when implementing an ECS

I am trying to write a simple ECS:
struct Ecs {
component_sets: HashMap<TypeId, Box<dyn Any>>,
}
impl Ecs {
pub fn read_all<Component>(&self) -> &SparseSet<Component> {
self.component_sets
.get(&TypeId::of::<Component>())
.unwrap()
.downcast_ref::<SparseSet<Component>>()
.unwrap()
}
pub fn write_all<Component>(&mut self) -> &mut SparseSet<Component> {
self.component_sets
.get_mut(&TypeId::of::<Component>())
.unwrap()
.downcast_mut::<SparseSet<Component>>()
.unwrap()
}
}
I am trying to get mutable access to a certain component while another is immutable. This testing code triggers the error:
fn testing() {
let all_pos = { ecs.write_all::<Pos>() };
let all_vel = { ecs.read_all::<Vel>() };
for (p, v) in all_pos.iter_mut().zip(all_vel.iter()) {
p.x += v.x;
p.y += v.y;
}
}
And the error
error[E0502]: cannot borrow `ecs` as immutable because it is also borrowed as mutable
--> src\ecs.rs:191:25
|
190 | let all_pos = { ecs.write_all::<Pos>() };
| --- mutable borrow occurs here
191 | let all_vel = { ecs.read_all::<Vel>() };
| ^^^ immutable borrow occurs here
My understanding of the borrow checker rules tells me that it's totally fine to get references to different component sets mutably or immutably (that is, &mut SparseSet<Pos> and &SparseSet<Vel>) since they are two different types. In order to get these references though, I need to go through the main ECS struct which owns the sets, which is where the compiler complains (i.e. first I use &mut Ecs when I call ecs.write_all and then &Ecs on ecs.read_all).
My first instinct was to enclose the statements in a scope, thinking it could just drop the &mut Ecs after I get the reference to the inner component set so as not to have both mutable and immutable Ecs references alive at the same time. This is probably very stupid, yet I don't fully understand how, so I wouldn't mind some more explaining there.
I suspect one additional level of indirection is needed (similar to RefCell's borrow and borrow_mut) but I am not sure what exactly I should wrap and how I should go about it.
Update
Solution 1: make the method signature of write_all take a &self despite returning a RefMut<'_, SparseSet<Component>> by wrapping the SparseSet in a RefCell (as illustrated in the answer below by Kevin Reid).
Solution 2: similar as above (method signature takes &self) but uses this piece of unsafe code:
fn write_all<Component>(&self) -> &mut SparseSet<Component> {
let set = self.component_sets
.get(&TypeId::of::<Component>())
.unwrap()
.downcast_ref::<SparseSet<Component>>()
.unwrap();
unsafe {
let set_ptr = set as *const SparseSet<Component>;
let set_ptr = set_ptr as *mut SparseSet<Component>;
&mut *set_ptr
}
}
What are benefits of using solution 1, is the implied runtime borrow-checking provided by RefCell an hindrance in this case or would it actually prove useful?
Would the use of unsafe be tolerable in this case? Are there benefits? (e.g. performance)
it's totally fine to get references to different component sets mutably or immutably
This is true: we can safely have multiple mutable, or mutable and immutable references, as long as no mutable reference points to the same data as any other reference.
However, not every means of obtaining those references will be accepted by the compiler's borrow checker. This doesn't mean they're unsound; just that we haven't convinced the compiler that they're safe. In particular, the only way the compiler understands to have simultaneous references is a struct's fields, because the compiler can know those are disjoint using a purely local analysis (looking only at the code of a single function):
struct Ecs {
pub pos: SparseSet<Pos>,
pub vel: SparseSet<Vel>,
}
for (p, v) in ecs.pos.iter_mut().zip(ecs.vel.iter()) {
p.x += v.x;
p.y += v.y;
}
This would compile, because the compiler can see that the references refer to different subsets of memory. It will not compile if you replace ecs.pos with a method ecs.pos() — let alone a HashMap. As soon as you get a function involved, information about field borrowing is hidden. Your function
pub fn write_all<Component>(&mut self) -> &mut SparseSet<Component>
has the elided lifetimes (lifetimes the compiler picks for you because every & must have a lifetime)
pub fn write_all<'a, Component>(&'a mut self) -> &'a mut SparseSet<Component>
which are the only information the compiler will use about what is borrowed. Hence, the 'a mutable reference to the SparseSet is borrowing all of the Ecs (as &'a mut self) and you can't have any other access to it.
The ways to arrange to be able to have multiple mutable references in a mostly-statically-checked way are discussed in the documentation page on Borrow Splitting. However, all of those are based on having some statically known property, which you don't. There's no way to express “this is okay as long as the Component type is not equal to another call's”. Therefore, to do this you do need RefCell, our general-purpose helper for runtime borrow checking.
Given what you've got already, the simplest thing to do is to replace SparseSet<Component> with RefCell<SparseSet<Component>>:
// no mut; changed return type
pub fn write_all<Component>(&self) -> RefMut<'_, SparseSet<Component>> {
self.component_sets
.get(&TypeId::of::<Component>())
.unwrap()
.downcast::<RefCell<SparseSet<Component>>>() // changed type
.unwrap()
.borrow_mut() // added this line
}
Note the changed return type, because borrowing a RefCell must return an explicit handle in order to track the duration of the borrow. However, a Ref or RefMut acts mostly like an & or &mut thanks to deref coercion. (Your code that inserts items in the map, which you didn't show in the question, will also need a RefCell::new.)
Another option is to put the interior mutability — likely via RefCell, but not necessarily — inside the SparseSet type, or create a wrapper type that does that. This might or might not help the code be cleaner.

Getting first member of a BTreeSet

In Rust, I have a BTreeSet that I'm using to keep my values in order. I have a loop that should retrieve and remove the first (lowest) member of the set. I'm using a cloned iterator to retrieve the first member. Here's the code:
use std::collections::BTreeSet;
fn main() {
let mut start_nodes = BTreeSet::new();
// add items to the set
while !start_nodes.is_empty() {
let mut start_iter = start_nodes.iter();
let mut start_iter_cloned = start_iter.cloned();
let n = start_iter_cloned.next().unwrap();
start_nodes.remove(&n);
}
}
This, however, gives me the following compile error:
error[E0502]: cannot borrow `start_nodes` as mutable because it is also borrowed as immutable
--> prog.rs:60:6
|
56 | let mut start_iter = start_nodes.iter();
| ----------- immutable borrow occurs here
...
60 | start_nodes.remove(&n);
| ^^^^^^^^^^^ mutable borrow occurs here
...
77 | }
| - immutable borrow ends here
Why is start_nodes.iter() considered an immutable borrow? What approach should I take instead to get the first member?
I'm using version 1.14.0 (not by choice).
Why is start_nodes.iter() considered an immutable borrow?
Whenever you ask a question like this one, you need to look at the prototype of the function, in this case the prototype of BTreeSet::iter():
fn iter(&self) -> Iter<T>
If we look up the Iter type that is returned, we find that it's defined as
pub struct Iter<'a, T> where T: 'a { /* fields omitted */ }
The lifetime 'a is not explicitly mentioned in the definition of iter(); however, the lifetime elision rules make the function definition equivalent to
fn iter<'a>(&'a self) -> Iter<'a, T>
From this expanded version, you can see that the return value has a lifetime that is bound to the lifetime of the reference to self that you pass in, which is just another way of stating that the function call creates a shared borrow that lives as long as the return value. If you store the return value in a variable, the borrow lives at least as long as the variable.
What approach should I take instead to get the first member?
As noted in the comments, your code works on recent versions of Rust due to non-lexical lifetimes – the compiler figures out by itself that start_iter and start_iter_cloned don't need to live longer than the call to next(). In older versions of Rust, you can artificially limit the lifetime by introducing a new scope:
while !start_nodes.is_empty() {
let n = {
let mut start_iter = start_nodes.iter();
let mut start_iter_cloned = start_iter.cloned();
start_iter_cloned.next().unwrap()
};
start_nodes.remove(&n);
}
However, note that this code is needlessly long-winded. The new iterator you create and its cloning version only live inside the new scope, and they aren't really used for any other purpose, so you could just as well write
while !start_nodes.is_empty() {
let n = start_nodes.iter().next().unwrap().clone();
start_nodes.remove(&n);
}
which does exactly the same, and avoids the issues with long-living borrows by avoiding to store the intermediate values in variables, to ensure their lifetime ends immediately after the expression.
Finally, while you don't give full details of your use case, I strongly suspect that you would be better off with a BinaryHeap instead of a BTreeSet:
use std::collections::BinaryHeap;
fn main() {
let mut start_nodes = BinaryHeap::new();
start_nodes.push(42);
while let Some(n) = start_nodes.pop() {
// Do something with `n`
}
}
This code is shorter, simpler, completely sidesteps the issue with the borrow checker, and will also be more efficient.
Not sure this is the best approach, but I fixed it by introducing a new scope to ensure that the immutable borrow ends before the mutable borrow occurs:
use std::collections::BTreeSet;
fn main() {
let mut start_nodes = BTreeSet::new();
// add items to the set
while !start_nodes.is_empty() {
let mut n = 0;
{
let mut start_iter = start_nodes.iter();
let mut start_iter_cloned = start_iter.cloned();
let x = &mut n;
*x = start_iter_cloned.next().unwrap();
}
start_nodes.remove(&n);
}
}

Variable said to be immutable even if declared as mutable [duplicate]

This question already has an answer here:
Cannot borrow immutable borrowed content as mutable
(1 answer)
Closed 5 years ago.
I am recreating the arithmetic operations in binary by representing numbers with a vector of booleans. Since the size of each vector can vary, I made a function to match the length of each vector:
fn match_lengths(mut bit_vec0: Vec<bool>, mut bit_vec1: Vec<bool>) -> (Vec<bool>, Vec<bool>) {
{
let (mut shorter, longer) = if bit_vec0.len() < bit_vec1.len() {
(&bit_vec0, &bit_vec1)
} else {
(&bit_vec1, &bit_vec0)
};
let bit_sign = match shorter.last() {
Some(content) => *content,
None => false,
};
for _ in shorter.len()..longer.len() {
shorter.push(bit_sign);
}
}
(bit_vec0, bit_vec1)
}
I get the error
error[E0596]: cannot borrow immutable borrowed content `*shorter` as mutable
--> src/main.rs:15:13
|
15 | shorter.push(bit_sign); // Error here
| ^^^^^^^ cannot borrow as mutable
Even though I declared it with the mut specifier.
The type of shorter is a reference, more precisely a &Vec<bool>, which means it refers to a Vec<bool> which it is not allowed to mutate1.
Declaring the variable as mut shorter only makes the shorter variable mutable, allowing you to e.g. use shorter = ... assignment to make it refer to a different Vec<bool>. Regardless of the variable's mutability, a shared reference of type &Vec<bool> is not allowed to mutate the object it refers to.
What you need to do is make a mutable reference of type &mut Vec<bool>, using &mut bit_vec0 and &mut bit_vec1. This change makes the code compile, and at that point shorter no longer needs to be mut.
Finally, and this is unrelated to the question, match_lengths accepts bit_vec0 and bit_vec1 by value, modifies them, and returns them. Although that certainly works, it is more idiomatic to accept mutable references. Such an approach is more ergonomic for the caller, and more clearly signals the fact that the function doesn't really "return" anything, it really modifies existing objects.
With those modifications, the function looks like this:
fn match_lengths(bit_vec0: &mut Vec<bool>, bit_vec1: &mut Vec<bool>) {
let (shorter, longer) = if bit_vec0.len() < bit_vec1.len() {
(bit_vec0, bit_vec1)
} else {
(bit_vec1, bit_vec0)
};
let bit_sign = match shorter.last() {
Some(content) => *content,
None => false,
};
for _ in shorter.len()..longer.len() {
shorter.push(bit_sign);
}
}
1
This sounds much like C++'s const, but the guarantee in Rust is even stronger than that of const: not only is a shared (non-mut) reference not allowed to mutate the object it refers to, but neither is anyone else! Rust's compiler and runtime prevent creation of a mut reference to an object while any shared references to that object exist.

Why can't I call a mutable method (and store the result) twice in a row?

In the following example:
struct SimpleMemoryBank {
vec: Vec<Box<i32>>,
}
impl SimpleMemoryBank {
fn new() -> SimpleMemoryBank {
SimpleMemoryBank{ vec: Vec::new() }
}
fn add(&mut self, value: i32) -> &mut i32 {
self.vec.push(Box::new(value));
let last = self.vec.len() - 1;
&mut *self.vec[last]
}
}
fn main() {
let mut foo = SimpleMemoryBank::new();
// Works okay
foo.add(1);
foo.add(2);
// Doesn't work: "cannot borrow `foo` as mutable more than once at a time"
let one = foo.add(1);
let two = foo.add(2);
}
add() can be called multiple times in a row, as long as I don't store the result of the function call. But if I store the result of the function (let one = ...), I then get the error:
problem.rs:26:15: 26:18 error: cannot borrow `foo` as mutable more than once at a time
problem.rs:26 let two = foo.add(2);
^~~
problem.rs:25:15: 25:18 note: previous borrow of `foo` occurs here; the mutable borrow prevents subsequent moves, borrows, or modification of `foo` until the borrow ends
problem.rs:25 let one = foo.add(1);
^~~
problem.rs:27:2: 27:2 note: previous borrow ends here
problem.rs:17 fn main() {
...
problem.rs:27 }
^
error: aborting due to previous error
Is this a manifestation of issue #6393: borrow scopes should not always be lexical?
How can I work around this? Essentially, I want to add a new Box to the vector, and then return a reference to it (so the caller can use it).
This is exactly the problem that Rust is designed to prevent you from causing. What would happen if you did:
let one = foo.add(1);
foo.vec.clear();
println!("{}", one);
Or what if foo.add worked by pushing the new value at the beginning of the vector? Bad things would happen! The main thing is that while you have a borrow out on a variable, you cannot mutate the variable any more. If you were able to mutate it, then you could potentially invalidate the memory underlying the borrow and then your program could do a number of things, the best case would be that it crashes.
Is this a manifestation of issue #6393: borrow scopes should not always be lexical?
Kind of, but not really. In this example, you never use one or two, so theoretically a non-lexical scope would allow it to compile. However, you then state
I want to add a new Box to the vector, and then return a reference to it (so the caller can use it)
Which means your real code wants to be
let one = foo.add(1);
let two = foo.add(2);
do_something(one);
do_something(two);
So the lifetimes of the variables would overlap.
In this case, if you just want a place to store variables that can't be deallocated individually, don't overlap with each other, and cannot be moved, try using a TypedArena:
extern crate arena;
use arena::TypedArena;
fn main() {
let arena = TypedArena::new();
let one = arena.alloc(1);
let two = arena.alloc(2);
*one = 3;
println!("{}, {}", one, two);
}

Resources