Skip to main content

low_latency_data_structures/seqlock/
writer.rs

1use std::marker::PhantomData;
2use std::sync::Arc;
3
4use crate::seqlock::lock::SeqLock;
5
6/// The writing handle of a [`SeqLock`](crate::seqlock).
7///
8/// `Writer` is [`Send`] but not [`Sync`]: at most one thread may write at a
9/// time. To enforce that, the type is neither [`Clone`] nor [`Copy`].
10pub struct Writer<T: bytemuck::AnyBitPattern> {
11    inner: Arc<SeqLock<T>>,
12    // Remove possibility to share ownership
13    _not_sync: PhantomData<*const ()>,
14}
15
16impl<T: bytemuck::AnyBitPattern> std::fmt::Debug for Writer<T> {
17    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
18        f.debug_struct("Writer").finish_non_exhaustive()
19    }
20}
21
22// SAFETY: SeqLock<T> is Send, we just need to forbid Sync.
23unsafe impl<T: bytemuck::AnyBitPattern> Send for Writer<T> {}
24
25impl<T: bytemuck::AnyBitPattern> Writer<T> {
26    pub(super) fn new(seqlock: Arc<SeqLock<T>>) -> Self {
27        Self {
28            inner: seqlock,
29            _not_sync: PhantomData,
30        }
31    }
32
33    /// Writes a new value, replacing the current one.
34    ///
35    /// Wait-free. Concurrent readers may observe the in-progress write but
36    /// will retry until they see a consistent value.
37    ///
38    /// # Examples
39    ///
40    /// ```
41    /// use low_latency_data_structures::seqlock::new;
42    ///
43    /// let (writer, reader) = new(0u64);
44    /// writer.write(7);
45    /// assert_eq!(reader.read(), 7);
46    /// ```
47    #[inline]
48    pub fn write(&self, value: T) {
49        self.inner.write(value)
50    }
51}
52
53#[cfg(test)]
54mod tests {
55    use super::*;
56
57    // Writer can be sent to another thread.
58    static_assertions::assert_impl_all!(Writer<u32>: Send);
59    // Though, there may only be single writer at most.
60    static_assertions::assert_not_impl_any!(Writer<u32>: Sync, Clone, Copy);
61    static_assertions::assert_not_impl_any!(Arc<Writer<u32>>: Send, Sync, Copy);
62}