1#[allow(deprecated)]
7use super::frozen::Frozen;
8use super::{
9 direct::{Direct, Obs},
10 traits::Wrap,
11};
12use crate::{
13 rb::RbRef,
14 traits::{
15 Observer,
16 consumer::{Consumer, impl_consumer_traits},
17 producer::{Producer, impl_producer_traits},
18 },
19};
20use core::{cell::Cell, mem::MaybeUninit, num::NonZeroUsize};
21
22pub struct Caching<R: RbRef, const P: bool, const C: bool> {
24 base: Direct<R, P, C>,
25 read: Cell<usize>,
26 write: Cell<usize>,
27}
28
29pub type CachingProd<R> = Caching<R, true, false>;
31pub type CachingCons<R> = Caching<R, false, true>;
33
34impl<R: RbRef, const P: bool, const C: bool> Caching<R, P, C> {
35 pub fn new(rb: R) -> Self {
39 Self::from_direct(Direct::new(rb))
40 }
41
42 pub(crate) fn from_direct(base: Direct<R, P, C>) -> Self {
43 Self {
44 read: Cell::new(base.read_index()),
45 write: Cell::new(base.write_index()),
46 base,
47 }
48 }
49
50 pub fn observe(&self) -> Obs<R> {
52 self.base.observe()
53 }
54
55 #[deprecated(note = "use the caching endpoint directly; freezing no longer delays publication")]
57 #[allow(deprecated)]
58 pub fn freeze(self) -> Frozen<R, P, C> {
59 Frozen::from_caching(self)
60 }
61
62 pub(crate) fn fetch(&self) {
63 if P {
64 self.read.set(self.base.read_index());
65 }
66 if C {
67 self.write.set(self.base.write_index());
68 }
69 }
70}
71
72impl<R: RbRef, const P: bool, const C: bool> Wrap for Caching<R, P, C> {
73 type RbRef = R;
74
75 fn rb_ref(&self) -> &R {
76 self.base.rb_ref()
77 }
78 fn into_rb_ref(self) -> R {
79 self.base.into_rb_ref()
80 }
81}
82
83impl<R: RbRef, const P: bool, const C: bool> AsRef<Self> for Caching<R, P, C> {
84 fn as_ref(&self) -> &Self {
85 self
86 }
87}
88impl<R: RbRef, const P: bool, const C: bool> AsMut<Self> for Caching<R, P, C> {
89 fn as_mut(&mut self) -> &mut Self {
90 self
91 }
92}
93
94impl<R: RbRef, const P: bool, const C: bool> Observer for Caching<R, P, C> {
95 type Item = <R::Rb as Observer>::Item;
96
97 #[inline]
98 fn capacity(&self) -> NonZeroUsize {
99 self.base.capacity()
100 }
101
102 #[inline]
103 fn read_index(&self) -> usize {
104 if P {
105 self.fetch();
106 }
107 self.read.get()
108 }
109 #[inline]
110 fn write_index(&self) -> usize {
111 if C {
112 self.fetch();
113 }
114 self.write.get()
115 }
116
117 unsafe fn unsafe_slices(&self, start: usize, end: usize) -> (&[MaybeUninit<Self::Item>], &[MaybeUninit<Self::Item>]) {
118 unsafe { self.base.unsafe_slices(start, end) }
119 }
120 unsafe fn unsafe_slices_mut(&self, start: usize, end: usize) -> (&mut [MaybeUninit<Self::Item>], &mut [MaybeUninit<Self::Item>]) {
121 unsafe { self.base.unsafe_slices_mut(start, end) }
122 }
123
124 #[inline]
125 fn read_is_held(&self) -> bool {
126 self.base.read_is_held()
127 }
128 #[inline]
129 fn write_is_held(&self) -> bool {
130 self.base.write_is_held()
131 }
132}
133
134impl<R: RbRef> Producer for CachingProd<R> {
135 #[inline]
136 unsafe fn set_write_index(&self, value: usize) {
137 self.write.set(value);
138 unsafe { self.base.set_write_index(value) };
139 }
140
141 fn try_push(&mut self, elem: Self::Item) -> Result<(), Self::Item> {
142 let capacity = self.capacity().get();
143 if self.write.get().abs_diff(self.read.get()) == capacity {
144 self.fetch();
145 }
146 if self.write.get().abs_diff(self.read.get()) == capacity {
147 return Err(elem);
148 }
149 let write = self.write.get();
150 unsafe {
152 self.unsafe_slices_mut(write, write + 1).0.get_unchecked_mut(0).write(elem);
153 self.advance_write_index(1);
154 }
155 Ok(())
156 }
157}
158
159impl<R: RbRef> Consumer for CachingCons<R> {
160 #[inline]
161 unsafe fn set_read_index(&self, value: usize) {
162 self.read.set(value);
163 unsafe { self.base.set_read_index(value) };
164 }
165
166 fn try_pop(&mut self) -> Option<<Self as Observer>::Item> {
167 if self.read.get() == self.write.get() {
168 self.fetch();
169 }
170 if self.read.get() == self.write.get() {
171 return None;
172 }
173 let read = self.read.get();
174 let item = unsafe { self.unsafe_slices(read, read + 1).0.get_unchecked(0).assume_init_read() };
176 unsafe { self.advance_read_index(1) };
177 Some(item)
178 }
179}
180
181impl_producer_traits!(CachingProd<R: RbRef>);
182impl_consumer_traits!(CachingCons<R: RbRef>);