Skip to main content

proxima_primitives/sync/
rwlock.rs

1//! `proxima::sync::RwLock` — async reader-writer lock, shape-
2//! compatible with `tokio::sync::RwLock`. Backed by
3//! `async_lock::RwLock` with a thin newtype that reshapes
4//! `try_read` / `try_write` from `Option` (async-lock) to
5//! `Result<_, TryLockError>` (tokio). The async-lock variant is
6//! fair (FIFO across readers and writers) and provides the same
7//! `read(&self).await` / `write(&self).await` shape as tokio.
8//!
9//! # Non-coverage
10//!
11//! - `read_owned() -> OwnedRwLockReadGuard<T>` /
12//!   `write_owned() -> OwnedRwLockWriteGuard<T>` — Arc-coupled owned
13//!   guards. tokio offers these for guards that outlive a borrow of
14//!   the lock; `async_lock::RwLock` has no analog. Mirror of the
15//!   `lock_owned` gap on Mutex.
16//! - `try_read_owned() -> Result<OwnedRwLockReadGuard<T>, TryLockError>`
17//!   and `try_write_owned()` — same.
18//! - `read_arc()` / `write_arc()` — async-lock's Arc-coupled variants;
19//!   not re-exported because no caller currently needs them.
20//! - `RwLock::blocking_read()` / `RwLock::blocking_write()` — sync-
21//!   context acquisition. Don't use sync acquisition from async code.
22
23pub use async_lock::{RwLockReadGuard, RwLockWriteGuard};
24
25use crate::sync::TryLockError;
26
27/// Async reader-writer lock matching `tokio::sync::RwLock`'s shape.
28#[derive(Debug, Default)]
29pub struct RwLock<T: ?Sized>(async_lock::RwLock<T>);
30
31impl<T> RwLock<T> {
32    /// New lock containing `value`.
33    #[must_use]
34    pub fn new(value: T) -> Self {
35        Self(async_lock::RwLock::new(value))
36    }
37
38    /// Consume the lock, returning the inner value.
39    pub fn into_inner(self) -> T {
40        self.0.into_inner()
41    }
42}
43
44impl<T: ?Sized> RwLock<T> {
45    /// Acquire shared read access asynchronously.
46    pub async fn read(&self) -> RwLockReadGuard<'_, T> {
47        self.0.read().await
48    }
49
50    /// Acquire exclusive write access asynchronously.
51    pub async fn write(&self) -> RwLockWriteGuard<'_, T> {
52        self.0.write().await
53    }
54
55    /// Try to acquire a read guard without waiting.
56    pub fn try_read(&self) -> Result<RwLockReadGuard<'_, T>, TryLockError> {
57        self.0
58            .try_read()
59            .ok_or_else(crate::sync::mutex::try_lock_error)
60    }
61
62    /// Try to acquire a write guard without waiting.
63    pub fn try_write(&self) -> Result<RwLockWriteGuard<'_, T>, TryLockError> {
64        self.0
65            .try_write()
66            .ok_or_else(crate::sync::mutex::try_lock_error)
67    }
68
69    /// Mutable access without locking — `&mut self` proves exclusivity
70    /// statically.
71    pub fn get_mut(&mut self) -> &mut T {
72        self.0.get_mut()
73    }
74}