1use std::{hash::BuildHasher, ops::Deref};
2
3use dashmap::{
4 mapref::entry::{
5 Entry as DashEntry,
6 OccupiedEntry as DashOccupiedEntry,
7 VacantEntry as DashVacantEntry,
8 },
9 DashMap,
10};
11use sharded_slab::{Entry as SlabEntry, Slab};
12
13use crate::{Index, Key};
14
15pub enum Entry<'a, K: Key, V, S> {
17 Vacant(VacantEntry<'a, K, V, S>),
18 Occupied(OccupiedEntry<'a, K, V, S>),
19}
20
21pub struct VacantEntry<'a, K: Key, V, S> {
23 idxs: DashVacantEntry<'a, K, usize, S>,
24 slab: &'a Slab<V>,
25}
26
27pub struct OccupiedEntry<'a, K: Key, V, S> {
29 idxs_entry: DashOccupiedEntry<'a, K, usize, S>,
30 slab_entry: SlabEntry<'a, V>,
31}
32
33impl<'a, K: Key, V, S> Entry<'a, K, V, S>
34where
35 S: BuildHasher + Clone,
36{
37 pub(super) fn new(
39 key: K,
40 idxs: &'a DashMap<K, usize, S>,
41 slab: &'a Slab<V>,
42 ) -> Self {
43 match idxs.entry(key) {
44 | DashEntry::Vacant(e) => Self::Vacant(VacantEntry::new(e, slab)),
45 | DashEntry::Occupied(e) => {
46 let slab_entry = slab.get(*e.get()).expect(
47 "BUG: slab entries should always exists if the index \
48 exists in the index map",
49 );
50
51 Self::Occupied(OccupiedEntry::new(e, slab_entry))
52 }
53 }
54 }
55
56 #[inline]
59 pub fn or_try_insert(self, value: V) -> Option<Index<K, V>> {
60 match self {
61 | Self::Occupied(entry) => Some(entry.index()),
62 | Self::Vacant(entry) => entry.try_insert(value),
63 }
64 }
65
66 #[inline]
70 pub fn or_try_insert_with(
71 self,
72 f: impl FnOnce() -> V,
73 ) -> Option<Index<K, V>> {
74 match self {
75 | Self::Occupied(entry) => Some(entry.index()),
76 | Self::Vacant(entry) => entry.try_insert(f()),
77 }
78 }
79
80 #[inline]
83 pub fn or_try_insert_default(self) -> Option<Index<K, V>>
84 where
85 V: Default,
86 {
87 self.or_try_insert_with(V::default)
88 }
89}
90
91impl<'a, K: Key, V, S> VacantEntry<'a, K, V, S>
92where
93 S: BuildHasher + Clone,
94{
95 #[inline]
97 pub(super) const fn new(
98 idxs: DashVacantEntry<'a, K, usize, S>,
99 slab: &'a Slab<V>,
100 ) -> Self {
101 Self { idxs, slab }
102 }
103
104 #[inline]
107 pub fn try_insert(self, value: V) -> Option<Index<K, V>>
108 where
109 Self: 'a,
110 {
111 let idx = match self.slab.insert(value) {
112 | Some(slab_idx) => self.idxs.insert(slab_idx),
113 | None => return None,
114 };
115
116 Some(Index::new(*idx.key(), *idx.value()))
117 }
118
119 #[inline]
121 pub fn key(&self) -> &K {
122 self.idxs.key()
123 }
124}
125
126impl<'a, K: Key, V, S> OccupiedEntry<'a, K, V, S>
127where
128 S: BuildHasher + Clone,
129{
130 #[inline]
132 pub(super) const fn new(
133 idxs_entry: DashOccupiedEntry<'a, K, usize, S>,
134 slab_entry: SlabEntry<'a, V>,
135 ) -> Self {
136 Self {
137 idxs_entry,
138 slab_entry,
139 }
140 }
141
142 #[inline]
144 pub fn key(&self) -> &K {
145 self.idxs_entry.key()
146 }
147
148 #[inline]
150 pub fn offset(&self) -> usize {
151 *self.idxs_entry.get()
152 }
153
154 #[inline]
156 pub fn index(&self) -> Index<K, V> {
157 Index::new(*self.idxs_entry.key(), *self.idxs_entry.get())
158 }
159
160 #[inline]
162 pub fn get(&self) -> &V {
163 self.slab_entry.deref()
164 }
165
166 #[inline]
173 pub unsafe fn unlink(self) -> usize {
174 self.idxs_entry.remove()
175 }
176}