Using Mutable Twice in Rc<RefCell<Api

Hello, I'm trying to use a data schema like this:

use std::cell::RefCell;
use std::rc::Rc;


struct Little {
    little_counter: i32,
}
impl Little {
    fn do_stuff(&self, api: Rc<RefCell<Api>>) {
        api.borrow_mut().sum();  <- ///// error here ////// 8
    }
}

struct Api {
    littles: Vec<Little>,
}
impl Api {
    fn new() -> Rc<RefCell<Self>> {
        let new_littles = vec![Little { little_counter: 0 }];
        Rc::new(RefCell::new(Self {
            littles: new_littles,
        }))
    }
    fn sum(&mut self) {
        for val in self.littles.iter_mut() {
            val.little_counter += 1;
        }
    }
    fn show(&self) {
        for val in self.littles.iter() {
            println!("{}", val.little_counter);
        }
    }
}

struct Big {
    api: Rc<RefCell<Api>>,
}
impl Big {
    pub fn new() -> Self {
        Self { api: Api::new() }
    }
    pub fn do_littles(&self, api: Rc<RefCell<Api>>) {
        for (i, _) in self.api.clone().borrow().littles.iter().enumerate() {
            api.borrow().littles[i].do_stuff(self.api.clone());
        }
    }
}

fn main() {
    let big = Big::new();
    big.do_littles(big.api.clone());
    big.api.clone().borrow().show();
}

The deal here is that i'm trying to pass the "Api" to do_stuff,
This Api changes "littles" which is an Vec of "Little".

So every Little should be able to change the counter in any other Little's including itself.

I have been trying pretty much everything but still i'm in constant fight with the borrow checker because i can't have two mutable references of the Api at one. For example here the problem is.

thread 'main' panicked at 'already borrowed: BorrowMutError', src/main.rs:9:13

expected behaviour:

1

Because there's only one "Little" and it's counter is 0,
and then here
big.do_littles(big.api.clone());

It's set to 1 (sums 1 to the counter for each Little that runs "do_stuff")

I have spent 2 entire days and still found no solution :frowning:

Thanks for reading!

Indeed, you can't borrow something mutably and immutably at the same time, not even RefCell can help with that. Your API design seems weird – normally, you shouldn't need to double-borrow like that.

Since the names in your example are not evocative of the real use case, I can't tell you how in particular you might want to redesign your code. Can you elaborate on what you are actually trying to do?

Well, i'm trying to accomplish an ECS, Entity Component System.
I "invented" this system where each component changes the entire world including itself.

Example:
Entity Fox tries to kill Entity Bunny if finds it

Rust pseudo code:

trait Components {
    fn call_every_turn(api) {}
}
impl Components for Hostile {
    fn call_every_turn(api) {
// if hostile finds bunny, kills it.
           if let some((index_bunny, _))) = api.get_entity::<bunny>() {
                 self.remove_ent(index_bunny);     
           }
     }
}



trait Entity {
    fn new(api) {}
}
// so Hostile is inside Fox.
impl Entity for Fox {
   fn new(api){
        api.add_comp(Hostile)
        api.add_comp(Life) 
        ....
    }
}
struct Api {
    entities_vec = Vec<(Entity, Vec<dyn Components) 
    // Entities and Components
}
impl Api {
    fn get_entity<Entity: 'static>(&self, ent_id) -> (ent_id, Entity) {
         for (id, entity) in self.entities[ent_id].0. enumerate() {
            if let some(entity) (entity.dowcast to comp) 
                   return (id, entity)
        }
    }
    fn remove_ent(id)  { self.entities.remove(i) } // "Kills" it
    fn add_components(comp) ...
    fn call_every_turn(&mut self) {
          for ent in self.entities { // iterate entities
                for comp in ent.1 { // iterate components
                     comp.call_every_turn(self);  // problem
                     // can't borrow mutable twice 
                }
          }
    }

So there is no way to make this system work?

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.