11use std:: {
2- alloc:: { self , GlobalAlloc , Layout , System } ,
2+ alloc:: { GlobalAlloc , Layout , System } ,
3+ error:: Error ,
4+ fmt,
35 mem:: { self , ManuallyDrop } ,
46 ptr:: NonNull ,
57 sync:: {
@@ -15,6 +17,26 @@ use crate::{
1517 generated:: fixed_size_constants:: { BLOCK_ALIGN , BLOCK_SIZE , RAW_METADATA_SIZE } ,
1618} ;
1719
20+ /// Error returned when a fixed-size allocator cannot be created due to allocation failure.
21+ #[ derive( Debug , Clone , Copy , PartialEq , Eq ) ]
22+ pub struct AllocError {
23+ /// The layout of the allocation that failed.
24+ pub layout : Layout ,
25+ }
26+
27+ impl fmt:: Display for AllocError {
28+ fn fmt ( & self , f : & mut fmt:: Formatter < ' _ > ) -> fmt:: Result {
29+ write ! (
30+ f,
31+ "memory allocation failed for fixed-size allocator: requested {} bytes with {} byte alignment" ,
32+ self . layout. size( ) ,
33+ self . layout. align( )
34+ )
35+ }
36+ }
37+
38+ impl Error for AllocError { }
39+
1840const TWO_GIB : usize = 1 << 31 ;
1941const FOUR_GIB : usize = 1 << 32 ;
2042
@@ -53,7 +75,7 @@ impl FixedSizeAllocatorPool {
5375 // Protect against IDs wrapping around.
5476 // TODO: Does this work? Do we need it anyway?
5577 assert ! ( id < u32 :: MAX , "Created too many allocators" ) ;
56- FixedSizeAllocator :: new ( id)
78+ FixedSizeAllocator :: try_new ( id) . unwrap ( )
5779 } ) ;
5880
5981 // Unwrap `FixedSizeAllocator`.
@@ -187,9 +209,11 @@ struct FixedSizeAllocator {
187209}
188210
189211impl FixedSizeAllocator {
190- /// Create a new [`FixedSizeAllocator`].
212+ /// Try to create a new [`FixedSizeAllocator`].
213+ ///
214+ /// Returns `Err(AllocError)` if memory allocation fails.
191215 #[ expect( clippy:: items_after_statements) ]
192- fn new ( id : u32 ) -> Self {
216+ fn try_new ( id : u32 ) -> Result < Self , AllocError > {
193217 // Only support little-endian systems. `Allocator::from_raw_parts` includes this same assertion.
194218 // This module is only compiled on 64-bit little-endian systems, so it should be impossible for
195219 // this panic to occur. But we want to make absolutely sure that if there's a mistake elsewhere,
@@ -203,9 +227,7 @@ impl FixedSizeAllocator {
203227 // Allocate block of memory.
204228 // SAFETY: `ALLOC_LAYOUT` does not have zero size.
205229 let alloc_ptr = unsafe { System . alloc ( ALLOC_LAYOUT ) } ;
206- let Some ( alloc_ptr) = NonNull :: new ( alloc_ptr) else {
207- alloc:: handle_alloc_error ( ALLOC_LAYOUT ) ;
208- } ;
230+ let alloc_ptr = NonNull :: new ( alloc_ptr) . ok_or ( AllocError { layout : ALLOC_LAYOUT } ) ?;
209231
210232 // All code in the rest of this function is infallible, so the allocation will always end up
211233 // owned by a `FixedSizeAllocator`, which takes care of freeing the memory correctly on drop
@@ -254,7 +276,7 @@ impl FixedSizeAllocator {
254276 metadata_ptr. write ( metadata) ;
255277 }
256278
257- Self { allocator }
279+ Ok ( Self { allocator } )
258280 }
259281
260282 /// Reset this [`FixedSizeAllocator`].
0 commit comments