Skip to main content

ringbuf/rb/
local.rs

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