Skip to content

Commit 1ed41c4

Browse files
NobodyXufolkertdev
authored andcommitted
Add MaybeUninit<u8> (de)compress API
Having a safe API for `MaybeUninit<u8>` would be necessary for async-compression to wrap and reduce the performance penalty of initializing the buffer for all `tokio::io::*` traits implementation
1 parent a165219 commit 1ed41c4

File tree

1 file changed

+55
-28
lines changed

1 file changed

+55
-28
lines changed

src/mem.rs

Lines changed: 55 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@ use std::error;
44
use std::fmt;
55
use std::marker;
66
use std::mem;
7-
use std::slice;
87

98
use core::ffi::{c_int, c_uint};
109

@@ -133,17 +132,11 @@ impl Compress {
133132
}
134133
}
135134

136-
/// Compress a block of input into a block of output.
137-
///
138-
/// If anything other than [`BZ_OK`] is seen, `Err` is returned.
139-
///
140-
/// The action given must be one of [`Action::Run`], [`Action::Flush`] or [`Action::Finish`].
141-
///
142-
/// [`BZ_OK`]: ffi::BZ_OK
143-
pub fn compress(
135+
unsafe fn compress_inner(
144136
&mut self,
145137
input: &[u8],
146-
output: &mut [u8],
138+
output_ptr: *mut u8,
139+
output_len: usize,
147140
action: Action,
148141
) -> Result<Status, Error> {
149142
// apparently 0-length compression requests which don't actually make
@@ -154,8 +147,8 @@ impl Compress {
154147
}
155148
self.inner.raw.next_in = input.as_ptr() as *mut _;
156149
self.inner.raw.avail_in = input.len().min(c_uint::MAX as usize) as c_uint;
157-
self.inner.raw.next_out = output.as_mut_ptr() as *mut _;
158-
self.inner.raw.avail_out = output.len().min(c_uint::MAX as usize) as c_uint;
150+
self.inner.raw.next_out = output_ptr as *mut _;
151+
self.inner.raw.avail_out = output_len.min(c_uint::MAX as usize) as c_uint;
159152
unsafe {
160153
match ffi::BZ2_bzCompress(&mut *self.inner.raw, action as c_int) {
161154
ffi::BZ_RUN_OK => Ok(Status::RunOk),
@@ -168,6 +161,32 @@ impl Compress {
168161
}
169162
}
170163

164+
/// Compress a block of input into a block of output.
165+
///
166+
/// If anything other than [`BZ_OK`] is seen, `Err` is returned.
167+
///
168+
/// The action given must be one of [`Action::Run`], [`Action::Flush`] or [`Action::Finish`].
169+
///
170+
/// [`BZ_OK`]: ffi::BZ_OK
171+
pub fn compress(
172+
&mut self,
173+
input: &[u8],
174+
output: &mut [u8],
175+
action: Action,
176+
) -> Result<Status, Error> {
177+
unsafe { self.compress_inner(input, output.as_mut_ptr(), output.len(), action) }
178+
}
179+
180+
/// Same as [`Self::compress`] but accepts an uninitialised `output` buffer.
181+
pub fn compress_uninit(
182+
&mut self,
183+
input: &[u8],
184+
output: &mut [mem::MaybeUninit<u8>],
185+
action: Action,
186+
) -> Result<Status, Error> {
187+
unsafe { self.compress_inner(input, output.as_mut_ptr() as *mut _, output.len(), action) }
188+
}
189+
171190
/// Compress a block of input into an output vector.
172191
///
173192
/// This function will not grow `output`, but it will fill the space after
@@ -179,16 +198,11 @@ impl Compress {
179198
output: &mut Vec<u8>,
180199
action: Action,
181200
) -> Result<Status, Error> {
182-
let cap = output.capacity();
183201
let len = output.len();
184202

185203
unsafe {
186204
let before = self.total_out();
187-
let ret = {
188-
let ptr = output.as_mut_ptr().add(len);
189-
let out = slice::from_raw_parts_mut(ptr, cap - len);
190-
self.compress(input, out, action)
191-
};
205+
let ret = self.compress_uninit(input, output.spare_capacity_mut(), action);
192206
output.set_len((self.total_out() - before) as usize + len);
193207

194208
ret
@@ -226,12 +240,16 @@ impl Decompress {
226240
}
227241
}
228242

229-
/// Decompress a block of input into a block of output.
230-
pub fn decompress(&mut self, input: &[u8], output: &mut [u8]) -> Result<Status, Error> {
243+
unsafe fn decompress_inner(
244+
&mut self,
245+
input: &[u8],
246+
output_ptr: *mut u8,
247+
output_len: usize,
248+
) -> Result<Status, Error> {
231249
self.inner.raw.next_in = input.as_ptr() as *mut _;
232250
self.inner.raw.avail_in = input.len().min(c_uint::MAX as usize) as c_uint;
233-
self.inner.raw.next_out = output.as_mut_ptr() as *mut _;
234-
self.inner.raw.avail_out = output.len().min(c_uint::MAX as usize) as c_uint;
251+
self.inner.raw.next_out = output_ptr as *mut _;
252+
self.inner.raw.avail_out = output_len.min(c_uint::MAX as usize) as c_uint;
235253
unsafe {
236254
match ffi::BZ2_bzDecompress(&mut *self.inner.raw) {
237255
ffi::BZ_OK => Ok(Status::Ok),
@@ -246,22 +264,31 @@ impl Decompress {
246264
}
247265
}
248266

267+
/// Decompress a block of input into a block of output.
268+
pub fn decompress(&mut self, input: &[u8], output: &mut [u8]) -> Result<Status, Error> {
269+
unsafe { self.decompress_inner(input, output.as_mut_ptr(), output.len()) }
270+
}
271+
272+
/// Same as [`Self::decompress`] but accepts an uninitialized buffer.
273+
pub fn decompress_uninit(
274+
&mut self,
275+
input: &[u8],
276+
output: &mut [mem::MaybeUninit<u8>],
277+
) -> Result<Status, Error> {
278+
unsafe { self.decompress_inner(input, output.as_mut_ptr() as *mut _, output.len()) }
279+
}
280+
249281
/// Decompress a block of input into an output vector.
250282
///
251283
/// This function will not grow `output`, but it will fill the space after
252284
/// its current length up to its capacity. The length of the vector will be
253285
/// adjusted appropriately.
254286
pub fn decompress_vec(&mut self, input: &[u8], output: &mut Vec<u8>) -> Result<Status, Error> {
255-
let cap = output.capacity();
256287
let len = output.len();
257288

258289
unsafe {
259290
let before = self.total_out();
260-
let ret = {
261-
let ptr = output.as_mut_ptr().add(len);
262-
let out = slice::from_raw_parts_mut(ptr, cap - len);
263-
self.decompress(input, out)
264-
};
291+
let ret = self.decompress_uninit(input, output.spare_capacity_mut());
265292
output.set_len((self.total_out() - before) as usize + len);
266293

267294
ret

0 commit comments

Comments
 (0)