Skip to main content

any_container/
map.rs

1use std::any::{Any, TypeId};
2use std::collections::HashMap;
3use std::collections::hash_map::Entry;
4use std::fmt;
5use std::hash::BuildHasherDefault;
6
7use crate::boxed::AnyCloneBox;
8use crate::utils::IdHasher;
9
10/// A type-erased map storing values of different types by their `TypeId`.
11///
12/// `AnyMap` allows storing and retrieving values of any type that implements
13/// `Clone + Send + Sync`. The map uses `TypeId` as keys, enabling type-safe
14/// lookups while maintaining type erasure through boxed trait objects.
15///
16/// # Examples
17///
18/// ```
19/// use any_container::AnyMap;
20///
21/// let mut map = AnyMap::new();
22/// map.insert(42i32);
23/// map.insert("world".to_string());
24///
25/// assert_eq!(map.len(), 2);
26/// assert_eq!(*map.get::<i32>().unwrap(), 42);
27/// ```
28#[repr(transparent)]
29#[derive(Clone)]
30pub struct AnyMap {
31    // A map from a TypeId to a Box of a type
32    map: HashMap<TypeId, AnyCloneBox, BuildHasherDefault<IdHasher>>,
33}
34
35impl Default for AnyMap {
36    fn default() -> Self {
37        Self::new()
38    }
39}
40
41impl AnyMap {
42    /// Creates a new empty `AnyMap`.
43    pub fn new() -> AnyMap {
44        AnyMap {
45            map: HashMap::default(),
46        }
47    }
48
49    /// Creates a new empty `AnyMap` with the specified capacity.
50    pub fn with_capacity(capacity: usize) -> AnyMap {
51        AnyMap {
52            map: HashMap::with_capacity_and_hasher(
53                capacity,
54                BuildHasherDefault::<IdHasher>::default(),
55            ),
56        }
57    }
58
59    /// Returns the number of elements that the map can hold without reallocating.
60    pub fn capacity(&self) -> usize {
61        self.map.capacity()
62    }
63
64    /// Reserves capacity for at least `additional` more elements in the map.
65    /// The map may reserve more space than requested to avoid frequent reallocations.
66    pub fn reserve(&mut self, additional: usize) {
67        self.map.reserve(additional);
68    }
69
70    /// Shrinks the capacity of the map as much as possible.
71    /// This reduces the allocated memory to fit the current contents.
72    pub fn shrink_to_fit(&mut self) {
73        self.map.shrink_to_fit();
74    }
75
76    /// Returns the number of elements in the map.
77    pub fn len(&self) -> usize {
78        self.map.len()
79    }
80
81    /// Returns true if the map contains no elements.
82    pub fn is_empty(&self) -> bool {
83        self.map.is_empty()
84    }
85
86    /// Removes all elements from the map.
87    pub fn clear(&mut self) {
88        self.map.clear();
89    }
90
91    /// Returns a reference to the value corresponding to the type `T`.
92    pub fn get<T: Any>(&self) -> Option<&T> {
93        self.map.get(&TypeId::of::<T>()).map(|elem| unsafe {
94            debug_assert_eq!(
95                AnyCloneBox::type_id(elem),
96                TypeId::of::<T>(),
97                "TypeId mismatch in AnyMap::get. This should never happen!"
98            );
99            // Safety: The invariants guarantee that the type of the value is the same as the type of the key.
100            elem.downcast_ref_unchecked()
101        })
102    }
103
104    /// Returns a mutable reference to the value corresponding to the type `T`.
105    pub fn get_mut<T: Any>(&mut self) -> Option<&mut T> {
106        self.map.get_mut(&TypeId::of::<T>()).map(|elem| unsafe {
107            debug_assert_eq!(
108                AnyCloneBox::type_id(elem),
109                TypeId::of::<T>(),
110                "TypeId mismatch in AnyMap::get_mut. This should never happen!"
111            );
112            // Safety: The invariants guarantee that the type of the value is the same as the type of the key.
113            elem.downcast_mut_unchecked()
114        })
115    }
116
117    // Inserts a value of type `T` into the map. If a value of type `T` already exists, it will be
118    // replaced and the old value will be returned.
119    pub fn insert<T: Any + Clone + Send + Sync>(&mut self, value: T) -> Option<T> {
120        self.map
121            .insert(TypeId::of::<T>(), AnyCloneBox::new(value))
122            .map(|old_value| unsafe {
123                debug_assert_eq!(
124                    AnyCloneBox::type_id(&old_value),
125                    TypeId::of::<T>(),
126                    "TypeId mismatch in AnyMap::insert. This should never happen!"
127                );
128                // Safety: The invariants guarantee that the type of the value is the same as the type of the key.
129                *old_value.downcast_unchecked()
130            })
131    }
132
133    /// Inserts a boxed value into the map.
134    /// If a value of the same `TypeId` already exists, it will be replaced and the old value
135    /// will be returned.
136    /// This method is useful when you already have an `AnyCloneBox` instance.
137    pub fn insert_boxed(&mut self, value: AnyCloneBox) -> Option<AnyCloneBox> {
138        self.map.insert(value.type_id(), value)
139    }
140
141    /// Inserts a value of type `T` into the map. If a value of type `T` already exists,
142    /// it will not be replaced and the new value will be returned as an error.
143    pub fn try_insert<T: Any + Clone + Send + Sync>(&mut self, value: T) -> Result<(), T> {
144        match self.map.entry(TypeId::of::<T>()) {
145            Entry::Occupied(_) => Err(value),
146            Entry::Vacant(entry) => {
147                entry.insert(AnyCloneBox::new(value));
148                Ok(())
149            }
150        }
151    }
152
153    /// Inserts a boxed value into the map. If a value of the same type already exists,
154    /// it will not be replaced and the new value will be returned as an error.
155    pub fn try_insert_boxed(&mut self, value: AnyCloneBox) -> Result<(), AnyCloneBox> {
156        match self.map.entry(value.type_id()) {
157            Entry::Occupied(_) => Err(value),
158            Entry::Vacant(entry) => {
159                entry.insert(value);
160                Ok(())
161            }
162        }
163    }
164
165    /// Removes the stored value of type `T` from the map and returns it, if it exists.
166    pub fn remove<T: Any>(&mut self) -> Option<T> {
167        self.map.remove(&TypeId::of::<T>()).map(|old_value| unsafe {
168            debug_assert_eq!(
169                AnyCloneBox::type_id(&old_value),
170                TypeId::of::<T>(),
171                "TypeId mismatch in AnyMap::remove. This should never happen!"
172            );
173            // Safety: The invariants guarantee that the type of the value is the same as the type of the key.
174            *old_value.downcast_unchecked()
175        })
176    }
177
178    /// Returns true if the map contains a value of type `T`.
179    pub fn contains<T: Any>(&self) -> bool {
180        self.map.contains_key(&TypeId::of::<T>())
181    }
182}
183
184impl fmt::Debug for AnyMap {
185    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
186        f.debug_set()
187            .entries(self.map.values().map(|any_clone| any_clone.type_name()))
188            .finish()
189    }
190}