Skip to content

Commit

Permalink
lzbuffer: own output sink instead of holding ref
Browse files Browse the repository at this point in the history
Changes `LZBuffer` trait to consume the output sink instead of holding a
reference to it. This makes it easier to store the sink and avoids
self-referential structs. It also makes sense for the buffer to own the
sink while it is performing decompression.

This also adds the methods `get_output` and `get_output_mut` to access
the output sink.
  • Loading branch information
cccs-sadugas committed Jul 14, 2020
1 parent 9b2261c commit 17e7aa2
Show file tree
Hide file tree
Showing 3 changed files with 77 additions and 44 deletions.
81 changes: 54 additions & 27 deletions src/decode/lzbuffer.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
use crate::error;
use std::io;

pub trait LZBuffer {
pub trait LZBuffer<W>
where
W: io::Write,
{
fn len(&self) -> usize;
// Retrieve the last byte or return a default
fn last_or(&self, lit: u8) -> u8;
Expand All @@ -11,30 +14,34 @@ pub trait LZBuffer {
fn append_literal(&mut self, lit: u8) -> error::Result<()>;
// Fetch an LZ sequence (length, distance) from inside the buffer
fn append_lz(&mut self, len: usize, dist: usize) -> error::Result<()>;
// Get a reference to the output sink
fn get_output(&self) -> &W;
// Get a mutable reference to the output sink
fn get_output_mut(&mut self) -> &mut W;
// Flush the buffer to the output
fn finish(self) -> io::Result<()>;
fn finish(self) -> io::Result<W>;
}

// An accumulating buffer for LZ sequences
pub struct LZAccumBuffer<'a, W>
pub struct LZAccumBuffer<W>
where
W: 'a + io::Write,
W: io::Write,
{
stream: &'a mut W, // Output sink
buf: Vec<u8>, // Buffer
memlimit: usize, // Buffer memory limit
len: usize, // Total number of bytes sent through the buffer
stream: W, // Output sink
buf: Vec<u8>, // Buffer
memlimit: usize, // Buffer memory limit
len: usize, // Total number of bytes sent through the buffer
}

impl<'a, W> LZAccumBuffer<'a, W>
impl<W> LZAccumBuffer<W>
where
W: io::Write,
{
pub fn from_stream(stream: &'a mut W) -> Self {
pub fn from_stream(stream: W) -> Self {
Self::from_stream_with_memlimit(stream, std::usize::MAX)
}

pub fn from_stream_with_memlimit(stream: &'a mut W, memlimit: usize) -> Self {
pub fn from_stream_with_memlimit(stream: W, memlimit: usize) -> Self {
Self {
stream,
buf: Vec::new(),
Expand All @@ -58,7 +65,7 @@ where
}
}

impl<'a, W> LZBuffer for LZAccumBuffer<'a, W>
impl<W> LZBuffer<W> for LZAccumBuffer<W>
where
W: io::Write,
{
Expand Down Expand Up @@ -126,32 +133,42 @@ where
Ok(())
}

// Get a reference to the output sink
fn get_output(&self) -> &W {
&self.stream
}

// Get a mutable reference to the output sink
fn get_output_mut(&mut self) -> &mut W {
&mut self.stream
}

// Flush the buffer to the output
fn finish(self) -> io::Result<()> {
fn finish(mut self) -> io::Result<W> {
self.stream.write_all(self.buf.as_slice())?;
self.stream.flush()?;
Ok(())
Ok(self.stream)
}
}

// A circular buffer for LZ sequences
pub struct LZCircularBuffer<'a, W>
pub struct LZCircularBuffer<W>
where
W: 'a + io::Write,
W: io::Write,
{
stream: &'a mut W, // Output sink
buf: Vec<u8>, // Circular buffer
dict_size: usize, // Length of the buffer
memlimit: usize, // Buffer memory limit
cursor: usize, // Current position
len: usize, // Total number of bytes sent through the buffer
stream: W, // Output sink
buf: Vec<u8>, // Circular buffer
dict_size: usize, // Length of the buffer
memlimit: usize, // Buffer memory limit
cursor: usize, // Current position
len: usize, // Total number of bytes sent through the buffer
}

impl<'a, W> LZCircularBuffer<'a, W>
impl<W> LZCircularBuffer<W>
where
W: io::Write,
{
pub fn from_stream_with_memlimit(stream: &'a mut W, dict_size: usize, memlimit: usize) -> Self {
pub fn from_stream_with_memlimit(stream: W, dict_size: usize, memlimit: usize) -> Self {
lzma_info!("Dict size in LZ buffer: {}", dict_size);
Self {
stream,
Expand Down Expand Up @@ -185,7 +202,7 @@ where
}
}

impl<'a, W> LZBuffer for LZCircularBuffer<'a, W>
impl<W> LZBuffer<W> for LZCircularBuffer<W>
where
W: io::Write,
{
Expand Down Expand Up @@ -264,12 +281,22 @@ where
Ok(())
}

// Get a reference to the output sink
fn get_output(&self) -> &W {
&self.stream
}

// Get a mutable reference to the output sink
fn get_output_mut(&mut self) -> &mut W {
&mut self.stream
}

// Flush the buffer to the output
fn finish(self) -> io::Result<()> {
fn finish(mut self) -> io::Result<W> {
if self.cursor > 0 {
self.stream.write_all(&self.buf[0..self.cursor])?;
self.stream.flush()?;
}
Ok(())
Ok(self.stream)
}
}
32 changes: 19 additions & 13 deletions src/decode/lzma.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ use crate::decode::rangecoder;
use crate::error;
use byteorder::{LittleEndian, ReadBytesExt};
use std::io;
use std::marker::PhantomData;

use crate::decompress::Options;
use crate::decompress::UnpackedSize;
Expand Down Expand Up @@ -97,10 +98,12 @@ impl LZMAParams {
}
}

pub struct DecoderState<LZB>
pub struct DecoderState<W, LZB>
where
LZB: lzbuffer::LZBuffer,
W: io::Write,
LZB: lzbuffer::LZBuffer<W>,
{
_phantom: PhantomData<W>,
pub output: LZB,
// most lc significant bits of previous byte are part of the literal context
pub lc: u32, // 0..8
Expand All @@ -125,17 +128,18 @@ where
}

// Initialize decoder with accumulating buffer
pub fn new_accum<'a, W>(
output: lzbuffer::LZAccumBuffer<'a, W>,
pub fn new_accum<W>(
output: lzbuffer::LZAccumBuffer<W>,
lc: u32,
lp: u32,
pb: u32,
unpacked_size: Option<u64>,
) -> DecoderState<lzbuffer::LZAccumBuffer<'a, W>>
) -> DecoderState<W, lzbuffer::LZAccumBuffer<W>>
where
W: io::Write,
{
DecoderState {
_phantom: PhantomData,
output,
lc,
lp,
Expand All @@ -159,27 +163,28 @@ where
}

// Initialize decoder with circular buffer
pub fn new_circular<'a, W>(
output: &'a mut W,
pub fn new_circular<W>(
output: W,
params: LZMAParams,
) -> error::Result<DecoderState<lzbuffer::LZCircularBuffer<'a, W>>>
) -> error::Result<DecoderState<W, lzbuffer::LZCircularBuffer<W>>>
where
W: io::Write,
{
new_circular_with_memlimit(output, params, std::usize::MAX)
}

// Initialize decoder with circular buffer
pub fn new_circular_with_memlimit<'a, W>(
output: &'a mut W,
pub fn new_circular_with_memlimit<W>(
output: W,
params: LZMAParams,
memlimit: usize,
) -> error::Result<DecoderState<lzbuffer::LZCircularBuffer<'a, W>>>
) -> error::Result<DecoderState<W, lzbuffer::LZCircularBuffer<W>>>
where
W: io::Write,
{
// Decoder
let decoder = DecoderState {
_phantom: PhantomData,
output: lzbuffer::LZCircularBuffer::from_stream_with_memlimit(
output,
params.dict_size as usize,
Expand Down Expand Up @@ -208,9 +213,10 @@ where
Ok(decoder)
}

impl<LZB> DecoderState<LZB>
impl<W, LZB> DecoderState<W, LZB>
where
LZB: lzbuffer::LZBuffer,
W: io::Write,
LZB: lzbuffer::LZBuffer<W>,
{
pub fn reset_state(&mut self, lc: u32, lp: u32, pb: u32) {
self.lc = lc;
Expand Down
8 changes: 4 additions & 4 deletions src/decode/lzma2.rs
Original file line number Diff line number Diff line change
Expand Up @@ -43,8 +43,8 @@ where
Ok(())
}

fn parse_lzma<'a, R, W>(
decoder: &mut lzma::DecoderState<lzbuffer::LZAccumBuffer<'a, W>>,
fn parse_lzma<R, W>(
decoder: &mut lzma::DecoderState<W, lzbuffer::LZAccumBuffer<W>>,
input: &mut R,
status: u8,
) -> error::Result<()>
Expand Down Expand Up @@ -165,8 +165,8 @@ where
decoder.process(&mut rangecoder)
}

fn parse_uncompressed<'a, R, W>(
decoder: &mut lzma::DecoderState<lzbuffer::LZAccumBuffer<'a, W>>,
fn parse_uncompressed<R, W>(
decoder: &mut lzma::DecoderState<W, lzbuffer::LZAccumBuffer<W>>,
input: &mut R,
reset_dict: bool,
) -> error::Result<()>
Expand Down

0 comments on commit 17e7aa2

Please sign in to comment.