Module typedmap::bounds

source ·
Expand description

Restricting types that may be stored in the hashmap.

Struct that implement Bounds trait may be used as a restriction on types for keys or values stored in the hashmap. Imagine that you’d like to store only values that implement some trait, e.g. service. One can implement new bounds using convenience macros impl_custom_bounds and impl_dyn_trait_wrapper:

use std::any::Any;
use std::hash::Hash;
use typedmap::bounds::{Bounds, ContainerWithHash, HasBounds};
use typedmap::{AnyBounds, impl_custom_bounds, impl_dyn_trait_wrapper, TypedMap, TypedMapKey};

// Your trait that map values must implement
trait Service {
    fn is_ready(&self) -> bool;
}

// You need a struct to represent bounds requirement
struct ServiceBounds;

// Implement a trait object type DynService to be stored in map and represent Service trait
impl_dyn_trait_wrapper!(DynService, Service);
// Implement Bounds trait & HasBounds<T> for ServiceBounds
impl_custom_bounds!(ServiceBounds, DynService, Service);

#[derive(Eq, PartialEq, Hash)]
struct Key;

impl TypedMapKey for Key {
    type Value = ServiceA;
}

struct ServiceA;
impl Service for ServiceA {
    fn is_ready(&self) -> bool {
        true
    }
}

// Use it
let mut map: TypedMap<(), AnyBounds, ServiceBounds, _> = TypedMap::new_with_bounds();
map.insert(Key, ServiceA);

for kv in map.iter() {
   // use function from Service trait;
   let _ = kv.value_container_ref().as_object().is_ready();
}

Manually one can do it in the following way:

use std::any::Any;
use std::hash::Hash;
use typedmap::bounds::{Bounds, ContainerWithHash, HasBounds};
use typedmap::{AnyBounds, impl_custom_bounds, impl_dyn_trait_wrapper, TypedMap, TypedMapKey};

// Your trait that map values must implement
trait Service {
    fn is_ready(&self) -> bool;
}

// You need a struct to represent bounds requirement
struct ServiceBounds;

impl Bounds for ServiceBounds {
    // Specify trait object type for keys (use dyn ContainerWithHash<Self> + Marker traits
    type KeyContainer = dyn ContainerWithHash<ServiceBounds>;
    // Specify trait object type for values (must be castable to Any and to Service trait)
    type Container = dyn DynService;

    // Implement basic conversion functions
    fn as_any(this: &Self::Container) -> &dyn Any {
         this.as_any()
    }

    fn as_any_mut(this: &mut Self::Container) -> &mut dyn Any {
        this.as_mut_any()
    }

    fn as_any_box(this: Box<Self::Container>) -> Box<dyn Any> {
        this.as_box_any()
    }
}

// Implement HasBounds trait with simple conversion functions
impl<T: DynService> HasBounds<T> for ServiceBounds {
    fn cast_box(this: Box<T>) -> Box<Self::Container> {
        this
    }

    fn as_ref(this: &T) -> &Self::Container {
        this
    }

    fn as_mut(this: &mut T) -> &mut Self::Container {
        this
    }

    fn cast_key_box(this: Box<T>) -> Box<Self::KeyContainer> where T: 'static + Sized + Hash + Eq {
        this
    }
}

trait DynService: Any + Service {
    fn as_object(&self) -> &dyn Service;

    fn as_any(&self) -> &dyn Any;
    fn as_mut_any(&mut self) -> &mut dyn Any;
    fn as_box_any(self: Box<Self>) -> Box<dyn Any>;
}

impl<T: Service + Any> DynService for T {
    fn as_object(&self) -> &dyn Service {
        self
    }

    fn as_any(&self) -> &dyn Any {
        self
    }

    fn as_mut_any(&mut self) -> &mut dyn Any {
        self
    }

    fn as_box_any(self: Box<Self>) -> Box<dyn Any> {
        self
    }
}

#[derive(Eq, PartialEq, Hash)]
struct Key;

impl TypedMapKey for Key {
    type Value = ServiceA;
}

struct ServiceA;
impl Service for ServiceA {
    fn is_ready(&self) -> bool {
        true
    }
}

// Use it
let mut map: TypedMap<(), AnyBounds, ServiceBounds, _> = TypedMap::new_with_bounds();
map.insert(Key, ServiceA);

for kv in map.iter() {
   // use function from Service trait;
   let _ = kv.value_container_ref().as_object().is_ready();
}

Structs§

  • Default bounds for TypedMap that require keys/values just to implement Any.
  • Default bounds for TypedDashMap that require keys/values just to implement Any + Send + Sync.

Traits§

  • Represents bounds for key or values. This allows to enforce TypedMap to store for example only cloneable values or ones that are Send+Sync.
  • Trait used as container for keys, i.e. instances of types that meet bounds B and implement Hash & Eq Use dyn ContainerWithHash<Self> + Marker traits as KeyContainer in Bounds trait.
  • Trait that marks that specific type fulfill specified bounds. For example HasBounds<CloneBounds> is implemented for all types that are implement Clone & Any.