0

I am trying to implement function get_render_module that should return a specific type while the container (HashMap) contains a trait objects. How can i cast one to another without any "unsafe" code?

This is the sample code:

pub type ModuleRef = Arc<RefCell<dyn Module>>;

#[derive(Debug)]
pub struct RenderModule {}

impl Display for RenderModule {
    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
        todo!()
    }
}

impl Module for RenderModule {
    fn reload(&mut self) -> Result<(), ModuleInternalError> {
        Ok(())
    }

    fn name(&self) -> &str {
        "render"
    }

    fn call_capability(
        &mut self,
        cap_name: &str,
        arguments: Vec<TransferType>,
    ) -> Result<TransferType, CapabilityCallError> {
        todo!()
    }
}

pub trait Module: fmt::Display + Debug {
    fn reload(&mut self) -> Result<(), ModuleInternalError>;
    fn name(&self) -> &str;
    fn call_capability(
        &mut self,
        cap_name: &str,
        arguments: Vec<TransferType>,
    ) -> Result<TransferType, CapabilityCallError>;
}


#[derive(Debug, Clone, PartialEq)]
pub enum CapabilityCallError {
    ModuleNameInvalid,
}

#[non_exhaustive]
#[derive(Debug, Default)]
pub struct Server {
    modules: HashMap<String, ModuleRef>,
}

impl Server {
    pub fn find_module(&self, name: &str) -> Result<ModuleRef, CapabilityCallError> {
        self.modules.get(name).cloned().ok_or(CapabilityCallError::ModuleNameInvalid)
    }
}

pub fn get_render_module(server: &Server) -> &RenderModule {
    todo!()
}
Toerktumlare
  • 12,548
  • 3
  • 35
  • 54
dath.vg
  • 86
  • 1
  • 7
  • 1
    As I understand, you're looking for "downcast" (Java and others) or "derivedcast" (C++). It's not supported in Rust directly, see [here](https://stackoverflow.com/q/33687447/767632) and [there](https://stackoverflow.com/a/69107589/767632) – yeputons Mar 18 '23 at 11:09

1 Answers1

1

Your example is not minimal, thus I cannot adjust it, and show you some complete code.

First, you need to make sure Module implements std::any::Any and declare some conversion methods.

pub trait Module: std::any::Any + fmt::Display + Debug {
    // ...
    fn as_any(&self) -> &dyn Any;
    fn as_any_mut(&mut self) -> &mut dyn Any;
}

Then, each type implementing Module provides these methods

impl Module for RenderModule {
    // ...
    fn as_any(&self) -> &dyn Any {
        self
    }
    fn as_any_mut(&mut self) -> &mut dyn Any {
        self
    }
}

Finally, when you obtain a ref on a Module you can try to downcast to the specific type

    let a_dyn_ref: &dyn Module = ...
    if let Some(r_ref) =
        a_dyn_ref.as_any().downcast::<RenderModule>()
    {
        // r_ref is known as a reference to a RenderModule 
    }

(the same goes for as_any_mut().downcast_mut::<...>())

prog-fh
  • 13,492
  • 1
  • 15
  • 30