use super::{Container, Rb, RbBase, RbRead, RbWrite, SharedStorage};
use crate::{consumer::Consumer, producer::Producer};
use core::{
mem::{ManuallyDrop, MaybeUninit},
num::NonZeroUsize,
ptr,
sync::atomic::{AtomicUsize, Ordering},
};
use crossbeam_utils::CachePadded;
#[cfg(feature = "alloc")]
use alloc::sync::Arc;
#[cfg_attr(
feature = "std",
doc = r##"
```
use std::{thread, vec::Vec};
use ringbuf::SharedRb;
let (mut prod, mut cons) = SharedRb::<i32, Vec<_>>::new(256).split();
thread::spawn(move || {
prod.push(123).unwrap();
})
.join();
thread::spawn(move || {
assert_eq!(cons.pop().unwrap(), 123);
})
.join();
```
"##
)]
pub struct SharedRb<T, C: Container<T>> {
storage: SharedStorage<T, C>,
head: CachePadded<AtomicUsize>,
tail: CachePadded<AtomicUsize>,
}
impl<T, C: Container<T>> RbBase<T> for SharedRb<T, C> {
#[inline]
unsafe fn data(&self) -> &mut [MaybeUninit<T>] {
self.storage.as_slice()
}
#[inline]
fn capacity_nonzero(&self) -> NonZeroUsize {
self.storage.len()
}
#[inline]
fn head(&self) -> usize {
self.head.load(Ordering::Acquire)
}
#[inline]
fn tail(&self) -> usize {
self.tail.load(Ordering::Acquire)
}
}
impl<T, C: Container<T>> RbRead<T> for SharedRb<T, C> {
#[inline]
unsafe fn set_head(&self, value: usize) {
self.head.store(value, Ordering::Release)
}
}
impl<T, C: Container<T>> RbWrite<T> for SharedRb<T, C> {
#[inline]
unsafe fn set_tail(&self, value: usize) {
self.tail.store(value, Ordering::Release)
}
}
impl<T, C: Container<T>> Rb<T> for SharedRb<T, C> {}
impl<T, C: Container<T>> Drop for SharedRb<T, C> {
fn drop(&mut self) {
self.clear();
}
}
impl<T, C: Container<T>> SharedRb<T, C> {
pub unsafe fn from_raw_parts(container: C, head: usize, tail: usize) -> Self {
Self {
storage: SharedStorage::new(container),
head: CachePadded::new(AtomicUsize::new(head)),
tail: CachePadded::new(AtomicUsize::new(tail)),
}
}
pub unsafe fn into_raw_parts(self) -> (C, usize, usize) {
let (head, tail) = (self.head(), self.tail());
let self_ = ManuallyDrop::new(self);
(ptr::read(&self_.storage).into_inner(), head, tail)
}
#[cfg(feature = "alloc")]
pub fn split(self) -> (Producer<T, Arc<Self>>, Consumer<T, Arc<Self>>)
where
Self: Sized,
{
let arc = Arc::new(self);
unsafe { (Producer::new(arc.clone()), Consumer::new(arc)) }
}
pub fn split_ref(&mut self) -> (Producer<T, &Self>, Consumer<T, &Self>)
where
Self: Sized,
{
unsafe { (Producer::new(self), Consumer::new(self)) }
}
}