1use super::{IdHashItem, IdHashMap, RefMut};
2use crate::{
3 DefaultHashBuilder,
4 support::{
5 ItemIndex,
6 alloc::{Allocator, Global},
7 map_hash::MapHash,
8 },
9};
10use core::{fmt, hash::BuildHasher};
11
12pub enum Entry<'a, T: IdHashItem, S = DefaultHashBuilder, A: Allocator = Global>
14{
15 Vacant(VacantEntry<'a, T, S, A>),
17 Occupied(OccupiedEntry<'a, T, S, A>),
19}
20
21impl<'a, T: IdHashItem, S, A: Allocator> fmt::Debug for Entry<'a, T, S, A> {
22 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
23 match self {
24 Entry::Vacant(entry) => {
25 f.debug_tuple("Vacant").field(entry).finish()
26 }
27 Entry::Occupied(entry) => {
28 f.debug_tuple("Occupied").field(entry).finish()
29 }
30 }
31 }
32}
33
34impl<'a, T: IdHashItem, S: Clone + BuildHasher, A: Allocator>
35 Entry<'a, T, S, A>
36{
37 #[inline]
45 pub fn or_insert(self, default: T) -> RefMut<'a, T, S> {
46 match self {
47 Entry::Occupied(entry) => entry.into_mut(),
48 Entry::Vacant(entry) => entry.insert(default),
49 }
50 }
51
52 #[inline]
61 pub fn or_insert_with<F: FnOnce() -> T>(
62 self,
63 default: F,
64 ) -> RefMut<'a, T, S> {
65 match self {
66 Entry::Occupied(entry) => entry.into_mut(),
67 Entry::Vacant(entry) => entry.insert(default()),
68 }
69 }
70
71 #[inline]
74 pub fn and_modify<F>(self, f: F) -> Self
75 where
76 F: FnOnce(RefMut<'_, T, S>),
77 {
78 match self {
79 Entry::Occupied(mut entry) => {
80 f(entry.get_mut());
81 Entry::Occupied(entry)
82 }
83 Entry::Vacant(entry) => Entry::Vacant(entry),
84 }
85 }
86}
87
88pub struct VacantEntry<
90 'a,
91 T: IdHashItem,
92 S = DefaultHashBuilder,
93 A: Allocator = Global,
94> {
95 map: &'a mut IdHashMap<T, S, A>,
96 hash: MapHash,
97}
98
99impl<'a, T: IdHashItem, S, A: Allocator> fmt::Debug
100 for VacantEntry<'a, T, S, A>
101{
102 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
103 f.debug_struct("VacantEntry")
104 .field("hash", &self.hash)
105 .finish_non_exhaustive()
106 }
107}
108
109impl<'a, T: IdHashItem, S: Clone + BuildHasher, A: Allocator>
110 VacantEntry<'a, T, S, A>
111{
112 pub(super) fn new(map: &'a mut IdHashMap<T, S, A>, hash: MapHash) -> Self {
113 VacantEntry { map, hash }
114 }
115
116 pub fn insert(self, value: T) -> RefMut<'a, T, S> {
119 let map = self.map;
120 let state = &map.tables.state;
121 if !self.hash.is_same_hash(state, value.key()) {
122 panic!("key hashes do not match");
123 }
124 let Ok(index) = map.insert_unique_impl(value) else {
125 panic!("key already present in map");
126 };
127 map.get_by_index_mut(index).expect("index is known to be valid")
128 }
129
130 #[inline]
136 pub(super) fn insert_known_unique(self, value: T) {
137 let map = self.map;
138 map.try_reserve_insert_overwrite_commit()
139 .expect("reserved space successfully");
140 let next_index = map.items.assert_can_grow().insert(value);
141 map.tables
142 .key_to_item
143 .insert_prehashed_unchecked(self.hash, next_index);
144 }
145
146 #[inline]
148 pub fn insert_entry(self, value: T) -> OccupiedEntry<'a, T, S, A> {
149 let state = &self.map.tables.state;
150 if !self.hash.is_same_hash(state, value.key()) {
151 panic!("key hashes do not match");
152 }
153 let Ok(index) = self.map.insert_unique_impl(value) else {
154 panic!("key already present in map");
155 };
156 OccupiedEntry::new(self.map, index)
157 }
158}
159
160pub struct OccupiedEntry<
163 'a,
164 T: IdHashItem,
165 S = DefaultHashBuilder,
166 A: Allocator = Global,
167> {
168 map: &'a mut IdHashMap<T, S, A>,
169 index: ItemIndex,
171}
172
173impl<'a, T: IdHashItem, S, A: Allocator> fmt::Debug
174 for OccupiedEntry<'a, T, S, A>
175{
176 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
177 f.debug_struct("OccupiedEntry")
178 .field("index", &self.index)
179 .finish_non_exhaustive()
180 }
181}
182
183impl<'a, T: IdHashItem, S: Clone + BuildHasher, A: Allocator>
184 OccupiedEntry<'a, T, S, A>
185{
186 pub(super) fn new(
187 map: &'a mut IdHashMap<T, S, A>,
188 index: ItemIndex,
189 ) -> Self {
190 OccupiedEntry { map, index }
191 }
192
193 pub fn get(&self) -> &T {
198 self.map.get_by_index(self.index).expect("index is known to be valid")
199 }
200
201 pub fn get_mut(&mut self) -> RefMut<'_, T, S> {
206 self.map
207 .get_by_index_mut(self.index)
208 .expect("index is known to be valid")
209 }
210
211 pub fn into_ref(self) -> &'a T {
216 self.map.get_by_index(self.index).expect("index is known to be valid")
217 }
218
219 pub fn into_mut(self) -> RefMut<'a, T, S> {
224 self.map
225 .get_by_index_mut(self.index)
226 .expect("index is known to be valid")
227 }
228
229 pub fn insert(&mut self, value: T) -> T {
235 self.map.replace_at_index(self.index, value)
237 }
238
239 pub fn remove(self) -> T {
241 self.map
242 .remove_by_index(self.index)
243 .expect("index is known to be valid")
244 }
245}