Skip to content

Commit e646424

Browse files
committed
Adapt some of hashbrown's raw entry docs as our own
1 parent 5c5d238 commit e646424

File tree

1 file changed

+136
-0
lines changed

1 file changed

+136
-0
lines changed

src/map/core/raw_entry_v1.rs

Lines changed: 136 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,9 +21,145 @@ use core::mem;
2121
/// See the [`raw_entry_v1`][self] module documentation for more information.
2222
pub trait RawEntryApiV1<K, V, S>: private::Sealed {
2323
/// Creates a raw immutable entry builder for the [`IndexMap`].
24+
///
25+
/// Raw entries provide the lowest level of control for searching and
26+
/// manipulating a map. They must be manually initialized with a hash and
27+
/// then manually searched.
28+
///
29+
/// This is useful for
30+
/// * Hash memoization
31+
/// * Using a search key that doesn't work with the [`Equivalent`] trait
32+
/// * Using custom comparison logic without newtype wrappers
33+
///
34+
/// Unless you are in such a situation, higher-level and more foolproof APIs like
35+
/// [`get`][IndexMap::get] should be preferred.
36+
///
37+
/// Immutable raw entries have very limited use; you might instead want
38+
/// [`raw_entry_mut_v1`][Self::raw_entry_mut_v1].
39+
///
40+
/// # Examples
41+
///
42+
/// ```
43+
/// use core::hash::{BuildHasher, Hash};
44+
/// use indexmap::map::{IndexMap, RawEntryApiV1};
45+
///
46+
/// let mut map = IndexMap::new();
47+
/// map.extend([("a", 100), ("b", 200), ("c", 300)]);
48+
///
49+
/// fn compute_hash<K: Hash + ?Sized, S: BuildHasher>(hash_builder: &S, key: &K) -> u64 {
50+
/// use core::hash::Hasher;
51+
/// let mut state = hash_builder.build_hasher();
52+
/// key.hash(&mut state);
53+
/// state.finish()
54+
/// }
55+
///
56+
/// for k in ["a", "b", "c", "d", "e", "f"] {
57+
/// let hash = compute_hash(map.hasher(), k);
58+
/// let v = map.get(k).cloned();
59+
/// let kv = v.as_ref().map(|v| (&k, v));
60+
///
61+
/// println!("Key: {} and value: {:?}", k, v);
62+
///
63+
/// assert_eq!(map.raw_entry_v1().from_key(k), kv);
64+
/// assert_eq!(map.raw_entry_v1().from_hash(hash, |q| *q == k), kv);
65+
/// assert_eq!(map.raw_entry_v1().from_key_hashed_nocheck(hash, k), kv);
66+
/// }
67+
/// ```
2468
fn raw_entry_v1(&self) -> RawEntryBuilder<'_, K, V, S>;
2569

2670
/// Creates a raw entry builder for the [`IndexMap`].
71+
///
72+
/// Raw entries provide the lowest level of control for searching and
73+
/// manipulating a map. They must be manually initialized with a hash and
74+
/// then manually searched. After this, insertions into a vacant entry
75+
/// still require an owned key to be provided.
76+
///
77+
/// Raw entries are useful for such exotic situations as:
78+
///
79+
/// * Hash memoization
80+
/// * Deferring the creation of an owned key until it is known to be required
81+
/// * Using a search key that doesn't work with the [`Equivalent`] trait
82+
/// * Using custom comparison logic without newtype wrappers
83+
///
84+
/// Because raw entries provide much more low-level control, it's much easier
85+
/// to put the `IndexMap` into an inconsistent state which, while memory-safe,
86+
/// will cause the map to produce seemingly random results. Higher-level and more
87+
/// foolproof APIs like [`entry`][IndexMap::entry] should be preferred when possible.
88+
///
89+
/// Raw entries give mutable access to the keys. This must not be used
90+
/// to modify how the key would compare or hash, as the map will not re-evaluate
91+
/// where the key should go, meaning the keys may become "lost" if their
92+
/// location does not reflect their state. For instance, if you change a key
93+
/// so that the map now contains keys which compare equal, search may start
94+
/// acting erratically, with two keys randomly masking each other. Implementations
95+
/// are free to assume this doesn't happen (within the limits of memory-safety).
96+
///
97+
/// # Examples
98+
///
99+
/// ```
100+
/// use core::hash::{BuildHasher, Hash};
101+
/// use indexmap::map::{IndexMap, RawEntryApiV1};
102+
/// use indexmap::map::raw_entry_v1::RawEntryMut;
103+
///
104+
/// let mut map = IndexMap::new();
105+
/// map.extend([("a", 100), ("b", 200), ("c", 300)]);
106+
///
107+
/// fn compute_hash<K: Hash + ?Sized, S: BuildHasher>(hash_builder: &S, key: &K) -> u64 {
108+
/// use core::hash::Hasher;
109+
/// let mut state = hash_builder.build_hasher();
110+
/// key.hash(&mut state);
111+
/// state.finish()
112+
/// }
113+
///
114+
/// // Existing key (insert and update)
115+
/// match map.raw_entry_mut_v1().from_key("a") {
116+
/// RawEntryMut::Vacant(_) => unreachable!(),
117+
/// RawEntryMut::Occupied(mut view) => {
118+
/// assert_eq!(view.get(), &100);
119+
/// let v = view.get_mut();
120+
/// let new_v = (*v) * 10;
121+
/// *v = new_v;
122+
/// assert_eq!(view.insert(1111), 1000);
123+
/// }
124+
/// }
125+
///
126+
/// assert_eq!(map["a"], 1111);
127+
/// assert_eq!(map.len(), 3);
128+
///
129+
/// // Existing key (take)
130+
/// let hash = compute_hash(map.hasher(), "c");
131+
/// match map.raw_entry_mut_v1().from_key_hashed_nocheck(hash, "c") {
132+
/// RawEntryMut::Vacant(_) => unreachable!(),
133+
/// RawEntryMut::Occupied(view) => {
134+
/// assert_eq!(view.shift_remove_entry(), ("c", 300));
135+
/// }
136+
/// }
137+
/// assert_eq!(map.raw_entry_v1().from_key("c"), None);
138+
/// assert_eq!(map.len(), 2);
139+
///
140+
/// // Nonexistent key (insert and update)
141+
/// let key = "d";
142+
/// let hash = compute_hash(map.hasher(), key);
143+
/// match map.raw_entry_mut_v1().from_hash(hash, |q| *q == key) {
144+
/// RawEntryMut::Occupied(_) => unreachable!(),
145+
/// RawEntryMut::Vacant(view) => {
146+
/// let (k, value) = view.insert("d", 4000);
147+
/// assert_eq!((*k, *value), ("d", 4000));
148+
/// *value = 40000;
149+
/// }
150+
/// }
151+
/// assert_eq!(map["d"], 40000);
152+
/// assert_eq!(map.len(), 3);
153+
///
154+
/// match map.raw_entry_mut_v1().from_hash(hash, |q| *q == key) {
155+
/// RawEntryMut::Vacant(_) => unreachable!(),
156+
/// RawEntryMut::Occupied(view) => {
157+
/// assert_eq!(view.swap_remove_entry(), ("d", 40000));
158+
/// }
159+
/// }
160+
/// assert_eq!(map.get("d"), None);
161+
/// assert_eq!(map.len(), 2);
162+
/// ```
27163
fn raw_entry_mut_v1(&mut self) -> RawEntryBuilderMut<'_, K, V, S>;
28164
}
29165

0 commit comments

Comments
 (0)