Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
44 changes: 31 additions & 13 deletions src/errors.rs
Original file line number Diff line number Diff line change
@@ -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
Comment thread
alejandro-vaz marked this conversation as resolved.
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<Type>(self) -> Type {
match self {
SmallVecError::CapacityOverflow => panic!("capacity overflow"),
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
SmallVecError
};

/// 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.unwrap_or_else(SmallVecError::handle);

let new_tail_start = self.tail_start + additional;
unsafe {
Expand Down
66 changes: 32 additions & 34 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 Down Expand Up @@ -93,17 +93,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 +429,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 +961,12 @@ 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)
.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(());
}
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)
.unwrap_or_else(SmallVecError::handle);
Comment thread
alejandro-vaz marked this conversation as resolved.
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)
.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(())
Expand Down Expand Up @@ -1093,7 +1083,11 @@ 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)
.unwrap_or_else(SmallVecError::handle)
};
}
}

Expand Down Expand Up @@ -1125,7 +1119,11 @@ 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)
.unwrap_or_else(SmallVecError::handle)
};
}
}
}
Expand Down Expand Up @@ -1674,7 +1672,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 +1685,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).unwrap_or_else(SmallVecError::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