ringbuf/wrap/
frozen.rs

1//! Frozen implementation.
2//!
3//! Changes are not synchronized with the ring buffer until its explicitly requested or when dropped.
4
5use super::{direct::Obs, traits::Wrap};
6use crate::{
7    rb::RbRef,
8    traits::{
9        consumer::{impl_consumer_traits, Consumer},
10        producer::{impl_producer_traits, Producer},
11        Observer, RingBuffer,
12    },
13};
14use core::{
15    cell::Cell,
16    mem::{ManuallyDrop, MaybeUninit},
17    num::NonZeroUsize,
18    ptr,
19};
20
21/// Frozen wrapper of the ring buffer.
22pub struct Frozen<R: RbRef, const P: bool, const C: bool> {
23    rb: R,
24    read: Cell<usize>,
25    write: Cell<usize>,
26}
27
28/// Frozen write end of some ring buffer.
29///
30/// Inserted items is not visible for an opposite write end until [`Self::commit`]/[`Self::sync`] is called or `Self` is dropped.
31/// A free space of items removed by an opposite write end is not visible for `Self` until [`Self::sync`] is called.
32pub type FrozenProd<R> = Frozen<R, true, false>;
33
34/// Frozen read end of some ring buffer.
35///
36/// A free space of removed items is not visible for an opposite write end until [`Self::commit`]/[`Self::sync`] is called or `Self` is dropped.
37/// Items inserted by an opposite write end is not visible for `Self` until [`Self::sync`] is called.
38pub type FrozenCons<R> = Frozen<R, false, true>;
39
40impl<R: RbRef, const P: bool, const C: bool> Frozen<R, P, C> {
41    /// Create a new ring buffer frozen wrapper.
42    ///
43    /// Panics if wrapper with matching rights already exists.
44    pub fn new(rb: R) -> Self {
45        if P {
46            assert!(!unsafe { rb.rb().hold_write(true) });
47        }
48        if C {
49            assert!(!unsafe { rb.rb().hold_read(true) });
50        }
51        unsafe { Self::new_unchecked(rb) }
52    }
53
54    /// Create wrapper without checking that such wrapper already exists.
55    ///
56    /// # Safety
57    ///
58    /// There must be maximum one instance of matching rights.
59    pub(crate) unsafe fn new_unchecked(rb: R) -> Self {
60        Self {
61            read: Cell::new(rb.rb().read_index()),
62            write: Cell::new(rb.rb().write_index()),
63            rb,
64        }
65    }
66
67    /// Get ring buffer observer.
68    pub fn observe(&self) -> Obs<R> {
69        Obs::new(self.rb.clone())
70    }
71
72    unsafe fn close(&mut self) {
73        if P {
74            self.rb().hold_write(false);
75        }
76        if C {
77            self.rb().hold_read(false);
78        }
79    }
80}
81
82impl<R: RbRef, const P: bool, const C: bool> Wrap for Frozen<R, P, C> {
83    type RbRef = R;
84
85    fn rb_ref(&self) -> &R {
86        &self.rb
87    }
88    fn into_rb_ref(mut self) -> R {
89        self.commit();
90        unsafe {
91            self.close();
92            let this = ManuallyDrop::new(self);
93            ptr::read(&this.rb)
94        }
95    }
96}
97
98impl<R: RbRef, const P: bool, const C: bool> AsRef<Self> for Frozen<R, P, C> {
99    fn as_ref(&self) -> &Self {
100        self
101    }
102}
103impl<R: RbRef, const P: bool, const C: bool> AsMut<Self> for Frozen<R, P, C> {
104    fn as_mut(&mut self) -> &mut Self {
105        self
106    }
107}
108
109impl<R: RbRef, const P: bool, const C: bool> Frozen<R, P, C> {
110    /// Commit changes to the ring buffer.
111    pub fn commit(&self) {
112        unsafe {
113            if P {
114                self.rb().set_write_index(self.write.get());
115            }
116            if C {
117                self.rb().set_read_index(self.read.get());
118            }
119        }
120    }
121
122    /// Fetch changes from the ring buffer.
123    pub fn fetch(&self) {
124        if P {
125            self.read.set(self.rb().read_index());
126        }
127        if C {
128            self.write.set(self.rb().write_index());
129        }
130    }
131
132    /// Commit changes to and fetch updates from the ring buffer.
133    pub fn sync(&self) {
134        self.commit();
135        self.fetch();
136    }
137}
138
139impl<R: RbRef> FrozenProd<R> {
140    /// Discard new items pushed since last sync.
141    pub fn discard(&mut self) {
142        let last_tail = self.rb().write_index();
143        let (first, second) = unsafe { self.rb().unsafe_slices_mut(last_tail, self.write.get()) };
144        for item_mut in first.iter_mut().chain(second.iter_mut()) {
145            unsafe { item_mut.assume_init_drop() };
146        }
147        self.write.set(last_tail);
148    }
149}
150
151impl<R: RbRef, const P: bool, const C: bool> Observer for Frozen<R, P, C> {
152    type Item = <R::Rb as Observer>::Item;
153
154    #[inline]
155    fn capacity(&self) -> NonZeroUsize {
156        self.rb().capacity()
157    }
158
159    #[inline]
160    fn read_index(&self) -> usize {
161        self.read.get()
162    }
163    #[inline]
164    fn write_index(&self) -> usize {
165        self.write.get()
166    }
167
168    unsafe fn unsafe_slices(&self, start: usize, end: usize) -> (&[MaybeUninit<Self::Item>], &[MaybeUninit<Self::Item>]) {
169        self.rb().unsafe_slices(start, end)
170    }
171    unsafe fn unsafe_slices_mut(&self, start: usize, end: usize) -> (&mut [MaybeUninit<Self::Item>], &mut [MaybeUninit<Self::Item>]) {
172        self.rb().unsafe_slices_mut(start, end)
173    }
174
175    #[inline]
176    fn read_is_held(&self) -> bool {
177        self.rb().read_is_held()
178    }
179    #[inline]
180    fn write_is_held(&self) -> bool {
181        self.rb().write_is_held()
182    }
183}
184
185impl<R: RbRef> Producer for FrozenProd<R> {
186    #[inline]
187    unsafe fn set_write_index(&self, value: usize) {
188        self.write.set(value);
189    }
190}
191
192impl<R: RbRef> Consumer for FrozenCons<R> {
193    #[inline]
194    unsafe fn set_read_index(&self, value: usize) {
195        self.read.set(value);
196    }
197}
198
199impl<R: RbRef, const P: bool, const C: bool> Drop for Frozen<R, P, C> {
200    fn drop(&mut self) {
201        self.commit();
202        unsafe { self.close() };
203    }
204}
205
206impl_producer_traits!(FrozenProd<R: RbRef>);
207impl_consumer_traits!(FrozenCons<R: RbRef>);