Skip to content

Commit

Permalink
Refactoring: Dedupe code into write_to_spare_capacity_of_vec helper.
Browse files Browse the repository at this point in the history
  • Loading branch information
anforowicz committed Aug 29, 2023
1 parent 20cdcbe commit 82e45fa
Showing 1 changed file with 39 additions and 25 deletions.
64 changes: 39 additions & 25 deletions src/mem.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
use std::error::Error;
use std::fmt;
use std::io;
use std::slice;

use crate::ffi::{self, Backend, Deflate, DeflateBackend, ErrorMessage, Inflate, InflateBackend};
use crate::Compression;
Expand Down Expand Up @@ -342,19 +341,12 @@ impl Compress {
output: &mut Vec<u8>,
flush: FlushCompress,
) -> Result<Status, CompressError> {
let cap = output.capacity();
let len = output.len();

unsafe {
write_to_spare_capacity_of_vec(output, |out| {
let before = self.total_out();
let ret = {
let ptr = output.as_mut_ptr().add(len);
let out = slice::from_raw_parts_mut(ptr, cap - len);
self.compress(input, out, flush)
};
output.set_len((self.total_out() - before) as usize + len);
ret
}
let ret = self.compress(input, out, flush);
let bytes_written = self.total_out() - before;
(bytes_written as usize, ret)
})
}
}

Expand Down Expand Up @@ -473,19 +465,12 @@ impl Decompress {
output: &mut Vec<u8>,
flush: FlushDecompress,
) -> Result<Status, DecompressError> {
let cap = output.capacity();
let len = output.len();

unsafe {
write_to_spare_capacity_of_vec(output, |out| {
let before = self.total_out();
let ret = {
let ptr = output.as_mut_ptr().add(len);
let out = slice::from_raw_parts_mut(ptr, cap - len);
self.decompress(input, out, flush)
};
output.set_len((self.total_out() - before) as usize + len);
ret
}
let ret = self.decompress(input, out, flush);
let bytes_written = self.total_out() - before;
(bytes_written as usize, ret)
})
}

/// Specifies the decompression dictionary to use.
Expand Down Expand Up @@ -574,6 +559,35 @@ impl fmt::Display for CompressError {
}
}

/// Allows `writer` to write data into the spare capacity of the `output` vector.
/// This will not reallocate the vector provided or attempt to grow it, so space
/// for the `output` must be reserved by the caller before calling this
/// function.
///
/// `writer` needs to return the number of bytes written (and can also return
/// another arbitrary return value).
fn write_to_spare_capacity_of_vec<T>(
output: &mut Vec<u8>,
writer: impl FnOnce(&mut [u8]) -> (usize, T),
) -> T {
let cap = output.capacity();
let len = output.len();

// FIXME: This is unsound - see https://github.com/rust-lang/flate2-rs/issues/220
// (The code below reimplements `Vec::spare_capacity_mut`, but returns `&mut [u8]`
// instead of `&mut [MaybeUninit<u8>]`.)
unsafe {
let (bytes_written, ret) = {
let ptr = output.as_mut_ptr().add(len);
let out = slice::from_raw_parts_mut(ptr, cap - len);
writer(out)
};
let new_len = core::cmp::min(len + bytes_written, cap); // Sanitizes `bytes_written`.
output.set_len(new_len);
ret
}
}

#[cfg(test)]
mod tests {
use std::io::Write;
Expand Down

0 comments on commit 82e45fa

Please sign in to comment.