Skip to content

Commit

Permalink
remove Sink from public api
Browse files Browse the repository at this point in the history
  • Loading branch information
PSeitz committed May 15, 2021
1 parent c7e58de commit 0534836
Show file tree
Hide file tree
Showing 6 changed files with 108 additions and 69 deletions.
80 changes: 56 additions & 24 deletions src/block/compress.rs
Original file line number Diff line number Diff line change
Expand Up @@ -338,11 +338,17 @@ fn backtrack_match(
pub(crate) fn compress_internal<T: HashTable, const USE_DICT: bool>(
input: &[u8],
input_pos: usize,
output: &mut Sink,
output: &mut [u8],
output_pos: usize,
dict: &mut T,
ext_dict: &[u8],
input_stream_offset: usize,
) -> Result<usize, CompressError> {
let mut output = Sink {
output,
pos: output_pos,
};
let output = &mut output;
assert!(input_pos <= input.len());
assert!(ext_dict.len() <= super::WINDOW_SIZE);
assert!(ext_dict.len() <= input_stream_offset);
Expand Down Expand Up @@ -603,48 +609,77 @@ pub fn get_maximum_output_size(input_len: usize) -> usize {

/// Compress all bytes of `input` into `output`.
/// The method chooses an appropriate hashtable to lookup duplicates and calls `compress_into_with_table`.
/// Sink should be preallocated with a size of `get_maximum_output_size`.
/// output should be preallocated with a size of `get_maximum_output_size`.
///
/// Returns the number of bytes written (compressed) into `output`.
#[inline]
pub fn compress_into(input: &[u8], compressed: &mut Sink) -> Result<usize, CompressError> {
pub fn compress_into(
input: &[u8],
output: &mut [u8],
output_pos: usize,
) -> Result<usize, CompressError> {
let (dict_size, dict_bitshift) = get_table_size(input.len());
if input.len() < u16::MAX as usize {
let mut dict = HashTableU16::new(dict_size, dict_bitshift);
compress_internal::<_, false>(input, 0, compressed, &mut dict, b"", 0)
compress_internal::<_, false>(input, 0, output, output_pos, &mut dict, b"", 0)
} else if input.len() < u32::MAX as usize {
let mut dict = HashTableU32::new(dict_size, dict_bitshift);
compress_internal::<_, false>(input, 0, compressed, &mut dict, b"", 0)
compress_internal::<_, false>(input, 0, output, output_pos, &mut dict, b"", 0)
} else {
let mut dict = HashTableUsize::new(dict_size, dict_bitshift);
compress_internal::<_, false>(input, 0, compressed, &mut dict, b"", 0)
compress_internal::<_, false>(input, 0, output, output_pos, &mut dict, b"", 0)
}
}

/// Compress all bytes of `input` into `output`.
/// The method chooses an appropriate hashtable to lookup duplicates and calls `compress_into_with_table`.
/// Sink should be preallocated with a size of `get_maximum_output_size`.
/// output should be preallocated with a size of `get_maximum_output_size`.
///
/// Returns the number of bytes written (compressed) into `output`.
#[inline]
pub fn compress_into_with_dict(
input: &[u8],
compressed: &mut Sink,
output: &mut [u8],
output_pos: usize,
mut dict_data: &[u8],
) -> Result<usize, CompressError> {
let (dict_size, dict_bitshift) = get_table_size(input.len());
if dict_data.len() + input.len() < u16::MAX as usize {
let mut dict = HashTableU16::new(dict_size, dict_bitshift);
init_dict(&mut dict, &mut dict_data);
compress_internal::<_, true>(input, 0, compressed, &mut dict, dict_data, dict_data.len())
compress_internal::<_, true>(
input,
0,
output,
output_pos,
&mut dict,
dict_data,
dict_data.len(),
)
} else if dict_data.len() + input.len() < u32::MAX as usize {
let mut dict = HashTableU32::new(dict_size, dict_bitshift);
init_dict(&mut dict, &mut dict_data);
compress_internal::<_, true>(input, 0, compressed, &mut dict, dict_data, dict_data.len())
compress_internal::<_, true>(
input,
0,
output,
output_pos,
&mut dict,
dict_data,
dict_data.len(),
)
} else {
let mut dict = HashTableUsize::new(dict_size, dict_bitshift);
init_dict(&mut dict, &mut dict_data);
compress_internal::<_, true>(input, 0, compressed, &mut dict, dict_data, dict_data.len())
compress_internal::<_, true>(
input,
0,
output,
output_pos,
&mut dict,
dict_data,
dict_data.len(),
)
}
}

Expand Down Expand Up @@ -682,33 +717,29 @@ pub(crate) fn get_output_vec(input_len: usize) -> Vec<u8> {
/// Can be used in conjunction with `decompress_size_prepended`
#[inline]
pub fn compress_prepend_size(input: &[u8]) -> Vec<u8> {
// In most cases, the compression won't expand the size, so we set the input size as capacity.
let mut compressed = get_output_vec(4 + input.len());
let mut sink: Sink = (&mut compressed).into();
push_u32(&mut sink, input.len() as u32);
let compressed_len = compress_into(input, &mut sink).unwrap();
let compressed_len = compress_into(input, &mut sink.output, sink.pos).unwrap();
compressed.truncate(4 + compressed_len);
compressed
}

/// Compress all bytes of `input`.
#[inline]
pub fn compress(input: &[u8]) -> Vec<u8> {
// In most cases, the compression won't expand the size, so we set the input size as capacity.
let mut compressed = get_output_vec(input.len());
let mut sink = (&mut compressed).into();
let compressed_len = compress_into(input, &mut sink).unwrap();
let mut sink: Sink = (&mut compressed).into();
let compressed_len = compress_into(input, &mut sink.output, sink.pos).unwrap();
compressed.truncate(compressed_len);
compressed
}

/// Compress all bytes of `input` with an external dictionary.
#[inline]
pub fn compress_with_dict(input: &[u8], ext_dict: &[u8]) -> Vec<u8> {
// In most cases, the compression won't expand the size, so we set the input size as capacity.
let mut compressed = get_output_vec(input.len());
let mut sink = (&mut compressed).into();
let compressed_len = compress_into_with_dict(input, &mut sink, ext_dict).unwrap();
let compressed_len = compress_into_with_dict(input, &mut compressed, 0, ext_dict).unwrap();
compressed.truncate(compressed_len);
compressed
}
Expand All @@ -721,7 +752,8 @@ pub fn compress_prepend_size_with_dict(input: &[u8], ext_dict: &[u8]) -> Vec<u8>
let mut compressed = get_output_vec(4 + input.len());
let mut sink: Sink = (&mut compressed).into();
push_u32(&mut sink, input.len() as u32);
let compressed_len = compress_into_with_dict(input, &mut sink, ext_dict).unwrap();
let compressed_len =
compress_into_with_dict(input, &mut sink.output, sink.pos, ext_dict).unwrap();
compressed.truncate(4 + compressed_len);
compressed
}
Expand Down Expand Up @@ -862,7 +894,8 @@ mod tests {
let mut uncompressed = vec![0u8; input.len()];
let uncomp_size = crate::block::decompress::decompress_into_with_dict(
&compressed,
&mut (&mut uncompressed).into(),
&mut uncompressed,
0,
&dict,
)
.unwrap();
Expand All @@ -885,11 +918,10 @@ mod tests {
let output_start = dict.len() - dict_cutoff;
uncompressed[..output_start].copy_from_slice(&dict[dict_cutoff..]);

let mut sink: Sink = (&mut uncompressed).into();
sink.set_pos(output_start);
let uncomp_len = crate::block::decompress::decompress_into_with_dict(
&compressed,
&mut sink,
&mut uncompressed,
output_start,
&dict[..dict_cutoff],
)
.unwrap();
Expand Down
24 changes: 15 additions & 9 deletions src/block/decompress.rs
Original file line number Diff line number Diff line change
Expand Up @@ -171,19 +171,27 @@ fn does_token_fit(token: u8) -> bool {
}

/// Decompress all bytes of `input` into `output`.
/// `Sink` should be preallocated with a size of of the uncompressed data.
/// `output` should be preallocated with a size of of the uncompressed data.
#[inline]
pub fn decompress_into(input: &[u8], output: &mut Sink) -> Result<usize, DecompressError> {
decompress_internal::<false>(input, output, b"")
pub fn decompress_into(
input: &[u8],
output: &mut [u8],
output_pos: usize,
) -> Result<usize, DecompressError> {
decompress_internal::<false>(input, &mut (output, output_pos).into(), b"")
}

/// Decompress all bytes of `input` into `output`.
///
/// Returns the number of bytes written (decompressed) into `output`.
#[inline]
pub fn decompress_into_with_dict(
input: &[u8],
output: &mut Sink,
output: &mut [u8],
output_pos: usize,
ext_dict: &[u8],
) -> Result<usize, DecompressError> {
decompress_internal::<true>(input, output, ext_dict)
decompress_internal::<true>(input, &mut (output, output_pos).into(), ext_dict)
}

/// Decompress all bytes of `input` into `output`.
Expand Down Expand Up @@ -441,8 +449,7 @@ pub fn decompress(input: &[u8], uncompressed_size: usize) -> Result<Vec<u8>, Dec
unsafe {
vec.set_len(uncompressed_size);
}
let mut sink: Sink = (&mut vec).into();
let decomp_len = decompress_into(input, &mut sink)?;
let decomp_len = decompress_into(input, &mut vec, 0)?;
if decomp_len != uncompressed_size {
return Err(DecompressError::UncompressedSizeDiffers {
expected: uncompressed_size,
Expand Down Expand Up @@ -480,8 +487,7 @@ pub fn decompress_with_dict(
unsafe {
vec.set_len(uncompressed_size);
}
let mut sink: Sink = (&mut vec).into();
let decomp_len = decompress_into_with_dict(input, &mut sink, ext_dict)?;
let decomp_len = decompress_into_with_dict(input, &mut vec, 0, ext_dict)?;
if decomp_len != uncompressed_size {
return Err(DecompressError::UncompressedSizeDiffers {
expected: uncompressed_size,
Expand Down
22 changes: 12 additions & 10 deletions src/block/decompress_safe.rs
Original file line number Diff line number Diff line change
Expand Up @@ -78,11 +78,14 @@ fn does_token_fit(token: u8) -> bool {
}

/// Decompress all bytes of `input` into `output`.
///
/// Returns the number of bytes written (decompressed) into `output`.
/// `output` should be preallocated with a size of of the uncompressed data.
#[inline]
pub fn decompress_into(input: &[u8], output: &mut Sink) -> Result<usize, DecompressError> {
decompress_internal::<false>(input, output, b"")
pub fn decompress_into(
input: &[u8],
output: &mut [u8],
output_pos: usize,
) -> Result<usize, DecompressError> {
decompress_internal::<false>(input, &mut (output, output_pos).into(), b"")
}

/// Decompress all bytes of `input` into `output`.
Expand All @@ -91,10 +94,11 @@ pub fn decompress_into(input: &[u8], output: &mut Sink) -> Result<usize, Decompr
#[inline]
pub fn decompress_into_with_dict(
input: &[u8],
output: &mut Sink,
output: &mut [u8],
output_pos: usize,
ext_dict: &[u8],
) -> Result<usize, DecompressError> {
decompress_internal::<true>(input, output, ext_dict)
decompress_internal::<true>(input, &mut (output, output_pos).into(), ext_dict)
}

/// Decompress all bytes of `input` into `output`.
Expand Down Expand Up @@ -345,8 +349,7 @@ pub fn decompress(input: &[u8], uncompressed_size: usize) -> Result<Vec<u8>, Dec
// Allocate a vector to contain the decompressed stream.
let mut vec: Vec<u8> = Vec::with_capacity(uncompressed_size);
vec.resize(uncompressed_size, 0);
let mut sink: Sink = (&mut vec).into();
let decomp_len = decompress_into(input, &mut sink)?;
let decomp_len = decompress_into(input, &mut vec, 0)?;
if decomp_len != uncompressed_size {
return Err(DecompressError::UncompressedSizeDiffers {
expected: uncompressed_size,
Expand Down Expand Up @@ -377,8 +380,7 @@ pub fn decompress_with_dict(
// Allocate a vector to contain the decompressed stream.
let mut vec: Vec<u8> = Vec::with_capacity(uncompressed_size);
vec.resize(uncompressed_size, 0);
let mut sink: Sink = (&mut vec).into();
let decomp_len = decompress_into_with_dict(input, &mut sink, ext_dict)?;
let decomp_len = decompress_into_with_dict(input, &mut vec, 0, ext_dict)?;
if decomp_len != uncompressed_size {
return Err(DecompressError::UncompressedSizeDiffers {
expected: uncompressed_size,
Expand Down
28 changes: 12 additions & 16 deletions src/block/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -145,17 +145,10 @@ fn uncompressed_size(input: &[u8]) -> Result<(usize, &[u8]), DecompressError> {
}

/// Sink is used as target to de/compress data into a preallocated space.
/// Make sure to allocate enough for compression (`get_maximum_output_size`) AND decompression(decompress_sink_size).
/// Make sure to allocate enough for compression (`get_maximum_output_size`)
/// Sink can be created from a `Vec` or a `Slice`. The new pos on the data after the operation
/// can be retrieved via `sink.pos()`
/// # Examples
/// ```
/// use lz4_flex::block::Sink;
/// let mut data = Vec::new();
/// data.resize(5, 0);
/// let mut sink: Sink = (&mut data).into();
/// ```
pub struct Sink<'a> {
pub(crate) struct Sink<'a> {
output: &'a mut [u8],
pos: usize,
}
Expand All @@ -180,6 +173,16 @@ impl<'a> From<&'a mut [u8]> for Sink<'a> {
}
}

impl<'a> From<(&'a mut [u8], usize)> for Sink<'a> {
#[inline]
fn from(data: (&'a mut [u8], usize)) -> Self {
Sink {
output: data.0,
pos: data.1,
}
}
}

impl<'a> Sink<'a> {
#[cfg(any(feature = "safe-encode", feature = "safe-decode"))]
#[inline]
Expand All @@ -200,11 +203,6 @@ impl<'a> Sink<'a> {
unsafe { self.output.as_mut_ptr().add(self.pos) }
}

#[inline]
pub fn get_data(&self) -> &[u8] {
&self.output[0..self.pos]
}

#[inline]
pub fn pos(&self) -> usize {
self.pos
Expand Down Expand Up @@ -232,9 +230,7 @@ fn test_sink() {
let mut data = Vec::new();
data.resize(5, 0);
let mut sink: Sink = (&mut data).into();
assert_eq!(sink.get_data(), &[]);
assert_eq!(sink.pos(), 0);
sink.extend_from_slice(&[1, 2, 3]);
assert_eq!(sink.get_data(), &[1, 2, 3]);
assert_eq!(sink.pos(), 3);
}
6 changes: 4 additions & 2 deletions src/frame/compress.rs
Original file line number Diff line number Diff line change
Expand Up @@ -242,7 +242,8 @@ impl<W: io::Write> FrameEncoder<W> {
compress_internal::<_, true>(
input,
self.src_start,
&mut (&mut self.dst[..]).into(),
&mut self.dst[..],
0,
&mut self.compression_table,
&self.src[self.ext_dict_offset..self.ext_dict_offset + self.ext_dict_len],
self.src_stream_offset,
Expand All @@ -251,7 +252,8 @@ impl<W: io::Write> FrameEncoder<W> {
compress_internal::<_, false>(
input,
self.src_start,
&mut (&mut self.dst[..]).into(),
&mut self.dst[..],
0,
&mut self.compression_table,
b"",
self.src_stream_offset,
Expand Down
17 changes: 9 additions & 8 deletions src/frame/decompress.rs
Original file line number Diff line number Diff line change
Expand Up @@ -251,20 +251,21 @@ impl<R: io::Read> FrameDecoder<R> {
let (head, tail) = self.dst.split_at_mut(self.ext_dict_offset);
let ext_dict = &tail[..self.ext_dict_len];

let mut sink: crate::block::Sink = head.into();
sink.set_pos(self.dst_start);
debug_assert!(sink.capacity() - sink.pos() >= max_block_size);
debug_assert!(head.len() - self.dst_start >= max_block_size);
crate::block::decompress::decompress_into_with_dict(
&self.src[..len],
&mut sink,
head,
self.dst_start,
ext_dict,
)
} else {
// Independent blocks OR linked blocks with only prefix data
let mut sink: crate::block::Sink = (&mut self.dst).into();
sink.set_pos(self.dst_start);
debug_assert!(sink.capacity() - sink.pos() >= max_block_size);
crate::block::decompress::decompress_into(&self.src[..len], &mut sink)
debug_assert!(self.dst.len() - self.dst_start >= max_block_size);
crate::block::decompress::decompress_into(
&self.src[..len],
&mut self.dst,
self.dst_start,
)
}
.map_err(Error::DecompressionError)?;

Expand Down

0 comments on commit 0534836

Please sign in to comment.