1use super::*;
2
3use core::fmt::Debug;
4use core::hash::Hash;
5
6#[derive(Clone, Debug)]
9pub struct TagLockGuard<T>
10where
11 T: Hash + Eq + Clone + Debug,
12{
13 inner: Arc<TagLockGuardInner<T>>,
14}
15
16impl<T> TagLockGuard<T>
17where
18 T: Hash + Eq + Clone + Debug,
19{
20 #[must_use]
22 pub fn tag(&self) -> T {
23 self.inner.tag()
24 }
25}
26
27struct TagLockGuardInner<T>
28where
29 T: Hash + Eq + Clone + Debug,
30{
31 table: TagLockTable<T>,
32 tag: T,
33 guard: Option<ArcMutexGuard<RawMutex, ()>>,
34}
35
36impl<T> fmt::Debug for TagLockGuardInner<T>
37where
38 T: Hash + Eq + Clone + Debug,
39{
40 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
41 f.debug_struct("TagLockGuardInner")
42 .field("tag", &self.tag)
43 .finish()
44 }
45}
46
47impl<T> TagLockGuardInner<T>
48where
49 T: Hash + Eq + Clone + Debug,
50{
51 fn new(table: TagLockTable<T>, tag: T, guard: ArcMutexGuard<RawMutex, ()>) -> Self {
52 Self {
53 table,
54 tag,
55 guard: Some(guard),
56 }
57 }
58
59 fn tag(&self) -> T {
60 self.tag.clone()
61 }
62}
63
64impl<T> Drop for TagLockGuardInner<T>
65where
66 T: Hash + Eq + Clone + Debug,
67{
68 fn drop(&mut self) {
69 let mut inner = self.table.inner.lock();
70 let guards = {
72 let entry = inner.table.get_mut(&self.tag).unwrap_or_log();
74 entry.guards -= 1;
76 entry.guards
78 };
79 if guards == 0 {
81 inner.table.remove(&self.tag).unwrap_or_log();
82 }
83 drop(self.guard.take());
85 }
86}
87
88#[derive(Clone, Debug)]
89struct TagLockTableEntry {
90 mutex: Arc<Mutex<()>>,
91 guards: usize,
92}
93
94struct TagLockTableInner<T>
95where
96 T: Hash + Eq + Clone + Debug,
97{
98 table: HashMap<T, TagLockTableEntry>,
99}
100
101#[derive(Clone)]
105pub struct TagLockTable<T>
106where
107 T: Hash + Eq + Clone + Debug,
108{
109 inner: Arc<Mutex<TagLockTableInner<T>>>,
110}
111
112impl<T> fmt::Debug for TagLockTable<T>
113where
114 T: Hash + Eq + Clone + Debug,
115{
116 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
117 f.debug_struct("TagLockTable").finish()
118 }
119}
120
121impl<T> TagLockTable<T>
122where
123 T: Hash + Eq + Clone + Debug,
124{
125 #[must_use]
127 pub fn new() -> Self {
128 Self {
129 inner: Arc::new(Mutex::new(TagLockTableInner {
130 table: HashMap::new(),
131 })),
132 }
133 }
134
135 #[must_use]
137 pub fn is_empty(&self) -> bool {
138 let inner = self.inner.lock();
139 inner.table.is_empty()
140 }
141
142 #[must_use]
144 pub fn len(&self) -> usize {
145 let inner = self.inner.lock();
146 inner.table.len()
147 }
148
149 pub fn lock_tag(&self, tag: T) -> TagLockGuard<T> {
153 let mutex = {
155 let mut inner = self.inner.lock();
156
157 let entry = inner
160 .table
161 .entry(tag.clone())
162 .or_insert_with(|| TagLockTableEntry {
163 mutex: Arc::new(Mutex::new(())),
164 guards: 0,
165 });
166
167 entry.guards += 1;
169
170 entry.mutex.clone()
172
173 };
175
176 let guard = mutex.lock_arc();
178
179 TagLockGuard {
181 inner: Arc::new(TagLockGuardInner::new(self.clone(), tag, guard)),
182 }
183 }
184
185 pub fn try_lock_tag(&self, tag: T) -> Option<TagLockGuard<T>> {
189 let mut inner = self.inner.lock();
191
192 let entry = inner.table.entry(tag.clone());
195
196 let guard = match entry {
198 std::collections::hash_map::Entry::Occupied(mut o) => {
199 let e = o.get_mut();
200 let guard = e.mutex.try_lock_arc()?;
201 e.guards += 1;
202 guard
203 }
204 std::collections::hash_map::Entry::Vacant(v) => {
205 let mutex = Arc::new(Mutex::new(()));
206 let guard = mutex.try_lock_arc().unwrap_or_log();
207 v.insert(TagLockTableEntry { mutex, guards: 1 });
208 guard
209 }
210 };
211 Some(TagLockGuard {
213 inner: Arc::new(TagLockGuardInner::new(self.clone(), tag, guard)),
214 })
215 }
216}
217
218impl<T> Default for TagLockTable<T>
219where
220 T: Hash + Eq + Clone + Debug,
221{
222 fn default() -> Self {
223 Self::new()
224 }
225}