use crate::{
ring_buffer::{RbBase, RbRead, RbReadCache, RbRef, RbWrap},
utils::{slice_assume_init_mut, slice_assume_init_ref, write_uninit_slice},
};
use core::{
cmp,
iter::{Chain, ExactSizeIterator},
marker::PhantomData,
mem::MaybeUninit,
slice,
};
#[cfg(feature = "std")]
use std::io::{self, Read, Write};
pub struct Consumer<T, R: RbRef>
where
R::Rb: RbRead<T>,
{
target: R,
_phantom: PhantomData<T>,
}
impl<T, R: RbRef> Consumer<T, R>
where
R::Rb: RbRead<T>,
{
pub unsafe fn new(target: R) -> Self {
Self {
target,
_phantom: PhantomData,
}
}
#[inline]
pub fn rb(&self) -> &R::Rb {
&self.target
}
pub fn into_rb_ref(self) -> R {
self.target
}
pub fn postponed(&mut self) -> Consumer<T, RbWrap<RbReadCache<T, &R::Rb>>> {
unsafe { Consumer::new(RbWrap(RbReadCache::new(&self.target))) }
}
pub fn into_postponed(self) -> Consumer<T, RbWrap<RbReadCache<T, R>>> {
unsafe { Consumer::new(RbWrap(RbReadCache::new(self.target))) }
}
#[inline]
pub fn capacity(&self) -> usize {
self.target.capacity().get()
}
#[inline]
pub fn is_empty(&self) -> bool {
self.target.is_empty()
}
#[inline]
pub fn is_full(&self) -> bool {
self.target.is_full()
}
#[inline]
pub fn len(&self) -> usize {
self.target.occupied_len()
}
#[inline]
pub fn free_len(&self) -> usize {
self.target.vacant_len()
}
#[inline]
pub unsafe fn as_uninit_slices(&self) -> (&[MaybeUninit<T>], &[MaybeUninit<T>]) {
let (left, right) = self.target.occupied_slices();
(left as &[_], right as &[_])
}
#[inline]
pub unsafe fn as_mut_uninit_slices(&self) -> (&mut [MaybeUninit<T>], &mut [MaybeUninit<T>]) {
self.target.occupied_slices()
}
#[inline]
pub unsafe fn advance(&mut self, count: usize) {
self.target.advance_head(count);
}
#[inline]
pub fn as_slices(&self) -> (&[T], &[T]) {
unsafe {
let (left, right) = self.as_uninit_slices();
(slice_assume_init_ref(left), slice_assume_init_ref(right))
}
}
#[inline]
pub fn as_mut_slices(&mut self) -> (&mut [T], &mut [T]) {
unsafe {
let (left, right) = self.as_mut_uninit_slices();
(slice_assume_init_mut(left), slice_assume_init_mut(right))
}
}
pub fn pop(&mut self) -> Option<T> {
if !self.is_empty() {
let elem = unsafe {
self.as_uninit_slices()
.0
.get_unchecked(0)
.assume_init_read()
};
unsafe { self.advance(1) };
Some(elem)
} else {
None
}
}
pub fn pop_iter(&mut self) -> PopIterator<'_, T, R> {
PopIterator::new(&self.target)
}
pub fn iter(&self) -> impl Iterator<Item = &T> + '_ {
let (left, right) = self.as_slices();
left.iter().chain(right.iter())
}
pub fn iter_mut(&mut self) -> impl Iterator<Item = &mut T> + '_ {
let (left, right) = self.as_mut_slices();
left.iter_mut().chain(right.iter_mut())
}
#[cfg_attr(
feature = "alloc",
doc = r##"
```rust
# extern crate ringbuf;
# use ringbuf::HeapRb;
# fn main() {
let target = HeapRb::<i32>::new(8);
let (mut prod, mut cons) = target.split();
assert_eq!(prod.push_iter(&mut (0..8)), 8);
assert_eq!(cons.skip(4), 4);
assert_eq!(cons.skip(8), 4);
assert_eq!(cons.skip(8), 0);
# }
```
"##
)]
pub fn skip(&mut self, count: usize) -> usize {
let count = cmp::min(count, self.len());
assert_eq!(unsafe { self.target.skip(Some(count)) }, count);
count
}
pub fn clear(&mut self) -> usize {
unsafe { self.target.skip(None) }
}
}
pub struct PopIterator<'a, T, R: RbRef>
where
R::Rb: RbRead<T>,
{
target: &'a R,
iter: Chain<slice::Iter<'a, MaybeUninit<T>>, slice::Iter<'a, MaybeUninit<T>>>,
len: usize,
}
impl<'a, T, R: RbRef> PopIterator<'a, T, R>
where
R::Rb: RbRead<T>,
{
fn new(target: &'a R) -> Self {
let slices = unsafe { target.occupied_slices() };
Self {
target,
len: slices.0.len() + slices.1.len(),
iter: slices.0.iter().chain(slices.1.iter()),
}
}
}
impl<'a, T, R: RbRef> Iterator for PopIterator<'a, T, R>
where
R::Rb: RbRead<T>,
{
type Item = T;
#[inline]
fn next(&mut self) -> Option<T> {
self.iter.next().map(|x| unsafe { x.assume_init_read() })
}
#[inline]
fn size_hint(&self) -> (usize, Option<usize>) {
self.iter.size_hint()
}
}
impl<'a, T, R: RbRef> ExactSizeIterator for PopIterator<'a, T, R> where R::Rb: RbRead<T> {}
impl<'a, T, R: RbRef> Drop for PopIterator<'a, T, R>
where
R::Rb: RbRead<T>,
{
fn drop(&mut self) {
unsafe { self.target.advance_head(self.len - self.iter.size_hint().0) };
}
}
impl<T: Copy, R: RbRef> Consumer<T, R>
where
R::Rb: RbRead<T>,
{
pub fn pop_slice(&mut self, elems: &mut [T]) -> usize {
let (left, right) = unsafe { self.as_uninit_slices() };
let count = if elems.len() < left.len() {
unsafe { write_uninit_slice(elems, &left[..elems.len()]) };
elems.len()
} else {
let (left_elems, elems) = elems.split_at_mut(left.len());
unsafe { write_uninit_slice(left_elems, left) };
left.len()
+ if elems.len() < right.len() {
unsafe { write_uninit_slice(elems, &right[..elems.len()]) };
elems.len()
} else {
unsafe { write_uninit_slice(&mut elems[..right.len()], right) };
right.len()
}
};
unsafe { self.advance(count) };
count
}
}
pub type PostponedConsumer<T, R> = Consumer<T, RbWrap<RbReadCache<T, R>>>;
impl<T, R: RbRef> PostponedConsumer<T, R>
where
R::Rb: RbRead<T>,
{
pub unsafe fn new_postponed(target: R) -> Self {
Consumer::new(RbWrap(RbReadCache::new(target)))
}
pub fn sync(&mut self) {
self.target.0.sync();
}
pub fn into_immediate(self) -> Consumer<T, R> {
unsafe { Consumer::new(self.target.0.release()) }
}
}
#[cfg(feature = "std")]
impl<R: RbRef> Consumer<u8, R>
where
R::Rb: RbRead<u8>,
{
pub fn write_into<P: Write>(
&mut self,
writer: &mut P,
count: Option<usize>,
) -> io::Result<usize> {
let (left, _) = unsafe { self.as_uninit_slices() };
let count = cmp::min(count.unwrap_or(left.len()), left.len());
let left_init = unsafe { slice_assume_init_ref(&left[..count]) };
let write_count = writer.write(left_init)?;
assert!(write_count <= count);
unsafe { self.advance(write_count) };
Ok(write_count)
}
}
#[cfg(feature = "std")]
impl<R: RbRef> Read for Consumer<u8, R>
where
R::Rb: RbRead<u8>,
{
fn read(&mut self, buffer: &mut [u8]) -> io::Result<usize> {
let n = self.pop_slice(buffer);
if n == 0 && !buffer.is_empty() {
Err(io::ErrorKind::WouldBlock.into())
} else {
Ok(n)
}
}
}