use std::mem::MaybeUninit;
struct DeallocGuard<T> {
ptr: *mut T,
cap: usize,
}
impl<T> DeallocGuard<T> {
fn new(ptr: *mut T, cap: usize) -> Self {
Self { ptr, cap }
}
fn disable(mut self) {
self.cap = 0;
}
}
impl<T> Drop for DeallocGuard<T> {
fn drop(&mut self) {
if self.cap > 0 {
unsafe {
let _ = Vec::from_raw_parts(self.ptr, 0, self.cap);
}
}
}
}
#[allow(unsafe_op_in_unsafe_fn)]
pub(crate) unsafe fn init_vec_with<E, F>(len: usize, f: F) -> Result<Vec<u8>, E>
where
F: FnOnce(&mut [u8]) -> Result<usize, E>,
{
let mut uninit: Vec<MaybeUninit<u8>> = Vec::with_capacity(len);
let ptr = uninit.as_mut_ptr();
let cap = uninit.capacity();
std::mem::forget(uninit);
let guard = DeallocGuard::new(ptr, cap);
let written = f(std::slice::from_raw_parts_mut(ptr as *mut u8, len))?;
debug_assert_eq!(
written, len,
"initialization function did not fill the whole buffer"
);
guard.disable();
Ok(Vec::from_raw_parts(ptr as *mut u8, len, cap))
}