use std::{ alloc, mem, ptr::{self, NonNull}, }; /// A typesafe helper that stores the allocated pointer without the data initialized. pub struct BoxAllocation( // ptr cannot be null since it would mean the allocation failed. // Note: covariance is acceptable since this eventually becomes a `Box`, // which is covariant too. NonNull, ); impl BoxAllocation { /// Consumes self and writes the given value into the allocation. #[inline(always)] // if this does not get inlined then copying happens pub fn init(self, value: T) -> Box { if mem::size_of::() == 0 { return Box::new(value); } unsafe { let ptr = self.0.as_ptr(); mem::forget(self); ptr::write(ptr, value); Box::from_raw(ptr) } } } impl Drop for BoxAllocation { fn drop(&mut self) { if mem::size_of::() == 0 { return; } let layout = alloc::Layout::new::(); unsafe { alloc::dealloc(self.0.as_ptr() as *mut u8, layout); } } } /// Helper trait for a `Box` type that allocates up-front. pub trait BoxHelper { /// Allocates the storage without providing any data. fn alloc() -> BoxAllocation; } impl BoxHelper for Box { fn alloc() -> BoxAllocation { if mem::size_of::() == 0 { return BoxAllocation(NonNull::dangling()); } let layout = alloc::Layout::new::(); BoxAllocation( NonNull::new(unsafe { alloc::alloc(layout) as *mut T }) .unwrap_or_else(|| alloc::handle_alloc_error(layout)), // oom ) } }