diff --git a/src/block/compress.rs b/src/block/compress.rs index 48f6734f..22afcf80 100644 --- a/src/block/compress.rs +++ b/src/block/compress.rs @@ -338,11 +338,17 @@ fn backtrack_match( pub(crate) fn compress_internal( 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 { + 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); @@ -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 { +pub fn compress_into( + input: &[u8], + output: &mut [u8], + output_pos: usize, +) -> Result { 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 { 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(), + ) } } @@ -682,11 +717,10 @@ pub(crate) fn get_output_vec(input_len: usize) -> Vec { /// Can be used in conjunction with `decompress_size_prepended` #[inline] pub fn compress_prepend_size(input: &[u8]) -> Vec { - // 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 } @@ -694,10 +728,9 @@ pub fn compress_prepend_size(input: &[u8]) -> Vec { /// Compress all bytes of `input`. #[inline] pub fn compress(input: &[u8]) -> Vec { - // 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 } @@ -705,10 +738,8 @@ pub fn compress(input: &[u8]) -> Vec { /// Compress all bytes of `input` with an external dictionary. #[inline] pub fn compress_with_dict(input: &[u8], ext_dict: &[u8]) -> Vec { - // 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 } @@ -721,7 +752,8 @@ pub fn compress_prepend_size_with_dict(input: &[u8], ext_dict: &[u8]) -> Vec 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 } @@ -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(); @@ -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(); diff --git a/src/block/decompress.rs b/src/block/decompress.rs index b1fca177..4de5f70e 100644 --- a/src/block/decompress.rs +++ b/src/block/decompress.rs @@ -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 { - decompress_internal::(input, output, b"") +pub fn decompress_into( + input: &[u8], + output: &mut [u8], + output_pos: usize, +) -> Result { + decompress_internal::(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 { - decompress_internal::(input, output, ext_dict) + decompress_internal::(input, &mut (output, output_pos).into(), ext_dict) } /// Decompress all bytes of `input` into `output`. @@ -441,8 +449,7 @@ pub fn decompress(input: &[u8], uncompressed_size: usize) -> Result, 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, @@ -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, diff --git a/src/block/decompress_safe.rs b/src/block/decompress_safe.rs index e09d1454..96ea6b7a 100644 --- a/src/block/decompress_safe.rs +++ b/src/block/decompress_safe.rs @@ -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 { - decompress_internal::(input, output, b"") +pub fn decompress_into( + input: &[u8], + output: &mut [u8], + output_pos: usize, +) -> Result { + decompress_internal::(input, &mut (output, output_pos).into(), b"") } /// Decompress all bytes of `input` into `output`. @@ -91,10 +94,11 @@ pub fn decompress_into(input: &[u8], output: &mut Sink) -> Result Result { - decompress_internal::(input, output, ext_dict) + decompress_internal::(input, &mut (output, output_pos).into(), ext_dict) } /// Decompress all bytes of `input` into `output`. @@ -345,8 +349,7 @@ pub fn decompress(input: &[u8], uncompressed_size: usize) -> Result, Dec // Allocate a vector to contain the decompressed stream. let mut vec: Vec = 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, @@ -377,8 +380,7 @@ pub fn decompress_with_dict( // Allocate a vector to contain the decompressed stream. let mut vec: Vec = 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, diff --git a/src/block/mod.rs b/src/block/mod.rs index 32671c6b..3c6cff09 100644 --- a/src/block/mod.rs +++ b/src/block/mod.rs @@ -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, } @@ -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] @@ -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 @@ -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); } diff --git a/src/frame/compress.rs b/src/frame/compress.rs index 0b97ee53..825b56dd 100644 --- a/src/frame/compress.rs +++ b/src/frame/compress.rs @@ -242,7 +242,8 @@ impl FrameEncoder { 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, @@ -251,7 +252,8 @@ impl FrameEncoder { 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, diff --git a/src/frame/decompress.rs b/src/frame/decompress.rs index 579cdffd..e0b0d3cc 100644 --- a/src/frame/decompress.rs +++ b/src/frame/decompress.rs @@ -251,20 +251,21 @@ impl FrameDecoder { 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)?;