better_as_any/
lib.rs

1//! ## Overview
2//!
3//! Better As-any is a refined implementation of the
4//! [`as-any`](https://crates.io/crates/as-any) crate. This crate avoids its
5//! predecessor's caveats that the API is error-prone when smart pointers are
6//! involved and it's impossible to downcasting an owned smart pointer.
7//!
8//! With `as-any` crate, you can't directly call `is` or `downcast*` methods on
9//! a smart pointer, since it simply takes the smart pointer's reference and
10//! leads to a runtime error, which is hardly to be figure out.
11//!
12//! ## Usage
13//!
14//! Make your traits inherit the [`InheritAny`] trait, and all necessary
15//! functionalities will be added to your traits' implementors, including trait
16//! objects.
17//!
18//! When downcasting is needed, corresponding helper traits including
19//! [`DowncastRef`], [`DowncastMut`] and [`Downcast`] are expected to be
20//! imported.
21//!
22//! ```rust
23//! use std::fmt::Debug;
24//! use std::sync::Arc;
25//!
26//! use better_as_any::{InheritAny, DowncastRef, Downcast};
27//!
28//! pub trait Trait: InheritAny + Debug + Send + Sync {}
29//!
30//! impl Trait for i32 {}
31//!
32//! let val: Box<dyn Trait> = Box::new(42i32);
33//! assert!(val.is::<i32>()); // No need to use `(*val).is::<i32>()`.
34//!
35//! let val: Arc<dyn Trait> = Arc::from(val);
36//! assert_eq!(*val.downcast_ref::<i32>().unwrap(), 42i32);
37//! assert_eq!(val.downcast::<i32>().unwrap(), Arc::new(42i32)); // Downcasts the `Arc`.
38//! ```
39
40pub mod downcasting;
41pub mod upcasting;
42
43use std::any::{self, Any};
44
45pub use downcasting::{Downcast, DowncastMut, DowncastRef};
46use upcasting::{AsAnyMut, AsAnyRef, IntoAnyArc, IntoAnyBox, IntoAnyRc};
47
48/// Trait which adds runtime reflection functionality to all its implementors
49pub trait InheritAny: Any + AsAnyRef + AsAnyMut + IntoAnyBox + IntoAnyRc + IntoAnyArc {
50    /// Returns the concrete type's name.
51    ///
52    /// Note that developers should not rely on the content of the value, since
53    /// it's subjected to the internal implementation of rustc, and may varies
54    /// on different machines, compilers or builds. See
55    /// [`std::any::type_name()`] for more information.
56    fn type_name(&self) -> &'static str;
57}
58
59impl<T: Any> InheritAny for T {
60    fn type_name(&self) -> &'static str {
61        any::type_name::<T>()
62    }
63}
64
65#[cfg(test)]
66mod tests {
67    use any::TypeId;
68
69    use super::*;
70
71    trait Trait: InheritAny {}
72
73    impl Trait for i32 {}
74
75    #[test]
76    fn dyn_trait_type_id_succeeds() {
77        let val = 42i32;
78        let val_ref: &dyn Trait = &val;
79        assert_eq!(val_ref.type_id(), TypeId::of::<i32>());
80    }
81
82    #[test]
83    fn dyn_trait_type_name_succeeds() {
84        let val = 42i32;
85        let val_ref: &dyn Trait = &val;
86        assert_eq!(val_ref.type_name(), any::type_name_of_val(&val));
87    }
88}