Skip to content
Snippets Groups Projects
buffer.rs 2.7 KiB
Newer Older
use core::ops::{Deref, DerefMut};
Stephen D's avatar
wip
Stephen D committed

#[derive(Debug)]
pub struct BufferOverflow;
Stephen D's avatar
wip
Stephen D committed

#[derive(Debug)]
Stephen D's avatar
Stephen D committed
pub struct Buffer<'a, const N: usize, T = u8> {
    data: &'a mut [T; N],
Stephen D's avatar
wip
Stephen D committed
    i: usize,
}

Stephen D's avatar
Stephen D committed
impl<'a, const N: usize, T: Copy> Buffer<'a, N, T> {
    /// Constructs a new `Buffer`.
    /// `data` is the backing array.
    /// `i` is the number of elements in `data` that contain data (and should thus be exposed by `Buffer`)
Stephen D's avatar
Stephen D committed
    pub fn new(data: &'a mut [T; N], i: usize) -> Self {
        assert!(i <= data.len());

Stephen D's avatar
wip
Stephen D committed
        Self { data, i }
    }

Stephen D's avatar
Stephen D committed
    pub fn new_full(data: &'a mut [T; N]) -> Self {
        let i = data.len();

        Self::new(data, i)
    }
Stephen D's avatar
wip
Stephen D committed

Stephen D's avatar
Stephen D committed
    pub fn new_empty(data: &'a mut [T; N]) -> Self {
        Self::new(data, 0)
    }
Stephen D's avatar
wip
Stephen D committed

    pub const fn remaining_capacity(&self) -> usize {
        N - self.i
    }

Stephen D's avatar
Stephen D committed
    pub fn try_push(&mut self, v: T) -> Result<(), BufferOverflow> {
Stephen D's avatar
wip
Stephen D committed
        if self.i == N {
            return Err(BufferOverflow);
        }

        self.data[self.i] = v;
        self.i += 1;

        Ok(())
    }

Stephen D's avatar
Stephen D committed
    pub fn push(&mut self, v: T) {
        self.try_push(v).unwrap();
    }

Stephen D's avatar
Stephen D committed
    pub fn try_extend_from_slice(&mut self, other: &[T]) -> Result<(), BufferOverflow> {
Stephen D's avatar
wip
Stephen D committed
        if self.remaining_capacity() < other.len() {
            return Err(BufferOverflow);
        }

        self.data[self.i..(self.i + other.len())].copy_from_slice(other);
        self.i += other.len();

        Ok(())
    }

Stephen D's avatar
Stephen D committed
    pub fn extend(&mut self, other: &[T]) {
        self.try_extend_from_slice(other).unwrap();
    }

Stephen D's avatar
Stephen D committed
    pub fn pop(&mut self) -> Option<T> {
Stephen D's avatar
wip
Stephen D committed
        if self.i == 0 {
            return None;
        }

        self.i -= 1;

        Some(self.data[self.i])
    }

    pub fn truncate(&mut self, new_len: usize) {
        assert!(self.i >= new_len);

        self.i = new_len;
    }

    pub fn drain(&mut self, start: usize, end: usize) {
        assert!(end >= start);
        assert!(end <= self.i);
        let delta = end - start;
        let surplus = self.len() - end;

        for i in start..(start + surplus) {
            self[i] = self[i + delta];
        }

        self.i -= delta;
    }

Stephen D's avatar
Stephen D committed
    pub fn clone_backing<'b>(&self, buf: &'b mut [T; N]) -> Buffer<'b, N, T> {
        let mut out = Buffer::new_empty(buf);

        out.extend(self);

        out
    }
Stephen D's avatar
wip
Stephen D committed
}

Stephen D's avatar
Stephen D committed
impl<'a, const N: usize, T> From<&'a mut [T; N]> for Buffer<'a, N, T> {
    fn from(data: &'a mut [T; N]) -> Self {
Stephen D's avatar
wip
Stephen D committed
        Self { data, i: 0 }
    }
}

Stephen D's avatar
Stephen D committed
impl<const N: usize, T> Deref for Buffer<'_, N, T> {
Stephen D's avatar
Stephen D committed
    type Target = [T];
Stephen D's avatar
wip
Stephen D committed

    fn deref(&self) -> &Self::Target {
        &self.data[..self.i]
    }
}
Stephen D's avatar
Stephen D committed
impl<const N: usize, T> DerefMut for Buffer<'_, N, T> {
Stephen D's avatar
Stephen D committed
    fn deref_mut(&mut self) -> &mut [T] {
        &mut self.data[..self.i]
    }
}