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>
12where
13 T: bytemuck::AnyBitPattern,
14{
15 inner: Arc<SeqLock<T>>,
16}
17
18impl<T> std::fmt::Debug for Reader<T>
19where
20 T: bytemuck::AnyBitPattern,
21{
22 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
23 f.debug_struct("Reader").finish_non_exhaustive()
24 }
25}
26
27impl<T> Clone for Reader<T>
28where
29 T: bytemuck::AnyBitPattern,
30{
31 fn clone(&self) -> Self {
32 Self {
33 inner: self.inner.clone(),
34 }
35 }
36}
37
38impl<T> Reader<T>
39where
40 T: bytemuck::AnyBitPattern,
41{
42 pub(super) fn new(seqlock: Arc<SeqLock<T>>) -> Self {
43 Self { inner: seqlock }
44 }
45
46 /// Reads the latest stable value.
47 ///
48 /// Spin-loops while the writer is mid-write or while a torn read is
49 /// observed; returns once a consistent value has been observed.
50 ///
51 /// # Examples
52 ///
53 /// ```
54 /// use low_latency_data_structures::seqlock::new;
55 ///
56 /// let (writer, reader) = new(0u64);
57 /// writer.write(42);
58 /// assert_eq!(reader.read(), 42);
59 /// ```
60 #[inline]
61 #[must_use]
62 pub fn read(&self) -> T {
63 self.inner.read()
64 }
65}
66
67#[cfg(test)]
68mod tests {
69 use super::*;
70
71 // There may be multiple readers as they only read and don't mutate anything.
72 // In case someone removes unsafe impl on SeqLock
73 static_assertions::assert_impl_all!(Reader<u32>: Send, Sync);
74 static_assertions::assert_impl_all!(Arc<Reader<u32>>: Send, Clone);
75}