Skip to main content

veilid_tools/async_locks/
async_rw_lock.rs

1//! AsyncRwLock
2use super::*;
3
4use async_lock::RwLock as InnerAsyncRwLock;
5use async_lock::RwLockReadGuard as InnerAsyncRwLockReadGuard;
6use async_lock::RwLockReadGuardArc as InnerAsyncRwLockReadGuardArc;
7use async_lock::RwLockWriteGuard as InnerAsyncRwLockWriteGuard;
8use async_lock::RwLockWriteGuardArc as InnerAsyncRwLockWriteGuardArc;
9
10#[derive(Debug)]
11pub struct AsyncRwLock<T>
12where
13    T: ?Sized,
14{
15    inner: Arc<InnerAsyncRwLock<T>>,
16    #[cfg(feature = "debug-locks")]
17    lock_id_container: LockIdContainer,
18}
19
20impl<T> AsyncRwLock<T> {
21    pub fn new(t: T) -> AsyncRwLock<T> {
22        AsyncRwLock {
23            inner: Arc::new(InnerAsyncRwLock::new(t)),
24            #[cfg(feature = "debug-locks")]
25            lock_id_container: LockIdContainer::next(),
26        }
27    }
28
29    #[inline]
30    pub async fn read_arc(self: &Arc<Self>) -> AsyncRwLockReadGuardArc<T> {
31        cfg_if! {
32            if #[cfg(feature = "debug-locks")] {
33                let inner = match timeout(DEBUG_LOCKS_DURATION_MS, self.inner.read_arc()).await {
34                    Ok(v) => v,
35                    Err(_) => {
36                        self.lock_id_container.report_deadlock("AsyncRwLock::read_arc deadlock");
37                    }
38                };
39            } else {
40                let inner = self.inner.read_arc().await;
41            }
42        }
43
44        AsyncRwLockReadGuardArc {
45            inner,
46            #[cfg(feature = "debug-locks")]
47            _guard_id_container: GuardIdContainer::next(
48                self.lock_id_container.clone(),
49                #[cfg(feature = "debug-locks-detect")]
50                LockSense::Read,
51            ),
52        }
53    }
54
55    #[inline]
56    #[must_use]
57    pub fn try_read_arc(self: &Arc<Self>) -> Option<AsyncRwLockReadGuardArc<T>> {
58        let inner = self.inner.try_read_arc()?;
59
60        let out = AsyncRwLockReadGuardArc {
61            inner,
62            #[cfg(feature = "debug-locks")]
63            _guard_id_container: GuardIdContainer::next(
64                self.lock_id_container.clone(),
65                #[cfg(feature = "debug-locks-detect")]
66                LockSense::TryRead,
67            ),
68        };
69
70        Some(out)
71    }
72}
73
74impl<T: ?Sized> AsyncRwLock<T> {
75    #[inline]
76    #[must_use]
77    pub fn try_read(&self) -> Option<AsyncRwLockReadGuard<'_, T>> {
78        let inner = self.inner.try_read()?;
79
80        let out = AsyncRwLockReadGuard {
81            inner,
82            #[cfg(feature = "debug-locks")]
83            _guard_id_container: GuardIdContainer::next(
84                self.lock_id_container.clone(),
85                #[cfg(feature = "debug-locks-detect")]
86                LockSense::TryRead,
87            ),
88        };
89
90        Some(out)
91    }
92
93    #[inline]
94    pub async fn read(&self) -> AsyncRwLockReadGuard<'_, T> {
95        cfg_if! {
96            if #[cfg(feature = "debug-locks")] {
97                let inner = match timeout(DEBUG_LOCKS_DURATION_MS, self.inner.read()).await {
98                    Ok(v) => v,
99                    Err(_) => {
100                        self.lock_id_container.report_deadlock("AsyncRwLock::read deadlock");
101                    }
102                };
103            } else {
104                let inner = self.inner.read().await;
105            }
106        }
107
108        AsyncRwLockReadGuard {
109            inner,
110            #[cfg(feature = "debug-locks")]
111            _guard_id_container: GuardIdContainer::next(
112                self.lock_id_container.clone(),
113                #[cfg(feature = "debug-locks-detect")]
114                LockSense::Read,
115            ),
116        }
117    }
118
119    #[inline]
120    #[must_use]
121    pub fn try_write(&self) -> Option<AsyncRwLockWriteGuard<'_, T>> {
122        let inner = self.inner.try_write()?;
123
124        let out = AsyncRwLockWriteGuard {
125            inner,
126            #[cfg(feature = "debug-locks")]
127            _guard_id_container: GuardIdContainer::next(
128                self.lock_id_container.clone(),
129                #[cfg(feature = "debug-locks-detect")]
130                LockSense::TryWrite,
131            ),
132        };
133
134        Some(out)
135    }
136
137    #[inline]
138    pub async fn write(&self) -> AsyncRwLockWriteGuard<'_, T> {
139        cfg_if! {
140            if #[cfg(feature = "debug-locks")] {
141                let inner = match timeout(DEBUG_LOCKS_DURATION_MS, self.inner.write()).await {
142                    Ok(v) => v,
143                    Err(_) => {
144                        self.lock_id_container.report_deadlock("AsyncRwLock::write deadlock");
145                    }
146                };
147            } else {
148                let inner = self.inner.write().await;
149            }
150        }
151
152        AsyncRwLockWriteGuard {
153            inner,
154            #[cfg(feature = "debug-locks")]
155            _guard_id_container: GuardIdContainer::next(
156                self.lock_id_container.clone(),
157                #[cfg(feature = "debug-locks-detect")]
158                LockSense::Write,
159            ),
160        }
161    }
162
163    #[inline]
164    #[must_use]
165    pub fn try_write_arc(self: &Arc<Self>) -> Option<AsyncRwLockWriteGuardArc<T>> {
166        let inner = self.inner.try_write_arc()?;
167
168        let out = AsyncRwLockWriteGuardArc {
169            inner,
170            #[cfg(feature = "debug-locks")]
171            _guard_id_container: GuardIdContainer::next(
172                self.lock_id_container.clone(),
173                #[cfg(feature = "debug-locks-detect")]
174                LockSense::TryWrite,
175            ),
176        };
177
178        Some(out)
179    }
180
181    #[inline]
182    pub async fn write_arc(self: &Arc<Self>) -> AsyncRwLockWriteGuardArc<T> {
183        cfg_if! {
184            if #[cfg(feature = "debug-locks")] {
185                let inner = match timeout(DEBUG_LOCKS_DURATION_MS, self.inner.write_arc()).await {
186                    Ok(v) => v,
187                    Err(_) => {
188                        self.lock_id_container.report_deadlock("AsyncRwLock::write_arc deadlock");
189                    }
190                };
191            } else {
192                let inner = self.inner.write_arc().await;
193            }
194        }
195
196        AsyncRwLockWriteGuardArc {
197            inner,
198            #[cfg(feature = "debug-locks")]
199            _guard_id_container: GuardIdContainer::next(
200                self.lock_id_container.clone(),
201                #[cfg(feature = "debug-locks-detect")]
202                LockSense::Write,
203            ),
204        }
205    }
206}
207
208impl<T> From<T> for AsyncRwLock<T> {
209    #[inline]
210    fn from(val: T) -> AsyncRwLock<T> {
211        AsyncRwLock::new(val)
212    }
213}
214
215#[clippy::has_significant_drop]
216#[derive(Debug)]
217pub struct AsyncRwLockReadGuard<'a, T: ?Sized> {
218    inner: InnerAsyncRwLockReadGuard<'a, T>,
219    #[cfg(feature = "debug-locks")]
220    _guard_id_container: GuardIdContainer,
221}
222
223impl<T: fmt::Display + ?Sized> fmt::Display for AsyncRwLockReadGuard<'_, T> {
224    #[inline]
225    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
226        self.inner.fmt(f)
227    }
228}
229
230impl<T: ?Sized> std::ops::Deref for AsyncRwLockReadGuard<'_, T> {
231    type Target = T;
232
233    #[inline]
234    fn deref(&self) -> &T {
235        &self.inner
236    }
237}
238
239#[clippy::has_significant_drop]
240#[derive(Debug)]
241pub struct AsyncRwLockReadGuardArc<T> {
242    inner: InnerAsyncRwLockReadGuardArc<T>,
243    #[cfg(feature = "debug-locks")]
244    _guard_id_container: GuardIdContainer,
245}
246
247impl<T: fmt::Display> fmt::Display for AsyncRwLockReadGuardArc<T> {
248    #[inline]
249    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
250        self.inner.fmt(f)
251    }
252}
253
254impl<T> std::ops::Deref for AsyncRwLockReadGuardArc<T> {
255    type Target = T;
256
257    #[inline]
258    fn deref(&self) -> &T {
259        &self.inner
260    }
261}
262
263#[clippy::has_significant_drop]
264#[derive(Debug)]
265pub struct AsyncRwLockWriteGuard<'a, T: ?Sized> {
266    inner: InnerAsyncRwLockWriteGuard<'a, T>,
267    #[cfg(feature = "debug-locks")]
268    _guard_id_container: GuardIdContainer,
269}
270
271impl<T: fmt::Display + ?Sized> fmt::Display for AsyncRwLockWriteGuard<'_, T> {
272    #[inline]
273    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
274        self.inner.fmt(f)
275    }
276}
277
278impl<T: ?Sized> std::ops::Deref for AsyncRwLockWriteGuard<'_, T> {
279    type Target = T;
280
281    #[inline]
282    fn deref(&self) -> &T {
283        &self.inner
284    }
285}
286
287impl<T: ?Sized> std::ops::DerefMut for AsyncRwLockWriteGuard<'_, T> {
288    #[inline]
289    fn deref_mut(&mut self) -> &mut T {
290        &mut self.inner
291    }
292}
293
294#[clippy::has_significant_drop]
295#[derive(Debug)]
296pub struct AsyncRwLockWriteGuardArc<T: ?Sized> {
297    inner: InnerAsyncRwLockWriteGuardArc<T>,
298    #[cfg(feature = "debug-locks")]
299    _guard_id_container: GuardIdContainer,
300}
301
302impl<T: fmt::Display + ?Sized> fmt::Display for AsyncRwLockWriteGuardArc<T> {
303    #[inline]
304    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
305        self.inner.fmt(f)
306    }
307}
308
309impl<T: ?Sized> std::ops::Deref for AsyncRwLockWriteGuardArc<T> {
310    type Target = T;
311
312    #[inline]
313    fn deref(&self) -> &T {
314        &self.inner
315    }
316}
317
318impl<T: ?Sized> std::ops::DerefMut for AsyncRwLockWriteGuardArc<T> {
319    #[inline]
320    fn deref_mut(&mut self) -> &mut T {
321        &mut self.inner
322    }
323}