Crate trait_map

source ·
Expand description

Trait Map

trait_map provides the TraitMap data structure, which can store variable data types and expose traits on those types. Types must implement the TraitMapEntry trait, which provides on_create() and on_update() hooks for specifying which traits should be exposed in the map.

Warning: This crate must be compiled using Rust Nightly. It uses the ptr_metadata and unsize features for working with raw pointers.

Usage

Assume we have some custom structs and traits defined:

trait ExampleTrait {
  fn do_something(&self) -> u32;
  fn do_another_thing(&mut self);
}

trait ExampleTraitTwo {
  fn test_method(&self);
}

struct MyStruct {
  // ...
}

struct AnotherStruct {
  // ...
}

impl ExampleTrait for MyStruct {
  fn do_something(&self) -> u32 { /* Code */ }
  fn do_another_thing(&mut self) { /* Code */ }
}

impl ExampleTrait for AnotherStruct {
  fn do_something(&self) -> u32 { /* Code */ }
  fn do_another_thing(&mut self) { /* Code */ }
}

impl ExampleTraitTwo for AnotherStruct{
  fn test_method(&self) { /* Code */ }
}

We can specify that we want to allow our struct types to work with the trait map by implementing the TraitMapEntry trait:

impl TraitMapEntry for MyStruct {
  fn on_create<'a>(&mut self, context: Context<'a>) {
    // Must explicitly list which traits to expose
    context
      .downcast::<Self>()
      .add_trait::<dyn ExampleTrait>();
  }

  // Can be overridden to update the exposed traits in the map
  fn on_update<'a>(&mut self, context: Context<'a>) {
    context
      .downcast::<Self>()
      .remove_trait::<dyn ExampleTrait>();
  }
}

impl TraitMapEntry for AnotherStruct {
  fn on_create<'a>(&mut self, context: Context<'a>) {
    context
      .downcast::<Self>()
      .add_trait::<dyn ExampleTrait>()
      .add_trait::<dyn ExampleTraitTwo>();
  }
}

Once this is done, we can store instances of these concrete types inside TraitMap and query them by trait. For example:

fn main() {
  let mut map = TraitMap::new();
  map.add_entry(MyStruct { /* ... */ });
  map.add_entry(AnotherStruct { /* ... */ });

  // Can iterate over all types that implement ExampleTrait
  //  Notice that entry is "&dyn mut ExampleTrait"
  for (entry_id, entry) in map.get_entries_mut::<dyn ExampleTrait>() {
    entry.do_another_thing();
  }

  // Can iterate over all types that implement ExampleTraitTwo
  //  Notice that entry is "&dyn ExampleTraitTwo"
  for (entry_id, entry) in map.get_entries::<dyn ExampleTraitTwo>() {
    entry.test_method();
  }
}

Structs

Stores type information about an entry inside of a TraitMap
Opaque ID type for each entry in the trait map.
Map structure that allows types to be dynamically queries by trait.
Stores concrete type for an entry inside a TraitMap

Traits

Rust type that can be stored inside of a TraitMap.