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
use crate::{
    mutex::{Guard, Mutex},
    rwlock::{ReadGuard, RwLock},
};

/// A reader-writer lock that only syncs when the `sync` method is called.
///
/// This is similar to a [`RwLock`], except that writes are not instantly
/// realized by parallel readers. Instead, writes are only realized when the
/// `sync` method is called. This is useful for cases where you want to write to a value, but you don't
/// want to block readers while you do so.
///
/// This type only implements [`Sync`] when `T` is [`Send`]. Syncing and the non-const [`new`](Self::new)
/// method require `T` to implement [`Clone`]. Values are provided through the [`Deref`](std::ops::Deref)
/// and [`DerefMut`](std::ops::DerefMut) implementations on the [`ReadGuard`] and [`Guard`] types.
///
/// # Examples
/// ```rust
/// use no_std_async::SwapLock;
/// # fn main() { pollster::block_on(foo()); }
///
/// async fn foo() {
///     let lock = SwapLock::new(42);
///     let read = lock.read().await;
///     assert_eq!(*read, 42);
///
///     let mut write = lock.write().await;
///     *write += 1;
///     assert_eq!(*write, 43); // All writers will read the new value.
///     assert_eq!(*read, 42); // The read value is not updated until `sync` is called.
///
///     drop(read);
///     drop(write);
///
///     lock.sync().await;
///     let read = lock.read().await;
///     assert_eq!(*read, 43); // The value has now been updated.
/// }
pub struct SwapLock<T> {
    data: RwLock<T>,
    write: Mutex<T>,
}
impl<T> SwapLock<T> {
    /// Creates a new [`SwapLock`] with the given data.
    pub fn new(val: T) -> Self
    where
        T: Clone,
    {
        Self {
            data: RwLock::new(val.clone()),
            write: Mutex::new(val),
        }
    }
    /// Creates a new [`SwapLock`] with the given data and write value.
    /// These values should be the same. In [`new`](Self::new), it is simply cloned,
    /// but this is not possible in a const context.
    pub const fn const_new(data: T, write: T) -> Self {
        Self {
            data: RwLock::new(data),
            write: Mutex::new(write),
        }
    }

    /// Syncs the data with the written value.
    /// This function waits for ***all locks*** to be released.
    /// This means that holding a read ***or*** write lock will deadlock
    /// if you call this function.
    pub async fn sync(&self)
    where
        T: Clone,
    {
        *self.data.write().await = self.write.lock().await.clone();
    }

    /// Acquires a read lock on the data.
    pub async fn read(&self) -> ReadGuard<'_, T> {
        self.data.read().await
    }
    /// Acquires a write lock on the data.
    pub async fn write(&self) -> Guard<'_, T> {
        self.write.lock().await
    }
}

unsafe impl<T: Send> Send for SwapLock<T> {}
unsafe impl<T: Send> Sync for SwapLock<T> {}