/** * 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::collections::HashMap; use std::rc::Rc; use std::sync::Arc; use linkme::distributed_slice; use once_cell::sync::Lazy; mod hasher; use hasher::BuildFastHasher; pub mod cast_box; pub mod cast_rc; pub type BoxedCaster = Box; #[distributed_slice] pub static CASTERS: [fn() -> (TypeId, BoxedCaster)] = [..]; static CASTER_MAP: Lazy> = Lazy::new(|| { CASTERS .iter() .map(|f| { let (type_id, caster) = f(); ((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 `T`. 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 `T`. 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 `S` to a trait `T` 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; } pub trait CastFromSync: CastFrom + Sync + Send + 'static { fn arc_any(self: Arc) -> Arc; } impl CastFrom for T { 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 } }