1use super::{
2 macros::rb_impl_init,
3 utils::{assert_capacity, ranges},
4};
5#[cfg(feature = "alloc")]
6use crate::traits::Split;
7use crate::{
8 storage::Storage,
9 traits::{
10 Observer, RingBuffer, SplitRef,
11 consumer::{Consumer, impl_consumer_traits},
12 producer::{Producer, impl_producer_traits},
13 },
14 wrap::{CachingCons, CachingProd},
15};
16use core::{
17 mem::{ManuallyDrop, MaybeUninit},
18 num::NonZeroUsize,
19 ptr,
20};
21use crossbeam_utils::CachePadded;
22
23#[cfg(not(feature = "portable-atomic"))]
24use core::sync::atomic::{AtomicBool, AtomicUsize, Ordering};
25#[cfg(feature = "portable-atomic")]
26use portable_atomic::{AtomicBool, AtomicUsize, Ordering};
27#[cfg(feature = "alloc")]
28use {crate::alias::Arc, alloc::boxed::Box};
29
30#[cfg_attr(
35 feature = "std",
36 doc = r##"
37```
38use std::thread;
39use ringbuf::{SharedRb, storage::Heap, traits::*};
40
41let rb = SharedRb::<Heap<i32>>::new(256);
42let (mut prod, mut cons) = rb.split();
43thread::spawn(move || {
44 prod.try_push(123).unwrap();
45})
46.join();
47thread::spawn(move || {
48 assert_eq!(cons.try_pop().unwrap(), 123);
49})
50.join();
51```
52"##
53)]
54pub struct SharedRb<S: Storage + ?Sized> {
55 read_index: CachePadded<AtomicUsize>,
56 write_index: CachePadded<AtomicUsize>,
57 read_held: AtomicBool,
58 write_held: AtomicBool,
59 storage: S,
60}
61
62impl<S: Storage> SharedRb<S> {
63 pub unsafe fn from_raw_parts(storage: S, read: usize, write: usize) -> Self {
72 assert_capacity(storage.len());
73 Self {
74 storage,
75 read_index: CachePadded::new(AtomicUsize::new(read)),
76 write_index: CachePadded::new(AtomicUsize::new(write)),
77 read_held: AtomicBool::new(false),
78 write_held: AtomicBool::new(false),
79 }
80 }
81 pub unsafe fn into_raw_parts(self) -> (S, usize, usize) {
87 let this = ManuallyDrop::new(self);
88 (unsafe { ptr::read(&this.storage) }, this.read_index(), this.write_index())
89 }
90}
91
92impl<S: Storage + ?Sized> Observer for SharedRb<S> {
93 type Item = S::Item;
94
95 #[inline]
96 fn capacity(&self) -> NonZeroUsize {
97 unsafe { NonZeroUsize::new_unchecked(self.storage.len()) }
98 }
99
100 #[inline]
101 fn read_index(&self) -> usize {
102 self.read_index.load(Ordering::Acquire)
103 }
104 #[inline]
105 fn write_index(&self) -> usize {
106 self.write_index.load(Ordering::Acquire)
107 }
108
109 unsafe fn unsafe_slices(&self, start: usize, end: usize) -> (&[MaybeUninit<S::Item>], &[MaybeUninit<S::Item>]) {
110 let (first, second) = ranges(self.capacity(), start, end);
111 unsafe { (self.storage.slice(first), self.storage.slice(second)) }
112 }
113 unsafe fn unsafe_slices_mut(&self, start: usize, end: usize) -> (&mut [MaybeUninit<S::Item>], &mut [MaybeUninit<S::Item>]) {
114 let (first, second) = ranges(self.capacity(), start, end);
115 unsafe { (self.storage.slice_mut(first), self.storage.slice_mut(second)) }
116 }
117
118 #[inline]
119 fn read_is_held(&self) -> bool {
120 self.read_held.load(Ordering::Acquire)
121 }
122 #[inline]
123 fn write_is_held(&self) -> bool {
124 self.write_held.load(Ordering::Acquire)
125 }
126}
127
128impl<S: Storage + ?Sized> Producer for SharedRb<S> {
129 #[inline]
130 unsafe fn set_write_index(&self, value: usize) {
131 self.write_index.store(value, Ordering::Release);
132 }
133}
134
135impl<S: Storage + ?Sized> Consumer for SharedRb<S> {
136 #[inline]
137 unsafe fn set_read_index(&self, value: usize) {
138 self.read_index.store(value, Ordering::Release);
139 }
140}
141
142impl<S: Storage + ?Sized> RingBuffer for SharedRb<S> {
143 #[inline]
144 unsafe fn hold_read(&self, flag: bool) -> bool {
145 self.read_held.swap(flag, Ordering::AcqRel)
146 }
147 #[inline]
148 unsafe fn hold_write(&self, flag: bool) -> bool {
149 self.write_held.swap(flag, Ordering::AcqRel)
150 }
151}
152
153impl<S: Storage + ?Sized> Drop for SharedRb<S> {
154 fn drop(&mut self) {
155 self.clear();
156 }
157}
158
159#[cfg(feature = "alloc")]
160impl<S: Storage> Split for SharedRb<S> {
161 type Prod = CachingProd<Arc<Self>>;
162 type Cons = CachingCons<Arc<Self>>;
163
164 fn split(self) -> (Self::Prod, Self::Cons) {
165 Arc::new(self).split()
166 }
167}
168#[cfg(feature = "alloc")]
169impl<S: Storage + ?Sized> Split for Arc<SharedRb<S>> {
170 type Prod = CachingProd<Self>;
171 type Cons = CachingCons<Self>;
172
173 fn split(self) -> (Self::Prod, Self::Cons) {
174 (CachingProd::new(self.clone()), CachingCons::new(self))
175 }
176}
177#[cfg(feature = "alloc")]
178impl<S: Storage + ?Sized> Split for Box<SharedRb<S>> {
179 type Prod = CachingProd<Arc<SharedRb<S>>>;
180 type Cons = CachingCons<Arc<SharedRb<S>>>;
181
182 fn split(self) -> (Self::Prod, Self::Cons) {
183 Arc::<SharedRb<S>>::from(self).split()
184 }
185}
186impl<S: Storage + ?Sized> SplitRef for SharedRb<S> {
187 type RefProd<'a>
188 = CachingProd<&'a Self>
189 where
190 Self: 'a;
191 type RefCons<'a>
192 = CachingCons<&'a Self>
193 where
194 Self: 'a;
195
196 fn split_ref(&mut self) -> (Self::RefProd<'_>, Self::RefCons<'_>) {
197 (CachingProd::new(self), CachingCons::new(self))
198 }
199}
200
201rb_impl_init!(SharedRb);
202
203impl_producer_traits!(SharedRb<S: Storage>);
204impl_consumer_traits!(SharedRb<S: Storage>);
205
206impl<S: Storage + ?Sized> AsRef<Self> for SharedRb<S> {
207 fn as_ref(&self) -> &Self {
208 self
209 }
210}
211impl<S: Storage + ?Sized> AsMut<Self> for SharedRb<S> {
212 fn as_mut(&mut self) -> &mut Self {
213 self
214 }
215}