use super::{ macros::rb_impl_init, utils::{assert_capacity, ranges}, }; #[cfg(feature = "alloc")] use crate::traits::Split; use crate::{ storage::Storage, traits::{ Observer, RingBuffer, SplitRef, consumer::{Consumer, impl_consumer_traits}, producer::{Producer, impl_producer_traits}, }, wrap::{Cons, Prod}, }; #[cfg(feature = "alloc")] use alloc::{boxed::Box, rc::Rc}; use core::{ cell::Cell, mem::{ManuallyDrop, MaybeUninit}, num::NonZeroUsize, ptr, }; struct Endpoint { index: Cell, held: Cell, } impl Endpoint { const fn new(index: usize) -> Self { Self { index: Cell::new(index), held: Cell::new(false), } } } /// Ring buffer for single-threaded use only. /// /// Slightly faster than multi-threaded version because it doesn't synchronize cache. pub struct LocalRb { read: Endpoint, write: Endpoint, storage: S, } impl LocalRb { /// Constructs ring buffer from storage and indices. /// /// Panics if the storage is empty or its length exceeds `usize::MAX / 2`. /// /// # Safety /// /// The items in storage inside `read..write` range must be initialized, items outside this range must be uninitialized. /// `read` and `write` positions must be valid (see implementation details). pub unsafe fn from_raw_parts(storage: S, read: usize, write: usize) -> Self { assert_capacity(storage.len()); Self { storage, read: Endpoint::new(read), write: Endpoint::new(write), } } /// Destructures ring buffer into underlying storage and `read` and `write` indices. /// /// # Safety /// /// Initialized contents of the storage must be properly dropped. pub unsafe fn into_raw_parts(self) -> (S, usize, usize) { let this = ManuallyDrop::new(self); (unsafe { ptr::read(&this.storage) }, this.read_index(), this.write_index()) } } impl Observer for LocalRb { type Item = S::Item; #[inline] fn capacity(&self) -> NonZeroUsize { unsafe { NonZeroUsize::new_unchecked(self.storage.len()) } } #[inline] fn read_index(&self) -> usize { self.read.index.get() } #[inline] fn write_index(&self) -> usize { self.write.index.get() } unsafe fn unsafe_slices(&self, start: usize, end: usize) -> (&[MaybeUninit], &[MaybeUninit]) { let (first, second) = ranges(self.capacity(), start, end); unsafe { (self.storage.slice(first), self.storage.slice(second)) } } unsafe fn unsafe_slices_mut(&self, start: usize, end: usize) -> (&mut [MaybeUninit], &mut [MaybeUninit]) { let (first, second) = ranges(self.capacity(), start, end); unsafe { (self.storage.slice_mut(first), self.storage.slice_mut(second)) } } #[inline] fn read_is_held(&self) -> bool { self.read.held.get() } #[inline] fn write_is_held(&self) -> bool { self.write.held.get() } } impl Producer for LocalRb { #[inline] unsafe fn set_write_index(&self, value: usize) { self.write.index.set(value); } } impl Consumer for LocalRb { #[inline] unsafe fn set_read_index(&self, value: usize) { self.read.index.set(value); } } impl RingBuffer for LocalRb { #[inline] unsafe fn hold_read(&self, flag: bool) -> bool { self.read.held.replace(flag) } #[inline] unsafe fn hold_write(&self, flag: bool) -> bool { self.write.held.replace(flag) } } impl Drop for LocalRb { fn drop(&mut self) { self.clear(); } } #[cfg(feature = "alloc")] impl Split for LocalRb { type Prod = Prod>; type Cons = Cons>; fn split(self) -> (Self::Prod, Self::Cons) { Rc::new(self).split() } } #[cfg(feature = "alloc")] impl Split for Rc> { type Prod = Prod; type Cons = Cons; fn split(self) -> (Self::Prod, Self::Cons) { (Prod::new(self.clone()), Cons::new(self)) } } #[cfg(feature = "alloc")] impl Split for Box> { type Prod = Prod>>; type Cons = Cons>>; fn split(self) -> (Self::Prod, Self::Cons) { Rc::>::from(self).split() } } impl SplitRef for LocalRb { type RefProd<'a> = Prod<&'a Self> where Self: 'a; type RefCons<'a> = Cons<&'a Self> where Self: 'a; fn split_ref(&mut self) -> (Self::RefProd<'_>, Self::RefCons<'_>) { (Prod::new(self), Cons::new(self)) } } rb_impl_init!(LocalRb); impl_producer_traits!(LocalRb); impl_consumer_traits!(LocalRb); impl AsRef for LocalRb { fn as_ref(&self) -> &Self { self } } impl AsMut for LocalRb { fn as_mut(&mut self) -> &mut Self { self } }