1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
//! compression using lz_fear pure rust implementation
//!

use crate::error::Result;
use bytes::{buf::BufMutExt, Buf, Bytes, BytesMut};
use lz_fear::raw; //framed::{CompressionSettings, LZ4FrameReader};
use std::io::{self, Error as IOError, ErrorKind, Write};
use std::marker::Unpin;

/// Compress data read from file or in byte arrays
#[derive(Debug)]
pub struct Compressor {}

impl Compressor {
    pub fn new() -> Self {
        Self {}
    }
}

#[derive(Debug)]
struct CompWriter<'w> {
    out: &'w mut BytesMut,
}

impl<'comp: 'req, 'req> Compressor {
    pub async fn from_file(&self, fname: &str, writer: &mut BytesMut) -> Result<(), io::Error> {
        let v: Vec<u8> = tokio::fs::read(fname).await?;
        let b: Bytes = Bytes::from(v);
        self.from_buf(&b, writer)
    }

    /// Compress the Buf data
    /// Pass in a writer, ideally preallocated to the expected size of compressed output.
    pub fn from_buf<R>(&self, reader: &R, writer: &mut BytesMut) -> Result<(), io::Error>
    where
        R: Buf + Sync + Unpin,
    {
        if reader.remaining() < 1 << 16 {
            raw::compress2(
                reader.bytes(), // TODO: not correct!!
                0,
                &mut lz_fear::raw::U16Table::default(),
                writer.writer(),
            )?;
        } else {
            raw::compress2(
                reader.bytes(), // TODO: not correct!!
                0,
                &mut lz_fear::raw::U32Table::default(),
                writer.writer(),
            )?;
        }
        Ok(())
    }
}

impl<'w> Write for CompWriter<'w> {
    fn write(&mut self, buf: &[u8]) -> Result<usize, io::Error> {
        self.out.extend_from_slice(buf);
        Ok(buf.len())
    }

    fn flush(&mut self) -> Result<(), io::Error> {
        Ok(())
    }
}

/// Uncompress data
#[derive(Debug)]
pub struct Uncompressor {}

impl<'uc: 'req, 'req> Uncompressor {
    /// Create a new uncompressor
    pub fn new() -> Self {
        Self {}
    }

    /// Uncompress the slice.
    /// 'writer' should be a BytesMut
    pub async fn from_slice(
        &'uc self,
        reader: &[u8],
        writer: &'req mut BytesMut,
    ) -> Result<(), io::Error> {
        // before I change the api from BytesMut to mut Vec to accommodate lz4_fear,
        // I want to test to see if this works. This is inefficient but functioanlly correct.
        let mut out = Vec::with_capacity(writer.len());
        let _ = raw::decompress_raw(reader, &[], &mut out, std::usize::MAX)
            .map_err(|e| IOError::new(ErrorKind::Other, e))?;
        writer.extend_from_slice(&out);
        //        let _ = raw::decompress_raw(reader, &[], &mut writer, std::usize::MAX)
        //            .map_err(|e| IOError::new(ErrorKind::Other, e))?;
        Ok(())
    }
}