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
4 changes: 4 additions & 0 deletions .github/workflows/rust.yml
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,10 @@ jobs:
if: matrix.nightly
run: rustup component add rustfmt && cargo fmt --all --check

- name: Clippy check
if: matrix.nightly
run: rustup component add clippy && cargo clippy --all-features --all-targets -- -D warnings

- name: Build
run: cargo build --verbose

Expand Down
11 changes: 6 additions & 5 deletions src/borsh.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,28 +28,29 @@ impl<Type: BorshSerialize, const INLINE: usize> BorshSerialize for SmallVec<Type
for element in self {
element.serialize(writer)?;
}
return Ok(());

Ok(())
}
}

impl<Type: BorshDeserialize, const INLINE: usize> BorshDeserialize for SmallVec<Type, INLINE> {
fn deserialize_reader<R: borsh::io::Read>(reader: &mut R) -> Serial<Self> {
let length = u64::deserialize_reader(reader)?;
return repeat_with(|| Type::deserialize_reader(reader))
repeat_with(|| Type::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"
))?)
.collect();
.collect()
}
}

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

fn add_definitions_recursively(definitions: &mut Map<Declaration, Definition>) -> () {
fn add_definitions_recursively(definitions: &mut Map<Declaration, Definition>) {
let declaration = Self::declaration();
if definitions.contains_key(&declaration) {
return;
Expand Down
4 changes: 2 additions & 2 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1132,7 +1132,7 @@ impl<T, const N: usize> SmallVec<T, N> {
// We have to do this so that Miri doesn't report a "Stacked
// Borrows" rule violation. See PR/406

debug_assert!(len + 1 <= self.capacity());
debug_assert!(len < self.capacity());
// SAFETY: we have wrote the value to the address already
unsafe {
self.len.increment();
Expand Down Expand Up @@ -1473,7 +1473,7 @@ impl<T, const N: usize> SmallVec<T, N> {
// We have to do this so that Miri doesn't report a "Stacked
// Borrows" rule violation. See PR/406

debug_assert!(len + 1 <= self.capacity());
debug_assert!(len < self.capacity());
// SAFETY: we have wrote the value to the address already
unsafe {
self.len.increment();
Expand Down
7 changes: 7 additions & 0 deletions src/rawsmallvec.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,13 @@ pub union RawSmallVec<T, const N: usize> {
pub heap: (NonNull<T>, usize)
}

impl<T, const N: usize> Default for RawSmallVec<T, N> {
#[inline]
fn default() -> Self {
Self::new()
}
}

impl<T, const N: usize> RawSmallVec<T, N> {
const IS_ZST: bool = size_of::<T>() == 0;

Expand Down
22 changes: 15 additions & 7 deletions src/taggedlen.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ use core::marker::PhantomData;
/// Vec guarantees that its length is always less than [`isize::MAX`] in
/// *bytes*.
///
/// For a non ZST, this means that the length is less than `isize::MAX` objects,
/// For a non-ZST, this means that the length is less than `isize::MAX` objects,
/// which implies we have at least one free bit we can use. We use the least
/// significant bit for the tag. And store the length in the `usize::BITS - 1`
/// most significant bits.
Expand All @@ -12,15 +12,12 @@ use core::marker::PhantomData;
#[repr(transparent)]
pub struct TaggedLen<T>(usize, PhantomData<T>);

// We don't use `#[derive(Clone, Copy)]` instead because `T` doesn't need to be
// `Copy` or `Clone`.
impl<T> Clone for TaggedLen<T> {
#[inline]
fn clone(&self) -> Self {
Self(self.0, PhantomData)
}

#[inline]
fn clone_from(&mut self, source: &Self) {
self.0 = source.0;
*self
}
}

Expand Down Expand Up @@ -58,6 +55,12 @@ impl<T> TaggedLen<T> {
/// Returns the same tag with the length increased by one.
///
/// This increases the length without rereading the `on heap` flag.
///
/// # Safety
///
/// The caller must ensure that after incrementing, the length would still
/// be less than [`isize::MAX`] in bytes. For non-ZSTs this means the
/// length must be less than `isize::MAX - 1` before the call.
#[inline]
pub const unsafe fn increment(&mut self) {
self.0 += if Self::IS_ZST {
Expand All @@ -71,6 +74,11 @@ impl<T> TaggedLen<T> {
/// Returns the same tag with the length decreased by one.
///
/// This decreases the length without rereading the `on heap` flag.
///
/// # Safety
///
/// The caller must ensure that the length is greater than zero before the
/// call.
#[inline]
pub const unsafe fn decrement(&mut self) {
debug_assert!(self.value() > 0);
Expand Down
4 changes: 2 additions & 2 deletions tests/borsh.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,15 @@ use {
};

#[test]
fn round_trip() -> () {
fn round_trip() {
let smallvec = SmallVec::<u8, 6>::from([1, 2, 3]);
let bytes = to_vec(&smallvec).unwrap();
let new = SmallVec::<u8, 6>::deserialize(&mut bytes.as_ref()).unwrap();
assert_eq!(new, smallvec);
}

#[test]
fn round_trip_zst() -> () {
fn round_trip_zst() {
let smallvec = SmallVec::<(), 5>::from([(); 0x100000]);
let bytes = to_vec(&smallvec).unwrap();
let new = SmallVec::<(), 100>::deserialize(&mut bytes.as_ref()).unwrap();
Expand Down
27 changes: 9 additions & 18 deletions tests/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -396,10 +396,7 @@ fn append() {
assert_eq!(v.len(), 6);
assert_eq!(n.len(), 0);

assert_eq!(
&v.iter().map(|v| *v).collect::<Vec<_>>(),
&[0, 1, 2, 3, 5, 6]
);
assert_eq!(v.iter().copied().collect::<Vec<_>>(), [0, 1, 2, 3, 5, 6]);
}

#[test]
Expand All @@ -425,20 +422,14 @@ fn extend_from_slice() {
}
assert_eq!(v.len(), 4);
v.extend_from_slice(&[5, 6]);
assert_eq!(
&v.iter().map(|v| *v).collect::<Vec<_>>(),
&[0, 1, 2, 3, 5, 6]
);
assert_eq!(v.iter().copied().collect::<Vec<_>>(), [0, 1, 2, 3, 5, 6]);
}

#[test]
fn extend_from_within() {
let mut v: SmallVec<u8, 8> = SmallVec::from([0, 1, 2, 3]);
v.extend_from_within(1..3);
assert_eq!(
&v.iter().map(|v| *v).collect::<Vec<_>>(),
&[0, 1, 2, 3, 1, 2],
);
assert_eq!(v.iter().copied().collect::<Vec<_>>(), [0, 1, 2, 3, 1, 2],);
}

#[test]
Expand Down Expand Up @@ -653,9 +644,9 @@ fn into_iter_as_slice() {
fn into_iter_clone() {
// Test that the cloned iterator yields identical elements and that it owns
// its own copy (i.e. no use after move errors).
let mut iter = SmallVec::<u8, 2>::from_iter(0..3).into_iter();
let iter = SmallVec::<u8, 2>::from_iter(0..3).into_iter();
let mut clone_iter = iter.clone();
while let Some(x) = iter.next() {
for x in iter {
assert_eq!(x, clone_iter.next().unwrap());
}
assert_eq!(clone_iter.next(), None);
Expand All @@ -665,9 +656,9 @@ fn into_iter_clone() {
fn into_iter_clone_partially_consumed_iterator() {
// Test that the cloned iterator only contains the remaining elements of the
// original iterator.
let mut iter = SmallVec::<u8, 2>::from_iter(0..3).into_iter().skip(1);
let iter = SmallVec::<u8, 2>::from_iter(0..3).into_iter().skip(1);
let mut clone_iter = iter.clone();
while let Some(x) = iter.next() {
for x in iter {
assert_eq!(x, clone_iter.next().unwrap());
}
assert_eq!(clone_iter.next(), None);
Expand Down Expand Up @@ -1012,7 +1003,7 @@ fn collect_from_iter() {
const ELEMENTS: usize = 1000;
#[cfg(not(miri))]
const ELEMENTS: usize = 1_000_000;
let iter = IterNoHint(std::iter::repeat(1u8).take(ELEMENTS));
let iter = IterNoHint(std::iter::repeat_n(1u8, ELEMENTS));

let _y: SmallVec<u8, 1> = SmallVec::from_iter(iter);
}
Expand Down Expand Up @@ -1047,6 +1038,6 @@ fn spare_capacity_mut() {
v.push(3);
assert!(v.spilled());
let spare = v.spare_capacity_mut();
assert!(spare.len() >= 1);
assert!(!spare.is_empty());
assert_eq!(spare.as_ptr().cast::<u8>(), unsafe { v.as_ptr().add(3) });
}