241 lines
6.9 KiB
Rust
241 lines
6.9 KiB
Rust
//! Implement pull-based [`Read`] trait for both compressing and decompressing.
|
|
use std::io::{self, BufRead, BufReader, Read};
|
|
|
|
use crate::dict::{DecoderDictionary, EncoderDictionary};
|
|
use crate::stream::{raw, zio};
|
|
use zstd_safe;
|
|
|
|
#[cfg(test)]
|
|
mod tests;
|
|
|
|
/// A decoder that decompress input data from another `Read`.
|
|
///
|
|
/// This allows to read a stream of compressed data
|
|
/// (good for files or heavy network stream).
|
|
pub struct Decoder<'a, R> {
|
|
reader: zio::Reader<R, raw::Decoder<'a>>,
|
|
}
|
|
|
|
/// An encoder that compress input data from another `Read`.
|
|
pub struct Encoder<'a, R> {
|
|
reader: zio::Reader<R, raw::Encoder<'a>>,
|
|
}
|
|
|
|
impl<R: Read> Decoder<'static, BufReader<R>> {
|
|
/// Creates a new decoder.
|
|
pub fn new(reader: R) -> io::Result<Self> {
|
|
let buffer_size = zstd_safe::DCtx::in_size();
|
|
|
|
Self::with_buffer(BufReader::with_capacity(buffer_size, reader))
|
|
}
|
|
}
|
|
|
|
impl<R: BufRead> Decoder<'static, R> {
|
|
/// Creates a new decoder around a `BufRead`.
|
|
pub fn with_buffer(reader: R) -> io::Result<Self> {
|
|
Self::with_dictionary(reader, &[])
|
|
}
|
|
/// Creates a new decoder, using an existing dictionary.
|
|
///
|
|
/// The dictionary must be the same as the one used during compression.
|
|
pub fn with_dictionary(reader: R, dictionary: &[u8]) -> io::Result<Self> {
|
|
let decoder = raw::Decoder::with_dictionary(dictionary)?;
|
|
let reader = zio::Reader::new(reader, decoder);
|
|
|
|
Ok(Decoder { reader })
|
|
}
|
|
}
|
|
impl<'a, R: BufRead> Decoder<'a, R> {
|
|
/// Creates a new decoder which employs the provided context for deserialization.
|
|
pub fn with_context(
|
|
reader: R,
|
|
context: &'a mut zstd_safe::DCtx<'static>,
|
|
) -> Self {
|
|
Self {
|
|
reader: zio::Reader::new(
|
|
reader,
|
|
raw::Decoder::with_context(context),
|
|
),
|
|
}
|
|
}
|
|
|
|
/// Sets this `Decoder` to stop after the first frame.
|
|
///
|
|
/// By default, it keeps concatenating frames until EOF is reached.
|
|
#[must_use]
|
|
pub fn single_frame(mut self) -> Self {
|
|
self.reader.set_single_frame();
|
|
self
|
|
}
|
|
|
|
/// Creates a new decoder, using an existing `DecoderDictionary`.
|
|
///
|
|
/// The dictionary must be the same as the one used during compression.
|
|
pub fn with_prepared_dictionary<'b>(
|
|
reader: R,
|
|
dictionary: &DecoderDictionary<'b>,
|
|
) -> io::Result<Self>
|
|
where
|
|
'b: 'a,
|
|
{
|
|
let decoder = raw::Decoder::with_prepared_dictionary(dictionary)?;
|
|
let reader = zio::Reader::new(reader, decoder);
|
|
|
|
Ok(Decoder { reader })
|
|
}
|
|
|
|
/// Creates a new decoder, using a ref prefix.
|
|
///
|
|
/// The prefix must be the same as the one used during compression.
|
|
pub fn with_ref_prefix<'b>(
|
|
reader: R,
|
|
ref_prefix: &'b [u8],
|
|
) -> io::Result<Self>
|
|
where
|
|
'b: 'a,
|
|
{
|
|
let decoder = raw::Decoder::with_ref_prefix(ref_prefix)?;
|
|
let reader = zio::Reader::new(reader, decoder);
|
|
|
|
Ok(Decoder { reader })
|
|
}
|
|
|
|
/// Recommendation for the size of the output buffer.
|
|
pub fn recommended_output_size() -> usize {
|
|
zstd_safe::DCtx::out_size()
|
|
}
|
|
|
|
/// Acquire a reference to the underlying reader.
|
|
pub fn get_ref(&self) -> &R {
|
|
self.reader.reader()
|
|
}
|
|
|
|
/// Acquire a mutable reference to the underlying reader.
|
|
///
|
|
/// Note that mutation of the reader may result in surprising results if
|
|
/// this decoder is continued to be used.
|
|
pub fn get_mut(&mut self) -> &mut R {
|
|
self.reader.reader_mut()
|
|
}
|
|
|
|
/// Return the inner `Read`.
|
|
///
|
|
/// Calling `finish()` is not *required* after reading a stream -
|
|
/// just use it if you need to get the `Read` back.
|
|
pub fn finish(self) -> R {
|
|
self.reader.into_inner()
|
|
}
|
|
|
|
crate::decoder_common!(reader);
|
|
}
|
|
|
|
impl<R: BufRead> Read for Decoder<'_, R> {
|
|
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
|
|
self.reader.read(buf)
|
|
}
|
|
}
|
|
|
|
impl<R: Read> Encoder<'static, BufReader<R>> {
|
|
/// Creates a new encoder.
|
|
pub fn new(reader: R, level: i32) -> io::Result<Self> {
|
|
let buffer_size = zstd_safe::CCtx::in_size();
|
|
|
|
Self::with_buffer(BufReader::with_capacity(buffer_size, reader), level)
|
|
}
|
|
}
|
|
|
|
impl<R: BufRead> Encoder<'static, R> {
|
|
/// Creates a new encoder around a `BufRead`.
|
|
pub fn with_buffer(reader: R, level: i32) -> io::Result<Self> {
|
|
Self::with_dictionary(reader, level, &[])
|
|
}
|
|
|
|
/// Creates a new encoder, using an existing dictionary.
|
|
///
|
|
/// The dictionary must be the same as the one used during compression.
|
|
pub fn with_dictionary(
|
|
reader: R,
|
|
level: i32,
|
|
dictionary: &[u8],
|
|
) -> io::Result<Self> {
|
|
let encoder = raw::Encoder::with_dictionary(level, dictionary)?;
|
|
let reader = zio::Reader::new(reader, encoder);
|
|
|
|
Ok(Encoder { reader })
|
|
}
|
|
}
|
|
|
|
impl<'a, R: BufRead> Encoder<'a, R> {
|
|
/// Creates a new encoder, using an existing `EncoderDictionary`.
|
|
///
|
|
/// The dictionary must be the same as the one used during compression.
|
|
pub fn with_prepared_dictionary<'b>(
|
|
reader: R,
|
|
dictionary: &EncoderDictionary<'b>,
|
|
) -> io::Result<Self>
|
|
where
|
|
'b: 'a,
|
|
{
|
|
let encoder = raw::Encoder::with_prepared_dictionary(dictionary)?;
|
|
let reader = zio::Reader::new(reader, encoder);
|
|
|
|
Ok(Encoder { reader })
|
|
}
|
|
|
|
/// Recommendation for the size of the output buffer.
|
|
pub fn recommended_output_size() -> usize {
|
|
zstd_safe::CCtx::out_size()
|
|
}
|
|
|
|
/// Acquire a reference to the underlying reader.
|
|
pub fn get_ref(&self) -> &R {
|
|
self.reader.reader()
|
|
}
|
|
|
|
/// Acquire a mutable reference to the underlying reader.
|
|
///
|
|
/// Note that mutation of the reader may result in surprising results if
|
|
/// this encoder is continued to be used.
|
|
pub fn get_mut(&mut self) -> &mut R {
|
|
self.reader.reader_mut()
|
|
}
|
|
|
|
/// Flush any internal buffer.
|
|
///
|
|
/// This ensures all input consumed so far is compressed.
|
|
///
|
|
/// Since it prevents bundling currently buffered data with future input,
|
|
/// it may affect compression ratio.
|
|
///
|
|
/// * Returns the number of bytes written to `out`.
|
|
/// * Returns `Ok(0)` when everything has been flushed.
|
|
pub fn flush(&mut self, out: &mut [u8]) -> io::Result<usize> {
|
|
self.reader.flush(out)
|
|
}
|
|
|
|
/// Return the inner `Read`.
|
|
///
|
|
/// Calling `finish()` is not *required* after reading a stream -
|
|
/// just use it if you need to get the `Read` back.
|
|
pub fn finish(self) -> R {
|
|
self.reader.into_inner()
|
|
}
|
|
|
|
crate::encoder_common!(reader);
|
|
}
|
|
|
|
impl<R: BufRead> Read for Encoder<'_, R> {
|
|
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
|
|
self.reader.read(buf)
|
|
}
|
|
}
|
|
|
|
fn _assert_traits() {
|
|
use std::io::Cursor;
|
|
|
|
fn _assert_send<T: Send>(_: T) {}
|
|
|
|
_assert_send(Decoder::new(Cursor::new(Vec::new())));
|
|
_assert_send(Encoder::new(Cursor::new(Vec::new()), 1));
|
|
}
|