ringmap/
lib.rs

1// We *mostly* avoid unsafe code, but `Slice` allows it for DST casting.
2#![deny(unsafe_code)]
3#![warn(rust_2018_idioms)]
4#![no_std]
5
6//! [`RingMap`] is a hash table where the iteration order of the key-value pairs is
7//! independent of the hash values of the keys. Entries are stored in a ring buffer
8//! (`VecDeque`), allowing efficient manipulation of both the front and back ends.
9//!
10//! [`RingSet`] is a corresponding hash set using the same implementation and
11//! with similar properties.
12//!
13//! ### Highlights
14//!
15//! [`RingMap`] and [`RingSet`] are nearly drop-in compatible with the std `HashMap`
16//! and `HashSet`, but they also have some features of note:
17//!
18//! - The ordering semantics (see their documentation for details)
19//! - Sorting methods and the [`.pop_back()`][RingMap::pop_back] and
20//!   [`.pop_front()`][RingMap::pop_front] methods.
21//! - The [`Equivalent`] trait, which offers more flexible equality definitions
22//!   between borrowed and owned versions of keys.
23//! - The [`MutableKeys`][map::MutableKeys] trait, which gives opt-in mutable
24//!   access to map keys, and [`MutableValues`][set::MutableValues] for sets.
25//!
26//! ### Feature Flags
27//!
28//! To reduce the amount of compiled code in the crate by default, certain
29//! features are gated behind [feature flags]. These allow you to opt in to (or
30//! out of) functionality. Below is a list of the features available in this
31//! crate.
32//!
33//! * `std`: Enables features which require the Rust standard library. For more
34//!   information see the section on [`no_std`].
35//! * `rayon`: Enables parallel iteration and other parallel methods.
36//! * `serde`: Adds implementations for [`Serialize`] and [`Deserialize`]
37//!   to [`RingMap`] and [`RingSet`]. Alternative implementations for
38//!   (de)serializing [`RingMap`] as an ordered sequence are available in the
39//!   [`map::serde_seq`] module.
40//! * `borsh`: Adds implementations for [`BorshSerialize`] and [`BorshDeserialize`]
41//!   to [`RingMap`] and [`RingSet`].
42//! * `arbitrary`: Adds implementations for the [`arbitrary::Arbitrary`] trait
43//!   to [`RingMap`] and [`RingSet`].
44//! * `quickcheck`: Adds implementations for the [`quickcheck::Arbitrary`] trait
45//!   to [`RingMap`] and [`RingSet`].
46//!
47//! _Note: only the `std` feature is enabled by default._
48//!
49//! [feature flags]: https://doc.rust-lang.org/cargo/reference/manifest.html#the-features-section
50//! [`no_std`]: #no-standard-library-targets
51//! [`Serialize`]: `::serde::Serialize`
52//! [`Deserialize`]: `::serde::Deserialize`
53//! [`BorshSerialize`]: `::borsh::BorshSerialize`
54//! [`BorshDeserialize`]: `::borsh::BorshDeserialize`
55//! [`arbitrary::Arbitrary`]: `::arbitrary::Arbitrary`
56//! [`quickcheck::Arbitrary`]: `::quickcheck::Arbitrary`
57//!
58//! ### Alternate Hashers
59//!
60//! [`RingMap`] and [`RingSet`] have a default hasher type
61//! [`S = RandomState`][std::collections::hash_map::RandomState],
62//! just like the standard `HashMap` and `HashSet`, which is resistant to
63//! HashDoS attacks but not the most performant. Type aliases can make it easier
64//! to use alternate hashers:
65//!
66//! ```
67//! use fnv::FnvBuildHasher;
68//! use ringmap::{RingMap, RingSet};
69//!
70//! type FnvRingMap<K, V> = RingMap<K, V, FnvBuildHasher>;
71//! type FnvRingSet<T> = RingSet<T, FnvBuildHasher>;
72//!
73//! let std: RingSet<i32> = (0..100).collect();
74//! let fnv: FnvRingSet<i32> = (0..100).collect();
75//! assert_eq!(std, fnv);
76//! ```
77//!
78//! ### Rust Version
79//!
80//! This version of ringmap requires Rust 1.68 or later.
81//!
82//! The ringmap 0.1 release series will use a carefully considered version
83//! upgrade policy, where in a later 0.x version, we will raise the minimum
84//! required Rust version.
85//!
86//! ## No Standard Library Targets
87//!
88//! This crate supports being built without `std`, requiring `alloc` instead.
89//! This is chosen by disabling the default "std" cargo feature, by adding
90//! `default-features = false` to your dependency specification.
91//!
92//! - Creating maps and sets using [`new`][RingMap::new] and
93//!   [`with_capacity`][RingMap::with_capacity] is unavailable without `std`.
94//!   Use methods [`RingMap::default`], [`with_hasher`][RingMap::with_hasher],
95//!   [`with_capacity_and_hasher`][RingMap::with_capacity_and_hasher] instead.
96//!   A no-std compatible hasher will be needed as well, for example
97//!   from the crate `twox-hash`.
98//! - Macros [`ringmap!`] and [`ringset!`] are unavailable without `std`. Use
99//!   the macros [`ringmap_with_default!`] and [`ringset_with_default!`] instead.
100
101#![cfg_attr(docsrs, feature(doc_cfg))]
102
103extern crate alloc;
104
105#[cfg(feature = "std")]
106#[macro_use]
107extern crate std;
108
109mod arbitrary;
110#[macro_use]
111mod macros;
112#[cfg(feature = "borsh")]
113mod borsh;
114#[cfg(feature = "serde")]
115mod serde;
116mod util;
117
118pub mod map;
119pub mod set;
120
121// Placed after `map` and `set` so new `rayon` methods on the types
122// are documented after the "normal" methods.
123#[cfg(feature = "rayon")]
124mod rayon;
125
126pub use crate::map::RingMap;
127pub use crate::set::RingSet;
128pub use equivalent::Equivalent;
129
130// shared private items
131
132/// Hash value newtype. Not larger than usize, since anything larger
133/// isn't used for selecting position anyway.
134#[derive(Clone, Copy, Debug, PartialEq)]
135struct HashValue(usize);
136
137impl HashValue {
138    #[inline(always)]
139    fn get(self) -> u64 {
140        self.0 as u64
141    }
142}
143
144#[derive(Copy, Debug)]
145struct Bucket<K, V> {
146    hash: HashValue,
147    key: K,
148    value: V,
149}
150
151impl<K, V> Clone for Bucket<K, V>
152where
153    K: Clone,
154    V: Clone,
155{
156    fn clone(&self) -> Self {
157        Bucket {
158            hash: self.hash,
159            key: self.key.clone(),
160            value: self.value.clone(),
161        }
162    }
163
164    fn clone_from(&mut self, other: &Self) {
165        self.hash = other.hash;
166        self.key.clone_from(&other.key);
167        self.value.clone_from(&other.value);
168    }
169}
170
171impl<K, V> Bucket<K, V> {
172    // field accessors -- used for `f` instead of closures in `.map(f)`
173    fn key_ref(&self) -> &K {
174        &self.key
175    }
176    fn value_ref(&self) -> &V {
177        &self.value
178    }
179    fn value_mut(&mut self) -> &mut V {
180        &mut self.value
181    }
182    fn key(self) -> K {
183        self.key
184    }
185    fn value(self) -> V {
186        self.value
187    }
188    fn key_value(self) -> (K, V) {
189        (self.key, self.value)
190    }
191    fn refs(&self) -> (&K, &V) {
192        (&self.key, &self.value)
193    }
194    fn ref_mut(&mut self) -> (&K, &mut V) {
195        (&self.key, &mut self.value)
196    }
197    fn muts(&mut self) -> (&mut K, &mut V) {
198        (&mut self.key, &mut self.value)
199    }
200}
201
202/// The error type for [`try_reserve`][RingMap::try_reserve] methods.
203#[derive(Clone, PartialEq, Eq, Debug)]
204pub struct TryReserveError {
205    kind: TryReserveErrorKind,
206}
207
208#[derive(Clone, PartialEq, Eq, Debug)]
209enum TryReserveErrorKind {
210    // The standard library's kind is currently opaque to us, otherwise we could unify this.
211    Std(alloc::collections::TryReserveError),
212    CapacityOverflow,
213    AllocError { layout: alloc::alloc::Layout },
214}
215
216// These are not `From` so we don't expose them in our public API.
217impl TryReserveError {
218    fn from_alloc(error: alloc::collections::TryReserveError) -> Self {
219        Self {
220            kind: TryReserveErrorKind::Std(error),
221        }
222    }
223
224    fn from_hashbrown(error: hashbrown::TryReserveError) -> Self {
225        Self {
226            kind: match error {
227                hashbrown::TryReserveError::CapacityOverflow => {
228                    TryReserveErrorKind::CapacityOverflow
229                }
230                hashbrown::TryReserveError::AllocError { layout } => {
231                    TryReserveErrorKind::AllocError { layout }
232                }
233            },
234        }
235    }
236}
237
238impl core::fmt::Display for TryReserveError {
239    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
240        let reason = match &self.kind {
241            TryReserveErrorKind::Std(e) => return core::fmt::Display::fmt(e, f),
242            TryReserveErrorKind::CapacityOverflow => {
243                " because the computed capacity exceeded the collection's maximum"
244            }
245            TryReserveErrorKind::AllocError { .. } => {
246                " because the memory allocator returned an error"
247            }
248        };
249        f.write_str("memory allocation failed")?;
250        f.write_str(reason)
251    }
252}
253
254#[cfg(feature = "std")]
255#[cfg_attr(docsrs, doc(cfg(feature = "std")))]
256impl std::error::Error for TryReserveError {}
257
258// NOTE: This is copied from the slice module in the std lib.
259/// The error type returned by [`get_disjoint_indices_mut`][`RingMap::get_disjoint_indices_mut`].
260///
261/// It indicates one of two possible errors:
262/// - An index is out-of-bounds.
263/// - The same index appeared multiple times in the array.
264//    (or different but overlapping indices when ranges are provided)
265#[derive(Debug, Clone, PartialEq, Eq)]
266pub enum GetDisjointMutError {
267    /// An index provided was out-of-bounds for the slice.
268    IndexOutOfBounds,
269    /// Two indices provided were overlapping.
270    OverlappingIndices,
271}
272
273impl core::fmt::Display for GetDisjointMutError {
274    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
275        let msg = match self {
276            GetDisjointMutError::IndexOutOfBounds => "an index is out of bounds",
277            GetDisjointMutError::OverlappingIndices => "there were overlapping indices",
278        };
279
280        core::fmt::Display::fmt(msg, f)
281    }
282}
283
284#[cfg(feature = "std")]
285#[cfg_attr(docsrs, doc(cfg(feature = "std")))]
286impl std::error::Error for GetDisjointMutError {}