downcast-trait 0.1.0

Allow casting between traits.
Documentation
  • Coverage
  • 100%
    9 out of 9 items documented1 out of 6 items with examples
  • Size
  • Source code size: 9.37 kB This is the summed size of all the files inside the crates.io package for this release.
  • Documentation size: 717.97 kB This is the summed size of all files generated by rustdoc for all configured targets
  • Ø build duration
  • this release: 9s Average build duration of successful builds.
  • all releases: 9s Average build duration of successful builds in releases after 2024-10-23.
  • Links
  • freqmod/downcast_trait
    1 1 1
  • crates.io
  • Dependencies
  • Versions
  • Owners
  • freqmod

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);
}