1use std::{
33 alloc::{self, Layout},
34 fmt::{Debug, Formatter},
35 mem::{ManuallyDrop, MaybeUninit},
36 num::NonZeroU8,
37 ops::{Deref, DerefMut},
38 ptr::{self, NonNull, drop_in_place, slice_from_raw_parts_mut},
39 slice::{Iter, IterMut},
40};
41
42use shrink_to_fit::ShrinkToFit;
43
44union Data<T, const INLINE: usize> {
45 inline: ManuallyDrop<[MaybeUninit<T>; INLINE]>,
46 heap: NonNull<T>,
48}
49
50const MAX_TINY_VEC_SIZE: usize = (u8::MAX - 1) as usize;
51pub struct TinyVec<T, const INLINE: usize, const MAX: usize = MAX_TINY_VEC_SIZE> {
53 len: NonZeroU8,
55 cap: u8,
58 data: Data<T, INLINE>,
59}
60
61unsafe impl<T: Send, const INLINE: usize, const MAX: usize> Send for TinyVec<T, INLINE, MAX> {}
64unsafe impl<T: Sync, const INLINE: usize, const MAX: usize> Sync for TinyVec<T, INLINE, MAX> {}
65
66impl<T, const INLINE: usize, const MAX: usize> TinyVec<T, INLINE, MAX> {
67 const ASSERT: () = {
70 assert!(MAX > 0, "TinyVec MAX must be > 0");
71 assert!(
72 INLINE <= MAX,
73 "TinyVec inline capacity INLINE must be <= MAX"
74 );
75 assert!(
76 MAX <= MAX_TINY_VEC_SIZE,
77 "TinyVec MAX must fit in NonZeroU8 with the +1 offset",
78 );
79 };
80
81 const EMPTY_LEN: NonZeroU8 = match NonZeroU8::new(1) {
83 Some(n) => n,
84 None => unreachable!(),
85 };
86
87 #[inline]
88 pub const fn new() -> Self {
89 let () = Self::ASSERT;
90 Self {
91 len: Self::EMPTY_LEN,
92 cap: INLINE as u8,
93 data: Data {
94 inline: ManuallyDrop::new([const { MaybeUninit::uninit() }; INLINE]),
95 },
96 }
97 }
98
99 #[inline]
102 pub fn with_capacity(capacity: usize) -> Self {
103 let () = Self::ASSERT;
104 if capacity <= INLINE {
105 return Self::new();
106 }
107 let cap = capacity.min(MAX);
108 let heap = Self::alloc(cap);
109 Self {
110 len: Self::EMPTY_LEN,
111 cap: cap as u8,
112 data: Data { heap },
113 }
114 }
115
116 #[inline]
117 const fn is_spilled(&self) -> bool {
118 self.cap as usize > INLINE
119 }
120
121 #[inline]
122 pub const fn len(&self) -> usize {
123 (self.len.get() - 1) as usize
124 }
125
126 #[inline]
127 pub const fn is_empty(&self) -> bool {
128 self.len.get() == 1
129 }
130
131 #[inline]
132 pub const fn capacity(&self) -> usize {
133 self.cap as usize
134 }
135
136 #[inline]
140 fn set_len(&mut self, actual: usize) {
141 debug_assert!(actual <= self.capacity());
142 debug_assert!(actual <= MAX);
143 self.len = unsafe { NonZeroU8::new_unchecked(actual as u8 + 1u8) };
145 }
146
147 #[inline]
149 fn as_ptr(&self) -> *const T {
150 if self.is_spilled() {
151 unsafe { self.data.heap.as_ptr() as *const T }
153 } else {
154 unsafe { (*ptr::addr_of!(self.data.inline)).as_ptr().cast::<T>() }
156 }
157 }
158
159 #[inline]
160 fn as_mut_ptr(&mut self) -> *mut T {
161 if self.is_spilled() {
162 unsafe { self.data.heap.as_ptr() }
164 } else {
165 unsafe {
167 (*ptr::addr_of_mut!(self.data.inline))
168 .as_mut_ptr()
169 .cast::<T>()
170 }
171 }
172 }
173
174 #[inline]
175 pub fn as_slice(&self) -> &[T] {
176 unsafe { std::slice::from_raw_parts(self.as_ptr(), self.len()) }
178 }
179
180 #[inline]
181 pub fn as_mut_slice(&mut self) -> &mut [T] {
182 let len = self.len();
183 unsafe { std::slice::from_raw_parts_mut(self.as_mut_ptr(), len) }
185 }
186
187 #[inline]
188 pub fn iter(&self) -> Iter<'_, T> {
189 self.as_slice().iter()
190 }
191
192 #[inline]
193 pub fn iter_mut(&mut self) -> IterMut<'_, T> {
194 self.as_mut_slice().iter_mut()
195 }
196
197 #[inline]
198 pub fn last_mut(&mut self) -> Option<&mut T> {
199 self.as_mut_slice().last_mut()
200 }
201
202 #[inline]
205 fn layout(cap: usize) -> Layout {
206 Layout::array::<T>(cap).expect("TinyVec allocation layout overflow")
207 }
208
209 #[inline]
215 unsafe fn dealloc(ptr: NonNull<T>, cap: usize) {
216 let layout = Self::layout(cap);
217 if layout.size() == 0 {
218 return;
219 }
220 unsafe { alloc::dealloc(ptr.as_ptr() as *mut u8, layout) }
223 }
224
225 fn alloc(cap: usize) -> NonNull<T> {
229 debug_assert!(cap > 0);
230 let layout = Self::layout(cap);
231 if layout.size() == 0 {
232 return NonNull::dangling();
234 }
235 let ptr = unsafe { alloc::alloc(layout) } as *mut T;
237 match NonNull::new(ptr) {
238 Some(p) => p,
239 None => alloc::handle_alloc_error(layout),
240 }
241 }
242
243 fn grow(&mut self) {
247 let old_cap = self.capacity();
248 debug_assert!(old_cap < MAX, "TinyVec grown past MAX");
249 let new_cap = (old_cap.max(1) * 2).clamp(INLINE + 1, MAX);
251 let len = self.len();
252
253 let new_heap = Self::alloc(new_cap);
254 unsafe {
258 ptr::copy_nonoverlapping(self.as_ptr(), new_heap.as_ptr(), len);
259 }
260 if self.is_spilled() {
261 unsafe {
264 let old = self.data.heap;
265 Self::dealloc(old, old_cap);
266 }
267 }
268 self.data = Data { heap: new_heap };
270 self.cap = new_cap as u8;
271 }
272
273 #[inline]
275 pub fn push(&mut self, value: T) {
276 let len = self.len();
277 if len == self.capacity() {
278 assert!(
283 len < MAX,
284 "TinyVec capacity overflow: already at MAX = {MAX}"
285 );
286 self.grow();
287 }
288 unsafe {
290 self.as_mut_ptr().add(len).write(value);
291 }
292 self.set_len(len + 1);
293 }
294
295 #[inline]
298 pub fn swap_remove(&mut self, index: usize) -> T {
299 let len = self.len();
300 assert!(index < len, "index out of bounds: {index} >= {len}");
301 let ptr = self.as_mut_ptr();
302 unsafe {
304 let out = ptr.add(index).read();
305 if index != len - 1 {
306 let last = ptr.add(len - 1).read();
307 ptr.add(index).write(last);
308 }
309 self.set_len(len - 1);
310 out
311 }
312 }
313
314 #[inline]
315 pub fn clear(&mut self) {
316 let len = self.len();
317 unsafe {
319 drop_in_place(slice_from_raw_parts_mut(self.as_mut_ptr(), len));
320 }
321 self.set_len(0);
322 }
323
324 #[inline]
327 unsafe fn dealloc_if_spilled(&mut self) {
328 if self.is_spilled() {
329 let cap = self.capacity();
330 unsafe {
332 Self::dealloc(self.data.heap, cap);
333 }
334 }
335 }
336
337 pub fn shrink_to_fit(&mut self) {
340 if !self.is_spilled() {
341 return;
342 }
343 let len = self.len();
344 if len <= INLINE {
345 let mut inline: [MaybeUninit<T>; INLINE] = [const { MaybeUninit::uninit() }; INLINE];
347 unsafe {
350 ptr::copy_nonoverlapping(
351 self.data.heap.as_ptr(),
352 inline.as_mut_ptr().cast::<T>(),
353 len,
354 );
355 let old = self.data.heap;
356 let old_cap = self.capacity();
357 self.data = Data {
358 inline: ManuallyDrop::new(inline),
359 };
360 self.cap = INLINE as u8;
361 Self::dealloc(old, old_cap);
362 }
363 } else if self.capacity() > len {
364 let new_heap = Self::alloc(len);
366 unsafe {
368 ptr::copy_nonoverlapping(self.data.heap.as_ptr(), new_heap.as_ptr(), len);
369 let old = self.data.heap;
370 let old_cap = self.capacity();
371 Self::dealloc(old, old_cap);
372 self.data = Data { heap: new_heap };
373 self.cap = len as u8;
374 }
375 }
376 }
377
378 #[inline]
380 pub fn drain(&mut self) -> Drain<'_, T, INLINE, MAX> {
381 let end = self.len();
382 self.set_len(0);
385 Drain {
386 vec: self,
387 idx: 0,
388 end,
389 }
390 }
391
392 pub fn reserve(&mut self, additional: usize) {
396 let needed = self.len() + additional;
397 if needed <= self.capacity() {
398 return;
399 }
400 let target = needed.min(MAX);
403 if target <= INLINE {
404 return;
405 }
406 let len = self.len();
407 let new_heap = Self::alloc(target);
408 unsafe {
411 ptr::copy_nonoverlapping(self.as_ptr(), new_heap.as_ptr(), len);
412 }
413 unsafe {
415 self.dealloc_if_spilled();
416 }
417 self.data = Data { heap: new_heap };
418 self.cap = target as u8;
419 }
420}
421
422impl<T, const INLINE: usize, const MAX: usize> TinyVec<T, INLINE, MAX> {
423 pub fn extend_exact<It>(&mut self, iter: It)
426 where
427 It: IntoIterator<Item = T>,
428 It::IntoIter: ExactSizeIterator,
429 {
430 let iter = iter.into_iter();
431 self.reserve(iter.len());
432 for item in iter {
433 self.push(item);
434 }
435 }
436}
437
438impl<T, const INLINE: usize, const MAX: usize> Default for TinyVec<T, INLINE, MAX> {
439 #[inline]
440 fn default() -> Self {
441 Self::new()
442 }
443}
444
445impl<T, const INLINE: usize, const MAX: usize> Drop for TinyVec<T, INLINE, MAX> {
446 #[inline]
447 fn drop(&mut self) {
448 let len = self.len();
449 unsafe {
452 drop_in_place(slice_from_raw_parts_mut(self.as_mut_ptr(), len));
453 self.dealloc_if_spilled();
454 }
455 }
456}
457
458impl<T: Clone, const INLINE: usize, const MAX: usize> Clone for TinyVec<T, INLINE, MAX> {
459 fn clone(&self) -> Self {
460 let mut out = Self::with_capacity(self.len());
461 for v in self.iter() {
462 out.push(v.clone());
463 }
464 out
465 }
466}
467
468impl<T, const INLINE: usize, const MAX: usize> ShrinkToFit for TinyVec<T, INLINE, MAX> {
469 #[inline]
470 fn shrink_to_fit(&mut self) {
471 Self::shrink_to_fit(self);
472 }
473}
474
475impl<T: Debug, const INLINE: usize, const MAX: usize> Debug for TinyVec<T, INLINE, MAX> {
476 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
477 f.debug_list().entries(self.iter()).finish()
478 }
479}
480
481impl<T, const INLINE: usize, const MAX: usize> Deref for TinyVec<T, INLINE, MAX> {
482 type Target = [T];
483 #[inline]
484 fn deref(&self) -> &[T] {
485 self.as_slice()
486 }
487}
488
489impl<T, const INLINE: usize, const MAX: usize> DerefMut for TinyVec<T, INLINE, MAX> {
490 #[inline]
491 fn deref_mut(&mut self) -> &mut [T] {
492 self.as_mut_slice()
493 }
494}
495
496impl<'a, T, const INLINE: usize, const MAX: usize> IntoIterator for &'a TinyVec<T, INLINE, MAX> {
497 type Item = &'a T;
498 type IntoIter = Iter<'a, T>;
499 #[inline]
500 fn into_iter(self) -> Self::IntoIter {
501 self.iter()
502 }
503}
504
505impl<'a, T, const INLINE: usize, const MAX: usize> IntoIterator
506 for &'a mut TinyVec<T, INLINE, MAX>
507{
508 type Item = &'a mut T;
509 type IntoIter = IterMut<'a, T>;
510 #[inline]
511 fn into_iter(self) -> Self::IntoIter {
512 self.iter_mut()
513 }
514}
515
516pub struct IntoIter<T, const INLINE: usize, const MAX: usize> {
518 vec: TinyVec<T, INLINE, MAX>,
519 idx: usize,
520 end: usize,
521}
522
523impl<T, const INLINE: usize, const MAX: usize> Iterator for IntoIter<T, INLINE, MAX> {
524 type Item = T;
525 #[inline]
526 fn next(&mut self) -> Option<T> {
527 if self.idx == self.end {
528 return None;
529 }
530 let v = unsafe { self.vec.as_ptr().add(self.idx).read() };
532 self.idx += 1;
533 Some(v)
534 }
535
536 #[inline]
537 fn size_hint(&self) -> (usize, Option<usize>) {
538 let rem = self.end - self.idx;
539 (rem, Some(rem))
540 }
541}
542
543impl<T, const INLINE: usize, const MAX: usize> ExactSizeIterator for IntoIter<T, INLINE, MAX> {}
544
545impl<T, const INLINE: usize, const MAX: usize> Drop for IntoIter<T, INLINE, MAX> {
546 fn drop(&mut self) {
547 unsafe {
551 let base = self.vec.as_mut_ptr();
552 drop_in_place(slice_from_raw_parts_mut(
553 base.add(self.idx),
554 self.end - self.idx,
555 ));
556 }
557 }
558}
559
560impl<T, const INLINE: usize, const MAX: usize> IntoIterator for TinyVec<T, INLINE, MAX> {
561 type Item = T;
562 type IntoIter = IntoIter<T, INLINE, MAX>;
563 #[inline]
564 fn into_iter(mut self) -> Self::IntoIter {
565 let end = self.len();
566 self.set_len(0);
569 IntoIter {
570 vec: self,
571 idx: 0,
572 end,
573 }
574 }
575}
576
577impl<T, const INLINE: usize, const MAX: usize> FromIterator<T> for TinyVec<T, INLINE, MAX> {
578 fn from_iter<It: IntoIterator<Item = T>>(iter: It) -> Self {
579 let iter = iter.into_iter();
580 let (lower, _) = iter.size_hint();
581 let mut out = Self::with_capacity(lower);
582 for v in iter {
583 out.push(v);
584 }
585 out
586 }
587}
588
589impl<T, const INLINE: usize, const MAX: usize> Extend<T> for TinyVec<T, INLINE, MAX> {
590 #[inline]
591 fn extend<It: IntoIterator<Item = T>>(&mut self, iter: It) {
592 for v in iter {
593 self.push(v);
594 }
595 }
596}
597
598pub struct Drain<'a, T, const INLINE: usize, const MAX: usize> {
600 vec: &'a mut TinyVec<T, INLINE, MAX>,
601 idx: usize,
602 end: usize,
603}
604
605impl<T, const INLINE: usize, const MAX: usize> Iterator for Drain<'_, T, INLINE, MAX> {
606 type Item = T;
607 #[inline]
608 fn next(&mut self) -> Option<T> {
609 if self.idx == self.end {
610 return None;
611 }
612 let v = unsafe { self.vec.as_ptr().add(self.idx).read() };
614 self.idx += 1;
615 Some(v)
616 }
617
618 #[inline]
619 fn size_hint(&self) -> (usize, Option<usize>) {
620 let rem = self.end - self.idx;
621 (rem, Some(rem))
622 }
623}
624
625impl<T, const INLINE: usize, const MAX: usize> ExactSizeIterator for Drain<'_, T, INLINE, MAX> {}
626
627impl<T, const INLINE: usize, const MAX: usize> Drop for Drain<'_, T, INLINE, MAX> {
628 fn drop(&mut self) {
629 unsafe {
631 let base = self.vec.as_mut_ptr();
632 drop_in_place(slice_from_raw_parts_mut(
633 base.add(self.idx),
634 self.end - self.idx,
635 ));
636 }
637 }
638}
639
640#[cfg(test)]
641mod tests {
642 use std::{cell::Cell, mem::size_of, num::NonZeroU32, rc::Rc};
643
644 use super::*;
645 use crate::MAX_USEFUL_LINEAR_SCAN;
646
647 #[allow(dead_code)]
650 enum MapLike<T, const INLINE: usize, const MAX: usize = MAX_USEFUL_LINEAR_SCAN> {
651 List(TinyVec<T, INLINE, MAX>),
652 Map(Box<u32>),
653 }
654
655 #[test]
656 #[cfg(target_pointer_width = "64")]
657 fn niche_and_sizes() {
658 type Tid = NonZeroU32;
659 assert_eq!(size_of::<TinyVec<(Tid, ()), 3>>(), 24);
661 assert_eq!(size_of::<MapLike<(Tid, ()), 3>>(), 24, "niche not folded");
662 assert_eq!(size_of::<MapLike<(Tid, ()), 0>>(), 16);
663 assert_eq!(size_of::<MapLike<(Tid, ()), 6>>(), 32);
664
665 assert_eq!(size_of::<TinyVec<u64, 0, 25>>(), 16);
669 assert_eq!(size_of::<TinyVec<u64, 0, 254>>(), 16); assert_eq!(
671 size_of::<MapLike<(Tid, ()), 0, 8>>(),
672 16,
673 "MAX must not affect layout"
674 );
675 }
676
677 #[test]
678 fn push_spill_and_back() {
679 let mut v: TinyVec<u32, 3> = TinyVec::new();
680 assert_eq!(v.capacity(), 3);
681 for i in 0..3 {
683 v.push(i);
684 }
685 assert_eq!(v.capacity(), 3);
686 assert_eq!(v.as_slice(), &[0, 1, 2]);
687 for i in 3..20 {
689 v.push(i);
690 }
691 assert_eq!(v.len(), 20);
692 assert!(v.capacity() > 3 && v.capacity() <= MAX_USEFUL_LINEAR_SCAN);
693 let got: Vec<u32> = v.iter().copied().collect();
694 assert_eq!(got, (0..20).collect::<Vec<_>>());
695 while v.len() > 2 {
697 v.swap_remove(v.len() - 1);
698 }
699 v.shrink_to_fit();
700 assert_eq!(v.capacity(), 3, "should return to inline storage");
701 assert_eq!(v.len(), 2);
702 }
703
704 #[test]
705 fn swap_remove_semantics() {
706 let mut v: TinyVec<u32, 4> = TinyVec::new();
707 v.extend([10, 20, 30, 40]);
708 assert_eq!(v.swap_remove(1), 20); let mut got: Vec<u32> = v.iter().copied().collect();
710 got.sort();
711 assert_eq!(got, vec![10, 30, 40]);
712 }
713
714 #[test]
715 fn drains_and_reuses() {
716 let mut v: TinyVec<u32, 2> = TinyVec::new();
717 v.extend([1, 2, 3, 4, 5]); let drained: Vec<u32> = v.drain().collect();
719 assert_eq!(drained, vec![1, 2, 3, 4, 5]);
720 assert!(v.is_empty());
721 v.push(99);
723 assert_eq!(v.as_slice(), &[99]);
724 }
725
726 struct DropTok(Rc<Cell<i32>>);
729 impl DropTok {
730 fn new(c: &Rc<Cell<i32>>) -> Self {
731 c.set(c.get() + 1);
732 Self(c.clone())
733 }
734 }
735 impl Drop for DropTok {
736 fn drop(&mut self) {
737 self.0.set(self.0.get() - 1);
738 }
739 }
740
741 fn assert_balanced(f: impl FnOnce(&Rc<Cell<i32>>)) {
742 let live = Rc::new(Cell::new(0));
743 f(&live);
744 assert_eq!(live.get(), 0, "unbalanced drops (leak or double free)");
745 }
746
747 #[test]
748 fn drop_paths() {
749 assert_balanced(|c| {
751 let mut v: TinyVec<DropTok, 4> = TinyVec::new();
752 v.push(DropTok::new(c));
753 v.push(DropTok::new(c));
754 });
755 assert_balanced(|c| {
757 let mut v: TinyVec<DropTok, 2> = TinyVec::new();
758 for _ in 0..10 {
759 v.push(DropTok::new(c));
760 }
761 });
762 assert_balanced(|c| {
764 let mut v: TinyVec<DropTok, 2> = TinyVec::new();
765 for _ in 0..6 {
766 v.push(DropTok::new(c));
767 }
768 v.clear();
769 assert!(v.is_empty());
770 });
771 assert_balanced(|c| {
773 let mut v: TinyVec<DropTok, 2> = TinyVec::new();
774 for _ in 0..6 {
775 v.push(DropTok::new(c));
776 }
777 let mut it = v.into_iter();
778 drop(it.next());
779 drop(it.next());
780 });
782 assert_balanced(|c| {
784 let mut v: TinyVec<DropTok, 4> = TinyVec::new();
785 for _ in 0..3 {
786 v.push(DropTok::new(c));
787 }
788 let mut d = v.drain();
789 drop(d.next());
790 drop(d); });
792 assert_balanced(|c| {
794 let mut v: TinyVec<DropTok, 4> = TinyVec::new();
795 for _ in 0..4 {
796 v.push(DropTok::new(c));
797 }
798 let x = v.swap_remove(0);
799 drop(x);
800 });
802 assert_balanced(|c| {
804 let mut v: TinyVec<DropTok, 3> = TinyVec::new();
805 for _ in 0..8 {
806 v.push(DropTok::new(c));
807 }
808 while v.len() > 2 {
809 drop(v.swap_remove(0));
810 }
811 v.shrink_to_fit();
812 assert_eq!(v.capacity(), 3);
813 assert_eq!(v.len(), 2);
814 });
815 }
816
817 #[test]
818 fn clone_matches() {
819 let mut v: TinyVec<u32, 2> = TinyVec::new();
820 v.extend([1, 2, 3, 4]); let c = v.clone();
822 assert_eq!(
823 v.iter().copied().collect::<Vec<_>>(),
824 c.iter().copied().collect::<Vec<_>>()
825 );
826 }
827
828 #[test]
829 fn zst_elements() {
830 let mut v: TinyVec<(), 1> = TinyVec::new();
832 for _ in 0..10 {
833 v.push(());
834 }
835 assert_eq!(v.len(), 10);
836 assert_eq!(v.iter().count(), 10);
837 v.clear();
838 assert!(v.is_empty());
839 }
840
841 #[test]
845 fn heap_only_push_grows() {
846 let mut v: TinyVec<u32, 0> = TinyVec::new();
847 assert_eq!(v.capacity(), 0);
848 for i in 0..20 {
849 v.push(i);
850 }
851 assert_eq!(v.len(), 20);
852 assert_eq!(
853 v.iter().copied().collect::<Vec<_>>(),
854 (0..20).collect::<Vec<_>>()
855 );
856 }
857
858 #[test]
859 fn extend_exact_reserves_once() {
860 let mut v: TinyVec<u32, 0> = TinyVec::new();
861 v.extend_exact(0..10);
862 assert_eq!(v.len(), 10);
863 assert_eq!(v.capacity(), 10);
865 v.extend_exact(10..15);
866 assert_eq!(
867 v.iter().copied().collect::<Vec<_>>(),
868 (0..15).collect::<Vec<_>>()
869 );
870 }
871
872 #[test]
874 fn tight_max_caps_growth_exactly() {
875 let mut v: TinyVec<u32, 0, 5> = TinyVec::new();
876 for i in 0..5 {
877 v.push(i);
878 }
879 assert_eq!(v.len(), 5);
880 assert_eq!(v.capacity(), 5, "growth must cap at MAX, not overshoot");
881 }
882
883 #[test]
884 #[should_panic(expected = "TinyVec capacity overflow")]
885 fn tight_max_panics_at_limit() {
886 let mut v: TinyVec<u32, 0, 3> = TinyVec::new();
887 for i in 0..3 {
888 v.push(i);
889 }
890 v.push(3); }
892
893 #[test]
897 fn tight_max_growth_schedule() {
898 let mut v: TinyVec<u32, 0, 10> = TinyVec::new();
899 let mut last = 0;
900 let mut changes = Vec::new();
901 for i in 0..10 {
902 v.push(i);
903 if v.capacity() != last {
904 changes.push(v.capacity());
905 last = v.capacity();
906 }
907 }
908 assert_eq!(changes, vec![2, 4, 8, 10]);
909 }
910}