Skip to main content

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;