no_std_async/
rwlock.rs

1use core::{
2    cell::UnsafeCell,
3    ops::{Deref, DerefMut},
4};
5
6use crate::semaphore::Semaphore;
7
8/// An async reader-writer lock.
9///
10/// This lock allows `max_readers` readers at once, or one writer. This is different from a mutex,
11/// which only allows one *lock* at a time, regardless of whether it is used for reading or writing.
12///
13/// This lock is fair, meaning that locks are provided in the order that they are requested.
14/// This is in contrast to a read-preferring lock, which would continue to allow readers to lock
15/// even if a writer is waiting. This stops the possibility of readers starving writers.
16///
17/// This type only implements [`Sync`] when `T` is [`Send`]. Values are provided through the [`Deref`]
18/// and [`DerefMut`] implementations on the [`ReadGuard`] and [`WriteGuard`] types.
19///
20/// # Examples
21/// ```rust
22/// use no_std_async::RwLock;
23/// # fn main() { pollster::block_on(foo()); }
24///
25/// async fn foo() {
26///     let lock = RwLock::new(42);
27///
28///     {
29///         // we can have as many readers as we want.
30///         let reads = [
31///            lock.read().await,
32///            lock.read().await,
33///            lock.read().await,
34///            lock.read().await,
35///            // ...and so on
36///         ];
37///         assert!(reads.iter().all(|r| **r == 42));
38///     } // all readers are dropped here.
39///
40///     {
41///         // we can only have one writer at a time.
42///         let mut write = lock.write().await;
43///         *write += 1;
44///         assert_eq!(*write, 43);
45///     } // the writer is dropped here.
46/// }
47/// ```
48pub struct RwLock<T> {
49    data: UnsafeCell<T>,
50    semaphore: Semaphore,
51    max_readers: usize,
52}
53impl<T> RwLock<T> {
54    /// Creates a new [`RwLock`] with the given data.
55    pub const fn new(data: T) -> Self {
56        Self::with_max_readers(data, usize::MAX)
57    }
58    /// Creates a new [`RwLock`] with the given data and maximum number of readers.
59    pub const fn with_max_readers(data: T, max_readers: usize) -> Self {
60        Self {
61            data: UnsafeCell::new(data),
62            semaphore: Semaphore::new(max_readers),
63            max_readers,
64        }
65    }
66
67    /// Acquires a read lock on the data.
68    pub async fn read(&self) -> ReadGuard<'_, T> {
69        self.semaphore.acquire(1).await;
70        ReadGuard { rwlock: self }
71    }
72    /// Acquires a write lock on the data.
73    pub async fn write(&self) -> WriteGuard<'_, T> {
74        self.semaphore.acquire(self.max_readers).await;
75        WriteGuard { rwlock: self }
76    }
77}
78
79unsafe impl<T: Send> Send for RwLock<T> {}
80unsafe impl<T: Send> Sync for RwLock<T> {}
81
82/// A guard that provides immutable access to the data in an [`RwLock`].
83/// The data can be accessed using the [`Deref`] implementation.
84pub struct ReadGuard<'a, T> {
85    rwlock: &'a RwLock<T>,
86}
87impl<T> Deref for ReadGuard<'_, T> {
88    type Target = T;
89
90    fn deref(&self) -> &Self::Target {
91        unsafe { &*self.rwlock.data.get() }
92    }
93}
94impl<T> Drop for ReadGuard<'_, T> {
95    fn drop(&mut self) {
96        self.rwlock.semaphore.release(1);
97    }
98}
99
100/// A guard that provides mutable access to the data in an [`RwLock`].
101/// The data can be accessed using the [`Deref`] and [`DerefMut`] implementations.
102pub struct WriteGuard<'a, T> {
103    rwlock: &'a RwLock<T>,
104}
105impl<T> Deref for WriteGuard<'_, T> {
106    type Target = T;
107
108    fn deref(&self) -> &Self::Target {
109        unsafe { &*self.rwlock.data.get() }
110    }
111}
112impl<T> DerefMut for WriteGuard<'_, T> {
113    fn deref_mut(&mut self) -> &mut Self::Target {
114        unsafe { &mut *self.rwlock.data.get() }
115    }
116}
117impl<T> Drop for WriteGuard<'_, T> {
118    fn drop(&mut self) {
119        self.rwlock.semaphore.release(self.rwlock.max_readers);
120    }
121}