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