Skip to content
51 changes: 38 additions & 13 deletions src/errors.rs
Original file line number Diff line number Diff line change
@@ -1,20 +1,45 @@
use core::alloc::Layout;
use {
alloc::alloc::handle_alloc_error,
core::{
alloc::Layout,
error::Error,
fmt::{
Debug,
Display,
Formatter,
Result as Format
}
}
};

pub trait Handle {
type Handled;
fn handle(self) -> Self::Handled;
}

/// 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 Error for SmallVecError {}

impl Display for SmallVecError {
fn fmt(&self, f: &mut Formatter<'_>) -> Format {
write!(f, "Allocation error: {self:?}")
}
}

impl core::error::Error for CollectionAllocErr {}
impl<Type> Handle for Result<Type, SmallVecError> {
type Handled = Type;

#[inline]
fn handle(self) -> Self::Handled {
match self {
Ok(value) => value,
Err(SmallVecError::CapacityOverflow) => panic!("smallvec capacity overflow"),
Err(SmallVecError::AllocationError(layout)) => handle_alloc_error(layout)
}
}
}
4 changes: 2 additions & 2 deletions src/iterators/drain.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use crate::{
Allocator,
SmallVec,
infallible
errors::Handle
};

/// An iterator that removes the items from a `SmallVec` and yields them by
Expand Down Expand Up @@ -180,7 +180,7 @@ impl<T, const N: usize, A: Allocator> 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.handle();

let new_tail_start = self.tail_start + additional;
unsafe {
Expand Down
60 changes: 25 additions & 35 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand All @@ -80,7 +80,8 @@ use {
copy_nonoverlapping,
drop_in_place
}
}
},
errors::Handle
};
#[cfg(feature = "internals")]
pub use {
Expand All @@ -93,17 +94,6 @@ use {
taggedlen::TaggedLen
};

#[inline]
fn infallible<T>(result: Result<T, CollectionAllocErr>) -> 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.
Expand Down Expand Up @@ -440,7 +430,7 @@ impl<T, const N: usize> SmallVec<T, N> {
Self::new_in(Global)
}

pub fn try_with_capacity(capacity: usize) -> Result<Self, CollectionAllocErr> {
pub fn try_with_capacity(capacity: usize) -> Result<Self, SmallVecError> {
Self::try_with_capacity_in(capacity, Global)
}

Expand Down Expand Up @@ -972,11 +962,11 @@ impl<T, const N: usize, A: Allocator> SmallVec<T, N, A> {

#[inline]
pub fn grow(&mut self, new_capacity: usize) {
infallible(self.try_grow(new_capacity));
self.try_grow(new_capacity).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(());
}
Expand Down Expand Up @@ -1022,24 +1012,24 @@ impl<T, const N: usize, A: Allocator> SmallVec<T, N, A> {
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)
.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(())
Expand All @@ -1050,22 +1040,22 @@ impl<T, const N: usize, A: Allocator> SmallVec<T, N, A> {
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)
.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(())
Expand Down Expand Up @@ -1093,7 +1083,7 @@ impl<T, const N: usize, A: Allocator> SmallVec<T, N, A> {
// 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<ZST, N> is never spilled.
unsafe { infallible(self.raw.try_grow_raw(self.len, len)) };
unsafe { self.raw.try_grow_raw(self.len, len).handle() };
}
}

Expand Down Expand Up @@ -1125,7 +1115,7 @@ impl<T, const N: usize, A: Allocator> SmallVec<T, N, A> {
// 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<ZST, N> is never spilled.
unsafe { infallible(self.raw.try_grow_raw(self.len, target)) };
unsafe { self.raw.try_grow_raw(self.len, target).handle() };
}
}
}
Expand Down Expand Up @@ -1674,7 +1664,7 @@ impl<T, const N: usize, A: Allocator> SmallVec<T, N, A> {
}
}

pub fn try_with_capacity_in(capacity: usize, alloc: A) -> Result<Self, CollectionAllocErr> {
pub fn try_with_capacity_in(capacity: usize, alloc: A) -> Result<Self, SmallVecError> {
let mut this = Self::new_in(alloc);
if capacity > Self::inline_size() && !Self::IS_ZST {
// SAFETY: we checked all the preconditions
Expand All @@ -1687,7 +1677,7 @@ impl<T, const N: usize, A: Allocator> SmallVec<T, N, A> {
}

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).handle()
}
}

Expand Down
16 changes: 6 additions & 10 deletions src/rawsmallvec.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use {
super::{
Allocator,
CollectionAllocErr,
SmallVecError,
taggedlen::TaggedLen
},
core::{
Expand Down Expand Up @@ -122,7 +122,7 @@ impl<T, const N: usize, A: Allocator> RawSmallVec<T, N, A> {
&mut self,
len: TaggedLen<T>,
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);
Expand All @@ -131,9 +131,9 @@ impl<T, const N: usize, A: Allocator> RawSmallVec<T, N, A> {
let ptr = unsafe { self.as_mut_ptr(was_on_heap) };

let new_layout =
Layout::array::<T>(new_capacity).map_err(|_| CollectionAllocErr::CapacityOverflow)?;
Layout::array::<T>(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 {
Expand All @@ -142,9 +142,7 @@ impl<T, const N: usize, A: Allocator> RawSmallVec<T, N, A> {
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
Expand Down Expand Up @@ -178,9 +176,7 @@ impl<T, const N: usize, A: Allocator> RawSmallVec<T, N, A> {
new_layout
)
}
.map_err(|_| CollectionAllocErr::AllocErr {
layout: new_layout
})?
.map_err(|_| SmallVecError::AllocationError(new_layout))?
.cast()
};
self.inner.heap = (new_ptr, new_capacity);
Expand Down
Loading