1 unstable release

0.1.0 Sep 9, 2020

#47 in #any

Download history 16/week @ 2024-03-28 14/week @ 2024-04-04

61 downloads per month

MIT/Apache

10KB
132 lines

Downcast trait: A module to support downcasting dyn traits using core::any. This trait is similar to intertrait, but does not require to make a hashtable or any fancy linker magic. For certain cases all casting is optimized away.

This crate uses transmute (which is generally considered unsafe rust) to pass an unknown type as a return value from a function, but the value is then transmuted back to the original type.

Downcast traits enables callers to convert dyn objects that implement the DowncastTrait trait to any trait that is supported by the struct implementing the trait. The most useful usecase for this is if a class contains a list of objects that implements a trait and want to call functions on a subset which implements another trait too. This is similar to casting to a sub-class in an object oriented language.

Example:

  • A Widget trait is implemented for all widgets in a graphical user interface system.
  • The widget trait extends the DowncastTrait.
  • A widget may implement the Container trait if it is possible to add child widgets to the widget.
  • A container has a list of widgets, and want to call a specific functions on all widgets that implement container.
#[macro_use] extern crate downcast_trait;
use downcast_trait::DowncastTrait;
use core::{any::{Any, TypeId}, mem};
trait Widget: DowncastTrait {}
trait Container: Widget {
    fn enumerate_widget_leaves_recursive(&self) -> Vec<&Box<dyn Widget>>;
}
struct Window {
    sub_widgets: Vec<Box<dyn Widget>>,
}
impl Widget for Window {}
impl Container for Window {
    fn enumerate_widget_leaves_recursive(&self) -> Vec<&Box<dyn Widget>> {
        let mut result = Vec::<&Box<dyn Widget>>::new();
        self.sub_widgets.iter().for_each(|sub_widget| {
            if let Some(sub_container) =
                downcast_trait!(dyn Container, sub_widget.as_ref().to_downcast_trait())
            {
                result.extend(sub_container.enumerate_widget_leaves_recursive());
            } else {
                result.push(sub_widget);
            }
        });
        result
    }
}
impl DowncastTrait for Window {
    downcast_trait_impl_convert_to!(dyn Container);
}

No runtime deps