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
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ v.sort();
- `serde`: implements serde's serialization and deserialization
- `specialization` (nightly): enables specialization,
improving performance on some cases
- `std`: implements the `std::io::Write` type for `SmallVec<u8, N>`
- `std`: implements the `std::io::Write` type for `SmallVec<u8, INLINE>`
- `zeroize`: implements `zeroize::Zeroize`, erasing elements and storage

> [!NOTE]
Expand Down
20 changes: 10 additions & 10 deletions src/borsh.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,8 @@ use {
core::iter::repeat_with
};

impl<Type: BorshSerialize, const INLINE: usize, A: Allocator> BorshSerialize
for SmallVec<Type, INLINE, A>
impl<Item: BorshSerialize, const INLINE: usize, Heap: Allocator> BorshSerialize
for SmallVec<Item, INLINE, Heap>
{
fn serialize<Writer: Write>(&self, writer: &mut Writer) -> Serial<()> {
(self.len() as u64).serialize(writer)?;
Expand All @@ -39,12 +39,12 @@ impl<Type: BorshSerialize, const INLINE: usize, A: Allocator> BorshSerialize
}
}

impl<Type: BorshDeserialize, const INLINE: usize> BorshDeserialize
for SmallVec<Type, INLINE, Global>
impl<Item: BorshDeserialize, const INLINE: usize> BorshDeserialize
for SmallVec<Item, INLINE, Global>
{
fn deserialize_reader<R: borsh::io::Read>(reader: &mut R) -> Serial<Self> {
let length = u64::deserialize_reader(reader)?;
repeat_with(|| Type::deserialize_reader(reader))
repeat_with(|| Item::deserialize_reader(reader))
.take(length.try_into().map_err(|_| Error::new(
ErrorKind::OutOfMemory,
"Cannot deserialize a sequence with more than usize::MAX elements in this machine"
Expand All @@ -53,25 +53,25 @@ impl<Type: BorshDeserialize, const INLINE: usize> BorshDeserialize
}
}

impl<Type: BorshSchema, const INLINE: usize, A: Allocator> BorshSchema
for SmallVec<Type, INLINE, A>
impl<Item: BorshSchema, const INLINE: usize, Heap: Allocator> BorshSchema
for SmallVec<Item, INLINE, Heap>
{
fn declaration() -> Declaration {
format!("Vec<{}>", Type::declaration())
format!("Vec<{}>", Item::declaration())
}

fn add_definitions_recursively(definitions: &mut Map<Declaration, Definition>) {
let declaration = Self::declaration();
if definitions.contains_key(&declaration) {
return;
}
Type::add_definitions_recursively(definitions);
Item::add_definitions_recursively(definitions);
definitions.insert(
declaration,
Definition::Sequence {
length_width: 8,
length_range: 0..=u64::MAX,
elements: Type::declaration()
elements: Item::declaration()
}
);
}
Expand Down
54 changes: 29 additions & 25 deletions src/comparisons.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,9 @@ use {

macro_rules! __impl_slice_eq1 {
([$($vars:tt)*] $lhs:ty, $rhs:ty $(where $ty:ty: $bound:ident)?) => {
impl<T, U, A: Allocator, const N: usize, $($vars)*> PartialEq<$rhs> for $lhs
impl<Item, U, Heap: Allocator, const INLINE: usize, $($vars)*> PartialEq<$rhs> for $lhs
where
T: PartialEq<U>,
Item: PartialEq<U>,
$($ty: $bound)?
{
#[inline]
Expand All @@ -23,25 +23,29 @@ macro_rules! __impl_slice_eq1 {
};
}

__impl_slice_eq1! { [const M: usize, A2: Allocator] SmallVec<T, M, A>, SmallVec<U, N, A2> }
__impl_slice_eq1! { [const M: usize] SmallVec<T, M, A>, [U; N] }
__impl_slice_eq1! { [const M: usize] SmallVec<T, M, A>, &[U; N] }
__impl_slice_eq1! { [] SmallVec<T, N, A>, [U] }
__impl_slice_eq1! { [] SmallVec<T, N, A>, &[U] }
__impl_slice_eq1! { [] SmallVec<T, N, A>, &mut [U] }
__impl_slice_eq1! { [] [T], SmallVec<U, N, A> }
__impl_slice_eq1! { [] &[T], SmallVec<U, N, A> }
__impl_slice_eq1! { [] &mut [T], SmallVec<U, N, A> }
__impl_slice_eq1! { [] Vec<T>, SmallVec<U, N, A> }
__impl_slice_eq1! { [] SmallVec<T, N, A>, Vec<U> }
__impl_slice_eq1! { [] Cow<'_, [T]>, SmallVec<U, N, A> where T: Clone }
__impl_slice_eq1! { [] SmallVec<T, N, A>, Cow<'_, [U]> where U: Clone }
__impl_slice_eq1! { [const M: usize, A2: Allocator]
SmallVec<Item, M, Heap>,
SmallVec<U, INLINE, A2>
}
__impl_slice_eq1! { [const M: usize] SmallVec<Item, M, Heap>, [U; INLINE] }
__impl_slice_eq1! { [const M: usize] SmallVec<Item, M, Heap>, &[U; INLINE] }
__impl_slice_eq1! { [] SmallVec<Item, INLINE, Heap>, [U] }
__impl_slice_eq1! { [] SmallVec<Item, INLINE, Heap>, &[U] }
__impl_slice_eq1! { [] SmallVec<Item, INLINE, Heap>, &mut [U] }
__impl_slice_eq1! { [] [Item], SmallVec<U, INLINE, Heap> }
__impl_slice_eq1! { [] &[Item], SmallVec<U, INLINE, Heap> }
__impl_slice_eq1! { [] &mut [Item], SmallVec<U, INLINE, Heap> }
__impl_slice_eq1! { [] Vec<Item>, SmallVec<U, INLINE, Heap> }
__impl_slice_eq1! { [] SmallVec<Item, INLINE, Heap>, Vec<U> }
__impl_slice_eq1! { [] Cow<'_, [Item]>, SmallVec<U, INLINE, Heap> where Item: Clone }
__impl_slice_eq1! { [] SmallVec<Item, INLINE, Heap>, Cow<'_, [U]> where U: Clone }

impl<T, U, const N: usize, A: Allocator> PartialEq<SmallVec<U, N, A>> for VecDeque<T>
where T: PartialEq<U>
impl<Item, U, const INLINE: usize, Heap: Allocator> PartialEq<SmallVec<U, INLINE, Heap>>
for VecDeque<Item>
where Item: PartialEq<U>
{
#[inline]
fn eq(&self, other: &SmallVec<U, N, A>) -> bool {
fn eq(&self, other: &SmallVec<U, INLINE, Heap>) -> bool {
let other = other.as_slice();
if self.len() != other.len() {
return false;
Expand All @@ -52,22 +56,22 @@ where T: PartialEq<U>
}
}

impl<T, const N: usize, A: Allocator> Eq for SmallVec<T, N, A> where T: Eq {}
impl<Item: Eq, const INLINE: usize, Heap: Allocator> Eq for SmallVec<Item, INLINE, Heap> {}

impl<T, const N: usize, A: Allocator> PartialOrd for SmallVec<T, N, A>
where T: PartialOrd
impl<Item, const INLINE: usize, Heap: Allocator> PartialOrd for SmallVec<Item, INLINE, Heap>
where Item: PartialOrd
{
#[inline]
fn partial_cmp(&self, other: &SmallVec<T, N, A>) -> Option<core::cmp::Ordering> {
fn partial_cmp(&self, other: &SmallVec<Item, INLINE, Heap>) -> Option<core::cmp::Ordering> {
self.as_slice().partial_cmp(other.as_slice())
}
}

impl<T, const N: usize, A: Allocator> Ord for SmallVec<T, N, A>
where T: Ord
impl<Item, const INLINE: usize, Heap: Allocator> Ord for SmallVec<Item, INLINE, Heap>
where Item: Ord
{
#[inline]
fn cmp(&self, other: &SmallVec<T, N, A>) -> core::cmp::Ordering {
fn cmp(&self, other: &SmallVec<Item, INLINE, Heap>) -> core::cmp::Ordering {
self.as_slice().cmp(other.as_slice())
}
}
70 changes: 40 additions & 30 deletions src/conversions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,9 @@ use {
}
};

impl<T: Clone, const N: usize> From<&[T]> for SmallVec<T, N, Global> {
impl<Item: Clone, const INLINE: usize> From<&[Item]> for SmallVec<Item, INLINE, Global> {
#[inline]
fn from(slice: &[T]) -> Self {
fn from(slice: &[Item]) -> Self {
if slice.len() > Self::inline_size() {
// Standard Rust vectors are already specialized.
Self::from_vec(Vec::from(slice))
Expand All @@ -24,7 +24,7 @@ impl<T: Clone, const N: usize> From<&[T]> for SmallVec<T, N, Global> {
unsafe {
#[cfg(feature = "specialization")]
{
<Self as crate::specialization::SpecFromSlice<T>>::spec_from(slice)
<Self as crate::specialization::SpecFromSlice<Item>>::spec_from(slice)
}

#[cfg(not(feature = "specialization"))]
Expand All @@ -36,35 +36,39 @@ impl<T: Clone, const N: usize> From<&[T]> for SmallVec<T, N, Global> {
}
}

impl<T: Clone, const N: usize> From<&mut [T]> for SmallVec<T, N, Global> {
impl<Item: Clone, const INLINE: usize> From<&mut [Item]> for SmallVec<Item, INLINE, Global> {
#[inline]
fn from(slice: &mut [T]) -> Self {
Self::from(slice as &[T])
fn from(slice: &mut [Item]) -> Self {
Self::from(slice as &[Item])
}
}

impl<T: Clone, const M: usize, const N: usize> From<&[T; M]> for SmallVec<T, N, Global> {
impl<Item: Clone, const M: usize, const INLINE: usize> From<&[Item; M]>
for SmallVec<Item, INLINE, Global>
{
#[inline]
fn from(slice: &[T; M]) -> Self {
Self::from(slice as &[T])
fn from(slice: &[Item; M]) -> Self {
Self::from(slice as &[Item])
}
}

impl<T: Clone, const M: usize, const N: usize> From<&mut [T; M]> for SmallVec<T, N, Global> {
impl<Item: Clone, const M: usize, const INLINE: usize> From<&mut [Item; M]>
for SmallVec<Item, INLINE, Global>
{
#[inline]
fn from(slice: &mut [T; M]) -> Self {
Self::from(slice as &[T])
fn from(slice: &mut [Item; M]) -> Self {
Self::from(slice as &[Item])
}
}

impl<T, const N: usize, const M: usize> From<[T; M]> for SmallVec<T, N, Global> {
fn from(array: [T; M]) -> Self {
if M > N {
// If M > N, we'd have to heap allocate anyway,
impl<Item, const INLINE: usize, const M: usize> From<[Item; M]> for SmallVec<Item, INLINE, Global> {
fn from(array: [Item; M]) -> Self {
if M > INLINE {
// If M > INLINE, we'd have to heap allocate anyway,
// so delegate for Vec for the allocation.
Self::from(Vec::from(array))
} else {
// M <= N
// M <= INLINE
let mut this = Self::new();
debug_assert!(M <= this.capacity());
let array = ManuallyDrop::new(array);
Expand All @@ -78,33 +82,37 @@ impl<T, const N: usize, const M: usize> From<[T; M]> for SmallVec<T, N, Global>
}
}

impl<T, const N: usize, const M: usize, A: Allocator> TryFrom<SmallVec<T, N, A>> for [T; M] {
type Error = SmallVec<T, N, A>;
impl<Item, const INLINE: usize, const M: usize, Heap: Allocator>
TryFrom<SmallVec<Item, INLINE, Heap>> for [Item; M]
{
type Error = SmallVec<Item, INLINE, Heap>;

#[inline]
fn try_from(mut this: SmallVec<T, N, A>) -> Result<[T; M], SmallVec<T, N, A>> {
fn try_from(
mut this: SmallVec<Item, INLINE, Heap>
) -> Result<[Item; M], SmallVec<Item, INLINE, Heap>> {
if this.len() != M {
Err(this)
} else {
// SAFETY: we release ownership of the elements we hold
unsafe {
this.set_len(0);
}
let ptr = this.as_ptr() as *const [T; M];
let ptr = this.as_ptr() as *const [Item; M];
// SAFETY: these elements are initialized since the length was `M`
unsafe { Ok(ptr.read()) }
}
}
}

impl<T, const N: usize> From<Vec<T>> for SmallVec<T, N, Global> {
fn from(array: Vec<T>) -> Self {
impl<Item, const INLINE: usize> From<Vec<Item>> for SmallVec<Item, INLINE, Global> {
fn from(array: Vec<Item>) -> Self {
Self::from_vec(array)
}
}

impl<T, const N: usize, A: Allocator> From<SmallVec<T, N, A>> for Vec<T> {
fn from(this: SmallVec<T, N, A>) -> Self {
impl<Item, const INLINE: usize, Heap: Allocator> From<SmallVec<Item, INLINE, Heap>> for Vec<Item> {
fn from(this: SmallVec<Item, INLINE, Heap>) -> Self {
let (length, on_heap) = this.length.parts();
if !on_heap {
let mut vec = Vec::with_capacity(length);
Expand All @@ -122,10 +130,10 @@ impl<T, const N: usize, A: Allocator> From<SmallVec<T, N, A>> for Vec<T> {
let this = ManuallyDrop::new(this);
// SAFETY:
// - `ptr` was created with the SmallVec's allocator
// - `ptr` was created with the appropriate alignment for `T`
// - the allocation pointed to by ptr is exactly cap * sizeof(T)
// - `ptr` was created with the appropriate alignment for `Item`
// - the allocation pointed to by ptr is exactly cap * sizeof(Item)
// - `length` is less than or equal to `cap`
// - the first `length` entries are proper `T`-values
// - the first `length` entries are proper `Item`-values
// - the allocation is not larger than `isize::MAX`
unsafe {
let (ptr, cap) = this.raw.heap;
Expand All @@ -135,8 +143,10 @@ impl<T, const N: usize, A: Allocator> From<SmallVec<T, N, A>> for Vec<T> {
}
}

impl<T, const N: usize, A: Allocator> From<SmallVec<T, N, A>> for Box<[T]> {
fn from(this: SmallVec<T, N, A>) -> Self {
impl<Item, const INLINE: usize, Heap: Allocator> From<SmallVec<Item, INLINE, Heap>>
for Box<[Item]>
{
fn from(this: SmallVec<Item, INLINE, Heap>) -> Self {
Vec::from(this).into_boxed_slice()
}
}
Loading
Loading