type_set/lib.rs
1#![deny(
2 clippy::dbg_macro,
3 missing_copy_implementations,
4 rustdoc::missing_crate_level_docs,
5 missing_debug_implementations,
6 nonstandard_style,
7 unused_qualifications
8)]
9#![warn(missing_docs, clippy::pedantic, clippy::perf, clippy::cargo)]
10#![allow(clippy::missing_panics_doc, clippy::module_name_repetitions)]
11/*!
12
13[`TypeSet`] is a collection for heterogeneous types. Each type can only exist once in the set, and
14can only be retrieved by naming the type.
15
16Because types can only be retrieved by naming them, rust's module system allows module-private
17storage in a shared `TypeSet`.
18
19Currently, this crate imposes `Send + Sync` bounds on the stored types, but future versions may
20offer variants without those bounds and/or with Clone bounds.
21
22Implementation is based on
23- <https://github.com/hyperium/http/blob/master/src/extensions.rs>
24- <https://github.com/kardeiz/type-map/blob/master/src/lib.rs>
25- <https://github.com/http-rs/http-types/blob/main/src/extensions.rs>
26*/
27use std::{
28 any::{type_name, Any, TypeId},
29 collections::BTreeMap,
30 fmt::{self, Debug, Formatter},
31};
32
33/// Types for interacting with a mutable view into a `TypeSet` for a given type
34pub mod entry;
35use entry::Entry;
36
37struct Value {
38 any: Box<dyn Any + Send + Sync>,
39 name: &'static str,
40}
41
42impl Value {
43 fn new<T: Any + Send + Sync + 'static>(value: T) -> Self {
44 Self {
45 any: Box::new(value),
46 name: type_name::<T>(),
47 }
48 }
49
50 fn downcast_mut<T: Any + Send + Sync + 'static>(&mut self) -> Option<&mut T> {
51 debug_assert_eq!(type_name::<T>(), self.name);
52 self.any.downcast_mut()
53 }
54
55 fn downcast<T: Any + Send + Sync + 'static>(self) -> Option<T> {
56 debug_assert_eq!(type_name::<T>(), self.name);
57 self.any.downcast().map(|t| *t).ok()
58 }
59
60 fn downcast_ref<T: Any + Send + Sync + 'static>(&self) -> Option<&T> {
61 debug_assert_eq!(type_name::<T>(), self.name);
62 self.any.downcast_ref()
63 }
64}
65
66type Key = TypeId;
67
68macro_rules! unwrap {
69 ($x:expr) => {
70 match $x {
71 #[cfg(debug_assertions)]
72 x => x.unwrap(),
73 #[cfg(not(debug_assertions))]
74 x => unsafe { x.unwrap_unchecked() },
75 }
76 };
77}
78use unwrap;
79
80/// A collection for heterogenous types
81///
82/// Note that there is currently no way to iterate over the collection, as there may be types stored
83/// that cannot be named by the calling code
84#[derive(Default)]
85pub struct TypeSet(BTreeMap<Key, Value>);
86
87fn field_with(f: impl Fn(&mut Formatter) -> fmt::Result) -> impl Debug {
88 struct DebugWith<F>(F);
89
90 impl<F> Debug for DebugWith<F>
91 where
92 F: Fn(&mut Formatter) -> fmt::Result,
93 {
94 fn fmt(&self, f: &mut Formatter) -> fmt::Result {
95 self.0(f)
96 }
97 }
98
99 DebugWith(f)
100}
101
102impl Debug for TypeSet {
103 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
104 f.debug_tuple("TypeSet")
105 .field(&field_with(|f| {
106 let mut values = self.0.values().map(|v| v.name).collect::<Vec<_>>();
107 values.sort_unstable();
108 f.debug_set().entries(values).finish()
109 }))
110 .finish()
111 }
112}
113
114fn key<T: 'static>() -> Key {
115 TypeId::of::<T>()
116}
117
118impl TypeSet {
119 /// Create an empty `TypeSet`.
120 #[must_use]
121 pub const fn new() -> Self {
122 Self(BTreeMap::new())
123 }
124
125 /// Returns true if the `TypeSet` contains zero types.
126 #[must_use]
127 pub fn is_empty(&self) -> bool {
128 self.0.is_empty()
129 }
130
131 /// Returns the number of distinct types in this `TypeSet`.
132 #[must_use]
133 pub fn len(&self) -> usize {
134 self.0.len()
135 }
136
137 /// Gets the corresponding type in the set for in-place manipulation.
138 ///
139 /// See [`Entry`] for usage.
140 pub fn entry<T: Send + Sync + 'static>(&mut self) -> Entry<'_, T> {
141 Entry::new(self.0.entry(key::<T>()))
142 }
143
144 /// Insert a value into this `TypeSet`.
145 ///
146 /// If a value of this type already exists, it will be replaced and returned.
147 ///
148 /// ## Example
149 /// ```rust
150 /// let mut set = type_set::TypeSet::new().with("hello");
151 /// let previous = set.insert("world");
152 /// assert_eq!(set.get::<&'static str>(), Some(&"world"));
153 /// assert_eq!(previous, Some("hello"));
154 /// ```
155 pub fn insert<T: Send + Sync + 'static>(&mut self, value: T) -> Option<T> {
156 self.entry().insert(value)
157 }
158
159 /// Chainable constructor to add a type to this `TypeSet`
160 ///
161 /// ## Example
162 /// ```rust
163 /// let set = type_set::TypeSet::new().with("hello");
164 /// assert_eq!(set.get::<&'static str>(), Some(&"hello"));
165 /// ```
166 #[must_use]
167 pub fn with<T: Send + Sync + 'static>(mut self, value: T) -> Self {
168 self.insert(value);
169 self
170 }
171
172 /// Check if this `TypeSet` contains a value for type T
173 ///
174 /// ## Example
175 ///
176 /// ```rust
177 /// let set = type_set::TypeSet::new().with("hello");
178 /// assert!(set.contains::<&'static str>());
179 /// assert!(!set.contains::<String>());
180 /// ```
181 #[must_use]
182 pub fn contains<T: Send + Sync + 'static>(&self) -> bool {
183 #[cfg(feature = "log")]
184 log::trace!(
185 "contains {}?: {}",
186 type_name::<T>(),
187 self.0.contains_key(&TypeId::of::<T>())
188 );
189 self.0.contains_key(&key::<T>())
190 }
191
192 /// Immutably borrow a value that has been inserted into this `TypeSet`.
193 #[must_use]
194 pub fn get<T: Send + Sync + 'static>(&self) -> Option<&T> {
195 #[cfg(feature = "log")]
196 log::trace!("getting {}", type_name::<T>(),);
197 self.0
198 .get(&key::<T>())
199 .map(|value| unwrap!(value.downcast_ref()))
200 }
201
202 /// Attempt to mutably borrow to a value that has been inserted into this `TypeSet`.
203 ///
204 /// ## Example
205 ///
206 /// ```rust
207 /// let mut set = type_set::TypeSet::new().with(String::from("hello"));
208 /// if let Some(string) = set.get_mut::<String>() {
209 /// string.push_str(" world");
210 /// }
211 /// assert_eq!(set.get::<String>().unwrap(), "hello world");
212 /// ```
213 pub fn get_mut<T: Send + Sync + 'static>(&mut self) -> Option<&mut T> {
214 self.0
215 .get_mut(&key::<T>())
216 .map(|value| unwrap!(value.downcast_mut()))
217 }
218
219 /// Remove a value from this `TypeSet`.
220 ///
221 /// If a value of this type exists, it will be returned.
222 ///
223 /// ## Example
224 ///
225 /// ```rust
226 /// let mut set = type_set::TypeSet::new().with("hello");
227 /// assert_eq!(set.take::<&'static str>(), Some("hello"));
228 /// assert_eq!(set.take::<&'static str>(), None);
229 /// ```
230 pub fn take<T: Send + Sync + 'static>(&mut self) -> Option<T> {
231 self.entry().take()
232 }
233
234 /// Get a value from this `TypeSet` or populate it with the provided default.
235 ///
236 /// Identical to [`Entry::or_insert`]
237 ///
238 /// If building T is expensive, use [`TypeSet::get_or_insert_with`] or [`Entry::or_insert_with`]
239 ///
240 /// ## Example
241 ///
242 /// ```rust
243 /// let mut set = type_set::TypeSet::new();
244 /// assert_eq!(set.get_or_insert("hello"), &mut "hello");
245 /// assert_eq!(set.get_or_insert("world"), &mut "hello");
246 /// ```
247 pub fn get_or_insert<T: Send + Sync + 'static>(&mut self, default: T) -> &mut T {
248 self.entry().or_insert(default)
249 }
250
251 /// Get a value from this `TypeSet` or populate it with the provided default function.
252 ///
253 /// Identical to [`Entry::or_insert_with`]
254 ///
255 /// Prefer this to [`TypeSet::get_or_insert`] when building type T is expensive, since it will only be
256 /// executed when T is absent.
257 ///
258 /// ## Example
259 ///
260 /// ```rust
261 /// let mut set = type_set::TypeSet::new();
262 /// assert_eq!(set.get_or_insert_with(|| String::from("hello")), "hello");
263 /// assert_eq!(set.get_or_insert_with::<String>(|| panic!("this is never called")), "hello");
264 /// ```
265 pub fn get_or_insert_with<T: Send + Sync + 'static>(
266 &mut self,
267 default: impl FnOnce() -> T,
268 ) -> &mut T {
269 self.entry().or_insert_with(default)
270 }
271
272 /// Ensure a value is present by filling with [`Default::default`]
273 ///
274 /// Identical to [`Entry::or_default`].
275 ///
276 /// ## Example
277 ///
278 /// ```rust
279 /// let mut set = type_set::TypeSet::new().with(10usize);
280 /// let ten: usize = *set.get_or_insert_default();
281 /// assert_eq!(ten, 10);
282 /// ```
283 pub fn get_or_insert_default<T: Default + Send + Sync + 'static>(&mut self) -> &mut T {
284 self.entry().or_default()
285 }
286
287 /// Merge another `TypeSet` into this one, replacing any collisions
288 ///
289 ///
290 /// ## Example
291 ///
292 /// ```rust
293 /// let mut set_a = type_set::TypeSet::new().with(8u8).with("hello");
294 /// let set_b = type_set::TypeSet::new().with(32u32).with("world");
295 /// set_a.merge(set_b);
296 /// assert_eq!(set_a.get::<u8>(), Some(&8));
297 /// assert_eq!(set_a.get::<u32>(), Some(&32));
298 /// assert_eq!(set_a.get::<&'static str>(), Some(&"world"));
299 /// ```
300 pub fn merge(&mut self, other: TypeSet) {
301 self.0.extend(other.0);
302 }
303}