use crate::{
ring_buffer::{RbBase, RbRef, RbWrap, RbWrite, RbWriteCache},
utils::write_slice,
};
use core::{marker::PhantomData, mem::MaybeUninit};
#[cfg(feature = "std")]
use crate::utils::slice_assume_init_mut;
#[cfg(feature = "std")]
use core::cmp;
#[cfg(feature = "std")]
use std::io::{self, Read, Write};
pub struct Producer<T, R: RbRef>
where
R::Rb: RbWrite<T>,
{
target: R,
_phantom: PhantomData<T>,
}
impl<T, R: RbRef> Producer<T, R>
where
R::Rb: RbWrite<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) -> PostponedProducer<T, &R::Rb> {
unsafe { Producer::new(RbWrap(RbWriteCache::new(&self.target))) }
}
pub fn into_postponed(self) -> PostponedProducer<T, R> {
unsafe { Producer::new(RbWrap(RbWriteCache::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 free_space_as_slices(
&mut self,
) -> (&mut [MaybeUninit<T>], &mut [MaybeUninit<T>]) {
self.target.vacant_slices()
}
#[inline]
pub unsafe fn advance(&mut self, count: usize) {
self.target.advance_tail(count)
}
pub fn push(&mut self, elem: T) -> Result<(), T> {
if !self.is_full() {
unsafe {
self.free_space_as_slices()
.0
.get_unchecked_mut(0)
.write(elem)
};
unsafe { self.advance(1) };
Ok(())
} else {
Err(elem)
}
}
pub fn push_iter<I: Iterator<Item = T>>(&mut self, iter: &mut I) -> usize {
let (left, right) = unsafe { self.free_space_as_slices() };
let mut count = 0;
for place in left.iter_mut().chain(right.iter_mut()) {
match iter.next() {
Some(elem) => unsafe { place.as_mut_ptr().write(elem) },
None => break,
}
count += 1;
}
unsafe { self.advance(count) };
count
}
}
impl<T: Copy, R: RbRef> Producer<T, R>
where
R::Rb: RbWrite<T>,
{
pub fn push_slice(&mut self, elems: &[T]) -> usize {
let (left, right) = unsafe { self.free_space_as_slices() };
let count = if elems.len() < left.len() {
write_slice(&mut left[..elems.len()], elems);
elems.len()
} else {
let (left_elems, elems) = elems.split_at(left.len());
write_slice(left, left_elems);
left.len()
+ if elems.len() < right.len() {
write_slice(&mut right[..elems.len()], elems);
elems.len()
} else {
write_slice(right, &elems[..right.len()]);
right.len()
}
};
unsafe { self.advance(count) };
count
}
}
pub type PostponedProducer<T, R> = Producer<T, RbWrap<RbWriteCache<T, R>>>;
impl<T, R: RbRef> PostponedProducer<T, R>
where
R::Rb: RbWrite<T>,
{
pub unsafe fn new_postponed(target: R) -> Self {
Producer::new(RbWrap(RbWriteCache::new(target)))
}
pub fn sync(&mut self) {
self.target.0.sync();
}
pub fn into_immediate(self) -> Producer<T, R> {
unsafe { Producer::new(self.target.0.release()) }
}
}
#[cfg(feature = "std")]
impl<R: RbRef> Producer<u8, R>
where
R::Rb: RbWrite<u8>,
{
pub fn read_from<P: Read>(
&mut self,
reader: &mut P,
count: Option<usize>,
) -> io::Result<usize> {
let (left, _) = unsafe { self.free_space_as_slices() };
let count = cmp::min(count.unwrap_or(left.len()), left.len());
let left_init = unsafe { slice_assume_init_mut(&mut left[..count]) };
let read_count = reader.read(left_init)?;
assert!(read_count <= count);
unsafe { self.advance(read_count) };
Ok(read_count)
}
}
#[cfg(feature = "std")]
impl<R: RbRef> Write for Producer<u8, R>
where
R::Rb: RbWrite<u8>,
{
fn write(&mut self, buffer: &[u8]) -> io::Result<usize> {
let n = self.push_slice(buffer);
if n == 0 && !buffer.is_empty() {
Err(io::ErrorKind::WouldBlock.into())
} else {
Ok(n)
}
}
fn flush(&mut self) -> io::Result<()> {
Ok(())
}
}