How to tackle interior mutability in a struct? - rust

I have a struct Screen that handles the manipulation of windows, drawing to the screen, and handling the input.
One of the methods, that handles the input, is as follows:
pub fn prompt(&mut self) {
for e in self.stdin.lock().events() {
match e.unwrap() {
Event::Key(Key::Char('\n')) => break,
Event::Key(Key::Char(c)) => {
if c.is_alphanumeric() {
self.overlay.putc(self.cursor_y, self.cursor_x, c);
self.move_cursor(self.cursor_y, self.cursor_x + 1);
}
}
_ => ()
}
}
}
The issue is that self.move_cursor() takes a mutable reference to self, and modifies the cursor position within the Screen.
The code produces the following error:
--> src/screen.rs:190:25
|
184 | for e in self.stdin.lock().events() {
| --------------------------
| |
| immutable borrow occurs here
| immutable borrow later used here
...
190 | self.move_cursor(self.cursor_y, self.cursor_x + 1);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ mutable borrow occurs here
The methods operate on different members, so it is safe.
I understand the issue and I'm thinking about how to tackle it. One option that I thought of is to wrap every member of the Screen in RefCell and pass an immutable reference &self to every method of Screen. This does not seem to me like a good solution, though. I was also thinking to simply use unsafe {} but was unable to use it properly in this context.
My question is: what would be the best, or idiomatic, way to handle this; or how to reorganize the struct.
For extra context: I'm drawing to the terminal, using the library termion.

Related

How to produce static references from append-only arena?

In my application (a compiler), I'd like to create data cyclic data structures of various kinds throughout my program's execution that all have the same lifetime (in my case, lasting until the end of compilation). In addition,
I don't need to worry about multi-threading
I only need to append information - no need to delete or garbage collect
I only need immutable references to my data
This seemed like a good use case for an Arena, but I saw that this would require passing the arena around to every function in my program, which seemed like a large overhead.
So instead I found a macro called thread_local! that I can use to define global data. Using this, I thought I might be able to define a custom type that wraps an index into the array, and implement Deref on that type:
use std::cell::RefCell;
enum Floop {
CaseA,
CaseB,
CaseC(FloopRef),
CaseD(FloopRef),
CaseE(Vec<FloopRef>),
}
thread_local! {
static FLOOP_ARRAY: RefCell<Vec<Box<Floop>>> = RefCell::new(Vec::new());
}
pub struct FloopRef(usize);
impl std::ops::Deref for FloopRef {
type Target = Floop;
fn deref(&self) -> &Self::Target {
return FLOOP_ARRAY.with(|floops| &floops.borrow()[self.0]);
}
}
pub fn main() {
// initialize some data
FLOOP_ARRAY.with(|floops| {
floops.borrow_mut().push(Box::new(Floop::CaseA));
let idx = floops.borrow_mut().len();
floops.borrow_mut().push(Box::new(Floop::CaseC(FloopRef(idx))));
});
}
Unfortunately I run into lifetime errors:
error: lifetime may not live long enough
--> src/main.rs:20:36
|
20 | return FLOOP_ARRAY.with(|floops| &floops.borrow()[self.0]);
| ------- ^^^^^^^^^^^^^^^^^^^^^^^^ returning this value requires that `'1` must outlive `'2`
| | |
| | return type of closure is &'2 Box<Floop>
| has type `&'1 RefCell<Vec<Box<Floop>>>`
error[E0515]: cannot return value referencing temporary value
--> src/main.rs:20:36
|
20 | return FLOOP_ARRAY.with(|floops| &floops.borrow()[self.0]);
| ^---------------^^^^^^^^
| ||
| |temporary value created here
| returns a value referencing data owned by the current function
What I'd like to tell the compiler is that I promise I'm never going to remove entries from the Array and that I'm not going to share values across threads and that the array will last until the end of the program so that I can in essence just return a &'static reference to a Floop object. But Rust doesn't seem to be convinced this is safe.
Is there any kind of Rust helper library that would let me do something like this? Or are there safety holes even when I guarantee I only append / only use data with a single thread?
If you would have a reference, you could send the data to another thread, then watch it after it has been dropped because the creating thread was finished.
Even if you would solve this problem, this would still require unsafe code, as the compiler can't be convinced that growing the Vec won't invalidate existing references. This is true in this case since you're using Box, but the compiler cannot know that.
If you pinky promise to never touch the data after the creating thread has finished, you can use the following code. Note that this code is technically UB as when the Vec will grow, we will move all Boxes, and at least currently, moving a Box invalidates all references deriven from it:
enum Floop {
CaseA,
CaseB,
CaseC(&'static Floop),
CaseD(&'static Floop),
CaseE(Vec<&'static Floop>),
}
thread_local! {
static FLOOP_ARRAY: RefCell<Vec<Box<Floop>>> = RefCell::new(Vec::new());
}
fn alloc_floop(floop: Floop) -> &'static mut Floop {
FLOOP_ARRAY.with(|floops| {
let mut floops = floops.borrow_mut();
floops.push(Box::new(floop));
let floop = &mut **floops.last_mut().unwrap() as *mut Floop;
// SAFETY: We never access the data after it has been dropped, and we are
// the only who access this `Box` as we access a `Box` only immediately
// after pushing it.
unsafe { &mut *floop }
})
}
fn main() {
let floop_a = alloc_floop(Floop::CaseA);
let floop_b = alloc_floop(Floop::CaseC(floop_a));
}
A better solution would be something like a thread-safe arena that you can use in a static, but sadly, I found no crate that implements that.

How can I do a mutable borrow after an immutable borrow?

The code
fn play(&self, game: &mut crate::game::Game) {
let player_in_turn: &Player = game.get_player_in_turn();
match player_in_turn.player_kind {
PlayerKind::AI => {
player_in_turn.do_random_move(&mut game);
}
_ => {
panic!("not implemented yet");
}
}
game.status = Status::ExitGame;
}
Where get_player_in_turn is
pub fn get_player_in_turn(&self) -> &Player {
match self.status {
Status::InGame(ig_status) => match ig_status {
InGameStatus::PlayFirst => {
if self.player_a.play_order == PlayOrder::First {
&self.player_a
} else {
&self.player_b
}
}
InGameStatus::PlaySecond => {
if self.player_a.play_order == PlayOrder::Second {
&self.player_a
} else {
&self.player_b
}
}
},
_ => {
panic!("get_player_in_turn called when not in a in-game status");
}
}
}
The compiler is telling me
error[E0502]: cannot borrow `game` as mutable because it is also borrowed as immutable
--> src\game\status\in_game_status.rs:28:47
|
25 | let player_in_turn: &Player = game.get_player_in_turn();
| ------------------------- immutable borrow occurs here
...
28 | player_in_turn.do_random_move(&mut game);
| -------------- ^^^^^^^^^ mutable borrow occurs here
| |
| immutable borrow later used by call
Usually I am able to understand the what and the why of compilers erros
I understand this
let player_in_turn: &Player = game.get_player_in_turn(); : I keep from game a ref to the current player; so I get an immutable ref of kind &Player
Here the game variable is immutably borrowed because of fn signature get_player_in_turn(&self). That's right, I do not want allow modifications to game in the get_player_in_turn, but also I need a ref because I need the player in turn, not a copy, or what else
player_in_turn.do_random_move(&mut game); : The instance of Player now alters the game itself doing its move
And here game should be passed as mutable because it's the goal of do_random_move
Question
I can understand the why of this but not how can I workaround
As you said, you know why this happens. Optimal workaround is to rewrite your code to use less borrowing. So you definitely can't do that if you want to modify some previously borrowed data. But if your do_random_move() function does not change internals of Players, then you can use this design pattern.
The core idea is to split borrowing into parts. Right now you are borrowing full Game structure when calling get_player_in_turn, but you only need 3 fields there: status, player_a, player_b. You can create a new function that takes them as arguments and this will split your borrowing and will allow you to borrow other fields of Game later (probably for do_random_move implementation).
here is example code

Having problem with mutability of Rc pointers

I'm trying to implement a simple tree structure with Rc pointers:
use std::rc::Rc;
fn main() {
println!("Hello, world!");
}
enum Expr {
B(i128),
A(Rc<Expr>, Rc<Expr>),
O(Rc<Expr>, Rc<Expr>),
}
struct Node {
data: Rc<Expr>,
parent: Option<Rc<Node>>,
children: Vec<Rc<Node>>,
}
impl Node {
fn add_to_children(mut self, node: &Rc<Node>) {
self.children.push(Rc::clone(node))
}
fn set_as_parent(mut self, node: &Rc<Node>) {
self.parent = Some(Rc::clone(node))
}
fn link_parent_child(parent: &mut Rc<Node>, child: &mut Rc<Node>) {
println!("eheeh");
parent.add_to_children(&child);
child.set_as_parent(&parent);
}
}
This won't compile however:
error[E0507]: cannot move out of an `Rc`
--> src/main.rs:32:9
|
32 | parent.add_to_children(&child);
| ^^^^^^^-----------------------
| | |
| | value moved due to this method call
| move occurs because value has type `Node`, which does not implement the `Copy` trait
|
note: this function takes ownership of the receiver `self`, which moves value
--> src/main.rs:21:28
|
21 | fn add_to_children(mut self, node: &Rc<Node>) {
What's the better way of implementing this type of tree? It is my signature that's wrong?
Your add_to_children and set_as_parent methods take mut self, which means they consume self and try to move out of the Rc. That's not allowed, as there may be other references to the object.
The methods should take &mut self... but you'll run into another issue: Rc only exposes an immutable reference. Because, again, there may be multiple references.
The way to solve that issue is interior mutability. In your case, RefCell is the easiest - it's essentially a single-threaded lock, allowing only one place mutable access at a time. It is not a pointer and does not allocate on the heap by itself - it simply wraps the underlying value.
There's also another issue: Because both your parent and children refer to each other via Rc, you end up with a circular reference, meaning your nodes won't free memory when you drop them. Using std::rc::Weak for the parent references will fix that.
As Chaymin Friedman points out, Rust's rules about mutability can make implementing a tree structure somewhat difficult, especially when it contains parent references. There are many crates out on crates.io that have implemented such tree structures, using a variety of techniques.

How can I iteratively traverse a tree built with Rc<RefCell<T>> while mutably matching on enums?

I cannot find a way to do simple tree traversal without recursion within the guidelines of the borrow checker.
Advent of Code 2021 Day 18 has numbers that can be represented either by a pair of numbers or by a value (perfect for Rust enums). There are also parts of the problem where I'm using a stack to traverse the tree so I'm using Rc<RefCell<T>> to represent child nodes. This led me to the following representation:
use std::{cell::RefCell, rc::Rc};
enum Number {
Pair(Rc<RefCell<Number>>, Rc<RefCell<Number>>),
Value(u8),
}
I'm trying to make a function that updates the value of the left-most value in a Number. Writing the recursive version took a few tries but ended up working. However, I cannot get an iterative version to compile no matter what I try. The combination of matching the node and having to borrow with RefMut leads me to borrow/lifetime problems. This is what I'm trying to do:
fn propagate_left(mut node: &Rc<RefCell<Number>>, val: u8) {
loop {
let mut ref_mut = node.borrow_mut();
match &mut (*ref_mut) {
Number::Pair(left_node, _) => {
node = left_node;
}
Number::Value(number_val) => {
*number_val += val;
return;
}
}
}
}
error[E0597]: `ref_mut` does not live long enough
--> src/lib.rs:11:22
|
8 | fn propagate_left(mut node: &Rc<RefCell<Number>>, val: u8) {
| - let's call the lifetime of this reference `'1`
...
11 | match &mut (*ref_mut) {
| ^^^^^^^ borrowed value does not live long enough
12 | Number::Pair(left_node, _) => {
| --------- assignment requires that `ref_mut` is borrowed for `'1`
...
20 | }
| - `ref_mut` dropped here while still borrowed
Is there any way to make this work without using unsafe code or recursion?
I used a Vec for storage and indices in my structures to avoid this kind of problem in other puzzles but I wanted to try with references in this one.
The problem with your attempt is that the lifetime of the return value of node.borrow_mut() is tied to node, but you are attempting to store that result into a variable that has a caller-provided lifetime. When the current iteration's borrow_mut() ends, the reference (used by left_node) expires and you cannot store something with a shorter lifetime into a variable with a longer lifetime — the entire point of memory safety.
A workaround is to avoid concurrently using references (&) and reference counting (Rc). Using only Rc, you can clone the child and replace the temporary variable:
use std::{cell::RefCell, rc::Rc};
enum Number {
Pair(Rc<RefCell<Number>>, Rc<RefCell<Number>>),
Value(u8),
}
fn propagate_left(mut node: Rc<RefCell<Number>>, val: u8) {
loop {
let next = match &mut *node.borrow_mut() {
Number::Pair(left_node, _) => Rc::clone(left_node),
Number::Value(number_val) => {
*number_val += val;
return;
}
};
node = next;
}
}
You can also use only references and avoid Rc / RefCell completely:
enum Number {
Pair(Box<Number>, Box<Number>),
Value(u8),
}
fn propagate_left(mut node: &mut Number, val: u8) {
loop {
match node {
Number::Pair(left_node, _) => {
node = left_node;
}
Number::Value(number_val) => {
*number_val += val;
return;
}
};
}
}
See also:
Borrowed value does not live long enough when adding to a binary tree built on RefCell
My solution to AoC 2021 Day 18
Cannot obtain a mutable reference when iterating a recursive structure: cannot borrow as mutable more than once at a time
Adding an append method to a singly linked list
How do I keep a mutable reference to the last node while building a linked list?

How to call a method while iterating in Rust

Appologies if this is very simple. I'm learning rust and getting used to the strange borrowing system. Usually, you can get the desired behavior just by changing the syntax of your method calls, however, in this case, there seems to be now way.
A simplified version of my code is this: EventPump if from SDL.
struct Example {
pump: EventPump
}
impl Example {
fn method(&mut self) {
for event in pump.poll_iter() {
self.other_method();
}
}
fn other_method(&self) {
}
}
However, I am getting the following error:
error[E0502]: cannot borrow `*self` as immutable because it is also borrowed as mutable
--> src\game.rs:53:67
|
30 | for event in self.pump.poll_iter();
| ---------------------
| |
| mutable borrow occurs here
| mutable borrow later used here
...
53 | self.other_method();
| ^^^^ immutable borrow occurs here
There is probably some proper way to do this so my struct can maintain ownership of itself, but I have not been able to find it.
I have tried the following:
Turn it into a while loop with explicit while let event = iterator.next(), same error
Making the function mutable, the error now says that no two mutable references are allowed either. I guess the entire "immutability" part of the error message is actually irrelevant.
I could perhaps copy the entire contents of the iterable into a vector or such, but that would defeat the purpose of a iterator, and what if the iterator is not finite? There has to be a better way right...
If someone with more rust experience could help me out it would be much appreciated.
If you want an attribute of a struct to be mutable when there is an immutable reference of a struct in the same block, you'll need RefCell. This is called interior mutability.
If an interior mutability of struct Example is desired, then you will need a RefCell.
use sdl2::{EventPump};
struct Example {
pump: RefCell<EventPump> // wrap in RefCell
}
impl Example {
// you have to decide whether you want a mutable or immutable chained methods
// i.e. method and other_method should be of same mutability because
// other method is called in method
fn method(&self) {
// borrow a mutable reference of pump inside a method with immutable self
let mut pump = self.pump.borrow_mut();
for event in pump.poll_iter() {
self.other_method();
}
}
fn other_method(&self) {
}
}
If you have a pattern like that:
fn method(&mut self) {
for item in self.some_iterator_that_borrow_mut() {
self.other_method();
}
}
The borrow rule that states exactly one mutable reference is broken:
there are one mutable and one immutable reference to self.
To avoid the double reference problem consume the iterator and collect the items into
a temporary collection, for example into a Vec:
impl Example {
fn method(&mut self) {
for event in self.pump.poll_iter().collect::<Vec<_>>(); {
self.other_method();
}
}
fn other_method(&self) {}
}

Resources