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}