#![cfg(feature = "alloc")] use super::*; use alloc::vec::{self, Vec}; use core::convert::TryFrom; use tinyvec_macros::impl_mirrored; #[cfg(feature = "rustc_1_57")] use alloc::collections::TryReserveError; #[cfg(feature = "serde")] use core::marker::PhantomData; #[cfg(feature = "serde")] use serde::de::{Deserialize, Deserializer, SeqAccess, Visitor}; #[cfg(feature = "serde")] use serde::ser::{Serialize, SerializeSeq, Serializer}; /// Helper to make a `TinyVec`. /// /// You specify the backing array type, and optionally give all the elements you /// want to initially place into the array. /// /// ```rust /// use tinyvec::*; /// /// // The backing array type can be specified in the macro call /// let empty_tv = tiny_vec!([u8; 16]); /// let some_ints = tiny_vec!([i32; 4] => 1, 2, 3); /// let many_ints = tiny_vec!([i32; 4] => 1, 2, 3, 4, 5, 6, 7, 8, 9, 10); /// /// // Or left to inference /// let empty_tv: TinyVec<[u8; 16]> = tiny_vec!(); /// let some_ints: TinyVec<[i32; 4]> = tiny_vec!(1, 2, 3); /// let many_ints: TinyVec<[i32; 4]> = tiny_vec!(1, 2, 3, 4, 5, 6, 7, 8, 9, 10); /// ``` #[macro_export] #[cfg_attr(docs_rs, doc(cfg(feature = "alloc")))] macro_rules! tiny_vec { ($array_type:ty => $($elem:expr),* $(,)?) => { { // https://github.com/rust-lang/lang-team/issues/28 const INVOKED_ELEM_COUNT: usize = 0 $( + { let _ = stringify!($elem); 1 })*; // If we have more `$elem` than the `CAPACITY` we will simply go directly // to constructing on the heap. match $crate::TinyVec::constructor_for_capacity(INVOKED_ELEM_COUNT) { $crate::TinyVecConstructor::Inline(f) => { f($crate::array_vec!($array_type => $($elem),*)) } $crate::TinyVecConstructor::Heap(f) => { f(vec!($($elem),*)) } } } }; ($array_type:ty) => { $crate::TinyVec::<$array_type>::default() }; ($($elem:expr),*) => { $crate::tiny_vec!(_ => $($elem),*) }; ($elem:expr; $n:expr) => { $crate::TinyVec::from([$elem; $n]) }; () => { $crate::tiny_vec!(_) }; } #[doc(hidden)] // Internal implementation details of `tiny_vec!` pub enum TinyVecConstructor { Inline(fn(ArrayVec) -> TinyVec), Heap(fn(Vec) -> TinyVec), } /// A vector that starts inline, but can automatically move to the heap. /// /// * Requires the `alloc` feature /// /// A `TinyVec` is either an Inline([`ArrayVec`](crate::ArrayVec::)) or /// Heap([`Vec`](https://doc.rust-lang.org/alloc/vec/struct.Vec.html)). The /// interface for the type as a whole is a bunch of methods that just match on /// the enum variant and then call the same method on the inner vec. /// /// ## Construction /// /// Because it's an enum, you can construct a `TinyVec` simply by making an /// `ArrayVec` or `Vec` and then putting it into the enum. /// /// There is also a macro /// /// ```rust /// # use tinyvec::*; /// let empty_tv = tiny_vec!([u8; 16]); /// let some_ints = tiny_vec!([i32; 4] => 1, 2, 3); /// ``` #[cfg_attr(docs_rs, doc(cfg(feature = "alloc")))] pub enum TinyVec { #[allow(missing_docs)] Inline(ArrayVec), #[allow(missing_docs)] Heap(Vec), } impl Clone for TinyVec where A: Array + Clone, A::Item: Clone, { #[inline] fn clone(&self) -> Self { match self { TinyVec::Heap(v) => TinyVec::Heap(v.clone()), TinyVec::Inline(v) => TinyVec::Inline(v.clone()), } } #[inline] fn clone_from(&mut self, o: &Self) { if o.len() > self.len() { self.reserve(o.len() - self.len()); } else { self.truncate(o.len()); } let (start, end) = o.split_at(self.len()); for (dst, src) in self.iter_mut().zip(start) { dst.clone_from(src); } self.extend_from_slice(end); } } impl Default for TinyVec { #[inline] #[must_use] fn default() -> Self { TinyVec::Inline(ArrayVec::default()) } } impl Deref for TinyVec { type Target = [A::Item]; impl_mirrored! { type Mirror = TinyVec; #[inline(always)] #[must_use] fn deref(self: &Self) -> &Self::Target; } } impl DerefMut for TinyVec { impl_mirrored! { type Mirror = TinyVec; #[inline(always)] #[must_use] fn deref_mut(self: &mut Self) -> &mut Self::Target; } } impl> Index for TinyVec { type Output = >::Output; #[inline(always)] #[must_use] fn index(&self, index: I) -> &Self::Output { &self.deref()[index] } } impl> IndexMut for TinyVec { #[inline(always)] #[must_use] fn index_mut(&mut self, index: I) -> &mut Self::Output { &mut self.deref_mut()[index] } } #[cfg(feature = "std")] #[cfg_attr(docs_rs, doc(cfg(feature = "std")))] impl> std::io::Write for TinyVec { #[inline(always)] fn write(&mut self, buf: &[u8]) -> std::io::Result { self.extend_from_slice(buf); Ok(buf.len()) } #[inline(always)] fn flush(&mut self) -> std::io::Result<()> { Ok(()) } } #[cfg(feature = "serde")] #[cfg_attr(docs_rs, doc(cfg(feature = "serde")))] impl Serialize for TinyVec where A::Item: Serialize, { #[must_use] fn serialize(&self, serializer: S) -> Result where S: Serializer, { let mut seq = serializer.serialize_seq(Some(self.len()))?; for element in self.iter() { seq.serialize_element(element)?; } seq.end() } } #[cfg(feature = "serde")] #[cfg_attr(docs_rs, doc(cfg(feature = "serde")))] impl<'de, A: Array> Deserialize<'de> for TinyVec where A::Item: Deserialize<'de>, { fn deserialize(deserializer: D) -> Result where D: Deserializer<'de>, { deserializer.deserialize_seq(TinyVecVisitor(PhantomData)) } } #[cfg(feature = "arbitrary")] #[cfg_attr(docs_rs, doc(cfg(feature = "arbitrary")))] impl<'a, A> arbitrary::Arbitrary<'a> for TinyVec where A: Array, A::Item: arbitrary::Arbitrary<'a>, { fn arbitrary(u: &mut arbitrary::Unstructured<'a>) -> arbitrary::Result { let v = Vec::arbitrary(u)?; let mut tv = TinyVec::Heap(v); tv.shrink_to_fit(); Ok(tv) } } impl TinyVec { /// Returns whether elements are on heap #[inline(always)] #[must_use] pub fn is_heap(&self) -> bool { match self { TinyVec::Heap(_) => true, TinyVec::Inline(_) => false, } } /// Returns whether elements are on stack #[inline(always)] #[must_use] pub fn is_inline(&self) -> bool { !self.is_heap() } /// Shrinks the capacity of the vector as much as possible.\ /// It is inlined if length is less than `A::CAPACITY`. /// ```rust /// use tinyvec::*; /// let mut tv = tiny_vec!([i32; 2] => 1, 2, 3); /// assert!(tv.is_heap()); /// let _ = tv.pop(); /// assert!(tv.is_heap()); /// tv.shrink_to_fit(); /// assert!(tv.is_inline()); /// ``` pub fn shrink_to_fit(&mut self) { let vec = match self { TinyVec::Inline(_) => return, TinyVec::Heap(h) => h, }; if vec.len() > A::CAPACITY { return vec.shrink_to_fit(); } let moved_vec = core::mem::replace(vec, Vec::new()); let mut av = ArrayVec::default(); let mut rest = av.fill(moved_vec); debug_assert!(rest.next().is_none()); *self = TinyVec::Inline(av); } /// Moves the content of the TinyVec to the heap, if it's inline. /// ```rust /// use tinyvec::*; /// let mut tv = tiny_vec!([i32; 4] => 1, 2, 3); /// assert!(tv.is_inline()); /// tv.move_to_the_heap(); /// assert!(tv.is_heap()); /// ``` #[allow(clippy::missing_inline_in_public_items)] pub fn move_to_the_heap(&mut self) { let arr = match self { TinyVec::Heap(_) => return, TinyVec::Inline(a) => a, }; let v = arr.drain_to_vec(); *self = TinyVec::Heap(v); } /// Tries to move the content of the TinyVec to the heap, if it's inline. /// /// # Errors /// /// If the allocator reports a failure, then an error is returned and the /// content is kept on the stack. /// /// ```rust /// use tinyvec::*; /// let mut tv = tiny_vec!([i32; 4] => 1, 2, 3); /// assert!(tv.is_inline()); /// assert_eq!(Ok(()), tv.try_move_to_the_heap()); /// assert!(tv.is_heap()); /// ``` #[cfg(feature = "rustc_1_57")] pub fn try_move_to_the_heap(&mut self) -> Result<(), TryReserveError> { let arr = match self { TinyVec::Heap(_) => return Ok(()), TinyVec::Inline(a) => a, }; let v = arr.try_drain_to_vec()?; *self = TinyVec::Heap(v); return Ok(()); } /// If TinyVec is inline, moves the content of it to the heap. /// Also reserves additional space. /// ```rust /// use tinyvec::*; /// let mut tv = tiny_vec!([i32; 4] => 1, 2, 3); /// assert!(tv.is_inline()); /// tv.move_to_the_heap_and_reserve(32); /// assert!(tv.is_heap()); /// assert!(tv.capacity() >= 35); /// ``` pub fn move_to_the_heap_and_reserve(&mut self, n: usize) { let arr = match self { TinyVec::Heap(h) => return h.reserve(n), TinyVec::Inline(a) => a, }; let v = arr.drain_to_vec_and_reserve(n); *self = TinyVec::Heap(v); } /// If TinyVec is inline, try to move the content of it to the heap. /// Also reserves additional space. /// /// # Errors /// /// If the allocator reports a failure, then an error is returned. /// /// ```rust /// use tinyvec::*; /// let mut tv = tiny_vec!([i32; 4] => 1, 2, 3); /// assert!(tv.is_inline()); /// assert_eq!(Ok(()), tv.try_move_to_the_heap_and_reserve(32)); /// assert!(tv.is_heap()); /// assert!(tv.capacity() >= 35); /// ``` #[cfg(feature = "rustc_1_57")] pub fn try_move_to_the_heap_and_reserve( &mut self, n: usize, ) -> Result<(), TryReserveError> { let arr = match self { TinyVec::Heap(h) => return h.try_reserve(n), TinyVec::Inline(a) => a, }; let v = arr.try_drain_to_vec_and_reserve(n)?; *self = TinyVec::Heap(v); return Ok(()); } /// Reserves additional space. /// Moves to the heap if array can't hold `n` more items /// ```rust /// use tinyvec::*; /// let mut tv = tiny_vec!([i32; 4] => 1, 2, 3, 4); /// assert!(tv.is_inline()); /// tv.reserve(1); /// assert!(tv.is_heap()); /// assert!(tv.capacity() >= 5); /// ``` pub fn reserve(&mut self, n: usize) { let arr = match self { TinyVec::Heap(h) => return h.reserve(n), TinyVec::Inline(a) => a, }; if n > arr.capacity() - arr.len() { let v = arr.drain_to_vec_and_reserve(n); *self = TinyVec::Heap(v); } /* In this place array has enough place, so no work is needed more */ return; } /// Tries to reserve additional space. /// Moves to the heap if array can't hold `n` more items. /// /// # Errors /// /// If the allocator reports a failure, then an error is returned. /// /// ```rust /// use tinyvec::*; /// let mut tv = tiny_vec!([i32; 4] => 1, 2, 3, 4); /// assert!(tv.is_inline()); /// assert_eq!(Ok(()), tv.try_reserve(1)); /// assert!(tv.is_heap()); /// assert!(tv.capacity() >= 5); /// ``` #[cfg(feature = "rustc_1_57")] pub fn try_reserve(&mut self, n: usize) -> Result<(), TryReserveError> { let arr = match self { TinyVec::Heap(h) => return h.try_reserve(n), TinyVec::Inline(a) => a, }; if n > arr.capacity() - arr.len() { let v = arr.try_drain_to_vec_and_reserve(n)?; *self = TinyVec::Heap(v); } /* In this place array has enough place, so no work is needed more */ return Ok(()); } /// Reserves additional space. /// Moves to the heap if array can't hold `n` more items /// /// From [Vec::reserve_exact](https://doc.rust-lang.org/std/vec/struct.Vec.html#method.reserve_exact) /// ```text /// Note that the allocator may give the collection more space than it requests. /// Therefore, capacity can not be relied upon to be precisely minimal. /// Prefer `reserve` if future insertions are expected. /// ``` /// ```rust /// use tinyvec::*; /// let mut tv = tiny_vec!([i32; 4] => 1, 2, 3, 4); /// assert!(tv.is_inline()); /// tv.reserve_exact(1); /// assert!(tv.is_heap()); /// assert!(tv.capacity() >= 5); /// ``` pub fn reserve_exact(&mut self, n: usize) { let arr = match self { TinyVec::Heap(h) => return h.reserve_exact(n), TinyVec::Inline(a) => a, }; if n > arr.capacity() - arr.len() { let v = arr.drain_to_vec_and_reserve(n); *self = TinyVec::Heap(v); } /* In this place array has enough place, so no work is needed more */ return; } /// Tries to reserve additional space. /// Moves to the heap if array can't hold `n` more items /// /// # Errors /// /// If the allocator reports a failure, then an error is returned. /// /// From [Vec::try_reserve_exact](https://doc.rust-lang.org/std/vec/struct.Vec.html#method.try_reserve_exact) /// ```text /// Note that the allocator may give the collection more space than it requests. /// Therefore, capacity can not be relied upon to be precisely minimal. /// Prefer `reserve` if future insertions are expected. /// ``` /// ```rust /// use tinyvec::*; /// let mut tv = tiny_vec!([i32; 4] => 1, 2, 3, 4); /// assert!(tv.is_inline()); /// assert_eq!(Ok(()), tv.try_reserve_exact(1)); /// assert!(tv.is_heap()); /// assert!(tv.capacity() >= 5); /// ``` #[cfg(feature = "rustc_1_57")] pub fn try_reserve_exact(&mut self, n: usize) -> Result<(), TryReserveError> { let arr = match self { TinyVec::Heap(h) => return h.try_reserve_exact(n), TinyVec::Inline(a) => a, }; if n > arr.capacity() - arr.len() { let v = arr.try_drain_to_vec_and_reserve(n)?; *self = TinyVec::Heap(v); } /* In this place array has enough place, so no work is needed more */ return Ok(()); } /// Makes a new TinyVec with _at least_ the given capacity. /// /// If the requested capacity is less than or equal to the array capacity you /// get an inline vec. If it's greater than you get a heap vec. /// ``` /// # use tinyvec::*; /// let t = TinyVec::<[u8; 10]>::with_capacity(5); /// assert!(t.is_inline()); /// assert!(t.capacity() >= 5); /// /// let t = TinyVec::<[u8; 10]>::with_capacity(20); /// assert!(t.is_heap()); /// assert!(t.capacity() >= 20); /// ``` #[inline] #[must_use] pub fn with_capacity(cap: usize) -> Self { if cap <= A::CAPACITY { TinyVec::Inline(ArrayVec::default()) } else { TinyVec::Heap(Vec::with_capacity(cap)) } } } impl TinyVec { /// Move all values from `other` into this vec. #[cfg(feature = "rustc_1_40")] #[inline] pub fn append(&mut self, other: &mut Self) { self.reserve(other.len()); /* Doing append should be faster, because it is effectively a memcpy */ match (self, other) { (TinyVec::Heap(sh), TinyVec::Heap(oh)) => sh.append(oh), (TinyVec::Inline(a), TinyVec::Heap(h)) => a.extend(h.drain(..)), (ref mut this, TinyVec::Inline(arr)) => this.extend(arr.drain(..)), } } /// Move all values from `other` into this vec. #[cfg(not(feature = "rustc_1_40"))] #[inline] pub fn append(&mut self, other: &mut Self) { match other { TinyVec::Inline(a) => self.extend(a.drain(..)), TinyVec::Heap(h) => self.extend(h.drain(..)), } } impl_mirrored! { type Mirror = TinyVec; /// Remove an element, swapping the end of the vec into its place. /// /// ## Panics /// * If the index is out of bounds. /// /// ## Example /// ```rust /// use tinyvec::*; /// let mut tv = tiny_vec!([&str; 4] => "foo", "bar", "quack", "zap"); /// /// assert_eq!(tv.swap_remove(1), "bar"); /// assert_eq!(tv.as_slice(), &["foo", "zap", "quack"][..]); /// /// assert_eq!(tv.swap_remove(0), "foo"); /// assert_eq!(tv.as_slice(), &["quack", "zap"][..]); /// ``` #[inline] pub fn swap_remove(self: &mut Self, index: usize) -> A::Item; /// Remove and return the last element of the vec, if there is one. /// /// ## Failure /// * If the vec is empty you get `None`. #[inline] pub fn pop(self: &mut Self) -> Option; /// Removes the item at `index`, shifting all others down by one index. /// /// Returns the removed element. /// /// ## Panics /// /// If the index is out of bounds. /// /// ## Example /// /// ```rust /// use tinyvec::*; /// let mut tv = tiny_vec!([i32; 4] => 1, 2, 3); /// assert_eq!(tv.remove(1), 2); /// assert_eq!(tv.as_slice(), &[1, 3][..]); /// ``` #[inline] pub fn remove(self: &mut Self, index: usize) -> A::Item; /// The length of the vec (in elements). #[inline(always)] #[must_use] pub fn len(self: &Self) -> usize; /// The capacity of the `TinyVec`. /// /// When not heap allocated this is fixed based on the array type. /// Otherwise its the result of the underlying Vec::capacity. #[inline(always)] #[must_use] pub fn capacity(self: &Self) -> usize; /// Reduces the vec's length to the given value. /// /// If the vec is already shorter than the input, nothing happens. #[inline] pub fn truncate(self: &mut Self, new_len: usize); /// A mutable pointer to the backing array. /// /// ## Safety /// /// This pointer has provenance over the _entire_ backing array/buffer. #[inline(always)] #[must_use] pub fn as_mut_ptr(self: &mut Self) -> *mut A::Item; /// A const pointer to the backing array. /// /// ## Safety /// /// This pointer has provenance over the _entire_ backing array/buffer. #[inline(always)] #[must_use] pub fn as_ptr(self: &Self) -> *const A::Item; } /// Walk the vec and keep only the elements that pass the predicate given. /// /// ## Example /// /// ```rust /// use tinyvec::*; /// /// let mut tv = tiny_vec!([i32; 10] => 1, 2, 3, 4); /// tv.retain(|&x| x % 2 == 0); /// assert_eq!(tv.as_slice(), &[2, 4][..]); /// ``` #[inline] pub fn retain bool>(self: &mut Self, acceptable: F) { match self { TinyVec::Inline(i) => i.retain(acceptable), TinyVec::Heap(h) => h.retain(acceptable), } } /// Helper for getting the mut slice. #[inline(always)] #[must_use] pub fn as_mut_slice(self: &mut Self) -> &mut [A::Item] { self.deref_mut() } /// Helper for getting the shared slice. #[inline(always)] #[must_use] pub fn as_slice(self: &Self) -> &[A::Item] { self.deref() } /// Removes all elements from the vec. #[inline(always)] pub fn clear(&mut self) { self.truncate(0) } /// De-duplicates the vec. #[cfg(feature = "nightly_slice_partition_dedup")] #[inline(always)] pub fn dedup(&mut self) where A::Item: PartialEq, { self.dedup_by(|a, b| a == b) } /// De-duplicates the vec according to the predicate given. #[cfg(feature = "nightly_slice_partition_dedup")] #[inline(always)] pub fn dedup_by(&mut self, same_bucket: F) where F: FnMut(&mut A::Item, &mut A::Item) -> bool, { let len = { let (dedup, _) = self.as_mut_slice().partition_dedup_by(same_bucket); dedup.len() }; self.truncate(len); } /// De-duplicates the vec according to the key selector given. #[cfg(feature = "nightly_slice_partition_dedup")] #[inline(always)] pub fn dedup_by_key(&mut self, mut key: F) where F: FnMut(&mut A::Item) -> K, K: PartialEq, { self.dedup_by(|a, b| key(a) == key(b)) } /// Creates a draining iterator that removes the specified range in the vector /// and yields the removed items. /// /// **Note: This method has significant performance issues compared to /// matching on the TinyVec and then calling drain on the Inline or Heap value /// inside. The draining iterator has to branch on every single access. It is /// provided for simplicity and compatability only.** /// /// ## Panics /// * If the start is greater than the end /// * If the end is past the edge of the vec. /// /// ## Example /// ```rust /// use tinyvec::*; /// let mut tv = tiny_vec!([i32; 4] => 1, 2, 3); /// let tv2: TinyVec<[i32; 4]> = tv.drain(1..).collect(); /// assert_eq!(tv.as_slice(), &[1][..]); /// assert_eq!(tv2.as_slice(), &[2, 3][..]); /// /// tv.drain(..); /// assert_eq!(tv.as_slice(), &[]); /// ``` #[inline] pub fn drain>( &mut self, range: R, ) -> TinyVecDrain<'_, A> { match self { TinyVec::Inline(i) => TinyVecDrain::Inline(i.drain(range)), TinyVec::Heap(h) => TinyVecDrain::Heap(h.drain(range)), } } /// Clone each element of the slice into this vec. /// ```rust /// use tinyvec::*; /// let mut tv = tiny_vec!([i32; 4] => 1, 2); /// tv.extend_from_slice(&[3, 4]); /// assert_eq!(tv.as_slice(), [1, 2, 3, 4]); /// ``` #[inline] pub fn extend_from_slice(&mut self, sli: &[A::Item]) where A::Item: Clone, { self.reserve(sli.len()); match self { TinyVec::Inline(a) => a.extend_from_slice(sli), TinyVec::Heap(h) => h.extend_from_slice(sli), } } /// Wraps up an array and uses the given length as the initial length. /// /// Note that the `From` impl for arrays assumes the full length is used. /// /// ## Panics /// /// The length must be less than or equal to the capacity of the array. #[inline] #[must_use] #[allow(clippy::match_wild_err_arm)] pub fn from_array_len(data: A, len: usize) -> Self { match Self::try_from_array_len(data, len) { Ok(out) => out, Err(_) => { panic!("TinyVec: length {} exceeds capacity {}!", len, A::CAPACITY) } } } /// This is an internal implementation detail of the `tiny_vec!` macro, and /// using it other than from that macro is not supported by this crate's /// SemVer guarantee. #[inline(always)] #[doc(hidden)] pub fn constructor_for_capacity(cap: usize) -> TinyVecConstructor { if cap <= A::CAPACITY { TinyVecConstructor::Inline(TinyVec::Inline) } else { TinyVecConstructor::Heap(TinyVec::Heap) } } /// Inserts an item at the position given, moving all following elements +1 /// index. /// /// ## Panics /// * If `index` > `len` /// /// ## Example /// ```rust /// use tinyvec::*; /// let mut tv = tiny_vec!([i32; 10] => 1, 2, 3); /// tv.insert(1, 4); /// assert_eq!(tv.as_slice(), &[1, 4, 2, 3]); /// tv.insert(4, 5); /// assert_eq!(tv.as_slice(), &[1, 4, 2, 3, 5]); /// ``` #[inline] pub fn insert(&mut self, index: usize, item: A::Item) { assert!( index <= self.len(), "insertion index (is {}) should be <= len (is {})", index, self.len() ); let arr = match self { TinyVec::Heap(v) => return v.insert(index, item), TinyVec::Inline(a) => a, }; if let Some(x) = arr.try_insert(index, item) { let mut v = Vec::with_capacity(arr.len() * 2); let mut it = arr.iter_mut().map(|r| core::mem::replace(r, Default::default())); v.extend(it.by_ref().take(index)); v.push(x); v.extend(it); *self = TinyVec::Heap(v); } } /// If the vec is empty. #[inline(always)] #[must_use] pub fn is_empty(&self) -> bool { self.len() == 0 } /// Makes a new, empty vec. #[inline(always)] #[must_use] pub fn new() -> Self { Self::default() } /// Place an element onto the end of the vec. /// ## Panics /// * If the length of the vec would overflow the capacity. /// ```rust /// use tinyvec::*; /// let mut tv = tiny_vec!([i32; 10] => 1, 2, 3); /// tv.push(4); /// assert_eq!(tv.as_slice(), &[1, 2, 3, 4]); /// ``` #[inline] pub fn push(&mut self, val: A::Item) { // The code path for moving the inline contents to the heap produces a lot // of instructions, but we have a strong guarantee that this is a cold // path. LLVM doesn't know this, inlines it, and this tends to cause a // cascade of other bad inlining decisions because the body of push looks // huge even though nearly every call executes the same few instructions. // // Moving the logic out of line with #[cold] causes the hot code to be // inlined together, and we take the extra cost of a function call only // in rare cases. #[cold] fn drain_to_heap_and_push( arr: &mut ArrayVec, val: A::Item, ) -> TinyVec { /* Make the Vec twice the size to amortize the cost of draining */ let mut v = arr.drain_to_vec_and_reserve(arr.len()); v.push(val); TinyVec::Heap(v) } match self { TinyVec::Heap(v) => v.push(val), TinyVec::Inline(arr) => { if let Some(x) = arr.try_push(val) { *self = drain_to_heap_and_push(arr, x); } } } } /// Resize the vec to the new length. /// /// If it needs to be longer, it's filled with clones of the provided value. /// If it needs to be shorter, it's truncated. /// /// ## Example /// /// ```rust /// use tinyvec::*; /// /// let mut tv = tiny_vec!([&str; 10] => "hello"); /// tv.resize(3, "world"); /// assert_eq!(tv.as_slice(), &["hello", "world", "world"][..]); /// /// let mut tv = tiny_vec!([i32; 10] => 1, 2, 3, 4); /// tv.resize(2, 0); /// assert_eq!(tv.as_slice(), &[1, 2][..]); /// ``` #[inline] pub fn resize(&mut self, new_len: usize, new_val: A::Item) where A::Item: Clone, { self.resize_with(new_len, || new_val.clone()); } /// Resize the vec to the new length. /// /// If it needs to be longer, it's filled with repeated calls to the provided /// function. If it needs to be shorter, it's truncated. /// /// ## Example /// /// ```rust /// use tinyvec::*; /// /// let mut tv = tiny_vec!([i32; 3] => 1, 2, 3); /// tv.resize_with(5, Default::default); /// assert_eq!(tv.as_slice(), &[1, 2, 3, 0, 0][..]); /// /// let mut tv = tiny_vec!([i32; 2]); /// let mut p = 1; /// tv.resize_with(4, || { /// p *= 2; /// p /// }); /// assert_eq!(tv.as_slice(), &[2, 4, 8, 16][..]); /// ``` #[inline] pub fn resize_with A::Item>(&mut self, new_len: usize, f: F) { match new_len.checked_sub(self.len()) { None => return self.truncate(new_len), Some(n) => self.reserve(n), } match self { TinyVec::Inline(a) => a.resize_with(new_len, f), TinyVec::Heap(v) => v.resize_with(new_len, f), } } /// Splits the collection at the point given. /// /// * `[0, at)` stays in this vec /// * `[at, len)` ends up in the new vec. /// /// ## Panics /// * if at > len /// /// ## Example /// /// ```rust /// use tinyvec::*; /// let mut tv = tiny_vec!([i32; 4] => 1, 2, 3); /// let tv2 = tv.split_off(1); /// assert_eq!(tv.as_slice(), &[1][..]); /// assert_eq!(tv2.as_slice(), &[2, 3][..]); /// ``` #[inline] pub fn split_off(&mut self, at: usize) -> Self { match self { TinyVec::Inline(a) => TinyVec::Inline(a.split_off(at)), TinyVec::Heap(v) => TinyVec::Heap(v.split_off(at)), } } /// Creates a splicing iterator that removes the specified range in the /// vector, yields the removed items, and replaces them with elements from /// the provided iterator. /// /// `splice` fuses the provided iterator, so elements after the first `None` /// are ignored. /// /// ## Panics /// * If the start is greater than the end. /// * If the end is past the edge of the vec. /// * If the provided iterator panics. /// /// ## Example /// ```rust /// use tinyvec::*; /// let mut tv = tiny_vec!([i32; 4] => 1, 2, 3); /// let tv2: TinyVec<[i32; 4]> = tv.splice(1.., 4..=6).collect(); /// assert_eq!(tv.as_slice(), &[1, 4, 5, 6][..]); /// assert_eq!(tv2.as_slice(), &[2, 3][..]); /// /// tv.splice(.., None); /// assert_eq!(tv.as_slice(), &[]); /// ``` #[inline] pub fn splice( &mut self, range: R, replacement: I, ) -> TinyVecSplice<'_, A, core::iter::Fuse> where R: RangeBounds, I: IntoIterator, { use core::ops::Bound; let start = match range.start_bound() { Bound::Included(x) => *x, Bound::Excluded(x) => x.saturating_add(1), Bound::Unbounded => 0, }; let end = match range.end_bound() { Bound::Included(x) => x.saturating_add(1), Bound::Excluded(x) => *x, Bound::Unbounded => self.len(), }; assert!( start <= end, "TinyVec::splice> Illegal range, {} to {}", start, end ); assert!( end <= self.len(), "TinyVec::splice> Range ends at {} but length is only {}!", end, self.len() ); TinyVecSplice { removal_start: start, removal_end: end, parent: self, replacement: replacement.into_iter().fuse(), } } /// Wraps an array, using the given length as the starting length. /// /// If you want to use the whole length of the array, you can just use the /// `From` impl. /// /// ## Failure /// /// If the given length is greater than the capacity of the array this will /// error, and you'll get the array back in the `Err`. #[inline] pub fn try_from_array_len(data: A, len: usize) -> Result { let arr = ArrayVec::try_from_array_len(data, len)?; Ok(TinyVec::Inline(arr)) } } /// Draining iterator for `TinyVecDrain` /// /// See [`TinyVecDrain::drain`](TinyVecDrain::::drain) #[cfg_attr(docs_rs, doc(cfg(feature = "alloc")))] pub enum TinyVecDrain<'p, A: Array> { #[allow(missing_docs)] Inline(ArrayVecDrain<'p, A::Item>), #[allow(missing_docs)] Heap(vec::Drain<'p, A::Item>), } impl<'p, A: Array> Iterator for TinyVecDrain<'p, A> { type Item = A::Item; impl_mirrored! { type Mirror = TinyVecDrain; #[inline] fn next(self: &mut Self) -> Option; #[inline] fn nth(self: &mut Self, n: usize) -> Option; #[inline] fn size_hint(self: &Self) -> (usize, Option); #[inline] fn last(self: Self) -> Option; #[inline] fn count(self: Self) -> usize; } #[inline] fn for_each(self, f: F) { match self { TinyVecDrain::Inline(i) => i.for_each(f), TinyVecDrain::Heap(h) => h.for_each(f), } } } impl<'p, A: Array> DoubleEndedIterator for TinyVecDrain<'p, A> { impl_mirrored! { type Mirror = TinyVecDrain; #[inline] fn next_back(self: &mut Self) -> Option; #[cfg(feature = "rustc_1_40")] #[inline] fn nth_back(self: &mut Self, n: usize) -> Option; } } /// Splicing iterator for `TinyVec` /// See [`TinyVec::splice`](TinyVec::::splice) #[cfg_attr(docs_rs, doc(cfg(feature = "alloc")))] pub struct TinyVecSplice<'p, A: Array, I: Iterator> { parent: &'p mut TinyVec, removal_start: usize, removal_end: usize, replacement: I, } impl<'p, A, I> Iterator for TinyVecSplice<'p, A, I> where A: Array, I: Iterator, { type Item = A::Item; #[inline] fn next(&mut self) -> Option { if self.removal_start < self.removal_end { match self.replacement.next() { Some(replacement) => { let removed = core::mem::replace( &mut self.parent[self.removal_start], replacement, ); self.removal_start += 1; Some(removed) } None => { let removed = self.parent.remove(self.removal_start); self.removal_end -= 1; Some(removed) } } } else { None } } #[inline] fn size_hint(&self) -> (usize, Option) { let len = self.len(); (len, Some(len)) } } impl<'p, A, I> ExactSizeIterator for TinyVecSplice<'p, A, I> where A: Array, I: Iterator, { #[inline] fn len(&self) -> usize { self.removal_end - self.removal_start } } impl<'p, A, I> FusedIterator for TinyVecSplice<'p, A, I> where A: Array, I: Iterator, { } impl<'p, A, I> DoubleEndedIterator for TinyVecSplice<'p, A, I> where A: Array, I: Iterator + DoubleEndedIterator, { #[inline] fn next_back(&mut self) -> Option { if self.removal_start < self.removal_end { match self.replacement.next_back() { Some(replacement) => { let removed = core::mem::replace( &mut self.parent[self.removal_end - 1], replacement, ); self.removal_end -= 1; Some(removed) } None => { let removed = self.parent.remove(self.removal_end - 1); self.removal_end -= 1; Some(removed) } } } else { None } } } impl<'p, A: Array, I: Iterator> Drop for TinyVecSplice<'p, A, I> { fn drop(&mut self) { for _ in self.by_ref() {} let (lower_bound, _) = self.replacement.size_hint(); self.parent.reserve(lower_bound); for replacement in self.replacement.by_ref() { self.parent.insert(self.removal_end, replacement); self.removal_end += 1; } } } impl AsMut<[A::Item]> for TinyVec { #[inline(always)] #[must_use] fn as_mut(&mut self) -> &mut [A::Item] { &mut *self } } impl AsRef<[A::Item]> for TinyVec { #[inline(always)] #[must_use] fn as_ref(&self) -> &[A::Item] { &*self } } impl Borrow<[A::Item]> for TinyVec { #[inline(always)] #[must_use] fn borrow(&self) -> &[A::Item] { &*self } } impl BorrowMut<[A::Item]> for TinyVec { #[inline(always)] #[must_use] fn borrow_mut(&mut self) -> &mut [A::Item] { &mut *self } } impl Extend for TinyVec { #[inline] fn extend>(&mut self, iter: T) { let iter = iter.into_iter(); let (lower_bound, _) = iter.size_hint(); self.reserve(lower_bound); let a = match self { TinyVec::Heap(h) => return h.extend(iter), TinyVec::Inline(a) => a, }; let mut iter = a.fill(iter); let maybe = iter.next(); let surely = match maybe { Some(x) => x, None => return, }; let mut v = a.drain_to_vec_and_reserve(a.len()); v.push(surely); v.extend(iter); *self = TinyVec::Heap(v); } } impl From> for TinyVec { #[inline(always)] #[must_use] fn from(arr: ArrayVec) -> Self { TinyVec::Inline(arr) } } impl From for TinyVec { fn from(array: A) -> Self { TinyVec::Inline(ArrayVec::from(array)) } } impl From<&'_ [T]> for TinyVec where T: Clone + Default, A: Array, { #[inline] #[must_use] fn from(slice: &[T]) -> Self { if let Ok(arr) = ArrayVec::try_from(slice) { TinyVec::Inline(arr) } else { TinyVec::Heap(slice.into()) } } } impl From<&'_ mut [T]> for TinyVec where T: Clone + Default, A: Array, { #[inline] #[must_use] fn from(slice: &mut [T]) -> Self { Self::from(&*slice) } } impl FromIterator for TinyVec { #[inline] #[must_use] fn from_iter>(iter: T) -> Self { let mut av = Self::default(); av.extend(iter); av } } /// Iterator for consuming an `TinyVec` and returning owned elements. #[cfg_attr(docs_rs, doc(cfg(feature = "alloc")))] pub enum TinyVecIterator { #[allow(missing_docs)] Inline(ArrayVecIterator), #[allow(missing_docs)] Heap(alloc::vec::IntoIter), } impl TinyVecIterator { impl_mirrored! { type Mirror = TinyVecIterator; /// Returns the remaining items of this iterator as a slice. #[inline] #[must_use] pub fn as_slice(self: &Self) -> &[A::Item]; } } impl FusedIterator for TinyVecIterator {} impl Iterator for TinyVecIterator { type Item = A::Item; impl_mirrored! { type Mirror = TinyVecIterator; #[inline] fn next(self: &mut Self) -> Option; #[inline(always)] #[must_use] fn size_hint(self: &Self) -> (usize, Option); #[inline(always)] fn count(self: Self) -> usize; #[inline] fn last(self: Self) -> Option; #[inline] fn nth(self: &mut Self, n: usize) -> Option; } } impl DoubleEndedIterator for TinyVecIterator { impl_mirrored! { type Mirror = TinyVecIterator; #[inline] fn next_back(self: &mut Self) -> Option; #[cfg(feature = "rustc_1_40")] #[inline] fn nth_back(self: &mut Self, n: usize) -> Option; } } impl Debug for TinyVecIterator where A::Item: Debug, { #[allow(clippy::missing_inline_in_public_items)] fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result { f.debug_tuple("TinyVecIterator").field(&self.as_slice()).finish() } } impl IntoIterator for TinyVec { type Item = A::Item; type IntoIter = TinyVecIterator; #[inline(always)] #[must_use] fn into_iter(self) -> Self::IntoIter { match self { TinyVec::Inline(a) => TinyVecIterator::Inline(a.into_iter()), TinyVec::Heap(v) => TinyVecIterator::Heap(v.into_iter()), } } } impl<'a, A: Array> IntoIterator for &'a mut TinyVec { type Item = &'a mut A::Item; type IntoIter = core::slice::IterMut<'a, A::Item>; #[inline(always)] #[must_use] fn into_iter(self) -> Self::IntoIter { self.iter_mut() } } impl<'a, A: Array> IntoIterator for &'a TinyVec { type Item = &'a A::Item; type IntoIter = core::slice::Iter<'a, A::Item>; #[inline(always)] #[must_use] fn into_iter(self) -> Self::IntoIter { self.iter() } } impl PartialEq for TinyVec where A::Item: PartialEq, { #[inline] #[must_use] fn eq(&self, other: &Self) -> bool { self.as_slice().eq(other.as_slice()) } } impl Eq for TinyVec where A::Item: Eq {} impl PartialOrd for TinyVec where A::Item: PartialOrd, { #[inline] #[must_use] fn partial_cmp(&self, other: &Self) -> Option { self.as_slice().partial_cmp(other.as_slice()) } } impl Ord for TinyVec where A::Item: Ord, { #[inline] #[must_use] fn cmp(&self, other: &Self) -> core::cmp::Ordering { self.as_slice().cmp(other.as_slice()) } } impl PartialEq<&A> for TinyVec where A::Item: PartialEq, { #[inline] #[must_use] fn eq(&self, other: &&A) -> bool { self.as_slice().eq(other.as_slice()) } } impl PartialEq<&[A::Item]> for TinyVec where A::Item: PartialEq, { #[inline] #[must_use] fn eq(&self, other: &&[A::Item]) -> bool { self.as_slice().eq(*other) } } impl Hash for TinyVec where A::Item: Hash, { #[inline] fn hash(&self, state: &mut H) { self.as_slice().hash(state) } } // // // // // // // // // Formatting impls // // // // // // // // impl Binary for TinyVec where A::Item: Binary, { #[allow(clippy::missing_inline_in_public_items)] fn fmt(&self, f: &mut Formatter) -> core::fmt::Result { write!(f, "[")?; if f.alternate() { write!(f, "\n ")?; } for (i, elem) in self.iter().enumerate() { if i > 0 { write!(f, ",{}", if f.alternate() { "\n " } else { " " })?; } Binary::fmt(elem, f)?; } if f.alternate() { write!(f, ",\n")?; } write!(f, "]") } } impl Debug for TinyVec where A::Item: Debug, { #[allow(clippy::missing_inline_in_public_items)] fn fmt(&self, f: &mut Formatter) -> core::fmt::Result { write!(f, "[")?; if f.alternate() { write!(f, "\n ")?; } for (i, elem) in self.iter().enumerate() { if i > 0 { write!(f, ",{}", if f.alternate() { "\n " } else { " " })?; } Debug::fmt(elem, f)?; } if f.alternate() { write!(f, ",\n")?; } write!(f, "]") } } impl Display for TinyVec where A::Item: Display, { #[allow(clippy::missing_inline_in_public_items)] fn fmt(&self, f: &mut Formatter) -> core::fmt::Result { write!(f, "[")?; if f.alternate() { write!(f, "\n ")?; } for (i, elem) in self.iter().enumerate() { if i > 0 { write!(f, ",{}", if f.alternate() { "\n " } else { " " })?; } Display::fmt(elem, f)?; } if f.alternate() { write!(f, ",\n")?; } write!(f, "]") } } impl LowerExp for TinyVec where A::Item: LowerExp, { #[allow(clippy::missing_inline_in_public_items)] fn fmt(&self, f: &mut Formatter) -> core::fmt::Result { write!(f, "[")?; if f.alternate() { write!(f, "\n ")?; } for (i, elem) in self.iter().enumerate() { if i > 0 { write!(f, ",{}", if f.alternate() { "\n " } else { " " })?; } LowerExp::fmt(elem, f)?; } if f.alternate() { write!(f, ",\n")?; } write!(f, "]") } } impl LowerHex for TinyVec where A::Item: LowerHex, { #[allow(clippy::missing_inline_in_public_items)] fn fmt(&self, f: &mut Formatter) -> core::fmt::Result { write!(f, "[")?; if f.alternate() { write!(f, "\n ")?; } for (i, elem) in self.iter().enumerate() { if i > 0 { write!(f, ",{}", if f.alternate() { "\n " } else { " " })?; } LowerHex::fmt(elem, f)?; } if f.alternate() { write!(f, ",\n")?; } write!(f, "]") } } impl Octal for TinyVec where A::Item: Octal, { #[allow(clippy::missing_inline_in_public_items)] fn fmt(&self, f: &mut Formatter) -> core::fmt::Result { write!(f, "[")?; if f.alternate() { write!(f, "\n ")?; } for (i, elem) in self.iter().enumerate() { if i > 0 { write!(f, ",{}", if f.alternate() { "\n " } else { " " })?; } Octal::fmt(elem, f)?; } if f.alternate() { write!(f, ",\n")?; } write!(f, "]") } } impl Pointer for TinyVec where A::Item: Pointer, { #[allow(clippy::missing_inline_in_public_items)] fn fmt(&self, f: &mut Formatter) -> core::fmt::Result { write!(f, "[")?; if f.alternate() { write!(f, "\n ")?; } for (i, elem) in self.iter().enumerate() { if i > 0 { write!(f, ",{}", if f.alternate() { "\n " } else { " " })?; } Pointer::fmt(elem, f)?; } if f.alternate() { write!(f, ",\n")?; } write!(f, "]") } } impl UpperExp for TinyVec where A::Item: UpperExp, { #[allow(clippy::missing_inline_in_public_items)] fn fmt(&self, f: &mut Formatter) -> core::fmt::Result { write!(f, "[")?; if f.alternate() { write!(f, "\n ")?; } for (i, elem) in self.iter().enumerate() { if i > 0 { write!(f, ",{}", if f.alternate() { "\n " } else { " " })?; } UpperExp::fmt(elem, f)?; } if f.alternate() { write!(f, ",\n")?; } write!(f, "]") } } impl UpperHex for TinyVec where A::Item: UpperHex, { #[allow(clippy::missing_inline_in_public_items)] fn fmt(&self, f: &mut Formatter) -> core::fmt::Result { write!(f, "[")?; if f.alternate() { write!(f, "\n ")?; } for (i, elem) in self.iter().enumerate() { if i > 0 { write!(f, ",{}", if f.alternate() { "\n " } else { " " })?; } UpperHex::fmt(elem, f)?; } if f.alternate() { write!(f, ",\n")?; } write!(f, "]") } } #[cfg(feature = "serde")] #[cfg_attr(docs_rs, doc(cfg(feature = "alloc")))] struct TinyVecVisitor(PhantomData); #[cfg(feature = "serde")] impl<'de, A: Array> Visitor<'de> for TinyVecVisitor where A::Item: Deserialize<'de>, { type Value = TinyVec; fn expecting( &self, formatter: &mut core::fmt::Formatter, ) -> core::fmt::Result { formatter.write_str("a sequence") } fn visit_seq(self, mut seq: S) -> Result where S: SeqAccess<'de>, { let mut new_tinyvec = match seq.size_hint() { Some(expected_size) => TinyVec::with_capacity(expected_size), None => Default::default(), }; while let Some(value) = seq.next_element()? { new_tinyvec.push(value); } Ok(new_tinyvec) } }