glassy 0.0.3

An easy and fast library for encoding and decoding binary data.
Documentation
use core::convert::{AsRef, AsMut};
use core::fmt;
use core::mem::{self, MaybeUninit};

/// A writer for partially filling a slice.
pub struct Writer<'b, T> {
    /// The underlying slice.
    buf: &'b mut [MaybeUninit<T>],

    /// The offset new items will start from.
    off: usize,
}

impl<'b, T> Writer<'b, T> {
    /// Construct a new [`Writer`].
    pub fn new(buf: &'b mut [MaybeUninit<T>]) -> Self {
        Self { buf, off: 0 }
    }

    /// The total capacity of the buffer.
    pub fn cap(&self) -> usize {
        self.buf.len()
    }

    /// The remaining slots in the buffer.
    pub fn rem(&mut self) -> &mut [MaybeUninit<T>] {
        // SAFETY: 'buf[off ..]' is valid and uninitialized.
        unsafe { self.buf.get_unchecked_mut(self.off ..) }
    }

    /// Copy elements from the given slice.
    ///
    /// The remaining elements of the slice are returned.
    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()
    }

    /// Append elements from the given iterator.
    ///
    /// Only the necessary number of elements are removed.
    pub fn extend<I>(&mut self, iter: I)
    where I: IntoIterator<Item = T> {
        // SAFETY: 'buf[off ..]' is valid and uninitialized.
        let rem = unsafe { self.buf.get_unchecked_mut(self.off ..) };
        let mut iter = iter.into_iter();
        for dst in rem {
            // Retrieve the next element, stopping once it finishes.
            let Some(src) = iter.next() else { break };

            dst.write(src);
            self.off += 1;
        }
    }

    /// Copy elements from the given iterator.
    ///
    /// This operates like [`Writer::extend()`], except that the given
    /// iterator provides referencs to elements which are then copied.
    pub fn extend_copying<'a, I>(&mut self, iter: I)
    where T: 'a + Copy, I: IntoIterator<Item = &'a T> {
        // SAFETY: 'buf[off ..]' is valid and uninitialized.
        let rem = unsafe { self.buf.get_unchecked_mut(self.off ..) };
        let mut iter = iter.into_iter();
        for dst in rem {
            // Retrieve the next element, stopping once it finishes.
            let Some(&src) = iter.next() else { break };

            dst.write(src);
            self.off += 1;
        }
    }

    /// Append chunks from the given iterator.
    ///
    /// Only the necessary number of chunks are removed.
    pub fn extend_chunks<I, const N: usize>(&mut self, iter: I)
    where I: IntoIterator<Item = [T; N]> {
        // SAFETY: 'buf[off ..]' is valid and uninitialized.
        let rem = unsafe { self.buf.get_unchecked_mut(self.off ..) };
        let mut iter = iter.into_iter();
        for dst in rem.chunks_exact_mut(N) {
            // Retrieve the next chunk, stopping once it finishes.
            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) {
        // SAFETY: 'buf[.. off]' is valid.
        let buf = unsafe { self.buf.get_unchecked_mut(.. self.off) };
        // SAFETY: 'buf[.. off]' is initialized.
        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] {
        // SAFETY: 'buf[.. off]' is valid and initialized.
        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] {
        // SAFETY: 'buf[.. off]' is valid and initialized.
        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()
    }
}