//! A library providing direct casting among trait objects implemented by a type. //! //! In Rust, an object of a sub-trait of [`Any`] can be downcast to a concrete type //! at runtime if the type is known. But no direct casting between two trait objects //! (i.e. without involving the concrete type of the backing value) is possible //! (even no coercion from a trait object to that of its super-trait yet). //! //! With this crate, any trait object with [`CastFrom`] as its super-trait can be cast directly //! to another trait object implemented by the underlying type if the target traits are //! registered beforehand with the macros provided by this crate. //! //! # Usage //! ``` //! use intertrait::*; //! use intertrait::cast::*; //! //! struct Data; //! //! trait Source: CastFrom {} //! //! trait Greet { //! fn greet(&self); //! } //! //! #[cast_to] //! impl Greet for Data { //! fn greet(&self) { //! println!("Hello"); //! } //! } //! //! impl Source for Data {} //! //! let data = Data; //! let source: &dyn Source = &data; //! let greet = source.cast::(); //! greet.unwrap().greet(); //! ``` //! //! Target traits must be explicitly designated beforehand. There are three ways to do it: //! //! * [`#[cast_to]`][cast_to] to `impl` item //! * [`#[cast_to(Trait)]`][cast_to] to type definition //! * [`castable_to!(Type => Trait1, Trait2)`][castable_to] //! //! If the underlying type involved is `Sync + Send` and you want to use it with [`Arc`], //! use [`CastFromSync`] in place of [`CastFrom`] and add `[sync]` flag before the list //! of traits in the macros. Refer to the documents for each of macros for details. //! //! For casting, refer to traits defined in [`cast`] module. //! //! [cast_to]: ./attr.cast_to.html //! [castable_to]: ./macro.castable_to.html //! [`CastFrom`]: ./trait.CastFrom.html //! [`CastFromSync`]: ./trait.CastFromSync.html //! [`cast`]: ./cast/index.html //! [`Any`]: https://doc.rust-lang.org/std/any/trait.Any.html //! [`Arc`]: https://doc.rust-lang.org/std/sync/struct.Arc.html #![cfg_attr(target_os = "none", no_std)] extern crate alloc; extern crate core; use core::{ any::{Any, TypeId}, marker::{Send, Sync}, }; use alloc::boxed::Box; use alloc::rc::Rc; use alloc::sync::Arc; use hashbrown::HashMap; use linkme::distributed_slice; pub use intertrait_macros::*; use crate::hasher::BuildFastHasher; pub mod cast; mod hasher; #[doc(hidden)] pub type BoxedCaster = Box; #[cfg(doctest)] doc_comment::doctest!("../README.md"); /// A distributed slice gathering constructor functions for [`Caster`]s. /// /// A constructor function returns `TypeId` of a concrete type involved in the casting /// and a `Box` of a trait object backed by a [`Caster`]. /// /// [`Caster`]: ./struct.Caster.html #[doc(hidden)] #[distributed_slice] pub static CASTERS: [fn() -> (TypeId, BoxedCaster)] = [..]; /// A `HashMap` mapping `TypeId` of a [`Caster`] to an instance of it. /// /// [`Caster`]: ./struct.Caster.html #[cfg(not(target_os = "none"))] static CASTER_MAP: once_cell::sync::Lazy> = once_cell::sync::Lazy::new(|| { CASTERS .iter() .map(|f| { let (type_id, caster) = f(); ((type_id, (*caster).type_id()), caster) }) .collect() }); /// CasterMap /// /// key.0: type_id of source /// key.1: type_id of target /// /// value: A BoxedCaster which can cast source to target #[cfg(target_os = "none")] static mut CASTER_MAP: Option> = None; #[cfg(target_os = "none")] pub fn caster_map() -> &'static HashMap<(TypeId, TypeId), BoxedCaster, BuildFastHasher> { return unsafe { CASTER_MAP.as_ref().unwrap_or_else(|| { panic!("intertrait_caster_map() must be called after CASTER_MAP is initialized") }) }; } /// Initializes the global [`CASTER_MAP`] with [`CASTERS`]. /// /// no_std环境下,需要手动调用此函数初始化CASTER_MAP #[cfg(target_os = "none")] pub fn init_caster_map() { use core::sync::atomic::AtomicBool; let pd = AtomicBool::new(false); let r = pd.compare_exchange( false, true, core::sync::atomic::Ordering::SeqCst, core::sync::atomic::Ordering::SeqCst, ); if r.is_err() { panic!("init_caster_map() must be called only once"); } let hashmap = CASTERS .iter() .map(|f| { let (type_id, caster) = f(); ((type_id, (*caster).type_id()), caster) }) .collect(); unsafe { CASTER_MAP = Some(hashmap) }; } #[cfg(not(target_os = "none"))] pub fn init_caster_map() {} fn cast_arc_panic(_: Arc) -> Arc { panic!("Prepend [sync] to the list of target traits for Sync + Send types") } /// A `Caster` knows how to cast a reference to or `Box` of a trait object for `Any` /// to a trait object of trait `T`. Each `Caster` instance is specific to a concrete type. /// That is, it knows how to cast to single specific trait implemented by single specific type. /// /// An implementation of a trait for a concrete type doesn't need to manually provide /// a `Caster`. Instead attach `#[cast_to]` to the `impl` block. #[doc(hidden)] pub struct Caster { /// Casts an immutable reference to a trait object for `Any` to a reference /// to a trait object for trait `T`. pub cast_ref: fn(from: &dyn Any) -> &T, /// Casts a mutable reference to a trait object for `Any` to a mutable reference /// to a trait object for trait `T`. pub cast_mut: fn(from: &mut dyn Any) -> &mut T, /// 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, /// Casts an `Arc` holding a trait object for `Any + Sync + Send + 'static` /// to another `Arc` holding a trait object for trait `T`. pub cast_arc: fn(from: Arc) -> Arc, } impl Caster { pub fn new( cast_ref: fn(from: &dyn Any) -> &T, cast_mut: fn(from: &mut dyn Any) -> &mut T, cast_box: fn(from: Box) -> Box, cast_rc: fn(from: Rc) -> Rc, ) -> Caster { Caster:: { cast_ref, cast_mut, cast_box, cast_rc, cast_arc: cast_arc_panic, } } pub fn new_sync( cast_ref: fn(from: &dyn Any) -> &T, cast_mut: fn(from: &mut dyn Any) -> &mut T, cast_box: fn(from: Box) -> Box, cast_rc: fn(from: Rc) -> Rc, cast_arc: fn(from: Arc) -> Arc, ) -> Caster { Caster:: { cast_ref, cast_mut, cast_box, cast_rc, cast_arc, } } } /// Returns a `Caster` from a concrete type `S` to a trait `T` implemented by it. /// /// ## 参数 /// /// - type_id: 源类型的type_id /// /// T: 目标trait fn caster(type_id: TypeId) -> Option<&'static Caster> { #[cfg(not(target_os = "none"))] { CASTER_MAP .get(&(type_id, TypeId::of::>())) .and_then(|caster| caster.downcast_ref::>()) } #[cfg(target_os = "none")] { 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 immutable reference to `Any`, which is backed by the type implementing this trait. fn ref_any(&self) -> &dyn Any; /// Returns a mutable reference to `Any`, which is backed by the type implementing this trait. fn mut_any(&mut self) -> &mut dyn Any; /// 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; } /// `CastFromSync` must be extended by a trait that is `Any + Sync + Send + 'static` /// and wants to allow for casting into another trait behind references and smart pointers /// especially including `Arc`. /// /// It is used for obtaining a trait object for [`Any + Sync + Send + 'static`] from an object /// for its sub-trait, and blanket implemented for all `Sized + Sync + Send + 'static` types. /// /// # Examples /// ```ignore /// trait Source: CastFromSync { /// ... /// } /// ``` pub trait CastFromSync: CastFrom + Sync + Send + 'static { fn arc_any(self: Arc) -> Arc; } impl CastFrom for T { fn ref_any(&self) -> &dyn Any { self } fn mut_any(&mut self) -> &mut dyn Any { self } fn box_any(self: Box) -> Box { self } fn rc_any(self: Rc) -> Rc { self } } impl CastFrom for dyn Any + 'static { fn ref_any(&self) -> &dyn Any { self } fn mut_any(&mut self) -> &mut dyn Any { self } fn box_any(self: Box) -> Box { self } fn rc_any(self: Rc) -> Rc { self } } impl CastFromSync for T { fn arc_any(self: Arc) -> Arc { self } } impl CastFrom for dyn Any + Sync + Send + 'static { fn ref_any(&self) -> &dyn Any { self } fn mut_any(&mut self) -> &mut dyn Any { self } fn box_any(self: Box) -> Box { self } fn rc_any(self: Rc) -> Rc { self } } impl CastFromSync for dyn Any + Sync + Send + 'static { fn arc_any(self: Arc) -> Arc { self } } #[cfg(test)] mod tests { extern crate std; use std::any::{Any, TypeId}; use std::fmt::{Debug, Display}; use linkme::distributed_slice; use crate::{BoxedCaster, CastFromSync}; use super::cast::*; use super::*; #[distributed_slice(super::CASTERS)] static TEST_CASTER: fn() -> (TypeId, BoxedCaster) = create_test_caster; #[derive(Debug)] struct TestStruct; trait SourceTrait: CastFromSync {} impl SourceTrait for TestStruct {} fn create_test_caster() -> (TypeId, BoxedCaster) { let type_id = TypeId::of::(); let caster = Box::new(Caster:: { cast_ref: |from| from.downcast_ref::().unwrap(), cast_mut: |from| from.downcast_mut::().unwrap(), cast_box: |from| from.downcast::().unwrap(), cast_rc: |from| from.downcast::().unwrap(), cast_arc: |from| from.downcast::().unwrap(), }); (type_id, caster) } #[test] fn cast_ref() { let ts = TestStruct; let st: &dyn SourceTrait = &ts; let debug = st.cast::(); assert!(debug.is_some()); } #[test] fn cast_mut() { let mut ts = TestStruct; let st: &mut dyn SourceTrait = &mut ts; let debug = st.cast::(); assert!(debug.is_some()); } #[test] fn cast_box() { let ts = Box::new(TestStruct); let st: Box = ts; let debug = st.cast::(); assert!(debug.is_ok()); } #[test] fn cast_rc() { let ts = Rc::new(TestStruct); let st: Rc = ts; let debug = st.cast::(); assert!(debug.is_ok()); } #[test] fn cast_arc() { let ts = Arc::new(TestStruct); let st: Arc = ts; let debug = st.cast::(); assert!(debug.is_ok()); } #[test] fn cast_ref_wrong() { let ts = TestStruct; let st: &dyn SourceTrait = &ts; let display = st.cast::(); assert!(display.is_none()); } #[test] fn cast_mut_wrong() { let mut ts = TestStruct; let st: &mut dyn SourceTrait = &mut ts; let display = st.cast::(); assert!(display.is_none()); } #[test] fn cast_box_wrong() { let ts = Box::new(TestStruct); let st: Box = ts; let display = st.cast::(); assert!(display.is_err()); } #[test] fn cast_rc_wrong() { let ts = Rc::new(TestStruct); let st: Rc = ts; let display = st.cast::(); assert!(display.is_err()); } #[test] fn cast_arc_wrong() { let ts = Arc::new(TestStruct); let st: Arc = ts; let display = st.cast::(); assert!(display.is_err()); } #[test] fn cast_ref_from_any() { let ts = TestStruct; let st: &dyn Any = &ts; let debug = st.cast::(); assert!(debug.is_some()); } #[test] fn cast_mut_from_any() { let mut ts = TestStruct; let st: &mut dyn Any = &mut ts; let debug = st.cast::(); assert!(debug.is_some()); } #[test] fn cast_box_from_any() { let ts = Box::new(TestStruct); let st: Box = ts; let debug = st.cast::(); assert!(debug.is_ok()); } #[test] fn cast_rc_from_any() { let ts = Rc::new(TestStruct); let st: Rc = ts; let debug = st.cast::(); assert!(debug.is_ok()); } #[test] fn cast_arc_from_any() { let ts = Arc::new(TestStruct); let st: Arc = ts; let debug = st.cast::(); assert!(debug.is_ok()); } #[test] fn impls_ref() { let ts = TestStruct; let st: &dyn SourceTrait = &ts; assert!(st.impls::()); } #[test] fn impls_mut() { let mut ts = TestStruct; let st: &mut dyn SourceTrait = &mut ts; assert!((*st).impls::()); } #[test] fn impls_box() { let ts = Box::new(TestStruct); let st: Box = ts; assert!((*st).impls::()); } #[test] fn impls_rc() { let ts = Rc::new(TestStruct); let st: Rc = ts; assert!((*st).impls::()); } #[test] fn impls_arc() { let ts = Arc::new(TestStruct); let st: Arc = ts; assert!((*st).impls::()); } #[test] fn impls_not_ref() { let ts = TestStruct; let st: &dyn SourceTrait = &ts; assert!(!st.impls::()); } #[test] fn impls_not_mut() { let mut ts = TestStruct; let st: &mut dyn Any = &mut ts; assert!(!(*st).impls::()); } #[test] fn impls_not_box() { let ts = Box::new(TestStruct); let st: Box = ts; assert!(!st.impls::()); } #[test] fn impls_not_rc() { let ts = Rc::new(TestStruct); let st: Rc = ts; assert!(!(*st).impls::()); } #[test] fn impls_not_arc() { let ts = Arc::new(TestStruct); let st: Arc = ts; assert!(!(*st).impls::()); } }