oca 0.2.0

An experiment with no_std
Documentation
#[derive(Debug, thiserror::Error)]
pub enum Error {
    #[error("buffer full")]
    BufferFull,

    #[error("not enough data")]
    NotEnoughData,
}

#[derive(Debug)]
pub struct Writer<'a> {
    buf: &'a mut [u8],
    len: usize,
}

pub struct Reserved<const N: usize> {
    offset: usize,
}

impl<'a> Writer<'a> {
    pub fn new(buf: &'a mut [u8]) -> Self {
        Self { buf, len: 0 }
    }

    pub fn len(&self) -> usize {
        self.len
    }

    pub fn is_empty(&self) -> bool {
        self.len == 0
    }

    pub fn remaining(&mut self) -> &mut [u8] {
        &mut self.buf[self.len..]
    }

    pub fn commit(&mut self, n: usize) {
        debug_assert!(n <= self.remaining().len());
        self.len += n;
    }

    pub fn write_bytes(&mut self, bytes: &[u8]) -> Result<(), Error> {
        let dest = self
            .buf
            .get_mut(self.len..self.len + bytes.len())
            .ok_or(Error::BufferFull)?;

        dest.copy_from_slice(bytes);
        self.commit(bytes.len());
        Ok(())
    }

    pub fn write_u8(&mut self, value: u8) -> Result<(), Error> {
        self.write_bytes(&[value])
    }

    pub fn write_u16(&mut self, value: u16) -> Result<(), Error> {
        self.write_bytes(&value.to_be_bytes())
    }

    pub fn write_u32(&mut self, value: u32) -> Result<(), Error> {
        self.write_bytes(&value.to_be_bytes())
    }

    pub fn reserve<const N: usize>(&mut self) -> Result<Reserved<N>, Error> {
        let end = self.len.checked_add(N).ok_or(Error::BufferFull)?;

        if end > self.buf.len() {
            return Err(Error::BufferFull);
        }

        let at = self.len;
        self.len = end;
        Ok(Reserved { offset: at })
    }

    pub fn apply<const N: usize>(
        &mut self,
        reserved: Reserved<N>,
        value: [u8; N],
    ) -> Result<(), Error> {
        let data = self.claim(reserved)?;
        data.copy_from_slice(&value);
        Ok(())
    }

    pub fn claim<const N: usize>(&mut self, reserved: Reserved<N>) -> Result<&mut [u8], Error> {
        let at = reserved.offset;
        Ok(&mut self.buf[at..at + N])
    }

    pub fn finish(self) -> (&'a mut [u8], &'a mut [u8]) {
        self.buf.split_at_mut(self.len)
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn writing_to_a_buffer() {
        let mut buffer = [0; 8];
        let mut writer = Writer::new(&mut buffer);

        assert_eq!(writer.len(), 0);
        assert!(writer.is_empty());

        writer.write_u32(0xDEADBEEF).unwrap();

        assert_eq!(writer.len(), 4);
        assert_eq!(writer.remaining(), &[0; 4]);

        let (written, remaining) = writer.finish();
        assert_eq!(written, &[0xDE, 0xAD, 0xBE, 0xEF]);
        assert_eq!(remaining, &[0; 4]);
    }
}