Hi everyone,
I’ve been stuck trying to solve this issue for quite a while now so I think I should reach out here for some advice. I’m trying to write a simple Entity Component System in Rust and as such I have an Entity object which stores a vec of different Components which all have a Component trait. The goal is that I’d like to call get_component along with an argument of the type that I would like to find and return that type from the entity if it is found. I’m also heavily depending on Rc<RefCell> to store and pass my types around.
The problem is that just after I call get_component and get an Rc<RefCell> I then try to borrow_mut that object (See the “main” fn of the code below) and I get a runtime error telling me that it’s already mutably borrowed “thread ‘main’ panicked at ‘already borrowed: BorrowMutError’”. The issue does not occur when I simply call borrow instead of a mut borrow.
So I think there is somewhere in my code where a borrow_mut has not gone out of scope or been un-borrowed so that I can borrow it again in the main function. Any ideas? I’m also happy for my approach to change as long as the basic concept of searching for specific types in a vec and returning them as a concrete type is preserved.
use std::mem::*;
use std::cell::*;
use std::rc::*;
#[derive(Clone, Copy, PartialEq, Debug)]
pub enum ComponentType {
Transform,
MeshBufferGL,
}
pub trait Component
{
fn get_type(&self) -> ComponentType;
}
struct TransformComponent {}
struct MeshBufferGLComponent {}
impl MeshBufferGLComponent {
fn unique_method_for_meshbuff(&self) {
println!("unique_method_for_meshbuff was called");
}
}
impl Component for TransformComponent {
fn get_type(&self) -> ComponentType {
ComponentType::Transform
}
}
impl Component for MeshBufferGLComponent {
fn get_type(&self) -> ComponentType {
ComponentType::MeshBufferGL
}
}
pub struct Entity {
components: Vec<Rc<RefCell<Component>>>
}
impl Entity
{
pub fn new() -> Entity
{
Entity {
components: Vec::new(),
}
}
pub fn add_component<T: 'static>(&mut self, component: Rc<RefCell<T>>) where T: Component {
self.components.push(component.clone());
}
pub fn get_component<T>(&self, component_type: ComponentType) -> Option<Rc<RefCell<T>>> where T: Component {
let mut result: Option<Rc<RefCell<T>>> = None;
for comp in self.components.iter() {
let a = comp.borrow();
if a.get_type() == component_type {
println!("'{:?} Type found' -> Downcasting to {:?} with transmute", component_type, component_type);
unsafe { result = Some(transmute::<_, Rc<RefCell<T>>>(&(comp.clone()))); }
}
}
result
}
pub fn num_components(&self) -> usize {
self.components.len()
}
}
fn main () {
let transform_component: TransformComponent = TransformComponent{};
let meshbuffer_component: MeshBufferGLComponent = MeshBufferGLComponent{};
let transform_component_rc = Rc::new(RefCell::new(transform_component));
let meshbuffer_component_rc = Rc::new(RefCell::new(meshbuffer_component));
let mut entity = Entity::new();
entity.add_component(transform_component_rc.clone());
entity.add_component(meshbuffer_component_rc.clone());
let mesh_buffer_retrieved = entity.get_component::<MeshBufferGLComponent>(ComponentType::MeshBufferGL).unwrap();
//let borrow = mesh_buffer_retrieved.borrow(); // NOTE: Using this standard borrow instead of the mut borrow below does not cause an error.
let borrow = mesh_buffer_retrieved.borrow_mut(); // thread 'main' panicked at 'already borrowed: BorrowMutError' ...
borrow.unique_method_for_meshbuff();
}
Thank you