ra_ap_stdx/
anymap.rs

1//! This file is a port of only the necessary features from <https://github.com/chris-morgan/anymap> version 1.0.0-beta.2 for use within rust-analyzer.
2//! Copyright © 2014–2022 Chris Morgan.
3//! COPYING: <https://github.com/chris-morgan/anymap/blob/master/COPYING>
4//! Note that the license is changed from Blue Oak Model 1.0.0 or MIT or Apache-2.0 to MIT OR Apache-2.0
5//!
6//! This implementation provides a safe and convenient store for one value of each type.
7//!
8//! Your starting point is [`Map`]. It has an example.
9//!
10//! # Cargo features
11//!
12//! This implementation has two independent features, each of which provides an implementation providing
13//! types `Map`, `AnyMap`, `OccupiedEntry`, `VacantEntry`, `Entry` and `RawMap`:
14//!
15//! - **std** (default, *enabled* in this build):
16//!   an implementation using `std::collections::hash_map`, placed in the crate root
17//!   (e.g. `anymap::AnyMap`).
18
19#![warn(missing_docs, unused_results)]
20
21use core::hash::Hasher;
22
23/// A hasher designed to eke a little more speed out, given `TypeId`’s known characteristics.
24///
25/// Specifically, this is a no-op hasher that expects to be fed a u64’s worth of
26/// randomly-distributed bits. It works well for `TypeId` (eliminating start-up time, so that my
27/// get_missing benchmark is ~30ns rather than ~900ns, and being a good deal faster after that, so
28/// that my insert_and_get_on_260_types benchmark is ~12μs instead of ~21.5μs), but will
29/// panic in debug mode and always emit zeros in release mode for any other sorts of inputs, so
30/// yeah, don’t use it! 😀
31#[derive(Default)]
32pub struct TypeIdHasher {
33    value: u64,
34}
35
36impl Hasher for TypeIdHasher {
37    #[inline]
38    fn write(&mut self, bytes: &[u8]) {
39        // This expects to receive exactly one 64-bit value, and there’s no realistic chance of
40        // that changing, but I don’t want to depend on something that isn’t expressly part of the
41        // contract for safety. But I’m OK with release builds putting everything in one bucket
42        // if it *did* change (and debug builds panicking).
43        debug_assert_eq!(bytes.len(), 8);
44        let _ = bytes.try_into().map(|array| self.value = u64::from_ne_bytes(array));
45    }
46
47    #[inline]
48    fn finish(&self) -> u64 {
49        self.value
50    }
51}
52
53use core::any::{Any, TypeId};
54use core::hash::BuildHasherDefault;
55use core::marker::PhantomData;
56
57use ::std::collections::hash_map;
58
59/// Raw access to the underlying `HashMap`.
60///
61/// This alias is provided for convenience because of the ugly third generic parameter.
62#[allow(clippy::disallowed_types)] // Uses a custom hasher
63pub type RawMap<A> = hash_map::HashMap<TypeId, Box<A>, BuildHasherDefault<TypeIdHasher>>;
64
65/// A collection containing zero or one values for any given type and allowing convenient,
66/// type-safe access to those values.
67///
68/// The type parameter `A` allows you to use a different value type; normally you will want
69/// it to be `core::any::Any` (also known as `std::any::Any`), but there are other choices:
70///
71/// - You can add on `+ Send` or `+ Send + Sync` (e.g. `Map<dyn Any + Send>`) to add those
72///   auto traits.
73///
74/// Cumulatively, there are thus six forms of map:
75///
76/// - <code>[Map]&lt;dyn [core::any::Any]&gt;</code>,
77///   also spelled [`AnyMap`] for convenience.
78/// - <code>[Map]&lt;dyn [core::any::Any] + Send&gt;</code>
79/// - <code>[Map]&lt;dyn [core::any::Any] + Send + Sync&gt;</code>
80///
81/// ## Example
82///
83/// (Here using the [`AnyMap`] convenience alias; the first line could use
84/// <code>[anymap::Map][Map]::&lt;[core::any::Any]&gt;::new()</code> instead if desired.)
85///
86/// ```
87/// # use stdx::anymap;
88#[doc = "let mut data = anymap::AnyMap::new();"]
89/// assert_eq!(data.get(), None::<&i32>);
90/// ```
91///
92/// Values containing non-static references are not permitted.
93#[derive(Debug)]
94pub struct Map<A: ?Sized + Downcast = dyn Any> {
95    raw: RawMap<A>,
96}
97
98/// The most common type of `Map`: just using `Any`; <code>[Map]&lt;dyn [Any]&gt;</code>.
99///
100/// Why is this a separate type alias rather than a default value for `Map<A>`?
101/// `Map::new()` doesn’t seem to be happy to infer that it should go with the default
102/// value. It’s a bit sad, really. Ah well, I guess this approach will do.
103pub type AnyMap = Map<dyn Any>;
104impl<A: ?Sized + Downcast> Default for Map<A> {
105    #[inline]
106    fn default() -> Map<A> {
107        Map::new()
108    }
109}
110
111impl<A: ?Sized + Downcast> Map<A> {
112    /// Create an empty collection.
113    #[inline]
114    pub fn new() -> Map<A> {
115        Map { raw: RawMap::with_hasher(Default::default()) }
116    }
117
118    /// Returns a reference to the value stored in the collection for the type `T`,
119    /// if it exists.
120    #[inline]
121    pub fn get<T: IntoBox<A>>(&self) -> Option<&T> {
122        self.raw.get(&TypeId::of::<T>()).map(|any| unsafe { any.downcast_ref_unchecked::<T>() })
123    }
124
125    /// Gets the entry for the given type in the collection for in-place manipulation
126    #[inline]
127    pub fn entry<T: IntoBox<A>>(&mut self) -> Entry<'_, A, T> {
128        match self.raw.entry(TypeId::of::<T>()) {
129            hash_map::Entry::Occupied(e) => {
130                Entry::Occupied(OccupiedEntry { inner: e, type_: PhantomData })
131            }
132            hash_map::Entry::Vacant(e) => {
133                Entry::Vacant(VacantEntry { inner: e, type_: PhantomData })
134            }
135        }
136    }
137}
138
139/// A view into a single occupied location in an `Map`.
140pub struct OccupiedEntry<'a, A: ?Sized + Downcast, V: 'a> {
141    inner: hash_map::OccupiedEntry<'a, TypeId, Box<A>>,
142    type_: PhantomData<V>,
143}
144
145/// A view into a single empty location in an `Map`.
146pub struct VacantEntry<'a, A: ?Sized + Downcast, V: 'a> {
147    inner: hash_map::VacantEntry<'a, TypeId, Box<A>>,
148    type_: PhantomData<V>,
149}
150
151/// A view into a single location in an `Map`, which may be vacant or occupied.
152pub enum Entry<'a, A: ?Sized + Downcast, V> {
153    /// An occupied Entry
154    Occupied(OccupiedEntry<'a, A, V>),
155    /// A vacant Entry
156    Vacant(VacantEntry<'a, A, V>),
157}
158
159impl<'a, A: ?Sized + Downcast, V: IntoBox<A>> Entry<'a, A, V> {
160    /// Ensures a value is in the entry by inserting the result of the default function if
161    /// empty, and returns a mutable reference to the value in the entry.
162    #[inline]
163    pub fn or_insert_with<F: FnOnce() -> V>(self, default: F) -> &'a mut V {
164        match self {
165            Entry::Occupied(inner) => inner.into_mut(),
166            Entry::Vacant(inner) => inner.insert(default()),
167        }
168    }
169}
170
171impl<'a, A: ?Sized + Downcast, V: IntoBox<A>> OccupiedEntry<'a, A, V> {
172    /// Converts the OccupiedEntry into a mutable reference to the value in the entry
173    /// with a lifetime bound to the collection itself
174    #[inline]
175    pub fn into_mut(self) -> &'a mut V {
176        unsafe { self.inner.into_mut().downcast_mut_unchecked() }
177    }
178}
179
180impl<'a, A: ?Sized + Downcast, V: IntoBox<A>> VacantEntry<'a, A, V> {
181    /// Sets the value of the entry with the VacantEntry's key,
182    /// and returns a mutable reference to it
183    #[inline]
184    pub fn insert(self, value: V) -> &'a mut V {
185        unsafe { self.inner.insert(value.into_box()).downcast_mut_unchecked() }
186    }
187}
188
189#[cfg(test)]
190mod tests {
191    use super::*;
192
193    #[test]
194    fn test_varieties() {
195        fn assert_send<T: Send>() {}
196        fn assert_sync<T: Sync>() {}
197        fn assert_debug<T: ::core::fmt::Debug>() {}
198        assert_send::<Map<dyn Any + Send>>();
199        assert_send::<Map<dyn Any + Send + Sync>>();
200        assert_sync::<Map<dyn Any + Send + Sync>>();
201        assert_debug::<Map<dyn Any>>();
202        assert_debug::<Map<dyn Any + Send>>();
203        assert_debug::<Map<dyn Any + Send + Sync>>();
204    }
205
206    #[test]
207    fn type_id_hasher() {
208        use core::any::TypeId;
209        use core::hash::Hash;
210        fn verify_hashing_with(type_id: TypeId) {
211            let mut hasher = TypeIdHasher::default();
212            type_id.hash(&mut hasher);
213            // SAFETY: u64 is valid for all bit patterns.
214            let _ = hasher.finish();
215        }
216        // Pick a variety of types, just to demonstrate it’s all sane. Normal, zero-sized, unsized, &c.
217        verify_hashing_with(TypeId::of::<usize>());
218        verify_hashing_with(TypeId::of::<()>());
219        verify_hashing_with(TypeId::of::<str>());
220        verify_hashing_with(TypeId::of::<&str>());
221        verify_hashing_with(TypeId::of::<Vec<u8>>());
222    }
223}
224
225/// Methods for downcasting from an `Any`-like trait object.
226///
227/// This should only be implemented on trait objects for subtraits of `Any`, though you can
228/// implement it for other types and it’ll work fine, so long as your implementation is correct.
229pub trait Downcast {
230    /// Gets the `TypeId` of `self`.
231    fn type_id(&self) -> TypeId;
232
233    // Note the bound through these downcast methods is 'static, rather than the inexpressible
234    // concept of Self-but-as-a-trait (where Self is `dyn Trait`). This is sufficient, exceeding
235    // TypeId’s requirements. Sure, you *can* do CloneAny.downcast_unchecked::<NotClone>() and the
236    // type system won’t protect you, but that doesn’t introduce any unsafety: the method is
237    // already unsafe because you can specify the wrong type, and if this were exposing safe
238    // downcasting, CloneAny.downcast::<NotClone>() would just return an error, which is just as
239    // correct.
240    //
241    // Now in theory we could also add T: ?Sized, but that doesn’t play nicely with the common
242    // implementation, so I’m doing without it.
243
244    /// Downcast from `&Any` to `&T`, without checking the type matches.
245    ///
246    /// # Safety
247    ///
248    /// The caller must ensure that `T` matches the trait object, on pain of *undefined behaviour*.
249    unsafe fn downcast_ref_unchecked<T: 'static>(&self) -> &T;
250
251    /// Downcast from `&mut Any` to `&mut T`, without checking the type matches.
252    ///
253    /// # Safety
254    ///
255    /// The caller must ensure that `T` matches the trait object, on pain of *undefined behaviour*.
256    unsafe fn downcast_mut_unchecked<T: 'static>(&mut self) -> &mut T;
257}
258
259/// A trait for the conversion of an object into a boxed trait object.
260pub trait IntoBox<A: ?Sized + Downcast>: Any {
261    /// Convert self into the appropriate boxed form.
262    fn into_box(self) -> Box<A>;
263}
264
265macro_rules! implement {
266    ($any_trait:ident $(+ $auto_traits:ident)*) => {
267        impl Downcast for dyn $any_trait $(+ $auto_traits)* {
268            #[inline]
269            fn type_id(&self) -> TypeId {
270                self.type_id()
271            }
272
273            #[inline]
274            unsafe fn downcast_ref_unchecked<T: 'static>(&self) -> &T {
275                unsafe { &*(self as *const Self as *const T) }
276            }
277
278            #[inline]
279            unsafe fn downcast_mut_unchecked<T: 'static>(&mut self) -> &mut T {
280                unsafe { &mut *(self as *mut Self as *mut T) }
281            }
282        }
283
284        impl<T: $any_trait $(+ $auto_traits)*> IntoBox<dyn $any_trait $(+ $auto_traits)*> for T {
285            #[inline]
286            fn into_box(self) -> Box<dyn $any_trait $(+ $auto_traits)*> {
287                Box::new(self)
288            }
289        }
290    }
291}
292
293implement!(Any);
294implement!(Any + Send);
295implement!(Any + Send + Sync);