use core::{convert::Infallible, fmt, mem::ManuallyDrop};
use crate::{
prelude::*,
producer::compat::{iterator_to_producer, IteratorToProducer},
};
pub struct IntoProducer<const N: usize, T> {
arr: ManuallyDrop<[T; N]>,
offset: usize,
}
impl<const N: usize, T> crate::IntoProducer for [T; N] {
type Item = T;
type Final = ();
type Error = Infallible;
type IntoProducer = IntoProducer<N, T>;
fn into_producer(self) -> Self::IntoProducer {
IntoProducer::new(self)
}
}
impl<const N: usize, T: fmt::Debug> fmt::Debug for IntoProducer<N, T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_tuple("IntoProducer")
.field(&self.as_slice())
.finish()
}
}
impl<const N: usize, T> IntoProducer<N, T> {
pub fn new(array: [T; N]) -> Self {
Self {
arr: ManuallyDrop::new(array),
offset: 0,
}
}
pub fn as_slice(&self) -> &[T] {
&self.arr[self.offset..]
}
pub fn as_mut_slice(&mut self) -> &mut [T] {
&mut self.arr[self.offset..]
}
#[inline]
#[allow(clippy::len_without_is_empty)]
pub fn len(&self) -> usize {
self.as_slice().len()
}
}
impl<const N: usize, T> AsRef<[T]> for IntoProducer<N, T> {
fn as_ref(&self) -> &[T] {
self.as_slice()
}
}
impl<const N: usize, T> AsMut<[T]> for IntoProducer<N, T> {
fn as_mut(&mut self) -> &mut [T] {
self.as_mut_slice()
}
}
impl<const N: usize, T> Producer for IntoProducer<N, T> {
type Item = T;
type Final = ();
type Error = Infallible;
async fn produce(&mut self) -> Result<either::Either<Self::Item, Self::Final>, Self::Error> {
if self.len() == 0 {
Ok(Right(()))
} else {
let item_ref = &self.arr[self.offset];
self.offset += 1;
Ok(Left(unsafe { (item_ref as *const T).read() }))
}
}
async fn slurp(&mut self) -> Result<(), Self::Error> {
Ok(())
}
}
impl<const N: usize, T> BulkProducer for IntoProducer<N, T> {
async fn expose_items_gracefully<F, R>(
&mut self,
f: F,
) -> Result<Either<R, (F, Self::Final)>, (F, Self::Error)>
where
F: AsyncFnOnce(&[Self::Item]) -> (usize, R),
{
if self.len() == 0 {
Ok(Right((f, ())))
} else {
let (amount, ret) = f(self.as_slice()).await;
assert!(amount <= self.len());
self.offset += amount;
Ok(Left(ret))
}
}
}
impl<const N: usize, T> Drop for IntoProducer<N, T> {
fn drop(&mut self) {
for unproduced in &mut self.arr[self.offset..] {
unsafe {
core::ptr::drop_in_place(unproduced);
}
}
}
}
pub struct IntoProducerRef<'s, T, const N: usize>(
IteratorToProducer<<&'s [T; N] as IntoIterator>::IntoIter>,
);
impl<'s, T, const N: usize> Producer for IntoProducerRef<'s, T, N> {
type Item = &'s T;
type Final = ();
type Error = Infallible;
async fn produce(&mut self) -> Result<Either<Self::Item, Self::Final>, Self::Error> {
self.0.produce().await
}
async fn slurp(&mut self) -> Result<(), Self::Error> {
Ok(())
}
}
impl<'s, T, const N: usize> crate::IntoProducer for &'s [T; N] {
type Item = &'s T;
type Final = ();
type Error = Infallible;
type IntoProducer = IntoProducerRef<'s, T, N>;
fn into_producer(self) -> Self::IntoProducer {
IntoProducerRef(iterator_to_producer(self.iter()))
}
}
pub struct IntoProducerMut<'s, T, const N: usize>(
IteratorToProducer<<&'s mut [T; N] as IntoIterator>::IntoIter>,
);
impl<'s, T, const N: usize> Producer for IntoProducerMut<'s, T, N> {
type Item = &'s mut T;
type Final = ();
type Error = Infallible;
async fn produce(&mut self) -> Result<Either<Self::Item, Self::Final>, Self::Error> {
self.0.produce().await
}
async fn slurp(&mut self) -> Result<(), Self::Error> {
Ok(())
}
}
impl<'s, T, const N: usize> crate::IntoProducer for &'s mut [T; N] {
type Item = &'s mut T;
type Final = ();
type Error = Infallible;
type IntoProducer = IntoProducerMut<'s, T, N>;
fn into_producer(self) -> Self::IntoProducer {
IntoProducerMut(iterator_to_producer(self.iter_mut()))
}
}