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}