Cannot modify the field in recursive structure - rust

I have a recursive structure, where field of a structure is a reference to other struct of same type:
use std::collections::HashMap;
pub struct RecursiveStruct<'a> {
outer: Option<Box<&'a RecursiveStruct<'a>>>,
dict: HashMap<u32, String>
}
With this structure I also have couple of methods such as constructor, method which adds (k,v) pair to calee's field and a getter:
impl<'a> RecursiveStruct<'a> {
pub fn new(outer: Option<Box<&'a RecursiveStruct<'a>>>) -> Self {
let dict: HashMap<u32, String> = HashMap::new();
RecursiveStruct { outer, dict }
}
// searches for value corresponding to key in all struct layers
pub fn get(&self, key: u32) -> Result<String, ()> {
let item = self.dict.get(&key);
match item {
Some(x) => Ok(x.clone()),
None => {
match &self.outer {
Some(x) => x.get(key),
None => Err(())
}
}
}
}
// adds (key, val) to "innermost" instance of struct
pub fn add(&mut self, key:u32, val: String) {
self.dict.insert(key, val);
}
}
These methods work fine, but when I try to add a method, which tries to modify dict field in any of the inner layers, I get cannot borrow '***x' as mutable, as it is behind a '&' reference error.
pub fn re_assign(&mut self, key: u32, val: String) {
if self.dict.contains_key(&key) {
self.dict.insert(key, val);
} else {
match &mut self.outer {
Some(x) => x.re_assign(key, val.clone()),
None => println!("Such key couldn't be found!"),
};
}
}
Here is the link to playground.

You are using a &, but want a &mut, rust references are immutable by default:
Playground: https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=be82b8ba01dff60e106af9e59df8228e
use std::collections::HashMap;
pub struct RecursiveStruct<'a> {
outer: Option<Box<&'a mut RecursiveStruct<'a>>>,
dict: HashMap<u32, String>
}
impl<'a> RecursiveStruct<'a> {
pub fn new(outer: Option<Box<&'a mut RecursiveStruct<'a>>>) -> Self {
let dict: HashMap<u32, String> = HashMap::new();
RecursiveStruct { outer, dict }
}
pub fn get(&self, key: u32) -> Result<String, ()> {
let item = self.dict.get(&key);
match item {
Some(x) => Ok(x.clone()),
None => {
match &self.outer {
Some(x) => x.get(key),
None => Err(())
}
}
}
}
pub fn re_assign(&mut self, key: u32, val: String) {
if self.dict.contains_key(&key) {
self.dict.insert(key, val);
} else {
match &mut self.outer {
Some(x) => x.re_assign(key, val.clone()),
None => println!("Such key couldn't be found!"),
};
}
}
pub fn add(&mut self, key:u32, val: String) {
self.dict.insert(key, val);
}
}
fn main() {
// instantiate "outer" struct and set its field
let mut S = RecursiveStruct::new(None);
S.add(42, "Answer to the universe!".to_string());
// instantiate "inner" struct
let mut S1 = RecursiveStruct::new(Some(Box::new(&mut S)));
println!("{}", S1.get(42).unwrap()); // get the field of outer struct
// modify the field of outer struct
S1.re_assign(42, "The answer has been changed.".to_string());
println!("{}", S1.get(42).unwrap());
}

Related

Rust: return &mut reference from downcast_ref of HashMap mutable value

As the title says, we have an application which runs wasm plugins. Each plugin can register their own State in the StateRegistry. Then whenever the plugins are executed, they will modify their respective State.
The code below illustrates this:
use std::{collections::HashMap, any::Any};
type ContractId = String;
type GenericContractState = Box<dyn Any>;
// This will be WASM code
mod foo_contract {
use super::StateRegistry;
pub struct State {
}
pub fn update(states: &mut StateRegistry) {
let state = states.states.get_mut(&"foo_contract".to_string()).unwrap();
let state = state.downcast_mut::<State>().unwrap();
// I'd prefer something like:
// let state = state.lookup::<State>().unwrap()
}
}
pub struct StateRegistry {
pub states: HashMap<ContractId, GenericContractState>,
}
impl StateRegistry {
fn new() -> Self {
Self { states: HashMap::new() }
}
fn register(&mut self, contract_id: ContractId, state: GenericContractState) {
self.states.insert(contract_id, state);
}
/*
fn lookup<'a, S>(&'a mut self, contract_id: &ContractId) -> Option<StateRefWrapper<'a, S>> {
match self.states.get_mut(contract_id) {
Some(state) => {
let ptr = state.downcast_mut::<S>();
match ptr {
Some(ptr) => Some(StateRefWrapper { _mut: state, ptr }),
None => None,
}
}
None => None,
}
}
*/
}
/*
struct StateRefWrapper<'a, S> {
_mut: &'a mut Box<dyn Any>,
ptr: &'a mut S,
}
*/
fn main() {
let mut states = StateRegistry::new();
let foo_state = Box::new(foo_contract::State {});
states.register("foo_contract".to_string(), foo_state);
foo_contract::update(&mut states);
}
The part I want to improve is that currently the plugin developer has to use this code to lookup their State in the registry:
let state = states.states.get_mut(&"foo_contract".to_string()).unwrap();
let state = state.downcast_mut::<State>().unwrap();
I want to create a respective method in StateRegistry that is usable like this:
let state = state.lookup::<State>().unwrap()
My attempt (commented above) was something like this:
impl StateRegistry {
// ...
fn lookup<'a, S>(&'a mut self, contract_id: &ContractId) -> Option<StateRefWrapper<'a, S>> {
match self.states.get_mut(contract_id) {
Some(state) => {
let ptr = state.downcast_mut::<S>();
match ptr {
Some(ptr) => Some(StateRefWrapper { _mut: state, ptr }),
None => None,
}
}
None => None,
}
}
}
struct StateRefWrapper<'a, S> {
_mut: &'a mut Box<dyn Any>,
ptr: &'a mut S,
}
How can I get this lookup() function working?
Thanks
You can't construct your StateRefWrapper in the way you want to, because it would contain two mutable borrows of the same value. You can, however, return just a &mut S which seems sufficient:
fn lookup<'a, S: 'static>(&'a mut self, contract_id: &ContractId) -> Option<&'a mut S> {
self.states
.get_mut(contract_id)
.and_then(|state| state.downcast_mut())
}
And use it like this:
pub fn update(states: &mut StateRegistry) {
let state = states.lookup::<State>(&"foo_contract".to_string()).unwrap();
// state.modify();
}

Heterogeneous collection as a member of a class in Rust

I am new to Rust, and does not fully understand lifetime, so probably, that is why I can't solv the following issue. I need a solution in which a class has a heterogeneous HashMap containing different objects derived from the same trait.
I have to be able to extend an object with some (multiple) functionality dinamically. Other solutions are also welcome. Adding functionality to the class in compile time could also work, but adding functionality directly to the main class not.
use std::collections::HashMap;
trait DoerTrait {
fn do_something( & self, a : u8, b : u8 ) -> u8;
}
struct MyDoer<'a> {
}
impl DoerTrait for MyDoer<'a> {
fn do_something( & self, a : u8, b : u8 ) -> u8 {
return a + b;
}
}
struct MyMain<'a> {
doers : HashMap<u8,&'a dyn DoerTrait>,
}
impl<'a> MyMain<'a> {
fn new() -> Self {
Self {
doers : HashMap::new()
}
}
fn add_doer( &mut self, id : u8, doer : & dyn DoerTrait ) {
self.doers.insert( id, doer );
}
fn do_something( & self, id : u8 ) {
match self.doers.get( &id ) {
Some( doer ) => {
println!( "{}", doer(19,26) );
}
None => {
println!( "Doer not specified!" );
}
}
}
}
fn main() {
let mut mymain = MyMain::new();
let mydoer = MyDoer{};
mymain.add_doer( 42, &mydoer );
mymain.do_something( 42 );
}
Not too sure what issue you have, once MyDoer has been stripped of its incorrect (unnecessary) lifetime and the lifetime has correctly been declared on impl MyMain, the compiler directly points to the parameter of add_doer not matching (after which it points out that doer in do_something is not a function):
use std::collections::HashMap;
trait DoerTrait {
fn do_something(&self, a: u8, b: u8) -> u8;
}
struct MyDoer;
impl DoerTrait for MyDoer {
fn do_something(&self, a: u8, b: u8) -> u8 {
return a + b;
}
}
struct MyMain<'a> {
doers: HashMap<u8, &'a dyn DoerTrait>,
}
impl<'a> MyMain<'a> {
fn new() -> Self {
Self {
doers: HashMap::new(),
}
}
fn add_doer(&mut self, id: u8, doer: &'a dyn DoerTrait) {
self.doers.insert(id, doer);
}
fn do_something(&self, id: u8) {
match self.doers.get(&id) {
Some(doer) => {
println!("{}", doer.do_something(19, 26));
}
None => {
println!("Doer not specified!");
}
}
}
}
fn main() {
let mut mymain = MyMain::new();
let mydoer = MyDoer {};
mymain.add_doer(42, &mydoer);
mymain.do_something(42);
}

Rust: Modifying to an object contained in a Vec from another object of the same Vec

I have a Vec<dyn MyObj> and the first implementation of MyObj contained in the Vec can contains something that refers to a second implementation of MyObj contained in the same Vec.
I'd like that the first implementation can mutate the second implementation.
Here is my first idea:
use std::{rc::{Rc, Weak}, cell::RefCell};
trait MyObj {
fn f(&mut self);
}
type CRef = Weak<RefCell<Container>>;
struct Container {
list: Vec<Box<dyn MyObj>>,
this: CRef,
}
impl Container {
fn new() -> Rc<RefCell<Self>> {
let res = Rc::new(RefCell::new(Self {
list: vec![],
this: Weak::new(),
}));
{
let this = Rc::downgrade(&res);
let mut ref_on_res = res.borrow_mut();
ref_on_res.this = this;
}
res
}
fn register(&mut self, v: impl MyObj + 'static) -> ObjRef {
let index = self.list.len();
self.list.push(Box::new(v));
ObjRef::new(self.this.clone(), index)
}
fn get(&mut self, index: usize) -> &mut (dyn MyObj + 'static) {
let elt = &mut self.list[index];
Box::as_mut(elt)
}
}
struct ObjRef {
c: CRef,
i: usize,
}
impl ObjRef {
fn new(c: CRef, i: usize) -> Self {
Self { c, i }
}
}
impl MyObj for ObjRef {
fn f(&mut self) {
let i = self.i;
self.c.upgrade().map(|c| c.borrow_mut().get(i).f());
}
}
struct A {
r: ObjRef,
}
// First implementation
impl A {
fn new(r: ObjRef) -> A {
A { r }
}
}
impl MyObj for A {
fn f(&mut self) {
self.r.f();
}
}
// Second implementation
struct B(usize);
impl MyObj for B {
fn f(&mut self) {
self.0 += 1;
println!("B({})", self.0);
}
}
fn main() {
let c = Container::new();
let mut r = {
let b = c.borrow_mut().register(B(100));
c.borrow_mut().register(A::new(b))
};
r.f(); // -> Panic: already borrowed: BorrowMutError
}
Obviously, it panics and i understand why but i have no idea to fix this problem.
Have you any idea to do this kind of modification ?

How do I mutate in a match which borrows an immutable value?

I can understand borrowing/ownership concepts in Rust, but I have no idea how to work around this case:
use std::collections::{HashMap, HashSet};
struct Val {
t: HashMap<u16, u16>,
l: HashSet<u16>,
}
impl Val {
fn new() -> Val {
Val {
t: HashMap::new(),
l: HashSet::new(),
}
}
fn set(&mut self, k: u16, v: u16) {
self.t.insert(k, v);
self.l.insert(v);
}
fn remove(&mut self, v: &u16) -> bool {
self.l.remove(v)
}
fn do_work(&mut self, v: u16) -> bool {
match self.t.get(&v) {
None => false,
Some(r) => self.remove(r),
}
}
}
fn main() {
let mut v = Val::new();
v.set(123, 100);
v.set(100, 1234);
println!("Size before: {}", v.l.len());
println!("Work: {}", v.do_work(123));
println!("Size after: {}", v.l.len());
}
playground
The compiler has the error:
error[E0502]: cannot borrow `*self` as mutable because it is also borrowed as immutable
--> src/main.rs:28:24
|
26 | match self.t.get(&v) {
| ------ immutable borrow occurs here
27 | None => false,
28 | Some(r) => self.remove(r),
| ^^^^^------^^^
| | |
| | immutable borrow later used by call
| mutable borrow occurs here
I don't understand why I can't mutate in the match arm when I did a get (read value) before; the self.t.get is finished when the mutation via remove begins.
Is this due to scope of the result (Option<&u16>) returned by the get? It's true that the lifetime of the result has a scope inside the match expression, but this design-pattern is used very often (mutate in a match expression).
How do I work around the error?
The declaration of function HashMap::<K,V>::get() is, a bit simplified:
pub fn get<'s>(&'s self, k: &K) -> Option<&'s V>
This means that it returns an optional reference to the contained value, not the value itself. Since the returned reference points to a value inside the map, it actually borrows the map, that is, you cannot mutate the map while this reference exists. This restriction is there to protect you, what would happen if you remove this value while the reference is still alive?
So when you write:
match self.t.get(&v) {
None => false,
//r: &u16
Some(r) => self.remove(r)
}
the captured r is of type &u16 and its lifetime is that of self.t, that is, it is borrowing it. Thus you cannot get a mutable reference to self, that is needed to call remove.
The simplest solution for your problem is the clone() solves every lifetime issue pattern. Since your values are of type u16, that is Copy, it is actually trivial:
match self.t.get(&v) {
None => false,
//r: u16
Some(&r) => self.remove(&r)
}
Now r is actually of type u16 so it borrows nothing and you can mutate self at will.
If your key/value types weren't Copy you could try and clone them, if you are willing to pay for that. If not, there is still another option as your remove() function does not modify the HashMap but an unrelated HashSet. You can still mutate that set if you take care not to reborrow self:
fn remove2(v: &u16, l: &mut HashSet<u16>) -> bool {
l.remove(v)
}
fn do_work(&mut self, v: u16) -> bool {
match self.t.get(&v) {
None => false,
//selt.t is borrowed, now we mut-borrow self.l, no problem
Some(r) => Self::remove2(r, &mut self.l)
}
}
You are trying to remove value from HashMap by using value you get, not key.
Only line 26 is changed Some(_) => self.remove(&v)
This will work:
use std::collections::HashMap;
struct Val {
t: HashMap<u16, u16>
}
impl Val {
fn new() -> Val {
Val { t: HashMap::new() }
}
fn set(&mut self, k: u16, v: u16) {
self.t.insert(k, v);
}
fn remove(&mut self, v: &u16) -> bool {
match self.t.remove(v) {
None => false,
_ => true,
}
}
fn do_work(&mut self, v: u16) -> bool {
match self.t.get(&v) {
None => false,
Some(_) => self.remove(&v)
}
}
}
fn main() {
let mut v = Val::new();
v.set(123, 100);
v.set(1100, 1234);
println!("Size before: {}", v.t.len());
println!("Work: {}", v.do_work(123));
println!("Size after: {}", v.t.len());
}
play.rust
It seems that the following solution is good for primitive types like here u16. For other types, the ownership is moved.
use std::collections::HashMap;
struct Val {
t: HashMap<u16, u16>,
}
impl Val {
fn new() -> Val {
Val { t: HashMap::new() }
}
fn set(&mut self, k: u16, v: u16) {
self.t.insert(k, v);
}
fn remove(&mut self, v: &u16) -> bool {
match self.t.remove(v) {
None => false,
_ => true,
}
}
fn do_work(&mut self, v: u16) -> bool {
match self.t.get(&v) {
None => false,
Some(&v) => self.remove(&v)
}
}
}
fn main() {
let mut v = Val::new();
v.set(123, 100);
v.set(100, 1234);
println!("Size before: {}", v.t.len());
println!("Work: {}", v.do_work(123));
println!("Size after: {}", v.t.len());
}
For other types, we must clone the value:
use std::collections::{HashMap, HashSet};
#[derive(Debug)]
struct Val {
t: HashMap<String, String>,
l: HashSet<String>
}
impl Val {
fn new() -> Val {
Val { t: HashMap::new(), l: HashSet::new() }
}
fn set(&mut self, k: String, v: String) {
self.l.insert(v.clone());
self.t.insert(k, v);
}
fn remove(&mut self, v: &String) -> bool {
self.l.remove(v)
}
fn do_work(&mut self, i: &String) -> bool {
match self.t.get(i) {
None => false,
Some(v) => {
let x = v.clone();
self.remove(&x)
}
}
}
fn do_task(&mut self, i: &String) -> bool {
match self.t.get(i) {
None => false,
Some(v) => self.l.insert(v.clone())
}
}
}
fn main() {
let mut v = Val::new();
v.set("AA".to_string(), "BB".to_string());
v.set("BB".to_string(), "CC".to_string());
println!("Start: {:#?}", v);
println!("Size before: {}", v.l.len());
println!("Work: {}", v.do_work(&"AA".to_string()));
println!("Size after: {}", v.l.len());
println!("After: {:#?}", v);
println!("Task [Exist]: {}", v.do_task(&"BB".to_string()));
println!("Task [New]: {}", v.do_task(&"AA".to_string()));
println!("End: {:#?}", v);
}
But i'd like a solution that has no allocation

How do I properly insert into a Rust AVL Tree?

I'm very new to rust and I'm trying to creating an AVL Tree. I used Rc because I want every node to be owned by nodes above it and RefCell to have it mutable internally.
I've started to build the "insert" method, but it isn't inserting a new node in the correct place, rather its replace the "root" node with the new node and I'm having trouble understanding why. I believe that this may be an ownership issue but I'm not sure.
use std::cell::RefCell;
use std::cmp::Ordering;
use std::rc::Rc;
#[derive(Debug)]
pub struct BaseNode {
pub key: u32,
pub left: AvlTree,
pub right: AvlTree,
}
pub type AvlNode = Rc<RefCell<BaseNode>>;
pub type AvlTree = Option<AvlNode>;
impl BaseNode {
fn new(key: u32) -> Self {
Self {
key: key,
left: None,
right: None,
}
}
}
trait AvlNodeTrait {
fn new_node(key: u32) -> Self;
}
impl AvlNodeTrait for AvlNode {
fn new_node(key: u32) -> Self {
Rc::new(RefCell::new(BaseNode::new(key)))
}
}
pub trait AvlTreeTrait {
fn new() -> Self;
fn left(&self) -> Self;
fn right(&self) -> Self;
fn insert(&mut self, key: u32);
fn dupe(&self) -> Self;
fn set(&mut self, node: AvlNode);
}
impl AvlTreeTrait for AvlTree {
fn new() -> Self {
None
}
fn left(&self) -> Self {
if let Some(node) = self {
return node.borrow().right.dupe();
}
panic!("Trying to get Left of None!")
}
fn right(&self) -> Self {
if let Some(node) = self {
return node.borrow().right.dupe();
}
panic!("Trying to get right of None!")
}
fn dupe(&self) -> Self {
match self {
Some(node) => Some(Rc::clone(&node)),
None => None,
}
}
fn set(&mut self, node: AvlNode) {
*self = Some(Rc::clone(&node));
}
fn insert(&mut self, key: u32) {
let node = AvlNode::new_node(key);
let mut curr_tree = self;
let mut curr_key = 0;
while !curr_tree.is_none() {
if let Some(node) = &curr_tree {
curr_key = node.borrow().key;
if key > curr_key {
*curr_tree = curr_tree.left()
} else if key < curr_key {
*curr_tree = curr_tree.right()
} else {
return;
}
}
}
*curr_tree = Some(Rc::clone(&node));
}
}
fn main() {
let mut tree = AvlTree::new();
println!("{:?}", tree); // None
tree.insert(5);
println!("{:?}", tree); // Some(RefCell { value: BaseNode { key: 5, left: None, right: None } })
tree.insert(56);
println!("{:?}", tree); // Some(RefCell { value: BaseNode { key: 2, left: None, right: None } })
}
I would say the use of RefCell is quite unnecessary and potentially unsafe in this context. RefCell hands over the ownership/borrow checking to the runtime instead of doing them during compile time. This can lead to your program to panic in case it violates any of the borrowing rules.
I would prefer a "recursive" type looking something like this:
struct AVLTree<T> {
val: T,
left: Option<Box<AVLTree<T>>>,
right: Option<Box<AVLTree<T>>>
}
This will of course introduce some overhead due to memory allocation.

Resources