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}