1 //! Low-level allocation and OOM-handling utilities. 2 3 mod arc; 4 mod boxed; 5 mod try_collect; 6 mod try_new; 7 mod vec; 8 9 pub use boxed::{ 10 BoxedSliceFromFallibleIterError, TooFewItemsOrOom, boxed_slice_write_iter, 11 new_boxed_slice_from_fallible_iter, new_boxed_slice_from_iter, 12 new_boxed_slice_from_iter_with_len, new_uninit_boxed_slice, 13 }; 14 pub use try_collect::{TryCollect, TryExtend, TryFromIterator}; 15 pub use try_new::{TryNew, try_new}; 16 pub use vec::Vec; 17 18 use crate::error::OutOfMemory; 19 use core::{alloc::Layout, ptr::NonNull}; 20 21 /// Try to allocate a block of memory that fits the given layout, or return an 22 /// `OutOfMemory` error. 23 /// 24 /// # Safety 25 /// 26 /// Same as `alloc::alloc::alloc`: layout must have non-zero size. 27 #[inline] 28 unsafe fn try_alloc(layout: Layout) -> Result<NonNull<u8>, OutOfMemory> { 29 // Safety: same as our safety conditions. 30 debug_assert!(layout.size() > 0); 31 let ptr = unsafe { std_alloc::alloc::alloc(layout) }; 32 33 if let Some(ptr) = NonNull::new(ptr) { 34 Ok(ptr) 35 } else { 36 Err(OutOfMemory::new(layout.size())) 37 } 38 } 39 40 /// Tries to reallocate a block of memory, returning `OutOfMemory` on failure. 41 /// 42 /// Analogue of [`alloc::alloc::realloc`]. 43 /// 44 /// # Safety 45 /// 46 /// Same as `alloc::alloc::realloc`: `ptr` must be allocated with `layout`, 47 /// `layout` must be nonzero in size, and `new_size` must be nonzero and valid. 48 #[inline] 49 unsafe fn try_realloc( 50 ptr: *mut u8, 51 layout: Layout, 52 new_size: usize, 53 ) -> Result<NonNull<u8>, OutOfMemory> { 54 // Safety: same as our safety conditions. 55 debug_assert!(layout.size() > 0); 56 debug_assert!(new_size > 0); 57 let ptr = unsafe { std_alloc::alloc::realloc(ptr, layout, new_size) }; 58 59 if let Some(ptr) = NonNull::new(ptr) { 60 Ok(ptr) 61 } else { 62 Err(OutOfMemory::new(new_size)) 63 } 64 } 65 66 /// An extension trait for ignoring `OutOfMemory` errors. 67 /// 68 /// Use this to unwrap a `Result<T, OutOfMemory>` into its inner `T` or 69 /// otherwise panic, leveraging the type system to be sure that you aren't ever 70 /// accidentally unwrapping non-`OutOfMemory` errors. 71 pub trait PanicOnOom { 72 /// The non-`OutOfMemory` result of calling `panic_on_oom`. 73 type Result; 74 75 /// Panic on `OutOfMemory` errors, returning the non-`OutOfMemory` result. 76 fn panic_on_oom(self) -> Self::Result; 77 } 78 79 impl<T> PanicOnOom for Result<T, OutOfMemory> { 80 type Result = T; 81 82 #[track_caller] 83 fn panic_on_oom(self) -> Self::Result { 84 match self { 85 Ok(x) => x, 86 Err(oom) => panic!("unhandled out-of-memory error: {oom}"), 87 } 88 } 89 } 90