simple_left_right/
lib.rs

1//! Simpler version of the left-right from Jon Gjengset library.
2//!
3//! Uses two copies of the value to allow doing small changes, while still allowing non-blocking reading.
4//! Writing can block, while reading doesn't.
5#![no_std]
6
7extern crate alloc;
8
9use core::{marker::PhantomData, ops::Deref, ptr::NonNull};
10
11use alloc::collections::vec_deque::VecDeque;
12
13mod shared;
14
15use shared::{Ptr, Shared};
16
17/// Should be implemented on structs that want to be shared with this library
18pub trait Absorb<O> {
19    /// has to be deterministic. Operations will be applied in the same order to both buffers
20    fn absorb(&mut self, operation: O);
21}
22
23/// Dropping the Reader isn't realtime safe, because if dropped after the Writer, it deallocates.
24/// Should only get dropped, when closing the real-time thread
25///
26/// Reader will be able to read data even if Writer has been dropped. Obviously that data won't change anymore
27/// When there is no Reader the Writer is able to create a new one. The other way around doesn't work.
28///
29/// Isn't Sync as there is no methos that takes &self, so it is useless anyways.
30#[derive(Debug)]
31pub struct Reader<T> {
32    shared: NonNull<Shared<T>>,
33    /// for drop check
34    _own: PhantomData<Shared<T>>,
35}
36
37impl<T> Reader<T> {
38    fn shared_ref(&self) -> &Shared<T> {
39        // SAFETY: Reader always has a valid Shared<T>, a mut ref to a shared is never created,
40        // only to the UnsafeCell<T>s inside of it
41        unsafe { self.shared.as_ref() }
42    }
43
44    /// this function never blocks. (`fetch_update` loop doesn't count)
45    #[inline]
46    pub fn lock(&mut self) -> ReadGuard<'_, T> {
47        let shared_ref = self.shared_ref();
48
49        ReadGuard {
50            shared: shared_ref,
51            value: shared_ref.lock_read(),
52            reader: PhantomData,
53        }
54    }
55}
56
57/// SAFETY: Owns a T
58unsafe impl<T: Send> Send for Reader<T> {}
59
60impl<T> Drop for Reader<T> {
61    #[inline]
62    fn drop(&mut self) {
63        // SAFETY: self.shared is valid and not used after this.
64        unsafe { Shared::drop(self.shared) };
65    }
66}
67
68/// Data won't change while holding the Guard. This also means the Writer can only issue one swap, while Guard is being held
69/// If T: !Sync this is guaranteed to be the only ref to this T
70///
71/// Doesn't implement Clone as that would require refcounting to know when to unlock.
72#[derive(Debug)]
73pub struct ReadGuard<'a, T> {
74    shared: &'a Shared<T>,
75    value: Ptr,
76    /// `PhantomData` makes the borrow checker prove that there only ever is one `ReadGuard`.
77    /// This allows resetting the readstate without some kind of counter
78    reader: PhantomData<&'a mut Reader<T>>,
79}
80
81impl<T> Deref for ReadGuard<'_, T> {
82    type Target = T;
83
84    #[inline]
85    fn deref(&self) -> &Self::Target {
86        // SAFETY: ReadGuard was created, so the Writer knows not to write in this spot
87        unsafe { self.shared.get_value_ref(self.value) }
88    }
89}
90
91impl<T, E> AsRef<E> for ReadGuard<'_, T>
92where
93    E: ?Sized,
94    T: AsRef<E>,
95{
96    #[inline]
97    fn as_ref(&self) -> &E {
98        self.deref().as_ref()
99    }
100}
101
102// /// SAFETY: behaves like a ref to T. https://doc.rust-lang.org/std/marker/trait.Sync.html
103// unsafe impl<T: Sync> Send for ReadGuard<'_, T> {}
104// /// SAFETY: behaves like a ref to T. https://doc.rust-lang.org/std/marker/trait.Sync.html
105// unsafe impl<T: Sync> Sync for ReadGuard<'_, T> {}
106
107impl<T> Drop for ReadGuard<'_, T> {
108    #[inline]
109    fn drop(&mut self) {
110        // release the read lock
111        self.shared.release_read_lock();
112    }
113}
114
115/// Not realtime safe object which can change the internal T value.
116#[derive(Debug)]
117pub struct Writer<T, O> {
118    shared: NonNull<Shared<T>>,
119    // sets which buffer the next write is applied to
120    // write_ptr doesn't need to be Atomics as it only changes, when the Writer itself swaps
121    write_ptr: Ptr,
122    // buffer is pushed at the back and popped at the front.
123    op_buffer: VecDeque<O>,
124    // needed for drop_check
125    _own: PhantomData<Shared<T>>,
126}
127
128impl<T, O> Writer<T, O> {
129    fn shared_ref(&self) -> &Shared<T> {
130        // SAFETY: Reader always has a valid Shared<T>, the only possibility to get a &mut Shared requires &mut self
131        unsafe { self.shared.as_ref() }
132    }
133
134    /// if no Reader exists this gives a mut ref to Shared.
135    fn shared_mut(&mut self) -> Option<&mut Shared<T>> {
136        self.shared_ref()
137            .is_unique()
138            // SAFETY: No `Reader` exists, as `is_unique` returns true
139            .then(|| unsafe { &mut *self.shared.as_ptr() })
140    }
141
142    /// swaps the read and write values. If no changes were made since the last swap nothing happens. Never blocks
143    /// not public as swapping without creating a before `WriteGuard` is pretty useless
144    fn swap(&mut self) {
145        if self.op_buffer.is_empty() {
146            return;
147        }
148
149        self.shared_ref().set_read_ptr(self.write_ptr);
150
151        self.write_ptr.switch();
152    }
153
154    /// get a Reader if none exists
155    #[inline]
156    pub fn build_reader(&mut self) -> Option<Reader<T>> {
157        let shared_ref = self.shared_ref();
158        // SAFETY: all is_unique_with_increase requirements are satisfied.
159        unsafe {
160            shared_ref.is_unique().then(|| {
161                shared_ref.set_shared();
162                Reader {
163                    shared: self.shared,
164                    _own: PhantomData,
165                }
166            })
167        }
168    }
169}
170
171impl<T: Absorb<O>, O> Writer<T, O> {
172    /// doesn't block. Returns None if the Reader has a `ReadGuard` pointing to the old value.
173    #[must_use]
174    pub fn try_lock(&mut self) -> Option<WriteGuard<'_, T, O>> {
175        self.shared_ref()
176            .lock_write(self.write_ptr)
177            .ok()
178            // locking was successful
179            .map(|()| {
180                // WriteGuard::new(self)
181                let mut guard = WriteGuard { writer: self };
182                while let Some(operation) = guard.writer.op_buffer.pop_front() {
183                    guard.get_data_mut().absorb(operation);
184                }
185                guard
186            })
187    }
188}
189
190impl<T: Clone, O> Writer<T, O> {
191    /// Creates a new Writer by cloning the value once to get two values
192    /// `T::clone()` shoulnd't give a different value, as that would make this library pretty useless
193    #[inline]
194    pub fn new(value: T) -> Self {
195        let (shared, write_ptr) = Shared::new(value, |value_1| value_1.clone());
196        Self {
197            shared,
198            write_ptr,
199            op_buffer: VecDeque::new(),
200            _own: PhantomData,
201        }
202    }
203}
204
205impl<T: Default, O> Default for Writer<T, O> {
206    /// Creates a new Writer by calling `T::default()` twice to create the two values
207    ///
208    /// Default impl of T needs to give the same result every time. Not upholding this doens't lead to UB, but turns the library basically useless
209    #[inline]
210    fn default() -> Self {
211        let (shared, write_ptr) = Shared::new(T::default(), |_| T::default());
212        Self {
213            shared,
214            write_ptr,
215            op_buffer: VecDeque::new(),
216            _own: PhantomData,
217        }
218    }
219}
220
221impl<T: Sync, O> Writer<T, O> {
222    /// The Value returned may be newer than the version the reader is currently seeing.
223    /// This value will be written to next.
224    /// If this is called after swapping the write_lock this will return an older value.
225    /// To get the newest value lock the writer and call `Writeguard::read`.
226    ///
227    /// Needs T: Sync because maybe this is the value the reader is curently reading
228    pub fn read(&self) -> &T {
229        // SAFETY: Only the WriteGuard can write to the values / create mut refs to them.
230        // The WriteGuard holds a mut ref to the writer so this function can't be called while a writeguard exists
231        // This means that reading them / creating refs is safe to do
232        unsafe { self.shared_ref().get_value_ref(self.write_ptr) }
233    }
234}
235
236/// SAFETY: owns T and O
237unsafe impl<T: Send, O: Send> Send for Writer<T, O> {}
238/// SAFETY: &self fn can only create a &T and never gives shared access to O
239unsafe impl<T: Sync, O> Sync for Writer<T, O> {}
240
241impl<T, O> Drop for Writer<T, O> {
242    #[inline]
243    fn drop(&mut self) {
244        // SAFETY: self.shared is valid and not used after this.
245        unsafe { Shared::drop(self.shared) };
246    }
247}
248
249// Don't create a WriteGuard directly, as that wouldn't sync with old Operations
250/// Can be used to write to the Data structure.
251///
252/// When this structure exists the Reader already switched to the other value
253///
254/// Dropping this makes all changes available to the Reader.
255#[derive(Debug)]
256pub struct WriteGuard<'a, T, O> {
257    writer: &'a mut Writer<T, O>,
258}
259
260impl<T, O> WriteGuard<'_, T, O> {
261    /// Makes the changes available to the reader. Equivalent to `std::mem::drop(self)`
262    #[inline]
263    pub fn swap(self) {}
264
265    /// Gets the value currently being written to.
266    #[inline]
267    pub fn read(&self) -> &T {
268        // SAFETY: Only the WriteGuard can write to the values / create mut refs to them.
269        // The WriteGuard holds a mut ref to the writer so this function can't be called while a writeguard exists
270        // This means that reading them / creating refs is safe to do
271        unsafe {
272            self.writer
273                .shared_ref()
274                .get_value_ref(self.writer.write_ptr)
275        }
276    }
277
278    /// Isn't public as this could easily create disconnects between the two versions.
279    /// While that wouldn't lead to UB it goes against the purpose of this library
280    fn get_data_mut(&mut self) -> &mut T {
281        // SAFETY: When creating the writeguad it is checked that the reader doesnt have access to the same data
282        // This function requires &mut self so there also isn't any ref created by writeguard.
283        unsafe {
284            &mut *self
285                .writer
286                .shared_ref()
287                .get_value(self.writer.write_ptr)
288                .get()
289        }
290    }
291}
292
293impl<T: Absorb<O>, O: Clone> WriteGuard<'_, T, O> {
294    /// applies operation to the current write Value and stores it to apply to the other later.
295    /// If there is no reader the operation is applied to both values immediately and not stored.
296    #[inline]
297    pub fn apply_op(&mut self, operation: O) {
298        if let Some(shared) = self.writer.shared_mut() {
299            shared.value_1.get_mut().absorb(operation.clone());
300            shared.value_2.get_mut().absorb(operation);
301        } else {
302            self.writer.op_buffer.push_back(operation.clone());
303            self.get_data_mut().absorb(operation);
304        }
305    }
306}
307
308// /// SAFETY: behaves like a &mut T and &mut Vec<O>. https://doc.rust-lang.org/stable/std/marker/trait.Sync.html
309// unsafe impl<T: Send, O: Send> Send for WriteGuard<'_, T, O> {}
310
311// /// Safety: can only create shared refs to T, not to O. https://doc.rust-lang.org/stable/std/marker/trait.Sync.html
312// unsafe impl<T: Sync, O> Sync for WriteGuard<'_, T, O> {}
313
314impl<T, O> Drop for WriteGuard<'_, T, O> {
315    #[inline]
316    fn drop(&mut self) {
317        self.writer.swap();
318    }
319}
320
321#[cfg(test)]
322mod internal_test {
323    use core::cell::Cell;
324
325    use crate::{Absorb, Writer};
326
327    #[derive(Clone, Copy, Debug)]
328    pub struct CounterAddOp(i32);
329
330    impl Absorb<CounterAddOp> for i32 {
331        fn absorb(&mut self, operation: CounterAddOp) {
332            *self += operation.0;
333        }
334    }
335
336    impl Absorb<CounterAddOp> for Cell<i32> {
337        fn absorb(&mut self, operation: CounterAddOp) {
338            self.set(self.get() + operation.0);
339        }
340    }
341
342    #[test]
343    fn drop_reader() {
344        let mut writer: Writer<i32, CounterAddOp> = Writer::default();
345        let reader = writer.build_reader().unwrap();
346
347        assert!(!writer.shared_ref().is_unique());
348        drop(reader);
349        assert!(writer.shared_ref().is_unique());
350    }
351
352    #[test]
353    fn drop_writer() {
354        let mut writer: Writer<i32, CounterAddOp> = Writer::default();
355        let reader = writer.build_reader().unwrap();
356
357        assert!(!reader.shared_ref().is_unique());
358        drop(writer);
359        assert!(reader.shared_ref().is_unique());
360    }
361}