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