meta_tuple/
dynamic.rs

1use crate::{Join, MetaItem, MetaTuple};
2use core::{any::Any, ptr::NonNull};
3
4/// Erased [`MetaTuple`].
5pub enum ErasedInner<'t> {
6    None,
7    Any(&'t dyn Any),
8    Joined(&'t dyn MetaBox, &'t dyn MetaBox),
9}
10
11/// Erased mutable [`MetaTuple`].
12pub enum ErasedInnerMut<'t> {
13    None,
14    Any(&'t mut dyn Any),
15    Joined(&'t mut dyn MetaBox, &'t mut dyn MetaBox),
16}
17
18/// A dyn compatible alternative to [`Any`] that can contain multiple items.
19pub trait MetaBox {
20    fn as_erased(&self) -> ErasedInner<'_>;
21    fn as_erased_mut(&mut self) -> ErasedInnerMut<'_>;
22}
23
24impl dyn MetaBox + '_ {
25    /// Obtain an item if it exists in the [`MetaBox`].
26    ///
27    /// Always returns `Some` for `()`.
28    pub fn get<T: 'static>(&self) -> Option<&T> {
29        if let Some(value) = (&() as &dyn Any).downcast_ref() {
30            return Some(value);
31        }
32        match self.as_erased() {
33            ErasedInner::None => None,
34            ErasedInner::Any(any) => any.downcast_ref(),
35            ErasedInner::Joined(a, b) => a.get().or_else(|| b.get()),
36        }
37    }
38
39    /// Obtain an item if it exists in the [`MetaBox`].
40    ///
41    /// Always returns `Some` for `()`.
42    pub fn get_mut<T: 'static>(&mut self) -> Option<&mut T> {
43        if (&mut () as &mut dyn Any).downcast_mut::<T>().is_some() {
44            // Safety:
45            //
46            // Safe since `()` is a ZST.
47            return Some(unsafe { NonNull::dangling().as_mut() });
48        }
49        match self.as_erased_mut() {
50            ErasedInnerMut::None => None,
51            ErasedInnerMut::Any(any) => any.downcast_mut(),
52            ErasedInnerMut::Joined(a, b) => a.get_mut().or_else(|| b.get_mut()),
53        }
54    }
55}
56
57impl MetaBox for () {
58    fn as_erased<'t>(&self) -> ErasedInner<'_> {
59        ErasedInner::None
60    }
61
62    fn as_erased_mut(&mut self) -> ErasedInnerMut<'_> {
63        ErasedInnerMut::None
64    }
65}
66
67impl<T: MetaBox> MetaBox for &T {
68    fn as_erased<'t>(&self) -> ErasedInner<'_> {
69        MetaBox::as_erased(*self)
70    }
71
72    fn as_erased_mut(&mut self) -> ErasedInnerMut<'_> {
73        ErasedInnerMut::None
74    }
75}
76
77impl<T: MetaBox> MetaBox for &mut T {
78    fn as_erased<'t>(&self) -> ErasedInner<'_> {
79        MetaBox::as_erased(*self)
80    }
81
82    fn as_erased_mut(&mut self) -> ErasedInnerMut<'_> {
83        MetaBox::as_erased_mut(*self)
84    }
85}
86
87impl<T: 'static> MetaBox for MetaItem<T> {
88    fn as_erased<'t>(&self) -> ErasedInner<'_> {
89        ErasedInner::Any(&self.0)
90    }
91
92    fn as_erased_mut(&mut self) -> ErasedInnerMut<'_> {
93        ErasedInnerMut::Any(&mut self.0)
94    }
95}
96
97impl<T: 'static> MetaBox for Option<T> {
98    fn as_erased<'t>(&self) -> ErasedInner<'_> {
99        match self.as_ref() {
100            Some(value) => ErasedInner::Any(value),
101            None => ErasedInner::None,
102        }
103    }
104
105    fn as_erased_mut(&mut self) -> ErasedInnerMut<'_> {
106        match self.as_mut() {
107            Some(value) => ErasedInnerMut::Any(value),
108            None => ErasedInnerMut::None,
109        }
110    }
111}
112
113impl<A: MetaTuple, B: MetaTuple> MetaBox for Join<A, B> {
114    fn as_erased<'t>(&self) -> ErasedInner<'_> {
115        ErasedInner::Joined(&self.0, &self.1)
116    }
117
118    fn as_erased_mut(&mut self) -> ErasedInnerMut<'_> {
119        ErasedInnerMut::Joined(&mut self.0, &mut self.1)
120    }
121}