Skip to main content

low_latency_data_structures/seqlock/
reader.rs

1use std::sync::Arc;
2
3use crate::seqlock::lock::SeqLock;
4
5/// A reading handle of a [`SeqLock`](crate::seqlock).
6///
7/// Cheap to clone: multiple readers may share the same lock. [`Reader`] is
8/// both [`Send`] and [`Sync`]; concurrent reads do not interfere because the
9/// underlying validation protocol is wait-free for readers in the absence of
10/// a concurrent writer and lock-free in its presence.
11pub struct Reader<T: bytemuck::AnyBitPattern> {
12    inner: Arc<SeqLock<T>>,
13}
14
15impl<T: bytemuck::AnyBitPattern> std::fmt::Debug for Reader<T> {
16    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
17        f.debug_struct("Reader").finish_non_exhaustive()
18    }
19}
20
21impl<T: bytemuck::AnyBitPattern> Clone for Reader<T> {
22    fn clone(&self) -> Self {
23        Self {
24            inner: self.inner.clone(),
25        }
26    }
27}
28
29impl<T: bytemuck::AnyBitPattern> Reader<T> {
30    pub(super) fn new(seqlock: Arc<SeqLock<T>>) -> Self {
31        Self { inner: seqlock }
32    }
33
34    /// Reads the latest stable value.
35    ///
36    /// Spin-loops while the writer is mid-write or while a torn read is
37    /// observed; returns once a consistent value has been observed.
38    ///
39    /// # Examples
40    ///
41    /// ```
42    /// use low_latency_data_structures::seqlock::new;
43    ///
44    /// let (writer, reader) = new(0u64);
45    /// writer.write(42);
46    /// assert_eq!(reader.read(), 42);
47    /// ```
48    #[inline]
49    #[must_use]
50    pub fn read(&self) -> T {
51        self.inner.read()
52    }
53}
54
55#[cfg(test)]
56mod tests {
57    use super::*;
58
59    // There may be multiple readers as they only read and don't mutate anything.
60    // In case someone removes unsafe impl on SeqLock
61    static_assertions::assert_impl_all!(Reader<u32>: Send, Sync);
62    static_assertions::assert_impl_all!(Arc<Reader<u32>>: Send, Clone);
63}