1use super::{IdHashItem, IdHashMap, RefMut};
2use crate::{
3 DefaultHashBuilder,
4 support::{
5 ItemIndex,
6 alloc::{Allocator, Global},
7 borrow::DormantMutRef,
8 map_hash::MapHash,
9 },
10};
11use core::{fmt, hash::BuildHasher};
12
13pub enum Entry<'a, T: IdHashItem, S = DefaultHashBuilder, A: Allocator = Global>
15{
16 Vacant(VacantEntry<'a, T, S, A>),
18 Occupied(OccupiedEntry<'a, T, S, A>),
20}
21
22impl<'a, T: IdHashItem, S, A: Allocator> fmt::Debug for Entry<'a, T, S, A> {
23 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
24 match self {
25 Entry::Vacant(entry) => {
26 f.debug_tuple("Vacant").field(entry).finish()
27 }
28 Entry::Occupied(entry) => {
29 f.debug_tuple("Occupied").field(entry).finish()
30 }
31 }
32 }
33}
34
35impl<'a, T: IdHashItem, S: Clone + BuildHasher, A: Allocator>
36 Entry<'a, T, S, A>
37{
38 #[inline]
46 pub fn or_insert(self, default: T) -> RefMut<'a, T, S> {
47 match self {
48 Entry::Occupied(entry) => entry.into_mut(),
49 Entry::Vacant(entry) => entry.insert(default),
50 }
51 }
52
53 #[inline]
62 pub fn or_insert_with<F: FnOnce() -> T>(
63 self,
64 default: F,
65 ) -> RefMut<'a, T, S> {
66 match self {
67 Entry::Occupied(entry) => entry.into_mut(),
68 Entry::Vacant(entry) => entry.insert(default()),
69 }
70 }
71
72 #[inline]
75 pub fn and_modify<F>(self, f: F) -> Self
76 where
77 F: FnOnce(RefMut<'_, T, S>),
78 {
79 match self {
80 Entry::Occupied(mut entry) => {
81 f(entry.get_mut());
82 Entry::Occupied(entry)
83 }
84 Entry::Vacant(entry) => Entry::Vacant(entry),
85 }
86 }
87}
88
89pub struct VacantEntry<
91 'a,
92 T: IdHashItem,
93 S = DefaultHashBuilder,
94 A: Allocator = Global,
95> {
96 map: DormantMutRef<'a, IdHashMap<T, S, A>>,
97 hash: MapHash,
98}
99
100impl<'a, T: IdHashItem, S, A: Allocator> fmt::Debug
101 for VacantEntry<'a, T, S, A>
102{
103 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
104 f.debug_struct("VacantEntry")
105 .field("hash", &self.hash)
106 .finish_non_exhaustive()
107 }
108}
109
110impl<'a, T: IdHashItem, S: Clone + BuildHasher, A: Allocator>
111 VacantEntry<'a, T, S, A>
112{
113 pub(super) unsafe fn new(
114 map: DormantMutRef<'a, IdHashMap<T, S, A>>,
115 hash: MapHash,
116 ) -> Self {
117 VacantEntry { map, hash }
118 }
119
120 pub fn insert(self, value: T) -> RefMut<'a, T, S> {
123 let map = unsafe { self.map.awaken() };
126 let state = &map.tables.state;
127 if !self.hash.is_same_hash(state, value.key()) {
128 panic!("key hashes do not match");
129 }
130 let Ok(index) = map.insert_unique_impl(value) else {
131 panic!("key already present in map");
132 };
133 map.get_by_index_mut(index).expect("index is known to be valid")
134 }
135
136 #[inline]
138 pub fn insert_entry(mut self, value: T) -> OccupiedEntry<'a, T, S, A> {
139 let index = {
140 let map = unsafe { self.map.reborrow() };
143 let state = &map.tables.state;
144 if !self.hash.is_same_hash(state, value.key()) {
145 panic!("key hashes do not match");
146 }
147 let Ok(index) = map.insert_unique_impl(value) else {
148 panic!("key already present in map");
149 };
150 index
151 };
152
153 unsafe { OccupiedEntry::new(self.map, index) }
156 }
157}
158
159pub struct OccupiedEntry<
162 'a,
163 T: IdHashItem,
164 S = DefaultHashBuilder,
165 A: Allocator = Global,
166> {
167 map: DormantMutRef<'a, IdHashMap<T, S, A>>,
168 index: ItemIndex,
170}
171
172impl<'a, T: IdHashItem, S, A: Allocator> fmt::Debug
173 for OccupiedEntry<'a, T, S, A>
174{
175 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
176 f.debug_struct("OccupiedEntry")
177 .field("index", &self.index)
178 .finish_non_exhaustive()
179 }
180}
181
182impl<'a, T: IdHashItem, S: Clone + BuildHasher, A: Allocator>
183 OccupiedEntry<'a, T, S, A>
184{
185 pub(super) unsafe fn new(
190 map: DormantMutRef<'a, IdHashMap<T, S, A>>,
191 index: ItemIndex,
192 ) -> Self {
193 OccupiedEntry { map, index }
194 }
195
196 pub fn get(&self) -> &T {
201 unsafe { self.map.reborrow_shared() }
204 .get_by_index(self.index)
205 .expect("index is known to be valid")
206 }
207
208 pub fn get_mut(&mut self) -> RefMut<'_, T, S> {
213 unsafe { self.map.reborrow() }
216 .get_by_index_mut(self.index)
217 .expect("index is known to be valid")
218 }
219
220 pub fn into_ref(self) -> &'a T {
225 unsafe { self.map.awaken() }
228 .get_by_index(self.index)
229 .expect("index is known to be valid")
230 }
231
232 pub fn into_mut(self) -> RefMut<'a, T, S> {
237 unsafe { self.map.awaken() }
240 .get_by_index_mut(self.index)
241 .expect("index is known to be valid")
242 }
243
244 pub fn insert(&mut self, value: T) -> T {
250 unsafe { self.map.reborrow() }.replace_at_index(self.index, value)
255 }
256
257 pub fn remove(mut self) -> T {
259 unsafe { self.map.reborrow() }
262 .remove_by_index(self.index)
263 .expect("index is known to be valid")
264 }
265}