diff --git a/src/errors.rs b/src/errors.rs index d878ea70..b470e07d 100644 --- a/src/errors.rs +++ b/src/errors.rs @@ -1,20 +1,38 @@ -use core::alloc::Layout; +use { + alloc::alloc::handle_alloc_error, + core::{ + alloc::Layout, + error::Error, + fmt::{ + Debug, + Display, + Formatter, + Result as Format + } + } +}; -/// Error type for APIs with fallible heap allocation #[derive(Debug)] -pub enum CollectionAllocErr { - /// Overflow `usize::MAX` or other error during size computation +pub enum SmallVecError { CapacityOverflow, - /// The allocator return an error - AllocErr { - /// The layout that was passed to the allocator - layout: Layout - } + AllocationError(Layout) } -impl core::fmt::Display for CollectionAllocErr { - fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { - write!(f, "Allocation error: {:?}", self) + +impl Display for SmallVecError { + fn fmt(&self, f: &mut Formatter<'_>) -> Format { + write!(f, "Allocation error: {self:?}") } } -impl core::error::Error for CollectionAllocErr {} +impl Error for SmallVecError {} + +impl SmallVecError { + #[cold] + #[inline(never)] + pub fn handle(self) -> Type { + match self { + SmallVecError::CapacityOverflow => panic!("capacity overflow"), + SmallVecError::AllocationError(layout) => handle_alloc_error(layout) + } + } +} diff --git a/src/iterators/drain.rs b/src/iterators/drain.rs index 8731d7c6..a68cfe65 100644 --- a/src/iterators/drain.rs +++ b/src/iterators/drain.rs @@ -1,7 +1,7 @@ use crate::{ Allocator, SmallVec, - infallible + SmallVecError }; /// An iterator that removes the items from a `SmallVec` and yields them by @@ -180,7 +180,7 @@ impl Drain<'_, T, N, A> { let result = vec.try_reserve(additional); // Restore the prefix length before a reservation error can panic. unsafe { vec.set_len(old_len) }; - infallible(result); + result.unwrap_or_else(SmallVecError::handle); let new_tail_start = self.tail_start + additional; unsafe { diff --git a/src/lib.rs b/src/lib.rs index 456517c7..4f5f40ca 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -53,7 +53,7 @@ use defmt::{ Formatter as DeFormatter, write as dewrite }; -pub use errors::CollectionAllocErr; +pub use errors::SmallVecError; #[cfg(feature = "std")] use std::io; use { @@ -93,17 +93,6 @@ use { taggedlen::TaggedLen }; -#[inline] -fn infallible(result: Result) -> T { - match result { - Ok(x) => x, - Err(CollectionAllocErr::CapacityOverflow) => panic!("capacity overflow"), - Err(CollectionAllocErr::AllocErr { - layout - }) => alloc::alloc::handle_alloc_error(layout) - } -} - #[inline] /// A local copy of [`core::slice::range`]. The latter function is unstable /// and thus cannot be used yet. @@ -440,7 +429,7 @@ impl SmallVec { Self::new_in(Global) } - pub fn try_with_capacity(capacity: usize) -> Result { + pub fn try_with_capacity(capacity: usize) -> Result { Self::try_with_capacity_in(capacity, Global) } @@ -972,11 +961,12 @@ impl SmallVec { #[inline] pub fn grow(&mut self, new_capacity: usize) { - infallible(self.try_grow(new_capacity)); + self.try_grow(new_capacity) + .unwrap_or_else(SmallVecError::handle); } #[cold] - pub fn try_grow(&mut self, new_capacity: usize) -> Result<(), CollectionAllocErr> { + pub fn try_grow(&mut self, new_capacity: usize) -> Result<(), SmallVecError> { if Self::IS_ZST { return Ok(()); } @@ -1022,24 +1012,24 @@ impl SmallVec { pub fn reserve(&mut self, additional: usize) { // can't overflow since len <= capacity if additional > self.capacity() - self.len() { - let new_capacity = infallible( - self.len() - .checked_add(additional) - .and_then(usize::checked_next_power_of_two) - .ok_or(CollectionAllocErr::CapacityOverflow) - ); + let new_capacity = self + .len() + .checked_add(additional) + .and_then(usize::checked_next_power_of_two) + .ok_or(SmallVecError::CapacityOverflow) + .unwrap_or_else(SmallVecError::handle); self.grow(new_capacity); } } #[inline] - pub fn try_reserve(&mut self, additional: usize) -> Result<(), CollectionAllocErr> { + pub fn try_reserve(&mut self, additional: usize) -> Result<(), SmallVecError> { if additional > self.capacity() - self.len() { let new_capacity = self .len() .checked_add(additional) .and_then(usize::checked_next_power_of_two) - .ok_or(CollectionAllocErr::CapacityOverflow)?; + .ok_or(SmallVecError::CapacityOverflow)?; self.try_grow(new_capacity) } else { Ok(()) @@ -1050,22 +1040,22 @@ impl SmallVec { pub fn reserve_exact(&mut self, additional: usize) { // can't overflow since len <= capacity if additional > self.capacity() - self.len() { - let new_capacity = infallible( - self.len() - .checked_add(additional) - .ok_or(CollectionAllocErr::CapacityOverflow) - ); + let new_capacity = self + .len() + .checked_add(additional) + .ok_or(SmallVecError::CapacityOverflow) + .unwrap_or_else(SmallVecError::handle); self.grow(new_capacity); } } #[inline] - pub fn try_reserve_exact(&mut self, additional: usize) -> Result<(), CollectionAllocErr> { + pub fn try_reserve_exact(&mut self, additional: usize) -> Result<(), SmallVecError> { if additional > self.capacity() - self.len() { let new_capacity = self .len() .checked_add(additional) - .ok_or(CollectionAllocErr::CapacityOverflow)?; + .ok_or(SmallVecError::CapacityOverflow)?; self.try_grow(new_capacity) } else { Ok(()) @@ -1093,7 +1083,11 @@ impl SmallVec { // SAFETY: len > Self::inline_size() >= 0 // so new capacity is non zero, it is equal to the length // T can't be a ZST because SmallVec is never spilled. - unsafe { infallible(self.raw.try_grow_raw(self.len, len)) }; + unsafe { + self.raw + .try_grow_raw(self.len, len) + .unwrap_or_else(SmallVecError::handle) + }; } } @@ -1125,7 +1119,11 @@ impl SmallVec { // SAFETY: len > Self::inline_size() >= 0 // so new capacity is non zero, it is equal to the length // T can't be a ZST because SmallVec is never spilled. - unsafe { infallible(self.raw.try_grow_raw(self.len, target)) }; + unsafe { + self.raw + .try_grow_raw(self.len, target) + .unwrap_or_else(SmallVecError::handle) + }; } } } @@ -1674,7 +1672,7 @@ impl SmallVec { } } - pub fn try_with_capacity_in(capacity: usize, alloc: A) -> Result { + pub fn try_with_capacity_in(capacity: usize, alloc: A) -> Result { let mut this = Self::new_in(alloc); if capacity > Self::inline_size() && !Self::IS_ZST { // SAFETY: we checked all the preconditions @@ -1687,7 +1685,7 @@ impl SmallVec { } pub fn with_capacity_in(capacity: usize, alloc: A) -> Self { - infallible(Self::try_with_capacity_in(capacity, alloc)) + Self::try_with_capacity_in(capacity, alloc).unwrap_or_else(SmallVecError::handle) } } diff --git a/src/rawsmallvec.rs b/src/rawsmallvec.rs index 9a359af7..c70d9aa2 100644 --- a/src/rawsmallvec.rs +++ b/src/rawsmallvec.rs @@ -1,7 +1,7 @@ use { super::{ Allocator, - CollectionAllocErr, + SmallVecError, taggedlen::TaggedLen }, core::{ @@ -122,7 +122,7 @@ impl RawSmallVec { &mut self, len: TaggedLen, new_capacity: usize - ) -> Result<(), CollectionAllocErr> { + ) -> Result<(), SmallVecError> { let (len, was_on_heap) = len.parts(); debug_assert!(!Self::IS_ZST); debug_assert!(new_capacity > 0 && new_capacity >= len); @@ -131,9 +131,9 @@ impl RawSmallVec { let ptr = unsafe { self.as_mut_ptr(was_on_heap) }; let new_layout = - Layout::array::(new_capacity).map_err(|_| CollectionAllocErr::CapacityOverflow)?; + Layout::array::(new_capacity).map_err(|_| SmallVecError::CapacityOverflow)?; if new_layout.size() > isize::MAX as usize { - return Err(CollectionAllocErr::CapacityOverflow); + return Err(SmallVecError::CapacityOverflow); } let new_ptr = if !was_on_heap { @@ -142,9 +142,7 @@ impl RawSmallVec { let new_ptr = self .alloc .allocate(new_layout) - .map_err(|_| CollectionAllocErr::AllocErr { - layout: new_layout - })? + .map_err(|_| SmallVecError::AllocationError(new_layout))? .cast(); unsafe { copy_nonoverlapping(ptr, new_ptr.as_ptr(), len) }; new_ptr @@ -178,9 +176,7 @@ impl RawSmallVec { new_layout ) } - .map_err(|_| CollectionAllocErr::AllocErr { - layout: new_layout - })? + .map_err(|_| SmallVecError::AllocationError(new_layout))? .cast() }; self.inner.heap = (new_ptr, new_capacity);