agzip 0.1.0

Async compatible gzip (de)compressor
Documentation
use std::mem;

#[derive(Debug)]
pub(crate) struct Writer<P> {
    rest: usize,
    data: P,
}

impl<P> Writer<P> {
    #[inline]
    pub fn new(data: P) -> Self
    where
        P: AsRef<[u8]>,
    {
        let rest = data.as_ref().len();
        Self { rest, data }
    }

    pub fn write_to(&mut self, output: &mut &mut [u8]) -> bool
    where
        P: Produce,
    {
        let n = usize::min(self.rest, output.len());
        let (left, right) = mem::take(output).split_at_mut(n);
        *output = right;
        self.data.produce(self.rest, left);

        self.rest -= n;
        self.rest == 0
    }
}

pub(crate) trait Produce {
    fn produce(&self, rest: usize, output: &mut [u8]);
}

impl<P> Produce for P
where
    P: AsRef<[u8]>,
{
    fn produce(&self, rest: usize, output: &mut [u8]) {
        let inner = self.as_ref();
        let step = inner.len() - rest;
        output.copy_from_slice(&inner[step..step + output.len()]);
    }
}

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

    #[test]
    fn write() {
        let mut w = Writer::new([0, 1, 2, 3]);
        assert_eq!(w.rest, 4);

        let mut buf = [0; 2];

        let mut output = buf.as_mut_slice();
        assert!(!w.write_to(&mut output));
        assert_eq!(w.rest, 2);
        assert!(output.is_empty());
        assert_eq!(buf, [0, 1]);

        let mut output = buf.as_mut_slice();
        assert!(w.write_to(&mut output));
        assert_eq!(w.rest, 0);
        assert!(output.is_empty());
        assert_eq!(buf, [2, 3]);

        let mut output = buf.as_mut_slice();
        assert!(w.write_to(&mut output));
        assert_eq!(w.rest, 0);
        assert_eq!(output.len(), 2);
        assert_eq!(buf, [2, 3]);
    }
}