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