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