amplify/traits/
as_any.rs

1// Rust language amplification library providing multiple generic trait
2// implementations, type wrappers, derive macros and other language enhancements
3//
4// Written in 2019-2020 by
5//     Dr. Maxim Orlovsky <orlovsky@ubideco.org>
6//
7// To the extent possible under law, the author(s) have dedicated all
8// copyright and related and neighboring rights to this software to
9// the public domain worldwide. This software is distributed without
10// any warranty.
11//
12// You should have received a copy of the MIT License
13// along with this software.
14// If not, see <https://opensource.org/licenses/MIT>.
15
16use core::any::Any;
17#[cfg(feature = "alloc")]
18use alloc::string::String;
19
20/// Trait `AsAny` allows simple conversion of any type into a generic "thick"
21/// pointer `&dyn Any` (see [`Any`]), that can be later converted
22/// back to the original type with a graceful failing for all other conversions.
23/// For simple conversions it is recommended to use `#[derive(AsAny)]` macro
24/// from `amplify_derive` crate (see [`amplify_derive::AsAny`]).
25///
26/// # Example
27///
28/// ```
29/// #[macro_use]
30/// use amplify::AsAny;
31///
32/// #[derive(AsAny, Copy, Clone, PartialEq, Eq, Debug)]
33/// struct Point {
34///     pub x: u64,
35///     pub y: u64,
36/// }
37///
38/// #[derive(AsAny, PartialEq, Debug)]
39/// struct Circle {
40///     pub radius: f64,
41///     pub center: Point,
42/// }
43///
44/// let mut point = Point { x: 1, y: 2 };
45/// let point_ptr = point.as_any();
46///
47/// let mut circle = Circle {
48///     radius: 18.,
49///     center: point,
50/// };
51/// let circle_ptr = circle.as_any();
52///
53/// assert_eq!(point_ptr.downcast_ref(), Some(&point));
54/// assert_eq!(circle_ptr.downcast_ref(), Some(&circle));
55/// assert_eq!(circle_ptr.downcast_ref::<Point>(), None);
56///
57/// let p = point_ptr.downcast_ref::<Point>().unwrap();
58/// assert_eq!(p.x, 1)
59/// ```
60pub trait AsAny {
61    /// Returns thick pointer of `&dyn Any` type, that can be later downcasted
62    /// back to a reference of the original type.
63    fn as_any(&self) -> &dyn Any;
64}
65
66impl AsAny for usize {
67    #[inline]
68    fn as_any(&self) -> &dyn Any {
69        self as &dyn Any
70    }
71}
72
73impl AsAny for u8 {
74    #[inline]
75    fn as_any(&self) -> &dyn Any {
76        self as &dyn Any
77    }
78}
79
80impl AsAny for u16 {
81    #[inline]
82    fn as_any(&self) -> &dyn Any {
83        self as &dyn Any
84    }
85}
86
87impl AsAny for u32 {
88    #[inline]
89    fn as_any(&self) -> &dyn Any {
90        self as &dyn Any
91    }
92}
93
94impl AsAny for u64 {
95    #[inline]
96    fn as_any(&self) -> &dyn Any {
97        self as &dyn Any
98    }
99}
100
101impl AsAny for u128 {
102    #[inline]
103    fn as_any(&self) -> &dyn Any {
104        self as &dyn Any
105    }
106}
107
108impl AsAny for i8 {
109    #[inline]
110    fn as_any(&self) -> &dyn Any {
111        self as &dyn Any
112    }
113}
114
115impl AsAny for i16 {
116    #[inline]
117    fn as_any(&self) -> &dyn Any {
118        self as &dyn Any
119    }
120}
121
122impl AsAny for i32 {
123    #[inline]
124    fn as_any(&self) -> &dyn Any {
125        self as &dyn Any
126    }
127}
128
129impl AsAny for i64 {
130    #[inline]
131    fn as_any(&self) -> &dyn Any {
132        self as &dyn Any
133    }
134}
135
136impl AsAny for i128 {
137    #[inline]
138    fn as_any(&self) -> &dyn Any {
139        self as &dyn Any
140    }
141}
142
143#[cfg(any(test, feature = "std", feature = "alloc"))]
144impl AsAny for String {
145    #[inline]
146    fn as_any(&self) -> &dyn Any {
147        self as &dyn Any
148    }
149}
150
151#[cfg(test)]
152mod test {
153    use ::core::any::Any;
154
155    use super::AsAny;
156
157    #[test]
158    fn test_as_any_correct() {
159        assert_eq!(1usize.as_any().type_id(), (&5usize as &dyn Any).type_id());
160        assert_eq!(1usize.as_any().downcast_ref::<usize>().unwrap(), &1usize);
161        assert_eq!(1u8.as_any().downcast_ref::<u8>().unwrap(), &1u8);
162        assert_eq!(1u16.as_any().downcast_ref::<u16>().unwrap(), &1u16);
163        assert_eq!(1u32.as_any().downcast_ref::<u32>().unwrap(), &1u32);
164        assert_eq!(1u64.as_any().downcast_ref::<u64>().unwrap(), &1u64);
165        assert_eq!(1u128.as_any().downcast_ref::<u128>().unwrap(), &1u128);
166        assert_eq!(1i8.as_any().downcast_ref::<i8>().unwrap(), &1i8);
167        assert_eq!(1i16.as_any().downcast_ref::<i16>().unwrap(), &1i16);
168        assert_eq!(1i32.as_any().downcast_ref::<i32>().unwrap(), &1i32);
169        assert_eq!(1i64.as_any().downcast_ref::<i64>().unwrap(), &1i64);
170        assert_eq!(1i128.as_any().downcast_ref::<i128>().unwrap(), &1i128);
171        assert_eq!(
172            s!("string").as_any().downcast_ref::<String>().unwrap(),
173            &"string"
174        );
175    }
176
177    #[test]
178    fn test_as_any_wrong() {
179        assert!(1usize.as_any().downcast_ref::<u32>().is_none());
180        assert!(1i8.as_any().downcast_ref::<u8>().is_none());
181        assert!(1i16.as_any().downcast_ref::<u16>().is_none());
182        assert!(1i32.as_any().downcast_ref::<u32>().is_none());
183        assert!(1i64.as_any().downcast_ref::<u64>().is_none());
184        assert!(1i128.as_any().downcast_ref::<u128>().is_none());
185        assert!(s!("str").as_any().downcast_ref::<&str>().is_none());
186    }
187}