clap_builder/util/
any_value.rs

1#[derive(Clone)]
2pub(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
9impl 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
35impl std::fmt::Debug for AnyValue {
36    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> {
37        f.debug_struct("AnyValue").field("inner", &self.id).finish()
38    }
39}
40
41#[derive(Copy, Clone)]
42pub struct AnyValueId {
43    type_id: std::any::TypeId,
44    #[cfg(debug_assertions)]
45    type_name: &'static str,
46}
47
48impl 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
58impl PartialEq for AnyValueId {
59    fn eq(&self, other: &Self) -> bool {
60        self.type_id == other.type_id
61    }
62}
63
64impl Eq for AnyValueId {}
65
66impl PartialOrd for AnyValueId {
67    fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
68        Some(self.cmp(other))
69    }
70}
71
72impl PartialEq<std::any::TypeId> for AnyValueId {
73    fn eq(&self, other: &std::any::TypeId) -> bool {
74        self.type_id == *other
75    }
76}
77
78impl Ord for AnyValueId {
79    fn cmp(&self, other: &Self) -> std::cmp::Ordering {
80        self.type_id.cmp(&other.type_id)
81    }
82}
83
84impl 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
90impl 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
103impl<'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)]
110mod 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}