Rust multiple mutable self borrowing from method calls - rust

I am learning Rust. For my first program, I wrote this code to maintain data about a partial ordering:
use std::collections::{HashMap, HashSet};
struct Node {
num_before: usize,
successors: HashSet<String>,
}
impl Node {
fn new() -> Node {
Node {
num_before: 0,
successors: HashSet::new(),
}
}
}
pub struct PartialOrdering {
node: HashMap<String, Node>,
}
impl PartialOrdering {
pub fn new() -> PartialOrdering {
PartialOrdering {
node: HashMap::new(),
}
}
pub fn get_node(&mut self, name: &String) -> &mut Node {
self.node.entry(name.clone()).or_insert_with(Node::new)
}
pub fn add_order(&mut self, before: &String, after: &String) {
let mut before_node = self.get_node(before);
if after != before {
let mut after_node = self.get_node(after);
if before_node.successors.insert(after.clone()) {
after_node.num_before += 1;
}
}
}
}
Compiling this code produces this error:
error[E0499]: cannot borrow `*self` as mutable more than once at a time
--> main.rs:35:25
|
33 | let before_node = self.get_node(before);
| ---- first mutable borrow occurs here
34 | if after != before {
35 | let mut after_node = self.get_node(after);
| ^^^^ second mutable borrow occurs here
36 | if before_node.successors.insert(after.clone()) {
| ---------------------- first borrow later used here
Admittedly I am new to the Rust borrowing rules, but this problem has me stumped. Please tell me what I am doing wrong, and how can I fix it?

The problem is that in Rust it is forbidden to take more than one mutable reference (&mut) to an object at a time (see here for details). Your get_node() takes &mut self and uses it to obtain an &mut Node contained in self (where self is a PartialOrdering). This causes the mutable borrow of self to exist for as long as the value returned by get_node() exists, preventing other calls to get_node(). This means that you can't have before_node: &mut Node and after_node: &mut Node in the same scope, unfortunately.

Related

Rust multiple borrowing struct

I am new to Rust and trying to implement a simple TCP-Server that sends me a live image. Therefore I am using this crate https://crates.io/crates/tinybmp for the RawBmp-type. Now I am struggling a bit to understand some of Rusts functionality. Or let's say I am still trying to figure out how to accomplish this in the 'Rust way'.
pub struct TCPBasePackage {
haspayload: bool,
pkgbytes: Vec<u8>,
}
impl TCPBasePackage {
pub const CMD: i32 = 0;
pub fn new() -> TCPBasePackage {
TCPBasePackage { haspayload: false, pkgbytes: Vec::new()}
}
}
impl TCPPackage for TCPBasePackage {
fn serialize(&mut self) -> &[u8] {
self.pkgbytes.append(&mut self.get_command().to_be_bytes().to_vec());
self.pkgbytes.append(&mut [u8::from(self.haspayload)].to_vec());
self.pkgbytes.as_slice()
}
fn read_from_stream(&mut self, mut stream: &TcpStream) -> Vec<u8> {
let mut vec: Vec<u8> = Vec::new();
let mut buf_pkg: [u8; 5] = [0; 5];
stream.read_exact(&mut buf_pkg).unwrap();
vec.append(&mut buf_pkg.to_vec());
self.pkgbytes = vec.to_vec();
return self.pkgbytes.clone();
}
fn deserialize(&mut self, buff: &[u8]) -> i32 {
self.haspayload = buff[4] != 0;
return 5;
}
fn get_command(&self) -> i32 {
TCPBasePackage::CMD
}
}
pub struct MsgLiveImage<'a> {
tcppackage: TCPBasePackage,
imgbytes: Vec::<u8>,
img: RawBmp<'a>,
}
impl<'a> MsgLiveImage<'a> {
pub const CMD: i32 = 2;
pub fn new() -> MsgLiveImage<'static> {
MsgLiveImage {
tcppackage: TCPBasePackage { haspayload: false, pkgbytes: Vec::new() },
imgbytes: Vec::new(),
img: RawBmp::from_slice(&[]).unwrap()
}
}
pub fn set_image_data(&'a mut self, data: Vec::<u8>) {
self.imgbytes = data;
self.img = RawBmp::from_slice(&self.imgbytes.as_slice()).unwrap();
}
}
In some function of my application I want to do this:
fn write_response_to_stream(
mut request: &Box<dyn mytcp::TCPPackage>,
mut stream: &TcpStream,
raspicam: &Arc<Mutex<camserv::CamServ>>,
) -> Result<Box<dyn mytcp::TCPPackage>, &'static str> {
match request.get_command() {
mytcp::MsgLiveImage::CMD => {
let mut pkg = mytcp::MsgLiveImage::new();
{
{
let tmpcam = raspicam.lock().unwrap(); // lock the camera server
let tmpbuff = tmpcam.imgbuff.lock().unwrap(); // lock the buffer of last image
pkg.set_image_data((*tmpbuff).clone()); // make copy of my image and transfer ownership of that copy to the package struct
}
{
let sbuff = pkg.serialize();
stream.write(&sbuff);
}
stream.flush();
}
Ok(Box::new(pkg)) // return the response package
}
_ => Err("Unknown request package"),
}
}
But the problem is, that the compiler is complaining about multiple borrowing the pkg-variable. As well as moving the pkg out of scope (which i learned should be possible by wrapping it in a Box.
Can someone explain me why the first mutable borrow still lasts even after the method returns? How can i achieve to call multiple methods on my struct without getting these borrowing conflicts?
Errors from rustc:
error[E0499]: cannot borrow `pkg` as mutable more than once at a time
--> src/raspiserv/mod.rs:90:33
|
87 | pkg.set_image_data((*tmpbuff).clone());
| -------------------------------------- first mutable borrow occurs here
...
90 | let sbuff = pkg.serialize();
| ^^^^^^^^^^^^^^^ second mutable borrow occurs here
...
95 | Ok(Box::new(pkg))
| ----------------- returning this value requires that `pkg` is borrowed for `'static`
error[E0515]: cannot return value referencing local variable `pkg`
--> src/raspiserv/mod.rs:95:13
|
87 | pkg.set_image_data((*tmpbuff).clone());
| -------------------------------------- `pkg` is borrowed here
...
95 | Ok(Box::new(pkg))
| ^^^^^^^^^^^^^^^^^ returns a value referencing data owned by the current function
error[E0505]: cannot move out of `pkg` because it is borrowed
--> src/raspiserv/mod.rs:95:25
|
87 | pkg.set_image_data((*tmpbuff).clone());
| -------------------------------------- borrow of `pkg` occurs here
...
95 | Ok(Box::new(pkg))
| ------------^^^--
| | |
| | move out of `pkg` occurs here
| returning this value requires that `pkg` is borrowed for `'static`
The problem is with your set_image_data
pub fn set_image_data(&'a mut self, data: Vec::<u8>) {
self.imgbytes = data;
self.img = RawBmp::from_slice(&self.imgbytes.as_slice()).unwrap();
}
you borrow self for the lifetime of 'a which is as long as the RawBmp inside of it is valid.
Thus the borrow lasts as long as the struct.
What you have is a self referential struct see this question on them for suggestions how to reslove this.
You can probably just drop the img from MsgLiveImage and replace it with a method:
impl MsgLiveImage {
pub fn as_img<'a>(&'a self) -> Result<RawBmp<'a>, ParseError> {
RawBmp::from_slice(&self.imgbytes.as_slice())
}
}
Might even be able to omit the lifetimes from that.

Passing both &mut self and &self to the same function

Stripped down to the bare essentials, my problematic code looks as follows:
pub struct Item;
impl Item {
/// Partial copy. Not the same as simple assignment.
pub fn copy_from(&mut self, _other: &Item) {
}
}
pub struct Container {
items: Vec<Item>,
}
impl Container {
pub fn copy_from(&mut self, self_idx: usize, other: &Container, other_idx: usize) {
self.items[self_idx].copy_from(&other.items[other_idx]);
}
}
fn main() {
let mut container = Container { items: vec![Item, Item] };
container.copy_from(0, &container, 1);
}
This is of course rejected by the borrow checker:
error[E0502]: cannot borrow `container` as mutable because it is also borrowed as immutable
--> src/main.rs:21:5
|
21 | container.copy_from(0, &container, 1);
| ^^^^^^^^^^---------^^^^----------^^^^
| | | |
| | | immutable borrow occurs here
| | immutable borrow later used by call
| mutable borrow occurs here
For more information about this error, try `rustc --explain E0502`.
I understand why that happens, but I don't have a good solution.
I've considered adding a dedicated copy_from_self function that callers need to use in cases where self == other:
pub fn copy_from_self(&mut self, to_idx: usize, from_idx: usize) {
if to_idx != from_idx {
unsafe {
let from_item: *const Item = &self.items[from_idx];
self.items[to_idx].copy_from(&*from_item);
}
}
}
But this is un-ergonomic, bloats the API surface, and needs unsafe code inside.
Note that in reality, the internal items data structure is not a simple Vec, so any approach specific to Vec or slice will not work.
Is there an elegant, idiomatic solution to this problem?
If I understand the comments on the question correctly, a general solution seems to be impossible, so this answer is necessarily specific to my actual situation.
As mentioned, the actual data structure is not a Vec. If it were a Vec, we could use split_at_mut to at least implement copy_from_self safely.
But as it happens, my actual data structure is backed by a Vec, so I was able to add a helper function:
/// Returns a pair of mutable references to different items. Useful if you need to pass
/// a reference to one item to a function that takes `&mut self` on another item.
/// Panics if `a == b`.
fn get_mut_2(&mut self, a: usize, b: usize) -> (&mut T, &mut T) {
assert!(a != b);
if a < b {
let (first, second) = self.items.split_at_mut(b);
(&mut first[a], &mut second[0])
} else if a > b {
let (first, second) = self.items.split_at_mut(a);
(&mut second[0], &mut first[b])
} else {
panic!("cannot call get_mut_2 with the same index {} == {}", a, b);
}
}
Now we can implement copy_from_self without unsafe code:
pub fn copy_from_self(&mut self, to_idx: usize, from_idx: usize) {
let (to, from) = self.items.get_mut_2(to_idx, from_idx);
to.unwrap().copy_from(from.unwrap());
}

Rust borrow checker and early returns

Rust-lang Playground link
struct Foo {
val: i32
}
impl Foo {
pub fn maybe_get(&mut self) -> Option<&mut i32> {
Some(&mut self.val)
}
pub fn definitely_get(&mut self) -> &mut i32 {
{ // Add closure to ensure things have a chance to get dropped
if let Some(val) = self.maybe_get() {
// Explicit return to avoid potential scope sharing with an else block or a match arms.
return val;
}
}
// One would think any mutable references would not longer be at play at this point
&mut self.val
}
}
I have some code that's similar but more complicated than what is provided above that I've been fighting with for quite a while. The borrow checker is unhappy with the implementation of definitely_get and has the following error
error[E0499]: cannot borrow `self.val` as mutable more than once at a time
--> src/main.rs:19:9
|
10 | pub fn definitely_get(&mut self) -> &mut i32 {
| - let's call the lifetime of this reference `'1`
11 | {
12 | if let Some(val) = self.maybe_get() {
| ---------------- first mutable borrow occurs here
13 | return val;
| --- returning this value requires that `*self` is borrowed for `'1`
...
19 | &mut self.val
| ^^^^^^^^^^^^^ second mutable borrow occurs here
It seems unreasonable for there to be no way to implement fallback logic with a mutable reference in Rust so I can't imagine there isn't a way.
I've managed to fix this with an unfortunately expensive alternative implementation due to how maybe_get is implemented in my non-trivial example.
impl Foo {
pub fn has_maybe_val(&self) -> bool {
// Non-trivial lookup...
true
}
pub fn maybe_get(&mut self) -> Option<&mut i32> {
// Same non-trivial lookup...
Some(&mut self.val)
}
pub fn definitely_get(&mut self) -> &mut i32 {
if self.has_maybe_val() {
self.maybe_get().unwrap() // Ouch!
} else {
&mut self.val
}
}
}

Multiple mutable borrows in Rust

I'm playing around with building a very simple stack based evaluator in Rust. I want the user to be able to define functions later, so I'm storing all operators in a HashMap with closures as values.
use std::collections::HashMap;
pub type Value = i32;
pub struct Evaluator<'a> {
stack: Vec<Value>,
ops: HashMap<String, &'a dyn FnMut(&'a mut Vec<Value>)>,
}
impl<'a> Evaluator<'a> {
pub fn new() -> Evaluator<'a> {
let stack: Vec<Value> = vec![];
let mut ops: HashMap<String, &'a dyn FnMut(&'a mut Vec<Value>)> = HashMap::new();
ops.insert("+".to_string(), &|stack: &'a mut Vec<Value>| {
if let (Some(x), Some(y)) = (stack.pop(), stack.pop()) {
stack.push(y + x);
}
});
Evaluator { stack, ops }
}
pub fn stack(&self) -> &[Value] {
&self.stack
}
pub fn eval(&'a mut self, input: &str) {
let symbols = input
.split_ascii_whitespace()
.collect::<Vec<_>>();
for sym in symbols {
if let Ok(n) = sym.parse::<i32>() {
self.stack.push(n);
} else {
let s = sym.to_ascii_lowercase();
if let Some(f) = self.ops.get(&s) {
f(&mut self.stack);
} else {
println!("error");
}
}
}
}
}
fn main() {
let mut e = Evaluator::new();
e.eval("1 2 +")
}
I'm currently getting two errors:
error[E0499]: cannot borrow `self.stack` as mutable more than once at a time
--> src/sample.rs:34:17
|
10 | impl<'a> Evaluator<'a> {
| -- lifetime `'a` defined here
...
34 | self.stack.push(n);
| ^^^^^^^^^^ second mutable borrow occurs here
...
38 | f(&mut self.stack);
| ------------------
| | |
| | first mutable borrow occurs here
| argument requires that `self.stack` is borrowed for `'a`
error[E0596]: cannot borrow `**f` as mutable, as it is behind a `&` reference
--> src/sample.rs:38:21
|
38 | f(&mut self.stack);
| ^ cannot borrow as mutable
error[E0499]: cannot borrow `self.stack` as mutable more than once at a time
--> src/sample.rs:38:23
|
10 | impl<'a> Evaluator<'a> {
| -- lifetime `'a` defined here
...
38 | f(&mut self.stack);
| --^^^^^^^^^^^^^^^-
| | |
| | `self.stack` was mutably borrowed here in the previous iteration of the loop
| argument requires that `self.stack` is borrowed for `'a`
error: aborting due to 3 previous errors
Some errors have detailed explanations: E0499, E0596.
For more information about an error, try `rustc --explain E0499`.
My concern is the first one. I'm not sure what I'm doing wrong as I'm not borrowing them at the same time. Can I tell Rust the previous borrow (self.stack.pop()) is done? Any help appreciated.
I think I solved my problem. The thing I kept coming back to is, "What owns the closures?" In this case I'm using references, but nothing is taking ownership of the data. When I refactored (below) with Box to take ownership, it worked.
I'm curious if there is a way to do this with with just references and/or if my explanation is wrong?
Working code:
use std::collections::HashMap;
pub type Value = i32;
pub struct Evaluator {
stack: Vec<Value>,
ops: HashMap<String, Box<dyn FnMut(&mut Vec<Value>)>>,
}
impl Evaluator {
pub fn new() -> Evaluator {
let stack: Vec<Value> = vec![];
let mut ops: HashMap<String, Box<dyn FnMut(&mut Vec<Value>)>> = HashMap::new();
ops.insert("+".to_string(), Box::new(|stack: &mut Vec<Value>| {
if let (Some(x), Some(y)) = (stack.pop(), stack.pop()) {
stack.push(y + x);
}
}));
Evaluator { stack, ops }
}
pub fn stack(&self) -> &[Value] {
&self.stack
}
pub fn eval(&mut self, input: &str) {
let symbols = input
.split_ascii_whitespace()
.collect::<Vec<_>>();
for sym in symbols {
if let Ok(n) = sym.parse::<i32>() {
self.stack.push(n);
} else {
let s = sym.to_ascii_lowercase();
if let Some(f) = self.ops.get_mut(&s) {
f(&mut self.stack);
} else {
println!("error");
}
}
}
}
}
fn main() {
let mut e = Evaluator::new();
e.eval("1 2 +")
}
You have borrows with conflicting lifetimes:
You are defining a lifetime 'a for the struct in line 5: pub struct Evaluator<'a> {
In line 7, you are stating that ops is a HashMap that holds functions that receive mutable borrows for the whole duration of 'a
Then, in line 28, you are defining an eval method that holds a mutable reference to self for the whole duration of the struct ('a)
The conflict can be solved if you use two different lifetimes, since the time that an operation borrows self should be inherently shorter than the lifetime for the whole evaluation, since in eval you are running a loop and multiple invocations to the operations.
This should fix the issues mentioned above:
pub struct Evaluator<'a, 'b> {
stack: Vec<Value>,
ops: HashMap<String, &'b dyn FnMut(&'b mut Vec<Value>)>,
}
impl<'a, 'b> Evaluator<'a, 'b> {
pub fn new() -> Evaluator<'a> {
let stack: Vec<Value> = vec![];
let mut ops: HashMap<String, &'b dyn FnMut(&'b mut Vec<Value>)> = HashMap::new();

Lifetime on trait returning iterator

I'm working with a trait requiring a function returning an iterator without consuming the object. The iterator itself returns copies of data values, not references. As the iterator implementation requires a reference to the object it is iterating over, I end up having to declare lots of lifetimes (more than I would have thought necessary, but could not get it to compile otherwise). I then run into trouble with borrow duration - a minimal "working" example is as follows:
pub trait MyTrait<'a> {
type IteratorType: Iterator<Item=u32>;
fn iter(&'a self) -> Self::IteratorType;
fn touch(&'a mut self, value: u32);
}
struct MyStruct {
data: Vec<u32>
}
struct MyIterator<'a> {
structref: &'a MyStruct,
next: usize,
}
impl<'a> Iterator for MyIterator<'a> {
type Item = u32;
fn next(&mut self) -> Option<u32> {
if self.next < self.structref.data.len() {
self.next += 1;
return Some(self.structref.data[self.next-1]);
} else {
return None;
}
}
}
impl<'a> MyTrait<'a> for MyStruct {
type IteratorType = MyIterator<'a>;
fn iter(&'a self) -> Self::IteratorType {
return MyIterator { structref: &self, next: 0 };
}
fn touch(&'a mut self, value: u32) {
}
}
fn touch_all<'a,T>(obj: &'a mut T) where T: MyTrait<'a> {
let data: Vec<u32> = obj.iter().collect();
for value in data {
obj.touch(value);
}
}
Compiling this gives me the error:
error[E0502]: cannot borrow `*obj` as mutable because it is also borrowed as immutable
|
39 | let data: Vec<u32> = obj.iter().collect();
| --- immutable borrow occurs here
40 | for value in data {
41 | obj.touch(value);
| ^^^ mutable borrow occurs here
42 | }
43 | }
| - immutable borrow ends here
By my limited understanding of lifetimes, I would have thought the immutable borrow only extends to the line where I make it - after all the iterator is consumed and I no longer hold any references to obj or data contained in it. Why does the lifetime of the borrow extend to the entire function, and how do I fix this?
Here is a sequence of steps on how I arrived here - running the code should provide the associated compiler errors.
no explicit lifetimes
IteratorType needs lifetime
Unconstrained lifetime parameter
To clarify: I'd like to be able to make calls like this:
fn main() {
let obj: MyStruct = MyStruct { data : vec![] };
touch_all(&mut obj);
}
rather than having to call
touch_all(&mut &obj);
which would be needed for the proposal by mcarton (1st and 2nd comment).

Resources