1 | #[derive (Clone)] |
2 | pub(crate) struct AnyValue { |
3 | inner: std::sync::Arc<dyn std::any::Any + Send + Sync + 'static>, |
4 | // While we can extract `TypeId` from `inner`, the debug repr is of a number, so let's track |
5 | // the type_name in debug builds. |
6 | id: AnyValueId, |
7 | } |
8 | |
9 | impl AnyValue { |
10 | pub(crate) fn new<V: std::any::Any + Clone + Send + Sync + 'static>(inner: V) -> Self { |
11 | let id = AnyValueId::of::<V>(); |
12 | let inner = std::sync::Arc::new(inner); |
13 | Self { inner, id } |
14 | } |
15 | |
16 | pub(crate) fn downcast_ref<T: std::any::Any + Clone + Send + Sync + 'static>( |
17 | &self, |
18 | ) -> Option<&T> { |
19 | self.inner.downcast_ref::<T>() |
20 | } |
21 | |
22 | pub(crate) fn downcast_into<T: std::any::Any + Clone + Send + Sync>(self) -> Result<T, Self> { |
23 | let id = self.id; |
24 | let value = |
25 | ok!(std::sync::Arc::downcast::<T>(self.inner).map_err(|inner| Self { inner, id })); |
26 | let value = std::sync::Arc::try_unwrap(value).unwrap_or_else(|arc| (*arc).clone()); |
27 | Ok(value) |
28 | } |
29 | |
30 | pub(crate) fn type_id(&self) -> AnyValueId { |
31 | self.id |
32 | } |
33 | } |
34 | |
35 | impl std::fmt::Debug for AnyValue { |
36 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> { |
37 | f.debug_struct("AnyValue" ).field(name:"inner" , &self.id).finish() |
38 | } |
39 | } |
40 | |
41 | #[derive (Copy, Clone)] |
42 | pub struct AnyValueId { |
43 | type_id: std::any::TypeId, |
44 | #[cfg (debug_assertions)] |
45 | type_name: &'static str, |
46 | } |
47 | |
48 | impl AnyValueId { |
49 | pub(crate) fn of<A: ?Sized + 'static>() -> Self { |
50 | Self { |
51 | type_id: std::any::TypeId::of::<A>(), |
52 | #[cfg (debug_assertions)] |
53 | type_name: std::any::type_name::<A>(), |
54 | } |
55 | } |
56 | } |
57 | |
58 | impl PartialEq for AnyValueId { |
59 | fn eq(&self, other: &Self) -> bool { |
60 | self.type_id == other.type_id |
61 | } |
62 | } |
63 | |
64 | impl Eq for AnyValueId {} |
65 | |
66 | impl PartialOrd for AnyValueId { |
67 | fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> { |
68 | Some(self.cmp(other)) |
69 | } |
70 | } |
71 | |
72 | impl PartialEq<std::any::TypeId> for AnyValueId { |
73 | fn eq(&self, other: &std::any::TypeId) -> bool { |
74 | self.type_id == *other |
75 | } |
76 | } |
77 | |
78 | impl Ord for AnyValueId { |
79 | fn cmp(&self, other: &Self) -> std::cmp::Ordering { |
80 | self.type_id.cmp(&other.type_id) |
81 | } |
82 | } |
83 | |
84 | impl std::hash::Hash for AnyValueId { |
85 | fn hash<H: std::hash::Hasher>(&self, state: &mut H) { |
86 | self.type_id.hash(state); |
87 | } |
88 | } |
89 | |
90 | impl std::fmt::Debug for AnyValueId { |
91 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> { |
92 | #[cfg (not(debug_assertions))] |
93 | { |
94 | self.type_id.fmt(f) |
95 | } |
96 | #[cfg (debug_assertions)] |
97 | { |
98 | f.debug_struct(self.type_name).finish() |
99 | } |
100 | } |
101 | } |
102 | |
103 | impl<'a, A: ?Sized + 'static> From<&'a A> for AnyValueId { |
104 | fn from(_: &'a A) -> Self { |
105 | Self::of::<A>() |
106 | } |
107 | } |
108 | |
109 | #[cfg (test)] |
110 | mod test { |
111 | #[test ] |
112 | #[cfg (debug_assertions)] |
113 | fn debug_impl() { |
114 | use super::*; |
115 | |
116 | assert_eq!(format!(" {:?}" , AnyValue::new(5)), "AnyValue { inner: i32 }" ); |
117 | } |
118 | |
119 | #[test ] |
120 | fn eq_to_type_id() { |
121 | use super::*; |
122 | |
123 | let any_value_id = AnyValueId::of::<i32>(); |
124 | let type_id = std::any::TypeId::of::<i32>(); |
125 | assert_eq!(any_value_id, type_id); |
126 | } |
127 | } |
128 | |