use Options;
use flate2::{Compress, FlushCompress};
use std::io::{self, Write};
pub struct Compressor {
compress: Compress,
buf: Vec<u8>,
}
impl Compressor {
pub fn new(opts: &Options) -> Self {
Self {
compress: Compress::new(opts.level, true),
buf: Vec::with_capacity(opts.buffer),
}
}
pub fn reset(&mut self, opts: &Options) {
self.compress.reset();
self.buf.clear();
self.buf.reserve(opts.buffer);
}
}
pub struct Writer<'a, F> {
compressor: &'a mut Compressor,
handler: F,
}
impl<'a, F> Writer<'a, F> {
pub fn new(compressor: &'a mut Compressor, handler: F) -> Self {
Self { compressor, handler }
}
}
impl<'a, F> Write for Writer<'a, F>
where
F: FnMut(&[u8]) -> io::Result<()>,
{
fn write(&mut self, raw: &[u8]) -> io::Result<usize> {
let Compressor {
ref mut compress,
ref mut buf,
} = *self.compressor;
let in1 = compress.total_in();
compress.compress_vec(raw, buf, FlushCompress::None)?;
let in2 = compress.total_in();
let processed = (in2 - in1) as usize;
if buf.len() == buf.capacity() {
(self.handler)(&buf)?;
buf.clear();
}
Ok(processed)
}
fn write_all(&mut self, mut buf: &[u8]) -> io::Result<()> {
while buf.len() > 0 {
match self.write(buf) {
Ok(n) => buf = &buf[n..],
Err(e) => {
if e.kind() != io::ErrorKind::Interrupted {
return Err(e);
}
},
}
}
Ok(())
}
fn flush(&mut self) -> io::Result<()> {
Ok(())
}
}
impl<'a, F> Writer<'a, F>
where
F: FnMut(&[u8]) -> io::Result<()>,
{
pub fn finish(&mut self) -> io::Result<()> {
let Compressor {
ref mut compress,
ref mut buf,
} = *self.compressor;
compress.compress_vec(&[], buf, FlushCompress::Finish)?;
loop {
if buf.len() > 0 {
(self.handler)(&buf)?;
buf.clear();
} else {
break;
}
compress.compress_vec(&[], buf, FlushCompress::Finish)?;
}
Ok(())
}
}