minilz4 0.2.0

Minimal interface for the LZ4 compression library frame format
Documentation
use crate::{context::*, sys::*};

pub use std::io::Read;

use libc::size_t;
use std::{
    io::{Error as IOError, ErrorKind as IOErrorKind, Result as IOResult},
    ptr,
};

const BUFFER_SIZE: usize = 32 * 1024;

pub struct Decoder<R: Read> {
    context:  LZ4FDecompressionContext,
    reader:   R,
    buffer:   Box<[u8]>,
    position: usize,
    length:   usize,
    next:     usize,
}

impl<'a, R: Read> Decoder<R> {
    pub fn new(reader: R) -> IOResult<Decoder<R>> {
        Ok(Decoder {
            reader,
            context: LZ4FDecompressionContext::new()?,
            buffer: Box::new([0; BUFFER_SIZE]),
            position: BUFFER_SIZE,
            length: BUFFER_SIZE,
            next: 11,
        })
    }

    pub fn finish(self) -> IOResult<R> {
        match self.next {
            0 => Ok(self.reader),
            _ => Err(IOError::new(
                IOErrorKind::Interrupted,
                "Finish runned before read end of compressed stream",
            )),
        }
    }
}


impl<R: Read> Read for Decoder<R> {
    fn read(&mut self, buffer: &mut [u8]) -> IOResult<usize> {
        if self.next == 0 || buffer.len() == 0 {
            return Ok(0);
        }
        let mut dst_offset: usize = 0;
        while dst_offset == 0 {
            if self.position >= self.length {
                let need = match self.buffer.len() < self.next {
                    true => self.buffer.len(),
                    false => self.next,
                };
                self.length = self.reader.read(&mut self.buffer[0..need])?;
                if self.length <= 0 {
                    break;
                }
                self.position = 0;
                self.next -= self.length;
            }
            while (dst_offset < buffer.len()) && (self.position < self.length) {
                let mut src_size = (self.length - self.position) as size_t;
                let mut dst_size = (buffer.len() - dst_offset) as size_t;
                let length = wrap_error(unsafe {
                    LZ4F_decompress(
                        self.context.0,
                        buffer[dst_offset..].as_mut_ptr(),
                        &mut dst_size,
                        self.buffer[self.position..].as_ptr(),
                        &mut src_size,
                        ptr::null(),
                    )
                })?;
                self.position += src_size as usize;
                dst_offset += dst_size as usize;
                if length == 0 {
                    self.next = 0;
                    return Ok(dst_offset);
                } else if self.next < length {
                    self.next = length;
                }
            }
        }
        Ok(dst_offset)
    }
}