Skip to main content

any_container/
boxed.rs

1use std::any::{Any, TypeId, type_name};
2use std::ops::{Deref, DerefMut};
3
4use crate::multimap::AnyMultiMap;
5
6/// A type-erased cloneable box that stores any `Clone + Send + Sync` type.
7///
8/// `AnyCloneBox` enables runtime type-erased storage of values while maintaining
9/// the ability to clone and downcast them to their original types. It is the
10/// fundamental building block for type-erased containers in the crate.
11///
12/// # Examples
13///
14/// ```
15/// use any_container::AnyCloneBox;
16///
17/// // Create an AnyCloneBox with an i32
18/// let boxed = AnyCloneBox::new(42i32);
19///
20/// // Downcast to get the original value
21/// assert_eq!(*boxed.downcast_ref::<i32>().unwrap(), 42);
22///
23/// // Downcasting to a wrong type returns None
24/// assert!(boxed.downcast_ref::<String>().is_none());
25///
26/// // Clone the boxed value
27/// let _clone = boxed.clone();
28/// ```
29pub struct AnyCloneBox {
30    inner: Box<dyn AnyClone>,
31    type_id: TypeId,
32    type_name: &'static str,
33}
34
35impl AnyCloneBox {
36    /// Creates a new `AnyCloneBox` containing the given value.
37    pub fn new<T: Clone + Send + Sync + 'static>(value: T) -> Self {
38        AnyCloneBox {
39            inner: Box::new(value),
40            type_id: TypeId::of::<T>(),
41            type_name: type_name::<T>(),
42        }
43    }
44
45    /// Returns the `TypeId` of the value contained in this `AnyCloneBox`.
46    pub fn type_id(&self) -> TypeId {
47        self.type_id
48    }
49
50    /// Returns the type name of the value contained in this `AnyCloneBox`.
51    pub fn type_name(&self) -> &'static str {
52        self.type_name
53    }
54
55    /// Attempts to downcast the `AnyCloneBox` to an immutable reference of type `T`.
56    pub fn downcast_ref<T: Any>(&self) -> Option<&T> {
57        if self.type_id == TypeId::of::<T>() {
58            Some(unsafe {
59                // SAFETY: The type has been checked to match, so this is safe.
60                self.downcast_ref_unchecked::<T>()
61            })
62        } else {
63            None
64        }
65    }
66
67    /// Unsafely downcasts the `AnyCloneBox` to an immutable reference of type `T` without checking the type.
68    ///
69    /// # Safety
70    /// The caller must ensure that the type `T` is the same as the type of the value contained in
71    /// this `AnyCloneBox`. If the types do not match, this will result in undefined behaviour.
72    pub unsafe fn downcast_ref_unchecked<T: Any>(&self) -> &T {
73        unsafe { &*(self.inner.deref() as *const dyn Any as *const T) }
74    }
75
76    /// Attempts to downcast the `AnyCloneBox` to a mutable reference of type `T`.
77    ///
78    /// This method allows mutation of the contained value through a type-safe interface.
79    /// Returns `None` if the contained type doesn't match `T`.
80    pub fn downcast_mut<T: Any>(&mut self) -> Option<&mut T> {
81        if self.type_id == TypeId::of::<T>() {
82            Some(unsafe {
83                // SAFETY: The type has been checked to match, so this is safe.
84                self.downcast_mut_unchecked::<T>()
85            })
86        } else {
87            None
88        }
89    }
90
91    /// Unsafely downcasts the `AnyCloneBox` to a mutable reference of type `T` without checking the type.
92    ///
93    /// # Safety
94    /// The caller must ensure that the type `T` is the same as the type of the value contained in
95    /// this `AnyCloneBox`. If the types do not match, this will result in undefined behaviour.
96    pub unsafe fn downcast_mut_unchecked<T: Any>(&mut self) -> &mut T {
97        unsafe { &mut *(self.inner.deref_mut() as *mut dyn Any as *mut T) }
98    }
99
100    /// Consumes the `AnyCloneBox` and attempts to downcast it to a boxed value of type `T`.
101    pub fn downcast<T: Any>(self) -> Result<Box<T>, Self> {
102        if self.type_id == TypeId::of::<T>() {
103            Ok(unsafe {
104                // SAFETY: The type has been checked to match, so this is safe.
105                self.downcast_unchecked::<T>()
106            })
107        } else {
108            Err(self)
109        }
110    }
111
112    /// Unsafely downcasts the `AnyCloneBox` to a boxed value of type `T` without checking the type.
113    ///
114    /// # Safety
115    /// The caller must ensure that the type `T` is the same as the type of the value contained in
116    /// this `AnyCloneBox`. If the types do not match, this will result in undefined behaviour.
117    pub unsafe fn downcast_unchecked<T: Any>(self) -> Box<T> {
118        unsafe {
119            let raw = Box::into_raw(self.inner);
120            Box::from_raw(raw as *mut T)
121        }
122    }
123}
124
125impl AnyCloneBox {
126    pub(super) fn insert_into_multimap(self, multimap: &mut AnyMultiMap) {
127        self.inner.insert_into_multimap(multimap);
128    }
129}
130
131impl Clone for AnyCloneBox {
132    fn clone(&self) -> Self {
133        AnyCloneBox {
134            inner: self.inner.clone_box(),
135            type_id: self.type_id,
136            type_name: self.type_name,
137        }
138    }
139}
140
141trait AnyClone: Any + Send + Sync {
142    fn clone_box(&self) -> Box<dyn AnyClone>;
143    fn insert_into_multimap(self: Box<Self>, multimap: &mut AnyMultiMap);
144}
145
146impl<T: Clone + Send + Sync + 'static> AnyClone for T {
147    fn clone_box(&self) -> Box<dyn AnyClone> {
148        Box::new(self.clone())
149    }
150    fn insert_into_multimap(self: Box<Self>, multimap: &mut AnyMultiMap) {
151        multimap.insert(*self);
152    }
153}