1 //! Low-level allocation and OOM-handling utilities. 2 3 mod arc; 4 mod boxed; 5 mod string; 6 mod try_clone; 7 mod try_collect; 8 mod try_cow; 9 mod try_new; 10 mod vec; 11 12 pub use boxed::{ 13 BoxedSliceFromFallibleIterError, TooFewItemsOrOom, boxed_slice_write_iter, 14 new_boxed_slice_from_fallible_iter, new_boxed_slice_from_iter, 15 new_boxed_slice_from_iter_with_len, new_uninit_boxed_slice, 16 }; 17 pub use string::String; 18 pub use try_clone::TryClone; 19 pub use try_collect::{TryCollect, TryExtend, TryFromIterator}; 20 pub use try_cow::{TryCow, TryToOwned}; 21 pub use try_new::{TryNew, try_new}; 22 pub use vec::Vec; 23 24 use crate::error::OutOfMemory; 25 use core::{alloc::Layout, ptr::NonNull}; 26 27 /// Try to allocate a block of memory that fits the given layout, or return an 28 /// `OutOfMemory` error. 29 /// 30 /// # Safety 31 /// 32 /// Same as `alloc::alloc::alloc`: layout must have non-zero size. 33 #[inline] 34 unsafe fn try_alloc(layout: Layout) -> Result<NonNull<u8>, OutOfMemory> { 35 // Safety: same as our safety conditions. 36 debug_assert!(layout.size() > 0); 37 let ptr = unsafe { std_alloc::alloc::alloc(layout) }; 38 39 if let Some(ptr) = NonNull::new(ptr) { 40 Ok(ptr) 41 } else { 42 Err(OutOfMemory::new(layout.size())) 43 } 44 } 45 46 /// Tries to reallocate a block of memory, returning `OutOfMemory` on failure. 47 /// 48 /// Analogue of [`alloc::alloc::realloc`]. 49 /// 50 /// # Safety 51 /// 52 /// Same as `alloc::alloc::realloc`: `ptr` must be allocated with `layout`, 53 /// `layout` must be nonzero in size, and `new_size` must be nonzero and valid. 54 #[inline] 55 unsafe fn try_realloc( 56 ptr: *mut u8, 57 layout: Layout, 58 new_size: usize, 59 ) -> Result<NonNull<u8>, OutOfMemory> { 60 // Safety: same as our safety conditions. 61 debug_assert!(layout.size() > 0); 62 debug_assert!(new_size > 0); 63 let ptr = unsafe { std_alloc::alloc::realloc(ptr, layout, new_size) }; 64 65 if let Some(ptr) = NonNull::new(ptr) { 66 Ok(ptr) 67 } else { 68 Err(OutOfMemory::new(new_size)) 69 } 70 } 71 72 /// An extension trait for ignoring `OutOfMemory` errors. 73 /// 74 /// Use this to unwrap a `Result<T, OutOfMemory>` into its inner `T` or 75 /// otherwise panic, leveraging the type system to be sure that you aren't ever 76 /// accidentally unwrapping non-`OutOfMemory` errors. 77 pub trait PanicOnOom { 78 /// The non-`OutOfMemory` result of calling `panic_on_oom`. 79 type Result; 80 81 /// Panic on `OutOfMemory` errors, returning the non-`OutOfMemory` result. 82 fn panic_on_oom(self) -> Self::Result; 83 } 84 85 impl<T> PanicOnOom for Result<T, OutOfMemory> { 86 type Result = T; 87 88 #[track_caller] 89 fn panic_on_oom(self) -> Self::Result { 90 match self { 91 Ok(x) => x, 92 Err(oom) => panic!("unhandled out-of-memory error: {oom}"), 93 } 94 } 95 } 96 97 /// Create a `*mut str` from a pointer and length pair. 98 /// 99 /// NB: This function is safe, but dereferencing it or otherwise using the 100 /// resulting `str` pointer's contents is unsafe and requires that the pointer 101 /// be valid for accessing and points to a valid utf8 sequence of `len` bytes. 102 fn str_ptr_from_raw_parts(ptr: *mut u8, len: usize) -> *mut str { 103 let ptr: *mut [u8] = core::ptr::slice_from_raw_parts_mut(ptr, len); 104 str_ptr_from_slice_ptr(ptr) 105 } 106 107 /// Create a `*mut str` from a slice pointer. 108 /// 109 /// NB: This function is safe, but dereferencing it or otherwise using the 110 /// resulting `str` pointer's contents is unsafe and requires that the pointer 111 /// be valid for accessing and points to a valid utf8 sequence of `len` bytes. 112 fn str_ptr_from_slice_ptr(ptr: *mut [u8]) -> *mut str { 113 // SAFETY: `str` is a newtype of `[u8]`. 114 let ptr: *mut str = unsafe { core::mem::transmute(ptr) }; 115 ptr 116 } 117