no_std_async/swap_lock.rs
1use crate::{
2 mutex::{Guard, Mutex},
3 rwlock::{ReadGuard, RwLock},
4};
5
6/// A reader-writer lock that only syncs when the `sync` method is called.
7///
8/// This is similar to a [`RwLock`], except that writes are not instantly
9/// realized by parallel readers. Instead, writes are only realized when the
10/// `sync` method is called. This is useful for cases where you want to write to a value, but you don't
11/// want to block readers while you do so.
12///
13/// This type only implements [`Sync`] when `T` is [`Send`]. Syncing and the non-const [`new`](Self::new)
14/// method require `T` to implement [`Clone`]. Values are provided through the [`Deref`](std::ops::Deref)
15/// and [`DerefMut`](std::ops::DerefMut) implementations on the [`ReadGuard`] and [`Guard`] types.
16///
17/// # Examples
18/// ```rust
19/// use no_std_async::SwapLock;
20/// # fn main() { pollster::block_on(foo()); }
21///
22/// async fn foo() {
23/// let lock = SwapLock::new(42);
24/// let read = lock.read().await;
25/// assert_eq!(*read, 42);
26///
27/// let mut write = lock.write().await;
28/// *write += 1;
29/// assert_eq!(*write, 43); // All writers will read the new value.
30/// assert_eq!(*read, 42); // The read value is not updated until `sync` is called.
31///
32/// drop(read);
33/// drop(write);
34///
35/// lock.sync().await;
36/// let read = lock.read().await;
37/// assert_eq!(*read, 43); // The value has now been updated.
38/// }
39pub struct SwapLock<T> {
40 data: RwLock<T>,
41 write: Mutex<T>,
42}
43impl<T> SwapLock<T> {
44 /// Creates a new [`SwapLock`] with the given data.
45 pub fn new(val: T) -> Self
46 where
47 T: Clone,
48 {
49 Self {
50 data: RwLock::new(val.clone()),
51 write: Mutex::new(val),
52 }
53 }
54 /// Creates a new [`SwapLock`] with the given data and write value.
55 /// These values should be the same. In [`new`](Self::new), it is simply cloned,
56 /// but this is not possible in a const context.
57 pub const fn const_new(data: T, write: T) -> Self {
58 Self {
59 data: RwLock::new(data),
60 write: Mutex::new(write),
61 }
62 }
63
64 /// Syncs the data with the written value.
65 /// This function waits for ***all locks*** to be released.
66 /// This means that holding a read ***or*** write lock will deadlock
67 /// if you call this function.
68 pub async fn sync(&self)
69 where
70 T: Clone,
71 {
72 *self.data.write().await = self.write.lock().await.clone();
73 }
74
75 /// Acquires a read lock on the data.
76 pub async fn read(&self) -> ReadGuard<'_, T> {
77 self.data.read().await
78 }
79 /// Acquires a write lock on the data.
80 pub async fn write(&self) -> Guard<'_, T> {
81 self.write.lock().await
82 }
83}
84
85unsafe impl<T: Send> Send for SwapLock<T> {}
86unsafe impl<T: Send> Sync for SwapLock<T> {}