ringbuf/rb/
local.rs

1use super::{macros::rb_impl_init, utils::ranges};
2#[cfg(feature = "alloc")]
3use crate::traits::Split;
4use crate::{
5    storage::Storage,
6    traits::{
7        consumer::{impl_consumer_traits, Consumer},
8        producer::{impl_producer_traits, Producer},
9        Observer, RingBuffer, SplitRef,
10    },
11    wrap::{Cons, Prod},
12};
13#[cfg(feature = "alloc")]
14use alloc::{boxed::Box, rc::Rc};
15use core::{
16    cell::Cell,
17    mem::{ManuallyDrop, MaybeUninit},
18    num::NonZeroUsize,
19    ptr,
20};
21
22struct End {
23    index: Cell<usize>,
24    held: Cell<bool>,
25}
26
27impl End {
28    fn new(index: usize) -> Self {
29        Self {
30            index: Cell::new(index),
31            held: Cell::new(false),
32        }
33    }
34}
35
36/// Ring buffer for single-threaded use only.
37///
38/// Slightly faster than multi-threaded version because it doesn't synchronize cache.
39pub struct LocalRb<S: Storage + ?Sized> {
40    read: End,
41    write: End,
42    storage: S,
43}
44
45impl<S: Storage> LocalRb<S> {
46    /// Constructs ring buffer from storage and indices.
47    ///
48    /// # Safety
49    ///
50    /// The items in storage inside `read..write` range must be initialized, items outside this range must be uninitialized.
51    /// `read` and `write` positions must be valid (see implementation details).
52    pub unsafe fn from_raw_parts(storage: S, read: usize, write: usize) -> Self {
53        assert!(!storage.is_empty());
54        Self {
55            storage,
56            read: End::new(read),
57            write: End::new(write),
58        }
59    }
60    /// Destructures ring buffer into underlying storage and `read` and `write` indices.
61    ///
62    /// # Safety
63    ///
64    /// Initialized contents of the storage must be properly dropped.
65    pub unsafe fn into_raw_parts(self) -> (S, usize, usize) {
66        let this = ManuallyDrop::new(self);
67        (ptr::read(&this.storage), this.read_index(), this.write_index())
68    }
69}
70
71impl<S: Storage + ?Sized> Observer for LocalRb<S> {
72    type Item = S::Item;
73
74    #[inline]
75    fn capacity(&self) -> NonZeroUsize {
76        unsafe { NonZeroUsize::new_unchecked(self.storage.len()) }
77    }
78
79    #[inline]
80    fn read_index(&self) -> usize {
81        self.read.index.get()
82    }
83    #[inline]
84    fn write_index(&self) -> usize {
85        self.write.index.get()
86    }
87
88    unsafe fn unsafe_slices(&self, start: usize, end: usize) -> (&[MaybeUninit<S::Item>], &[MaybeUninit<S::Item>]) {
89        let (first, second) = ranges(self.capacity(), start, end);
90        (self.storage.slice(first), self.storage.slice(second))
91    }
92    unsafe fn unsafe_slices_mut(&self, start: usize, end: usize) -> (&mut [MaybeUninit<S::Item>], &mut [MaybeUninit<S::Item>]) {
93        let (first, second) = ranges(self.capacity(), start, end);
94        (self.storage.slice_mut(first), self.storage.slice_mut(second))
95    }
96
97    #[inline]
98    fn read_is_held(&self) -> bool {
99        self.read.held.get()
100    }
101    #[inline]
102    fn write_is_held(&self) -> bool {
103        self.write.held.get()
104    }
105}
106
107impl<S: Storage + ?Sized> Producer for LocalRb<S> {
108    #[inline]
109    unsafe fn set_write_index(&self, value: usize) {
110        self.write.index.set(value);
111    }
112}
113
114impl<S: Storage + ?Sized> Consumer for LocalRb<S> {
115    #[inline]
116    unsafe fn set_read_index(&self, value: usize) {
117        self.read.index.set(value);
118    }
119}
120
121impl<S: Storage + ?Sized> RingBuffer for LocalRb<S> {
122    #[inline]
123    unsafe fn hold_read(&self, flag: bool) -> bool {
124        self.read.held.replace(flag)
125    }
126    #[inline]
127    unsafe fn hold_write(&self, flag: bool) -> bool {
128        self.write.held.replace(flag)
129    }
130}
131
132impl<S: Storage + ?Sized> Drop for LocalRb<S> {
133    fn drop(&mut self) {
134        self.clear();
135    }
136}
137
138#[cfg(feature = "alloc")]
139impl<S: Storage> Split for LocalRb<S> {
140    type Prod = Prod<Rc<Self>>;
141    type Cons = Cons<Rc<Self>>;
142
143    fn split(self) -> (Self::Prod, Self::Cons) {
144        Rc::new(self).split()
145    }
146}
147#[cfg(feature = "alloc")]
148impl<S: Storage + ?Sized> Split for Rc<LocalRb<S>> {
149    type Prod = Prod<Self>;
150    type Cons = Cons<Self>;
151
152    fn split(self) -> (Self::Prod, Self::Cons) {
153        (Prod::new(self.clone()), Cons::new(self))
154    }
155}
156#[cfg(feature = "alloc")]
157impl<S: Storage + ?Sized> Split for Box<LocalRb<S>> {
158    type Prod = Prod<Rc<LocalRb<S>>>;
159    type Cons = Cons<Rc<LocalRb<S>>>;
160
161    fn split(self) -> (Self::Prod, Self::Cons) {
162        Rc::<LocalRb<S>>::from(self).split()
163    }
164}
165impl<S: Storage + ?Sized> SplitRef for LocalRb<S> {
166    type RefProd<'a> = Prod<&'a Self> where Self: 'a;
167    type RefCons<'a> = Cons<&'a Self> where Self: 'a;
168
169    fn split_ref(&mut self) -> (Self::RefProd<'_>, Self::RefCons<'_>) {
170        (Prod::new(self), Cons::new(self))
171    }
172}
173
174rb_impl_init!(LocalRb);
175
176impl_producer_traits!(LocalRb<S: Storage>);
177impl_consumer_traits!(LocalRb<S: Storage>);
178
179impl<S: Storage + ?Sized> AsRef<Self> for LocalRb<S> {
180    fn as_ref(&self) -> &Self {
181        self
182    }
183}
184impl<S: Storage + ?Sized> AsMut<Self> for LocalRb<S> {
185    fn as_mut(&mut self) -> &mut Self {
186        self
187    }
188}