ringbuf/wrap/
frozen.rs
1use 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
21pub struct Frozen<R: RbRef, const P: bool, const C: bool> {
23 rb: R,
24 read: Cell<usize>,
25 write: Cell<usize>,
26}
27
28pub type FrozenProd<R> = Frozen<R, true, false>;
33
34pub type FrozenCons<R> = Frozen<R, false, true>;
39
40impl<R: RbRef, const P: bool, const C: bool> Frozen<R, P, C> {
41 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 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 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 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 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 pub fn sync(&self) {
134 self.commit();
135 self.fetch();
136 }
137}
138
139impl<R: RbRef> FrozenProd<R> {
140 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>);