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