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