Skip to main content

cocoon_tpm_utils_async/asynchronous/
rwlock.rs

1// SPDX-License-Identifier: Apache-2.0
2// Copyright 2023-2025 SUSE LLC
3// Author: Nicolai Stange <nstange@suse.de>
4
5//! Implementation of [`AsyncRwLock`]
6
7extern crate alloc;
8use super::semaphore;
9use crate::sync_types;
10use core::ptr;
11use core::{convert, future, marker, ops, pin, task};
12
13/// Error information returned by the [`AsyncRwLock`] API.
14#[derive(Clone, Copy, Debug)]
15pub enum AsyncRwLockError {
16    /// A pending operation's associated [`AsyncRwLock`] has been
17    /// dropped.
18    StaleRwLock,
19
20    /// Memory allocation failure.
21    MemoryAllocationFailure,
22
23    /// Internal error.
24    Internal,
25}
26
27impl convert::From<semaphore::AsyncSemaphoreError> for AsyncRwLockError {
28    fn from(value: semaphore::AsyncSemaphoreError) -> Self {
29        match value {
30            semaphore::AsyncSemaphoreError::RequestExceedsSemaphoreCapacity => AsyncRwLockError::Internal,
31            semaphore::AsyncSemaphoreError::StaleSemaphore => AsyncRwLockError::StaleRwLock,
32            semaphore::AsyncSemaphoreError::MemoryAllocationFailure => AsyncRwLockError::MemoryAllocationFailure,
33            semaphore::AsyncSemaphoreError::Internal => AsyncRwLockError::Internal,
34        }
35    }
36}
37
38/// A Read-Write Lock which can be waited asynchronously for.
39///
40/// The locking operations [`read()`](Self::read) and [`write()`](Self::write)
41/// return [`Future`]s which can subsequently get polled to eventually obtain
42/// the lock.
43///
44/// [`AsyncRwLock`] follows the common Read-Write Lock semantics: locking for
45/// writes is mutually exclusive, with either locking type whereas any number of
46/// read lockings can be granted at a time.
47///
48/// `AsyncRwlock` is **not** robust against threads "loosing interest", e.g.
49/// because the execution environment somehow abandoned them: any lock waiting
50/// [`Future`] acquired from [`read()`](Self::read) or [`write()`](Self::write)
51/// must either get polled to completion or dropped, otherwise it might block
52/// other waiters for forever. Similar reasoning applies to the lock grant
53/// guards themselves: [`AsyncRwLockReadGuard`] and [`AsyncRwLockWriteGuard`]
54/// instances may always block other waiters, so it must be made sure that
55/// progress is always driven forward for a lock holder until the respective
56/// locking guard gets eventually dropped again.
57pub struct AsyncRwLock<ST: sync_types::SyncTypes, T: marker::Send + marker::Sync> {
58    sem: semaphore::AsyncSemaphore<ST, T>,
59}
60
61impl<ST: sync_types::SyncTypes, T: marker::Send + marker::Sync> AsyncRwLock<ST, T> {
62    /// Instantiate a new [`AsyncRwLock`]
63    ///
64    /// Note that the caller is supposed to move the returned `AsyncSemaphore`
65    /// into a [`SyncRcPtr`](sync_types::SyncRcPtr) -- the other parts of
66    /// the API expect that.
67    ///
68    /// # Arguments:
69    ///
70    /// * `data` - the data to wrap in the the lock.
71    pub fn new(data: T) -> Self {
72        Self {
73            sem: semaphore::AsyncSemaphore::new_with_no_capacity(data),
74        }
75    }
76
77    /// Asynchronous, non-exclusive locking for read semantics.
78    ///
79    /// Instantiate a [`AsyncRwLockReadFuture`] for taking the lock
80    /// asynchronously for read semantics.
81    ///
82    /// The returned future will not become ready as long as an exlusive write
83    /// locking, i.e. an [`AsyncRwLockWriteGuard`] is active, or some waiter
84    /// for an exclusive write locking is ahead in line.
85    ///
86    /// Note that the mere existence of a [`AsyncRwLockReadFuture`]
87    /// returned from this function may block other waiters -- it **must**
88    /// always get either polled to completion or dropped again.
89    ///
90    /// # Errors:
91    ///
92    /// * [`AsyncRwLockError::MemoryAllocationFailure`] - Memory allocation
93    ///   failure.
94    pub fn read<'a, LP: 'a + sync_types::SyncRcPtr<Self>, LR: 'a + sync_types::SyncRcPtrRef<'a, Self, LP>>(
95        this: &LR,
96    ) -> Result<AsyncRwLockReadFuture<ST, T, LP>, AsyncRwLockError>
97    where
98        Self: 'a,
99    {
100        let this_sem = sync_types::SyncRcPtrRefForInner::<'_, _, _, _, AsyncRwLockIndexInnerSemTag>::new(this);
101        let sem_trivial_lease_fut = semaphore::AsyncSemaphore::acquire_leases(&this_sem, 0)?;
102        Ok(AsyncRwLockReadFuture { sem_trivial_lease_fut })
103    }
104
105    /// Asynchronous, exclusive locking for write semantics.
106    ///
107    /// Instantiate a [`AsyncRwLockWriteFuture`] for taking the lock
108    /// asynchronously for write semantics.
109    ///
110    /// The returned future will not become ready as long as some locking of any
111    /// type, i.e. an [`AsyncRwLockWriteGuard`] or [`AsyncRwLockReadGuard`]
112    /// is active, or some other waiter is ahead in line.
113    ///
114    /// Note that the mere existence of a [`AsyncRwLockWriteFuture`]
115    /// returned from this function may block other waiters -- it **must**
116    /// always get either polled to completion or dropped again.
117    ///
118    /// # Errors:
119    ///
120    /// * [`AsyncRwLockError::MemoryAllocationFailure`] - Memory allocation
121    ///   failure.
122    pub fn write<'a, LP: 'a + sync_types::SyncRcPtr<Self>, LR: 'a + sync_types::SyncRcPtrRef<'a, Self, LP>>(
123        this: &LR,
124    ) -> Result<AsyncRwLockWriteFuture<ST, T, LP>, AsyncRwLockError>
125    where
126        Self: 'a,
127    {
128        let this_sem = sync_types::SyncRcPtrRefForInner::<'_, _, _, _, AsyncRwLockIndexInnerSemTag>::new(this);
129        let sem_exclusive_all_fut = semaphore::AsyncSemaphore::acquire_exclusive_all(&this_sem)?;
130        Ok(AsyncRwLockWriteFuture { sem_exclusive_all_fut })
131    }
132
133    /// Try to synchronously acquire lock non-exclusively for read semantics.
134    ///
135    /// The operation will only succeed and return a [`AsyncRwLockReadGuard`] if
136    /// no exclusive locking is active or waited for to become available.
137    /// Otherwise [`None`] will get returned.
138    pub fn try_read<'a, LP: 'a + sync_types::SyncRcPtr<Self>, LR: 'a + sync_types::SyncRcPtrRef<'a, Self, LP>>(
139        this: &LR,
140    ) -> Option<AsyncRwLockReadGuard<ST, T, LP>>
141    where
142        Self: 'a,
143    {
144        let this_sem = sync_types::SyncRcPtrRefForInner::<'_, _, _, _, AsyncRwLockIndexInnerSemTag>::new(this);
145        semaphore::AsyncSemaphore::try_acquire_leases(&this_sem, 0)
146            .unwrap()
147            .map(|sem_trivial_lease_guard| AsyncRwLockReadGuard {
148                sem_trivial_lease_guard,
149            })
150    }
151
152    /// Try to synchronously acquire lock exclusively for write semantics.
153    ///
154    /// The operation will only succeed and return a [`AsyncRwLockWriteGuard`]
155    /// if no locking is active or waited for to become available.
156    /// Otherwise [`None`] will get returned.
157    pub fn try_write<'a, LP: 'a + sync_types::SyncRcPtr<Self>, LR: 'a + sync_types::SyncRcPtrRef<'a, Self, LP>>(
158        this: &LR,
159    ) -> Option<AsyncRwLockWriteGuard<ST, T, LP>>
160    where
161        Self: 'a,
162    {
163        let this_sem = sync_types::SyncRcPtrRefForInner::<'_, _, _, _, AsyncRwLockIndexInnerSemTag>::new(this);
164        semaphore::AsyncSemaphore::try_acquire_exclusive_all(&this_sem).map(|sem_exclusive_all_guard| {
165            AsyncRwLockWriteGuard {
166                sem_exclusive_all_guard,
167            }
168        })
169    }
170}
171
172/// [`DerefInnerByTag`](sync_types::DerefInnerByTag) `TAG` for dereferencing
173/// [`AsyncRwLock::sem`].
174///
175/// Enables presenting the [`SyncRcPtr`](sync_types::SyncRcPtr) of the
176/// [`AsyncRwLock`] as one for its [`AsyncRwLock::sem`] member
177/// via the [`SyncRcPtrForInner`](sync_types::SyncRcPtrForInner) mechanism.
178struct AsyncRwLockIndexInnerSemTag;
179
180impl<ST: sync_types::SyncTypes, T: marker::Send + marker::Sync> sync_types::DerefInnerByTag<AsyncRwLockIndexInnerSemTag>
181    for AsyncRwLock<ST, T>
182{
183    crate::impl_deref_inner_by_tag!(sem, semaphore::AsyncSemaphore<ST, T>);
184}
185
186/// Asynchronous wait for non-exclusive locking of an [`AsyncRwLock`].
187///
188/// To be obtained through [`AsyncRwLock::read()`].
189///
190/// # Note on lifetime management
191///
192/// An [`AsyncRwLockReadFuture`] instance will only maintain a weak reference
193/// (i.e. a [`WeakSyncRcPtr`](sync_types::WeakSyncRcPtr)) to the associated
194/// [`AsyncRwLock`] instance and thus, would not hinder its deallocation. In
195/// case the lock gets dropped before the future had a chance to acquire it, its
196/// `poll()` would return [`AsyncRwLockError::StaleRwLock`].
197pub struct AsyncRwLockReadFuture<
198    ST: sync_types::SyncTypes,
199    T: marker::Send + marker::Sync,
200    LP: sync_types::SyncRcPtr<AsyncRwLock<ST, T>>,
201> {
202    sem_trivial_lease_fut: semaphore::AsyncSemaphoreLeasesFuture<
203        ST,
204        T,
205        sync_types::SyncRcPtrForInner<AsyncRwLock<ST, T>, LP, AsyncRwLockIndexInnerSemTag>,
206    >,
207}
208
209impl<ST: sync_types::SyncTypes, T: marker::Send + marker::Sync, LP: sync_types::SyncRcPtr<AsyncRwLock<ST, T>>>
210    AsyncRwLockReadFuture<ST, T, LP>
211{
212    /// Obtain the associated [`AsyncRwLock`].
213    ///
214    /// Return the associated [`AsyncRwLock`] wrapped in `Some` if still
215    /// alive, `None` otherwise.
216    pub fn get_rwlock(&self) -> Option<LP> {
217        self.sem_trivial_lease_fut
218            .get_semaphore()
219            .map(|sem| sem.into_container())
220    }
221}
222
223impl<ST: sync_types::SyncTypes, T: marker::Send + marker::Sync, LP: sync_types::SyncRcPtr<AsyncRwLock<ST, T>>>
224    marker::Unpin for AsyncRwLockReadFuture<ST, T, LP>
225{
226}
227
228impl<ST: sync_types::SyncTypes, T: marker::Send + marker::Sync, LP: sync_types::SyncRcPtr<AsyncRwLock<ST, T>>>
229    future::Future for AsyncRwLockReadFuture<ST, T, LP>
230{
231    type Output = Result<AsyncRwLockReadGuard<ST, T, LP>, AsyncRwLockError>;
232
233    /// Poll for a locking grant of the associated [`AsyncRwLock`].
234    ///
235    /// Upon future completion, either a [`AsyncRwLockReadGuard`] is returned
236    /// or, if the associated [`AsyncRwLock`] had been dropped in the
237    /// meanwhile, an error of [`AsyncRwLockError::StaleRwLock`].
238    ///
239    /// The future must not get polled any further once completed.
240    fn poll(self: pin::Pin<&mut Self>, cx: &mut task::Context<'_>) -> task::Poll<Self::Output> {
241        future::Future::poll(pin::Pin::new(&mut self.get_mut().sem_trivial_lease_fut), cx)
242            .map_ok(|sem_trivial_lease_guard| AsyncRwLockReadGuard {
243                sem_trivial_lease_guard,
244            })
245            .map_err(AsyncRwLockError::from)
246    }
247}
248
249/// Non-exclusive locking grant on an [`AsyncRwLock`].
250///
251/// Besides the common functionality one would expect from a locking guard, it's
252/// noteworthy that a `AsyncRwLockReadGuard` instance can get presented as a
253/// [`SyncRcPtr`](sync_types) for the [`AsyncRwLock`]'s inner value (or any of
254/// its members) via [`AsyncRwLockReadGuardForInner`] to APIs that expect such
255/// one.
256pub struct AsyncRwLockReadGuard<
257    ST: sync_types::SyncTypes,
258    T: marker::Send + marker::Sync,
259    LP: sync_types::SyncRcPtr<AsyncRwLock<ST, T>>,
260> {
261    sem_trivial_lease_guard: semaphore::AsyncSemaphoreLeasesGuard<
262        ST,
263        T,
264        sync_types::SyncRcPtrForInner<AsyncRwLock<ST, T>, LP, AsyncRwLockIndexInnerSemTag>,
265    >,
266}
267
268impl<ST: sync_types::SyncTypes, T: marker::Send + marker::Sync, LP: sync_types::SyncRcPtr<AsyncRwLock<ST, T>>>
269    AsyncRwLockReadGuard<ST, T, LP>
270{
271    /// Obtain the associated [`AsyncRwLock`].
272    pub fn get_rwlock(&self) -> LP::SyncRcPtrRef<'_> {
273        self.sem_trivial_lease_guard.get_semaphore().get_container().clone()
274    }
275
276    /// Release the lock and return the associated [`AsyncRwLock`].
277    pub fn into_rwlock(self) -> LP {
278        self.sem_trivial_lease_guard.into_semaphore().into_container()
279    }
280
281    /// Convert into an [`AsyncRwLockReadWeakGuard`] not hindering
282    /// destruction of the associated [`AsyncRwLock`].
283    pub fn into_weak(self) -> AsyncRwLockReadWeakGuard<ST, T, LP> {
284        AsyncRwLockReadWeakGuard {
285            sem_trivial_lease_guard: Some(self.sem_trivial_lease_guard.into_weak()),
286        }
287    }
288
289    /// Convert into a raw pointer to the protected inner value.
290    ///
291    /// Must eventually get converted back with [`from_raw()`](Self::from_raw)
292    /// or the locking grant will be leaked forever.
293    fn into_raw(this: Self) -> *const T {
294        let (ptr, leases_granted) = this.sem_trivial_lease_guard.into_raw();
295        debug_assert_eq!(leases_granted, 0);
296        ptr
297    }
298
299    /// Convert back from a raw pointer to the protected value obtained from
300    /// [`from_raw()`](Self::from_raw).
301    ///
302    /// # Safety
303    ///
304    /// The raw pointer to the protected value must have been previously
305    /// obtained from [`from_raw()`](Self::from_raw).
306    unsafe fn from_raw(ptr: *const T) -> Self {
307        let sem_trivial_lease_guard = unsafe { semaphore::AsyncSemaphoreLeasesGuard::from_raw(ptr, 0) };
308        Self {
309            sem_trivial_lease_guard,
310        }
311    }
312}
313
314impl<ST: sync_types::SyncTypes, T: marker::Send + marker::Sync, LP: sync_types::SyncRcPtr<AsyncRwLock<ST, T>>>
315    ops::Deref for AsyncRwLockReadGuard<ST, T, LP>
316{
317    type Target = T;
318
319    fn deref(&self) -> &Self::Target {
320        &self.sem_trivial_lease_guard
321    }
322}
323
324impl<ST: sync_types::SyncTypes, T: marker::Send + marker::Sync, LP: sync_types::SyncRcPtr<AsyncRwLock<ST, T>>> Clone
325    for AsyncRwLockReadGuard<ST, T, LP>
326{
327    fn clone(&self) -> Self {
328        let sem_trivial_lease_guard = self.sem_trivial_lease_guard.spawn_trivial_lease();
329        Self {
330            sem_trivial_lease_guard,
331        }
332    }
333}
334
335/// Weak variant of [`AsyncRwLockReadGuard`] not hindering destruction of the
336/// associated [`AsyncRwLock`].
337///
338/// In cases were it's desired that long-living locking grants don't prevent a
339/// destruction of the associated [`AsyncRwLock`], or to break cycles, a
340/// `AsyncRwLockReadWeakGuard` may be used. To be obtained via
341/// [`AsyncRwLockReadGuard::into_weak()`].
342///
343/// An `AsyncRwLockReadWeakGuard` may get converted back into a full
344/// [`AsyncRwLockReadGuard`] via [`upgrade()`](Self::upgrade).
345pub struct AsyncRwLockReadWeakGuard<
346    ST: sync_types::SyncTypes,
347    T: marker::Send + marker::Sync,
348    LP: sync_types::SyncRcPtr<AsyncRwLock<ST, T>>,
349> {
350    #[allow(clippy::type_complexity)]
351    sem_trivial_lease_guard: Option<
352        semaphore::AsyncSemaphoreLeasesWeakGuard<
353            ST,
354            T,
355            sync_types::SyncRcPtrForInner<AsyncRwLock<ST, T>, LP, AsyncRwLockIndexInnerSemTag>,
356        >,
357    >,
358}
359
360impl<ST: sync_types::SyncTypes, T: marker::Send + marker::Sync, LP: sync_types::SyncRcPtr<AsyncRwLock<ST, T>>>
361    AsyncRwLockReadWeakGuard<ST, T, LP>
362{
363    /// Attempt to convert back into an [`AsyncRwLockReadGuard`].
364    ///
365    /// Returns the [`AsyncRwLockReadGuard`] wrapped in `Some` if the
366    /// associated [`AsyncRwLock`] is still alive, `None otherwise.
367    pub fn upgrade(self) -> Option<AsyncRwLockReadGuard<ST, T, LP>> {
368        self.sem_trivial_lease_guard
369            .and_then(|sem_trivial_lease_guard| sem_trivial_lease_guard.upgrade())
370            .map(|sem_trivial_lease_guard| AsyncRwLockReadGuard {
371                sem_trivial_lease_guard,
372            })
373    }
374
375    /// Attempt to convert back into an [`AsyncRwLockReadGuard`] by reference.
376    ///
377    /// Returns the [`AsyncRwLockReadGuard`] wrapped in `Some` if the
378    /// associated [`AsyncRwLock`] is still alive, `None otherwise.
379    fn upgrade_by_ref(&self) -> Option<AsyncRwLockReadGuard<ST, T, LP>> {
380        self.sem_trivial_lease_guard
381            .as_ref()
382            .and_then(|sem_trivial_lease_guard| sem_trivial_lease_guard.try_spawn_trivial_lease())
383            .map(|sem_trivial_lease_guard| AsyncRwLockReadGuard {
384                sem_trivial_lease_guard,
385            })
386    }
387
388    /// Convert into a raw pointer to the protected inner value.
389    ///
390    /// Must eventually get converted back with [`from_raw()`](Self::from_raw)
391    /// or the locking grant will be leaked forever.
392    ///
393    /// The returned raw pointer **must not** be used for anything except for
394    /// passing it back to [`from_raw()`](Self::from_raw). In particular it
395    /// must not get dereferenced, as the associated [`AsyncRwLock`], and
396    /// hence its wrapped value, might have been dropped already.
397    fn into_raw(mut this: Self) -> *const T {
398        this.sem_trivial_lease_guard
399            .take()
400            .map(|sem_trivial_lease_guard| {
401                let (ptr, leases_granted) = sem_trivial_lease_guard.into_raw();
402                debug_assert_eq!(leases_granted, 0);
403                ptr
404            })
405            .unwrap_or(ptr::null())
406    }
407
408    /// Convert back from a raw pointer to the protected value obtained from
409    /// [`from_raw()`](Self::from_raw).
410    ///
411    /// # Safety
412    ///
413    /// The raw pointer to the protected value must have been previously
414    /// obtained from [`from_raw()`](Self::from_raw).
415    unsafe fn from_raw(ptr: *const T) -> Self {
416        if !ptr.is_null() {
417            let sem_trivial_lease_guard = unsafe { semaphore::AsyncSemaphoreLeasesWeakGuard::from_raw(ptr, 0) };
418            Self {
419                sem_trivial_lease_guard: Some(sem_trivial_lease_guard),
420            }
421        } else {
422            Self {
423                sem_trivial_lease_guard: None,
424            }
425        }
426    }
427}
428
429impl<ST: sync_types::SyncTypes, T: marker::Send + marker::Sync, LP: sync_types::SyncRcPtr<AsyncRwLock<ST, T>>> Clone
430    for AsyncRwLockReadWeakGuard<ST, T, LP>
431{
432    fn clone(&self) -> Self {
433        let sem_trivial_lease_guard = self
434            .sem_trivial_lease_guard
435            .as_ref()
436            .and_then(|sem_trivial_lease_guard| sem_trivial_lease_guard.try_spawn_trivial_lease())
437            .map(|sem_trivial_lease_guard| sem_trivial_lease_guard.into_weak());
438        Self {
439            sem_trivial_lease_guard,
440        }
441    }
442}
443
444/// Present a `AsyncRwLockReadGuard` instance as a [`SyncRcPtr`](sync_types) for
445/// the [`AsyncRwLock`]'s inner value (or any of its members).
446///
447/// Useful for presenting APIs with a [`SyncRcPtr`](sync_types::SyncRcPtr) to
448/// the [`AsyncRwLock`]'s wrapped value or any of its members if needed.
449///
450/// Users are supposed to implement
451/// [`DerefInnerByTag`](sync_types::DerefInnerByTag) the [`AsyncRwLock`]'s
452/// wrapped value's type, for a `TAG` routing either to the [`AsyncRwLock`]'s
453/// wrapped value itself or to one of its members.
454///
455/// Note that the [`AsyncRwLockReadGuardForInner`] (as well its cloning spawns)
456/// own a read lock on the associated [`AsyncRwLock`] for its whole lifetime. In
457/// particular it blocks other tasks waiting to acquire a write lock.
458pub struct AsyncRwLockReadGuardForInner<
459    ST: sync_types::SyncTypes,
460    OT,
461    LP: sync_types::SyncRcPtr<AsyncRwLock<ST, OT>>,
462    TAG,
463> where
464    OT: sync_types::DerefInnerByTag<TAG> + marker::Send + marker::Sync,
465    <OT as sync_types::DerefInnerByTag<TAG>>::Output: marker::Send + marker::Sync,
466{
467    guard_for_outer: AsyncRwLockReadGuard<ST, OT, LP>,
468    _phantom: marker::PhantomData<fn() -> TAG>,
469}
470
471impl<ST: sync_types::SyncTypes, OT, LP: sync_types::SyncRcPtr<AsyncRwLock<ST, OT>>, TAG> Clone
472    for AsyncRwLockReadGuardForInner<ST, OT, LP, TAG>
473where
474    OT: sync_types::DerefInnerByTag<TAG> + marker::Send + marker::Sync,
475    <OT as sync_types::DerefInnerByTag<TAG>>::Output: marker::Send + marker::Sync,
476{
477    fn clone(&self) -> Self {
478        Self {
479            guard_for_outer: self.guard_for_outer.clone(),
480            _phantom: marker::PhantomData,
481        }
482    }
483}
484
485impl<ST: sync_types::SyncTypes, OT, LP: sync_types::SyncRcPtr<AsyncRwLock<ST, OT>>, TAG>
486    convert::From<AsyncRwLockReadGuard<ST, OT, LP>> for AsyncRwLockReadGuardForInner<ST, OT, LP, TAG>
487where
488    OT: sync_types::DerefInnerByTag<TAG> + marker::Send + marker::Sync,
489    <OT as sync_types::DerefInnerByTag<TAG>>::Output: marker::Send + marker::Sync,
490{
491    fn from(value: AsyncRwLockReadGuard<ST, OT, LP>) -> Self {
492        Self {
493            guard_for_outer: value,
494            _phantom: marker::PhantomData,
495        }
496    }
497}
498
499impl<ST: sync_types::SyncTypes, OT, LP: sync_types::SyncRcPtr<AsyncRwLock<ST, OT>>, TAG> ops::Deref
500    for AsyncRwLockReadGuardForInner<ST, OT, LP, TAG>
501where
502    OT: sync_types::DerefInnerByTag<TAG> + marker::Send + marker::Sync,
503    <OT as sync_types::DerefInnerByTag<TAG>>::Output: marker::Send + marker::Sync,
504{
505    type Target = <OT as sync_types::DerefInnerByTag<TAG>>::Output;
506
507    fn deref(&self) -> &Self::Target {
508        <OT as sync_types::DerefInnerByTag<TAG>>::deref_inner(&self.guard_for_outer)
509    }
510}
511
512impl<ST: sync_types::SyncTypes, OT, LP: sync_types::SyncRcPtr<AsyncRwLock<ST, OT>>, TAG>
513    sync_types::SyncRcPtr<<OT as sync_types::DerefInnerByTag<TAG>>::Output>
514    for AsyncRwLockReadGuardForInner<ST, OT, LP, TAG>
515where
516    OT: sync_types::DerefInnerByTag<TAG> + marker::Send + marker::Sync,
517    <OT as sync_types::DerefInnerByTag<TAG>>::Output: Sized + marker::Send + marker::Sync,
518{
519    type WeakSyncRcPtr = AsyncRwLockReadWeakGuardForInner<ST, OT, LP, TAG>;
520
521    type SyncRcPtrRef<'a>
522        = sync_types::GenericSyncRcPtrRef<'a, <OT as sync_types::DerefInnerByTag<TAG>>::Output, Self>
523    where
524        Self: 'a;
525
526    fn downgrade(&self) -> Self::WeakSyncRcPtr {
527        Self::WeakSyncRcPtr::from(self.guard_for_outer.clone().into_weak())
528    }
529
530    fn into_raw(this: Self) -> *const <OT as sync_types::DerefInnerByTag<TAG>>::Output {
531        let ptr_to_outer = AsyncRwLockReadGuard::into_raw(this.guard_for_outer);
532        <OT as sync_types::DerefInnerByTag<TAG>>::to_inner_ptr(ptr_to_outer)
533    }
534
535    unsafe fn from_raw(ptr: *const <OT as sync_types::DerefInnerByTag<TAG>>::Output) -> Self {
536        let ptr_to_outer = unsafe { <OT as sync_types::DerefInnerByTag<TAG>>::container_of(ptr) };
537        let guard_for_outer = unsafe { AsyncRwLockReadGuard::from_raw(ptr_to_outer) };
538        Self {
539            guard_for_outer,
540            _phantom: marker::PhantomData,
541        }
542    }
543}
544
545/// Weak variant of [`AsyncRwLockReadGuardForInner`] not hindering destruction
546/// of the associated [`AsyncRwLock`].
547///
548/// Implements [`WeakSyncRcPtr`](sync_types::WeakSyncRcPtr) and is to be
549/// obtained from an [`AsyncRwLockReadGuardForInner`] through the
550/// [`SyncRcPtr`](sync_types::SyncRcPtr) API,
551/// i.e. via [`SyncRcPtr::downgrade`](sync_types::SyncRcPtr::downgrade).
552pub struct AsyncRwLockReadWeakGuardForInner<
553    ST: sync_types::SyncTypes,
554    OT,
555    LP: sync_types::SyncRcPtr<AsyncRwLock<ST, OT>>,
556    TAG,
557> where
558    OT: sync_types::DerefInnerByTag<TAG> + marker::Send + marker::Sync,
559    <OT as sync_types::DerefInnerByTag<TAG>>::Output: marker::Send + marker::Sync,
560{
561    guard_for_outer: AsyncRwLockReadWeakGuard<ST, OT, LP>,
562    _phantom: marker::PhantomData<fn() -> TAG>,
563}
564
565impl<ST: sync_types::SyncTypes, OT, LP: sync_types::SyncRcPtr<AsyncRwLock<ST, OT>>, TAG> Clone
566    for AsyncRwLockReadWeakGuardForInner<ST, OT, LP, TAG>
567where
568    OT: sync_types::DerefInnerByTag<TAG> + marker::Send + marker::Sync,
569    <OT as sync_types::DerefInnerByTag<TAG>>::Output: marker::Send + marker::Sync,
570{
571    fn clone(&self) -> Self {
572        Self {
573            guard_for_outer: self.guard_for_outer.clone(),
574            _phantom: marker::PhantomData,
575        }
576    }
577}
578
579impl<ST: sync_types::SyncTypes, OT, LP: sync_types::SyncRcPtr<AsyncRwLock<ST, OT>>, TAG>
580    convert::From<AsyncRwLockReadWeakGuard<ST, OT, LP>> for AsyncRwLockReadWeakGuardForInner<ST, OT, LP, TAG>
581where
582    OT: sync_types::DerefInnerByTag<TAG> + marker::Send + marker::Sync,
583    <OT as sync_types::DerefInnerByTag<TAG>>::Output: marker::Send + marker::Sync,
584{
585    fn from(value: AsyncRwLockReadWeakGuard<ST, OT, LP>) -> Self {
586        Self {
587            guard_for_outer: value,
588            _phantom: marker::PhantomData,
589        }
590    }
591}
592
593impl<ST: sync_types::SyncTypes, OT, LP: sync_types::SyncRcPtr<AsyncRwLock<ST, OT>>, TAG>
594    sync_types::WeakSyncRcPtr<
595        <OT as sync_types::DerefInnerByTag<TAG>>::Output,
596        AsyncRwLockReadGuardForInner<ST, OT, LP, TAG>,
597    > for AsyncRwLockReadWeakGuardForInner<ST, OT, LP, TAG>
598where
599    OT: sync_types::DerefInnerByTag<TAG> + marker::Send + marker::Sync,
600    <OT as sync_types::DerefInnerByTag<TAG>>::Output: Sized + marker::Send + marker::Sync,
601{
602    fn upgrade(&self) -> Option<AsyncRwLockReadGuardForInner<ST, OT, LP, TAG>> {
603        self.guard_for_outer
604            .upgrade_by_ref()
605            .map(|guard_for_outer| AsyncRwLockReadGuardForInner {
606                guard_for_outer,
607                _phantom: marker::PhantomData,
608            })
609    }
610
611    fn into_raw(this: Self) -> *const <OT as sync_types::DerefInnerByTag<TAG>>::Output {
612        let ptr_to_outer = AsyncRwLockReadWeakGuard::into_raw(this.guard_for_outer);
613        if !ptr_to_outer.is_null() {
614            <OT as sync_types::DerefInnerByTag<TAG>>::to_inner_ptr(ptr_to_outer)
615        } else {
616            ptr::null()
617        }
618    }
619
620    unsafe fn from_raw(ptr: *const <OT as sync_types::DerefInnerByTag<TAG>>::Output) -> Self {
621        let ptr_to_outer = if !ptr.is_null() {
622            unsafe { <OT as sync_types::DerefInnerByTag<TAG>>::container_of(ptr) }
623        } else {
624            ptr::null()
625        };
626        let guard_for_outer = unsafe { AsyncRwLockReadWeakGuard::from_raw(ptr_to_outer) };
627        Self {
628            guard_for_outer,
629            _phantom: marker::PhantomData,
630        }
631    }
632}
633
634/// Asynchronous wait for exclusive locking of an [`AsyncRwLock`].
635///
636/// To be obtained through [`AsyncRwLock::write()`].
637///
638/// # Note on lifetime management
639///
640/// An [`AsyncRwLockWriteFuture`] instance will only maintain a weak reference
641/// (i.e. a [`WeakSyncRcPtr`](sync_types::WeakSyncRcPtr)) to the associated
642/// [`AsyncRwLock`] instance and thus, would not hinder its deallocation. In
643/// case the lock gets dropped before the future had a chance to acquire it, its
644/// `poll()` would return [`AsyncRwLockError::StaleRwLock`].
645pub struct AsyncRwLockWriteFuture<
646    ST: sync_types::SyncTypes,
647    T: marker::Send + marker::Sync,
648    LP: sync_types::SyncRcPtr<AsyncRwLock<ST, T>>,
649> {
650    sem_exclusive_all_fut: semaphore::AsyncSemaphoreExclusiveAllFuture<
651        ST,
652        T,
653        sync_types::SyncRcPtrForInner<AsyncRwLock<ST, T>, LP, AsyncRwLockIndexInnerSemTag>,
654    >,
655}
656
657impl<ST: sync_types::SyncTypes, T: marker::Send + marker::Sync, LP: sync_types::SyncRcPtr<AsyncRwLock<ST, T>>>
658    AsyncRwLockWriteFuture<ST, T, LP>
659{
660    pub fn get_rwlock(&self) -> Option<LP> {
661        self.sem_exclusive_all_fut
662            .get_semaphore()
663            .map(|sem| sem.into_container())
664    }
665}
666
667impl<ST: sync_types::SyncTypes, T: marker::Send + marker::Sync, LP: sync_types::SyncRcPtr<AsyncRwLock<ST, T>>>
668    marker::Unpin for AsyncRwLockWriteFuture<ST, T, LP>
669{
670}
671
672impl<ST: sync_types::SyncTypes, T: marker::Send + marker::Sync, LP: sync_types::SyncRcPtr<AsyncRwLock<ST, T>>>
673    future::Future for AsyncRwLockWriteFuture<ST, T, LP>
674{
675    type Output = Result<AsyncRwLockWriteGuard<ST, T, LP>, AsyncRwLockError>;
676
677    /// Poll for a locking grant of the associated [`AsyncRwLock`].
678    ///
679    /// Upon future completion, either a [`AsyncRwLockWriteGuard`] is returned
680    /// or, if the associated [`AsyncRwLock`] had been dropped in the
681    /// meanwhile, an error of [`AsyncRwLockError::StaleRwLock`].
682    ///
683    /// The future must not get polled any further once completed.
684    fn poll(self: pin::Pin<&mut Self>, cx: &mut task::Context<'_>) -> task::Poll<Self::Output> {
685        future::Future::poll(pin::Pin::new(&mut self.get_mut().sem_exclusive_all_fut), cx)
686            .map_ok(|sem_exclusive_all_guard| AsyncRwLockWriteGuard {
687                sem_exclusive_all_guard,
688            })
689            .map_err(AsyncRwLockError::from)
690    }
691}
692
693/// Exclusive locking grant on an [`AsyncRwLock`].
694pub struct AsyncRwLockWriteGuard<
695    ST: sync_types::SyncTypes,
696    T: marker::Send + marker::Sync,
697    LP: sync_types::SyncRcPtr<AsyncRwLock<ST, T>>,
698> {
699    sem_exclusive_all_guard: semaphore::AsyncSemaphoreExclusiveAllGuard<
700        ST,
701        T,
702        sync_types::SyncRcPtrForInner<AsyncRwLock<ST, T>, LP, AsyncRwLockIndexInnerSemTag>,
703    >,
704}
705
706impl<ST: sync_types::SyncTypes, T: marker::Send + marker::Sync, LP: sync_types::SyncRcPtr<AsyncRwLock<ST, T>>>
707    AsyncRwLockWriteGuard<ST, T, LP>
708{
709    /// Obtain the associated [`AsyncRwLock`].
710    pub fn get_rwlock(&self) -> LP::SyncRcPtrRef<'_> {
711        self.sem_exclusive_all_guard.get_semaphore().get_container().clone()
712    }
713
714    /// Release the lock and return the associated [`AsyncRwLock`].
715    pub fn into_rwlock(self) -> LP {
716        self.sem_exclusive_all_guard.into_semaphore().into_container()
717    }
718
719    /// Convert into an [`AsyncRwLockWriteWeakGuard`] not hindering
720    /// destruction of the associated [`AsyncRwLock`].
721    pub fn into_weak(self) -> AsyncRwLockWriteWeakGuard<ST, T, LP> {
722        AsyncRwLockWriteWeakGuard {
723            sem_exclusive_all_guard: self.sem_exclusive_all_guard.into_weak(),
724        }
725    }
726
727    /// Simultaneously obtain an immutable reference to the associated
728    /// [`AsyncRwLock`] as well as a mutable one to its wrapped inner value.
729    ///
730    /// Mutably dereferencing the [`AsyncRwLockWriteGuard`] to obtain a `mut`
731    /// reference on the protected value would result in a borrow on `self`
732    /// and thus, prohibits any use of [`get_rwlock()`](Self::get_rwlock)
733    /// over the course of the reference's lifetime.
734    ///
735    /// However, due to the [`AsyncRwLockWriteGuard`]'s locking semantics, there
736    /// isn't anything problematic about immutably referencing the
737    /// associated [`AsyncRwLock`] at the same time. It's useful in e.g.
738    /// situations where the lock lives in some zero-overhead
739    /// [`SyncRcPtrForInner`](sync_types::SyncRcPtrForInner) and one seeks to
740    /// obtain a reference to the container starting out from the lock
741    /// guard.
742    pub fn borrow_outer_inner_mut<'a>(&'a mut self) -> (LP::SyncRcPtrRef<'a>, &'a mut T) {
743        let (sem, v) = self.sem_exclusive_all_guard.borrow_outer_inner_mut();
744        (sem.get_container().clone(), v)
745    }
746}
747
748impl<ST: sync_types::SyncTypes, T: marker::Send + marker::Sync, LP: sync_types::SyncRcPtr<AsyncRwLock<ST, T>>>
749    ops::Deref for AsyncRwLockWriteGuard<ST, T, LP>
750{
751    type Target = T;
752
753    fn deref(&self) -> &Self::Target {
754        &self.sem_exclusive_all_guard
755    }
756}
757
758impl<ST: sync_types::SyncTypes, T: marker::Send + marker::Sync, LP: sync_types::SyncRcPtr<AsyncRwLock<ST, T>>>
759    ops::DerefMut for AsyncRwLockWriteGuard<ST, T, LP>
760{
761    fn deref_mut(&mut self) -> &mut Self::Target {
762        &mut self.sem_exclusive_all_guard
763    }
764}
765
766/// Weak variant of [`AsyncRwLockWriteGuard`] not hindering destruction of the
767/// associated [`AsyncRwLock`].
768///
769/// In cases were it's desired that long-living locking grants don't prevent a
770/// destruction of the associated [`AsyncRwLock`], or to break cycles, a
771/// `AsyncRwLockWriteWeakGuard` may be used. To be obtained via
772/// [`AsyncRwLockWriteGuard::into_weak()`].
773///
774/// An `AsyncRwLockWriteWeakGuard` may get converted back into a full
775/// [`AsyncRwLockWriteGuard`] via [`upgrade()`](Self::upgrade).
776pub struct AsyncRwLockWriteWeakGuard<
777    ST: sync_types::SyncTypes,
778    T: marker::Send + marker::Sync,
779    LP: sync_types::SyncRcPtr<AsyncRwLock<ST, T>>,
780> {
781    sem_exclusive_all_guard: semaphore::AsyncSemaphoreExclusiveAllWeakGuard<
782        ST,
783        T,
784        sync_types::SyncRcPtrForInner<AsyncRwLock<ST, T>, LP, AsyncRwLockIndexInnerSemTag>,
785    >,
786}
787
788impl<ST: sync_types::SyncTypes, T: marker::Send + marker::Sync, LP: sync_types::SyncRcPtr<AsyncRwLock<ST, T>>>
789    AsyncRwLockWriteWeakGuard<ST, T, LP>
790{
791    /// Attempt to convert back into an [`AsyncRwLockWriteGuard`].
792    ///
793    /// Returns the [`AsyncRwLockWriteGuard`] wrapped in `Some` if the
794    /// associated [`AsyncRwLock`] is still alive, `None otherwise.
795    pub fn upgrade(self) -> Option<AsyncRwLockWriteGuard<ST, T, LP>> {
796        self.sem_exclusive_all_guard
797            .upgrade()
798            .map(|sem_exclusive_all_guard| AsyncRwLockWriteGuard {
799                sem_exclusive_all_guard,
800            })
801    }
802}