use core::convert::{AsRef, AsMut};
use core::fmt;
use core::mem::{self, MaybeUninit};
pub struct Writer<'b, T> {
buf: &'b mut [MaybeUninit<T>],
off: usize,
}
impl<'b, T> Writer<'b, T> {
pub fn new(buf: &'b mut [MaybeUninit<T>]) -> Self {
Self { buf, off: 0 }
}
pub fn cap(&self) -> usize {
self.buf.len()
}
pub fn rem(&mut self) -> &mut [MaybeUninit<T>] {
unsafe { self.buf.get_unchecked_mut(self.off ..) }
}
pub fn append_copying<'a>(&mut self, elems: &'a [T]) -> &'a [T]
where T: Copy {
let mut iter = elems.iter();
self.extend(iter.by_ref().copied());
iter.as_slice()
}
pub fn extend<I>(&mut self, iter: I)
where I: IntoIterator<Item = T> {
let rem = unsafe { self.buf.get_unchecked_mut(self.off ..) };
let mut iter = iter.into_iter();
for dst in rem {
let Some(src) = iter.next() else { break };
dst.write(src);
self.off += 1;
}
}
pub fn extend_copying<'a, I>(&mut self, iter: I)
where T: 'a + Copy, I: IntoIterator<Item = &'a T> {
let rem = unsafe { self.buf.get_unchecked_mut(self.off ..) };
let mut iter = iter.into_iter();
for dst in rem {
let Some(&src) = iter.next() else { break };
dst.write(src);
self.off += 1;
}
}
pub fn extend_chunks<I, const N: usize>(&mut self, iter: I)
where I: IntoIterator<Item = [T; N]> {
let rem = unsafe { self.buf.get_unchecked_mut(self.off ..) };
let mut iter = iter.into_iter();
for dst in rem.chunks_exact_mut(N) {
let Some(src) = iter.next() else { break };
dst.iter_mut().zip(src).for_each(|(d, s)| { d.write(s); });
self.off += N;
}
}
}
impl<'b, T> Drop for Writer<'b, T> {
fn drop(&mut self) {
let buf = unsafe { self.buf.get_unchecked_mut(.. self.off) };
buf.iter_mut().for_each(|v| unsafe { v.assume_init_drop() });
self.off = 0;
}
}
impl<'b, T> AsRef<[T]> for Writer<'b, T> {
fn as_ref(&self) -> &[T] {
unsafe { mem::transmute(self.buf.get_unchecked(.. self.off)) }
}
}
impl<'b, T> AsMut<[T]> for Writer<'b, T> {
fn as_mut(&mut self) -> &mut [T] {
unsafe { mem::transmute(self.buf.get_unchecked_mut(.. self.off)) }
}
}
impl<'b, T: fmt::Debug> fmt::Debug for Writer<'b, T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("Writer")
.field("cur", &self.as_ref())
.field("len", &self.buf.len())
.finish()
}
}