/** * Originally from Intertrait by CodeChain * * * * * Licensed under either of * * Apache License, Version 2.0 (LICENSE-APACHE or ) * MIT license (LICENSE-MIT or ) * at your option. */ use std::any::{Any, TypeId}; use std::rc::Rc; use ahash::AHashMap; use linkme::distributed_slice; use once_cell::sync::Lazy; pub mod cast_box; pub mod cast_rc; pub type BoxedCaster = Box; type CasterFn = fn() -> (TypeId, BoxedCaster); #[distributed_slice] pub static CASTERS: [CasterFn] = [..]; static CASTER_MAP: Lazy> = Lazy::new(|| { CASTERS .iter() .map(|caster_fn| { let (type_id, caster) = caster_fn(); ((type_id, (*caster).type_id()), caster) }) .collect() }); pub struct Caster { /// Casts a `Box` holding a trait object for `Any` to another `Box` holding a trait object /// for `Trait`. pub cast_box: fn(from: Box) -> Box, /// Casts an `Rc` holding a trait object for `Any` to another `Rc` holding a trait object /// for `Trait`. pub cast_rc: fn(from: Rc) -> Rc, } impl Caster { pub fn new( cast_box: fn(from: Box) -> Box, cast_rc: fn(from: Rc) -> Rc, ) -> Caster { Caster:: { cast_box, cast_rc } } } /// Returns a `Caster` from a concrete type `Implementation` /// from inside `CASTER_MAP` to a `Trait` implemented by it. fn caster(type_id: TypeId) -> Option<&'static Caster> { CASTER_MAP .get(&(type_id, TypeId::of::>())) .and_then(|caster| caster.downcast_ref::>()) } /// `CastFrom` must be extended by a trait that wants to allow for casting into another trait. /// /// It is used for obtaining a trait object for [`Any`] from a trait object for its sub-trait, /// and blanket implemented for all `Sized + Any + 'static` types. /// /// # Examples /// ```ignore /// trait Source: CastFrom { /// ... /// } /// ``` pub trait CastFrom: Any + 'static { /// Returns a `Box` of `Any`, which is backed by the type implementing this trait. fn box_any(self: Box) -> Box; /// Returns an `Rc` of `Any`, which is backed by the type implementing this trait. fn rc_any(self: Rc) -> Rc; } impl CastFrom for Trait { fn box_any(self: Box) -> Box { self } fn rc_any(self: Rc) -> Rc { self } } impl CastFrom for dyn Any + 'static { fn box_any(self: Box) -> Box { self } fn rc_any(self: Rc) -> Rc { self } } impl CastFrom for dyn Any + Sync + Send + 'static { fn box_any(self: Box) -> Box { self } fn rc_any(self: Rc) -> Rc { self } }