agzip 0.1.0

Async compatible gzip (de)compressor
Documentation
#[derive(Debug)]
pub(crate) struct Reader<C> {
    rest: usize,
    data: C,
}

impl<C> Reader<C> {
    pub fn fill(self) -> Reader<Skippable<C>> {
        Reader {
            rest: self.rest,
            data: Skippable::Fill(self.data),
        }
    }

    pub fn read_from(&mut self, input: &mut &[u8]) -> Option<&mut C>
    where
        C: Consume,
    {
        let n = usize::min(self.rest, input.len());
        let (left, right) = input.split_at(n);
        *input = right;
        self.data.consume(self.rest, left);

        self.rest -= n;
        if self.rest == 0 {
            Some(&mut self.data)
        } else {
            None
        }
    }
}

impl<C> Reader<Skippable<C>> {
    pub fn skip(rest: usize) -> Self {
        let data = Skippable::Skip;
        Self { rest, data }
    }
}

impl Reader<Box<[u8]>> {
    pub fn alloc(rest: usize) -> Self {
        let data = Box::from(vec![0; rest]);
        Self { rest, data }
    }
}

impl<C> Default for Reader<C>
where
    C: Default + AsMut<[u8]>,
{
    #[inline]
    fn default() -> Self {
        let mut data = C::default();
        let rest = data.as_mut().len();
        Self { rest, data }
    }
}

pub(crate) trait Consume {
    fn consume(&mut self, rest: usize, input: &[u8]);
}

impl<C> Consume for C
where
    C: AsMut<[u8]>,
{
    fn consume(&mut self, rest: usize, input: &[u8]) {
        let inner = self.as_mut();
        let step = inner.len() - rest;
        inner[step..step + input.len()].copy_from_slice(input);
    }
}

#[derive(Debug, PartialEq, Eq)]
pub(crate) enum Skippable<C> {
    Fill(C),
    Skip,
}

impl<C> Consume for Skippable<C>
where
    C: Consume,
{
    fn consume(&mut self, rest: usize, input: &[u8]) {
        match self {
            Self::Fill(c) => c.consume(rest, input),
            Self::Skip => {}
        }
    }
}

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

    #[test]
    fn read() {
        let mut b: Reader<[u8; 4]> = Reader::default();
        assert_eq!(b.rest, 4);

        let mut input = [0, 1].as_slice();
        assert!(b.read_from(&mut input).is_none());
        assert_eq!(b.rest, 2);
        assert!(input.is_empty());

        let mut input = [2, 3].as_slice();
        assert_eq!(b.read_from(&mut input), Some(&mut [0, 1, 2, 3]));
        assert_eq!(b.rest, 0);
        assert!(input.is_empty());

        let mut input = [4, 5].as_slice();
        assert_eq!(b.read_from(&mut input), Some(&mut [0, 1, 2, 3]));
        assert_eq!(b.rest, 0);
        assert_eq!(input, [4, 5]);
    }

    #[test]
    fn read_more_input() {
        let mut b: Reader<[u8; 4]> = Reader::default();
        assert_eq!(b.rest, 4);

        let mut input = [0, 1, 2, 3, 4, 5].as_slice();
        assert_eq!(b.read_from(&mut input), Some(&mut [0, 1, 2, 3]));
        assert_eq!(b.rest, 0);
        assert_eq!(input, [4, 5]);
    }

    #[test]
    fn read_skip() {
        let mut b: Reader<Skippable<[u8; 0]>> = Reader::skip(4);
        assert_eq!(b.rest, 4);

        let mut input = [0, 1].as_slice();
        assert!(b.read_from(&mut input).is_none());
        assert_eq!(b.rest, 2);
        assert!(input.is_empty());

        let mut input = [2, 3].as_slice();
        assert_eq!(b.read_from(&mut input), Some(&mut Skippable::Skip));
        assert_eq!(b.rest, 0);
        assert!(input.is_empty());
    }
}