veilid_tools/async_locks/
async_rw_lock.rs1use 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}