Unnamed repository; edit this file 'description' to name the repository.
Diffstat (limited to 'crates/stdx/src/anymap.rs')
| -rw-r--r-- | crates/stdx/src/anymap.rs | 104 |
1 files changed, 51 insertions, 53 deletions
diff --git a/crates/stdx/src/anymap.rs b/crates/stdx/src/anymap.rs index faf2e6c717..a3f6ab8951 100644 --- a/crates/stdx/src/anymap.rs +++ b/crates/stdx/src/anymap.rs @@ -1,4 +1,5 @@ //! 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. +//! //! Copyright © 2014–2022 Chris Morgan. //! COPYING: <https://github.com/chris-morgan/anymap/blob/master/COPYING> //! 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 @@ -20,14 +21,14 @@ use core::hash::Hasher; -/// A hasher designed to eke a little more speed out, given `TypeId`’s known characteristics. +/// A hasher designed to eke a little more speed out, given `TypeId`'s known characteristics. /// -/// Specifically, this is a no-op hasher that expects to be fed a u64’s worth of +/// Specifically, this is a no-op hasher that expects to be fed a u64's worth of /// randomly-distributed bits. It works well for `TypeId` (eliminating start-up time, so that my -/// get_missing benchmark is ~30ns rather than ~900ns, and being a good deal faster after that, so -/// that my insert_and_get_on_260_types benchmark is ~12μs instead of ~21.5μs), but will +/// `get_missing` benchmark is ~30ns rather than ~900ns, and being a good deal faster after that, so +/// that my `insert_and_get_on_260_types` benchmark is ~12μs instead of ~21.5μs), but will /// panic in debug mode and always emit zeros in release mode for any other sorts of inputs, so -/// yeah, don’t use it! 😀 +/// yeah, don't use it! 😀 #[derive(Default)] pub struct TypeIdHasher { value: u64, @@ -36,9 +37,9 @@ pub struct TypeIdHasher { impl Hasher for TypeIdHasher { #[inline] fn write(&mut self, bytes: &[u8]) { - // This expects to receive exactly one 64-bit value, and there’s no realistic chance of - // that changing, but I don’t want to depend on something that isn’t expressly part of the - // contract for safety. But I’m OK with release builds putting everything in one bucket + // This expects to receive exactly one 64-bit value, and there's no realistic chance of + // that changing, but I don't want to depend on something that isn't expressly part of the + // contract for safety. But I'm OK with release builds putting everything in one bucket // if it *did* change (and debug builds panicking). debug_assert_eq!(bytes.len(), 8); let _ = bytes.try_into().map(|array| self.value = u64::from_ne_bytes(array)); @@ -59,7 +60,7 @@ use ::std::collections::hash_map; /// Raw access to the underlying `HashMap`. /// /// This alias is provided for convenience because of the ugly third generic parameter. -#[allow(clippy::disallowed_types)] // Uses a custom hasher +#[expect(clippy::disallowed_types, reason = "Uses a custom hasher")] pub type RawMap<A> = hash_map::HashMap<TypeId, Box<A>, BuildHasherDefault<TypeIdHasher>>; /// A collection containing zero or one values for any given type and allowing convenient, @@ -73,19 +74,20 @@ pub type RawMap<A> = hash_map::HashMap<TypeId, Box<A>, BuildHasherDefault<TypeId /// /// Cumulatively, there are thus six forms of map: /// -/// - <code>[Map]<dyn [core::any::Any]></code>, +/// - `[Map]<dyn [core::any::Any]>`, /// also spelled [`AnyMap`] for convenience. -/// - <code>[Map]<dyn [core::any::Any] + Send></code> -/// - <code>[Map]<dyn [core::any::Any] + Send + Sync></code> +/// - `[Map]<dyn [core::any::Any] + Send>` +/// - `[Map]<dyn [core::any::Any] + Send + Sync>` /// /// ## Example /// -/// (Here using the [`AnyMap`] convenience alias; the first line could use -/// <code>[anymap::Map][Map]::<[core::any::Any]>::new()</code> instead if desired.) +/// (Here, the [`AnyMap`] convenience alias is used; +/// the first line could use `[anymap::Map][Map]::<[core::any::Any]>::default()` +/// instead if desired.) /// /// ``` /// # use stdx::anymap; -#[doc = "let mut data = anymap::AnyMap::new();"] +/// let mut data = anymap::AnyMap::default(); /// assert_eq!(data.get(), None::<&i32>); /// ``` /// @@ -95,29 +97,25 @@ pub struct Map<A: ?Sized + Downcast = dyn Any> { raw: RawMap<A>, } -/// The most common type of `Map`: just using `Any`; <code>[Map]<dyn [Any]></code>. +/// The most common type of `Map`: just using `Any`; `[Map]<dyn [Any]>`. /// /// Why is this a separate type alias rather than a default value for `Map<A>`? -/// `Map::new()` doesn’t seem to be happy to infer that it should go with the default -/// value. It’s a bit sad, really. Ah well, I guess this approach will do. +/// `Map::default()` doesn't seem to be happy to infer that it should go with the default +/// value. It's a bit sad, really. Ah well, I guess this approach will do. pub type AnyMap = Map<dyn Any>; + impl<A: ?Sized + Downcast> Default for Map<A> { #[inline] fn default() -> Map<A> { - Map::new() + Map { raw: RawMap::with_hasher(Default::default()) } } } impl<A: ?Sized + Downcast> Map<A> { - /// Create an empty collection. - #[inline] - pub fn new() -> Map<A> { - Map { raw: RawMap::with_hasher(Default::default()) } - } - /// Returns a reference to the value stored in the collection for the type `T`, /// if it exists. #[inline] + #[must_use] pub fn get<T: IntoBox<A>>(&self) -> Option<&T> { self.raw.get(&TypeId::of::<T>()).map(|any| unsafe { any.downcast_ref_unchecked::<T>() }) } @@ -137,30 +135,30 @@ impl<A: ?Sized + Downcast> Map<A> { } /// A view into a single occupied location in an `Map`. -pub struct OccupiedEntry<'a, A: ?Sized + Downcast, V: 'a> { - inner: hash_map::OccupiedEntry<'a, TypeId, Box<A>>, +pub struct OccupiedEntry<'map, A: ?Sized + Downcast, V: 'map> { + inner: hash_map::OccupiedEntry<'map, TypeId, Box<A>>, type_: PhantomData<V>, } /// A view into a single empty location in an `Map`. -pub struct VacantEntry<'a, A: ?Sized + Downcast, V: 'a> { - inner: hash_map::VacantEntry<'a, TypeId, Box<A>>, +pub struct VacantEntry<'map, A: ?Sized + Downcast, V: 'map> { + inner: hash_map::VacantEntry<'map, TypeId, Box<A>>, type_: PhantomData<V>, } /// A view into a single location in an `Map`, which may be vacant or occupied. -pub enum Entry<'a, A: ?Sized + Downcast, V> { +pub enum Entry<'map, A: ?Sized + Downcast, V> { /// An occupied Entry - Occupied(OccupiedEntry<'a, A, V>), + Occupied(OccupiedEntry<'map, A, V>), /// A vacant Entry - Vacant(VacantEntry<'a, A, V>), + Vacant(VacantEntry<'map, A, V>), } -impl<'a, A: ?Sized + Downcast, V: IntoBox<A>> Entry<'a, A, V> { +impl<'map, A: ?Sized + Downcast, V: IntoBox<A>> Entry<'map, A, V> { /// Ensures a value is in the entry by inserting the result of the default function if /// empty, and returns a mutable reference to the value in the entry. #[inline] - pub fn or_insert_with<F: FnOnce() -> V>(self, default: F) -> &'a mut V { + pub fn or_insert_with<F: FnOnce() -> V>(self, default: F) -> &'map mut V { match self { Entry::Occupied(inner) => inner.into_mut(), Entry::Vacant(inner) => inner.insert(default()), @@ -168,20 +166,21 @@ impl<'a, A: ?Sized + Downcast, V: IntoBox<A>> Entry<'a, A, V> { } } -impl<'a, A: ?Sized + Downcast, V: IntoBox<A>> OccupiedEntry<'a, A, V> { - /// Converts the OccupiedEntry into a mutable reference to the value in the entry +impl<'map, A: ?Sized + Downcast, V: IntoBox<A>> OccupiedEntry<'map, A, V> { + /// Converts the `OccupiedEntry` into a mutable reference to the value in the entry /// with a lifetime bound to the collection itself #[inline] - pub fn into_mut(self) -> &'a mut V { + #[must_use] + pub fn into_mut(self) -> &'map mut V { unsafe { self.inner.into_mut().downcast_mut_unchecked() } } } -impl<'a, A: ?Sized + Downcast, V: IntoBox<A>> VacantEntry<'a, A, V> { - /// Sets the value of the entry with the VacantEntry's key, +impl<'map, A: ?Sized + Downcast, V: IntoBox<A>> VacantEntry<'map, A, V> { + /// Sets the value of the entry with the `VacantEntry`'s key, /// and returns a mutable reference to it #[inline] - pub fn insert(self, value: V) -> &'a mut V { + pub fn insert(self, value: V) -> &'map mut V { unsafe { self.inner.insert(value.into_box()).downcast_mut_unchecked() } } } @@ -206,14 +205,13 @@ mod tests { #[test] fn type_id_hasher() { use core::any::TypeId; - use core::hash::Hash; + use core::hash::Hash as _; fn verify_hashing_with(type_id: TypeId) { let mut hasher = TypeIdHasher::default(); type_id.hash(&mut hasher); - // SAFETY: u64 is valid for all bit patterns. - let _ = hasher.finish(); + _ = hasher.finish(); } - // Pick a variety of types, just to demonstrate it’s all sane. Normal, zero-sized, unsized, &c. + // Pick a variety of types, just to demonstrate it's all sane. Normal, zero-sized, unsized, &c. verify_hashing_with(TypeId::of::<usize>()); verify_hashing_with(TypeId::of::<()>()); verify_hashing_with(TypeId::of::<str>()); @@ -225,34 +223,34 @@ mod tests { /// Methods for downcasting from an `Any`-like trait object. /// /// This should only be implemented on trait objects for subtraits of `Any`, though you can -/// implement it for other types and it’ll work fine, so long as your implementation is correct. +/// implement it for other types and it'll work fine, so long as your implementation is correct. pub trait Downcast { /// Gets the `TypeId` of `self`. fn type_id(&self) -> TypeId; // Note the bound through these downcast methods is 'static, rather than the inexpressible // concept of Self-but-as-a-trait (where Self is `dyn Trait`). This is sufficient, exceeding - // TypeId’s requirements. Sure, you *can* do CloneAny.downcast_unchecked::<NotClone>() and the - // type system won’t protect you, but that doesn’t introduce any unsafety: the method is + // TypeId's requirements. Sure, you *can* do CloneAny.downcast_unchecked::<NotClone>() and the + // type system won't protect you, but that doesn't introduce any unsafety: the method is // already unsafe because you can specify the wrong type, and if this were exposing safe // downcasting, CloneAny.downcast::<NotClone>() would just return an error, which is just as // correct. // - // Now in theory we could also add T: ?Sized, but that doesn’t play nicely with the common - // implementation, so I’m doing without it. + // Now in theory we could also add T: ?Sized, but that doesn't play nicely with the common + // implementation, so I'm doing without it. /// Downcast from `&Any` to `&T`, without checking the type matches. /// /// # Safety /// - /// The caller must ensure that `T` matches the trait object, on pain of *undefined behaviour*. + /// The caller must ensure that `T` matches the trait object, on pain of *undefined behavior*. unsafe fn downcast_ref_unchecked<T: 'static>(&self) -> &T; /// Downcast from `&mut Any` to `&mut T`, without checking the type matches. /// /// # Safety /// - /// The caller must ensure that `T` matches the trait object, on pain of *undefined behaviour*. + /// The caller must ensure that `T` matches the trait object, on pain of *undefined behavior*. unsafe fn downcast_mut_unchecked<T: 'static>(&mut self) -> &mut T; } @@ -272,12 +270,12 @@ macro_rules! implement { #[inline] unsafe fn downcast_ref_unchecked<T: 'static>(&self) -> &T { - unsafe { &*(self as *const Self as *const T) } + unsafe { &*std::ptr::from_ref::<Self>(self).cast::<T>() } } #[inline] unsafe fn downcast_mut_unchecked<T: 'static>(&mut self) -> &mut T { - unsafe { &mut *(self as *mut Self as *mut T) } + unsafe { &mut *std::ptr::from_mut::<Self>(self).cast::<T>() } } } |