use error::Error;
pub use error::Error as CollectorError;
use std::{
mem::{ManuallyDrop as MD, MaybeUninit as MU, forget},
ptr::drop_in_place,
};
mod error;
mod maybe;
use maybe::Maybe;
pub trait CollectArray: Iterator + Sized {
fn collect_array<const N: usize>(&mut self) -> [Self::Item; N] {
self.collect_array_checked()
.unwrap_or_else(|x| panic!("couldnt fill buffer of length {N} only had {x} elements"))
}
fn collect_array_checked<const N: usize>(&mut self) -> Result<[Self::Item; N], usize> {
try_from_fn(|elem| self.next().ok_or(elem))
}
fn try_collect_array<const N: usize>(
&mut self,
) -> Result<[<Self::Item as Maybe>::Unwrap; N], Error<N, <Self::Item as Maybe>::Or>>
where
Self::Item: Maybe,
{
try_from_fn(|elem| {
self.next()
.ok_or(None)
.and_then(|x| x.asr().map_err(Some))
.map_err(|x| Error { error: x, at: elem })
})
}
fn items<const N: usize>(&mut self) -> [Option<Self::Item>; N] {
std::array::from_fn(|_| self.next())
}
}
impl<I: Iterator> CollectArray for I {}
struct OnDrop<F: FnOnce()> {
f: MD<F>,
}
impl<F: FnOnce()> OnDrop<F> {
fn guard(x: F) -> Self {
Self { f: MD::new(x) }
}
}
impl<F: FnOnce()> Drop for OnDrop<F> {
fn drop(&mut self) {
unsafe { MD::take(&mut self.f)() }
}
}
const unsafe fn transmute_unchecked<T, U>(value: T) -> U {
const { assert!(size_of::<T>() == size_of::<U>()) }
#[repr(C)]
union Transmute<T, U> {
t: MD<T>,
u: MD<U>,
}
unsafe { MD::into_inner(Transmute { t: MD::new(value) }.u) }
}
pub fn try_from_fn<R: Maybe, const N: usize>(
mut x: impl FnMut(usize) -> R,
) -> Result<[R::Unwrap; N], R::Or> {
let mut out = [const { MU::uninit() }; N];
for elem in 0..N {
let guard = OnDrop::guard(|| unsafe {
let p = &raw mut out[..elem] as *mut [R::Unwrap];
let guard = OnDrop::guard(|| drop_in_place(p));
drop_in_place(p);
forget(guard);
});
let e = x(elem).asr()?;
forget(guard);
out[elem] = MU::new(e);
}
Ok(unsafe { transmute_unchecked(out) })
}
#[doc(no_inline)]
pub use std::array::from_fn;