@@ -17,10 +17,19 @@ use crate::collections::TryReserveErrorKind::*;
1717#[ cfg( test) ]
1818mod tests;
1919
20+ // One central function responsible for reporting capacity overflows. This'll
21+ // ensure that the code generation related to these panics is minimal as there's
22+ // only one location which panics rather than a bunch throughout the module.
2023#[ cfg( not( no_global_oom_handling) ) ]
24+ #[ cfg_attr( not( feature = "panic_immediate_abort" ) , inline( never) ) ]
25+ fn capacity_overflow ( ) -> ! {
26+ panic ! ( "capacity overflow" ) ;
27+ }
28+
2129enum AllocInit {
2230 /// The contents of the new memory are uninitialized.
2331 Uninitialized ,
32+ #[ cfg( not( no_global_oom_handling) ) ]
2433 /// The new memory is guaranteed to be zeroed.
2534 Zeroed ,
2635}
@@ -93,6 +102,8 @@ impl<T> RawVec<T, Global> {
93102 /// zero-sized. Note that if `T` is zero-sized this means you will
94103 /// *not* get a `RawVec` with the requested capacity.
95104 ///
105+ /// Non-fallible version of `try_with_capacity`
106+ ///
96107 /// # Panics
97108 ///
98109 /// Panics if the requested capacity exceeds `isize::MAX` bytes.
@@ -104,7 +115,7 @@ impl<T> RawVec<T, Global> {
104115 #[ must_use]
105116 #[ inline]
106117 pub fn with_capacity ( capacity : usize ) -> Self {
107- Self :: with_capacity_in ( capacity, Global )
118+ handle_reserve ( Self :: try_allocate_in ( capacity, AllocInit :: Uninitialized , Global ) )
108119 }
109120
110121 /// Like `with_capacity`, but guarantees the buffer is zeroed.
@@ -142,15 +153,22 @@ impl<T, A: Allocator> RawVec<T, A> {
142153 #[ cfg( not( no_global_oom_handling) ) ]
143154 #[ inline]
144155 pub fn with_capacity_in ( capacity : usize , alloc : A ) -> Self {
145- Self :: allocate_in ( capacity, AllocInit :: Uninitialized , alloc)
156+ handle_reserve ( Self :: try_allocate_in ( capacity, AllocInit :: Uninitialized , alloc) )
157+ }
158+
159+ /// Like `try_with_capacity`, but parameterized over the choice of
160+ /// allocator for the returned `RawVec`.
161+ #[ inline]
162+ pub fn try_with_capacity_in ( capacity : usize , alloc : A ) -> Result < Self , TryReserveError > {
163+ Self :: try_allocate_in ( capacity, AllocInit :: Uninitialized , alloc)
146164 }
147165
148166 /// Like `with_capacity_zeroed`, but parameterized over the choice
149167 /// of allocator for the returned `RawVec`.
150168 #[ cfg( not( no_global_oom_handling) ) ]
151169 #[ inline]
152170 pub fn with_capacity_zeroed_in ( capacity : usize , alloc : A ) -> Self {
153- Self :: allocate_in ( capacity, AllocInit :: Zeroed , alloc)
171+ handle_reserve ( Self :: try_allocate_in ( capacity, AllocInit :: Zeroed , alloc) )
154172 }
155173
156174 /// Converts the entire buffer into `Box<[MaybeUninit<T>]>` with the specified `len`.
@@ -179,35 +197,41 @@ impl<T, A: Allocator> RawVec<T, A> {
179197 }
180198 }
181199
182- #[ cfg( not( no_global_oom_handling) ) ]
183- fn allocate_in ( capacity : usize , init : AllocInit , alloc : A ) -> Self {
200+ fn try_allocate_in (
201+ capacity : usize ,
202+ init : AllocInit ,
203+ alloc : A ,
204+ ) -> Result < Self , TryReserveError > {
184205 // Don't allocate here because `Drop` will not deallocate when `capacity` is 0.
206+
185207 if T :: IS_ZST || capacity == 0 {
186- Self :: new_in ( alloc)
208+ Ok ( Self :: new_in ( alloc) )
187209 } else {
188210 // We avoid `unwrap_or_else` here because it bloats the amount of
189211 // LLVM IR generated.
190212 let layout = match Layout :: array :: < T > ( capacity) {
191213 Ok ( layout) => layout,
192- Err ( _) => capacity_overflow ( ) ,
214+ Err ( _) => return Err ( CapacityOverflow . into ( ) ) ,
193215 } ;
194- match alloc_guard ( layout . size ( ) ) {
195- Ok ( _ ) => { }
196- Err ( _ ) => capacity_overflow ( ) ,
216+
217+ if let Err ( err ) = alloc_guard ( layout . size ( ) ) {
218+ return Err ( err ) ;
197219 }
220+
198221 let result = match init {
199222 AllocInit :: Uninitialized => alloc. allocate ( layout) ,
223+ #[ cfg( not( no_global_oom_handling) ) ]
200224 AllocInit :: Zeroed => alloc. allocate_zeroed ( layout) ,
201225 } ;
202226 let ptr = match result {
203227 Ok ( ptr) => ptr,
204- Err ( _) => handle_alloc_error ( layout) ,
228+ Err ( _) => return Err ( AllocError { layout, non_exhaustive : ( ) } . into ( ) ) ,
205229 } ;
206230
207231 // Allocators currently return a `NonNull<[u8]>` whose length
208232 // matches the size requested. If that ever changes, the capacity
209233 // here should change to `ptr.len() / mem::size_of::<T>()`.
210- Self { ptr : Unique :: from ( ptr. cast ( ) ) , cap : unsafe { Cap ( capacity) } , alloc }
234+ Ok ( Self { ptr : Unique :: from ( ptr. cast ( ) ) , cap : unsafe { Cap ( capacity) } , alloc } )
211235 }
212236 }
213237
@@ -537,11 +561,11 @@ unsafe impl<#[may_dangle] T, A: Allocator> Drop for RawVec<T, A> {
537561// Central function for reserve error handling.
538562#[ cfg( not( no_global_oom_handling) ) ]
539563#[ inline]
540- fn handle_reserve ( result : Result < ( ) , TryReserveError > ) {
564+ fn handle_reserve < T > ( result : Result < T , TryReserveError > ) -> T {
541565 match result. map_err ( |e| e. kind ( ) ) {
566+ Ok ( res) => res,
542567 Err ( CapacityOverflow ) => capacity_overflow ( ) ,
543568 Err ( AllocError { layout, .. } ) => handle_alloc_error ( layout) ,
544- Ok ( ( ) ) => { /* yay */ }
545569 }
546570}
547571
@@ -561,12 +585,3 @@ fn alloc_guard(alloc_size: usize) -> Result<(), TryReserveError> {
561585 Ok ( ( ) )
562586 }
563587}
564-
565- // One central function responsible for reporting capacity overflows. This'll
566- // ensure that the code generation related to these panics is minimal as there's
567- // only one location which panics rather than a bunch throughout the module.
568- #[ cfg( not( no_global_oom_handling) ) ]
569- #[ cfg_attr( not( feature = "panic_immediate_abort" ) , inline( never) ) ]
570- fn capacity_overflow ( ) -> ! {
571- panic ! ( "capacity overflow" ) ;
572- }
0 commit comments