1use std::{
26 alloc::{Layout, alloc, dealloc, handle_alloc_error},
27 fmt,
28 marker::PhantomData,
29 mem::ManuallyDrop,
30 ptr::{self, NonNull},
31};
32
33pub struct TinyVec<T, const MAX: u8 = { u8::MAX }> {
36 ptr: NonNull<T>,
38 len: u8,
39 cap: u8,
40 _marker: PhantomData<T>,
42}
43
44unsafe impl<T: Send, const MAX: u8> Send for TinyVec<T, MAX> {}
47unsafe impl<T: Sync, const MAX: u8> Sync for TinyVec<T, MAX> {}
48
49impl<T, const MAX: u8> Default for TinyVec<T, MAX> {
50 fn default() -> Self {
51 Self::new()
52 }
53}
54
55impl<T, const MAX: u8> TinyVec<T, MAX> {
56 const _ASSERT_MAX_NONZERO: () = assert!(MAX > 0, "TinyVec MAX must be > 0");
60
61 const fn new() -> Self {
62 #[allow(clippy::let_unit_value)]
66 let _: () = Self::_ASSERT_MAX_NONZERO;
67 Self {
68 ptr: NonNull::dangling(),
69 len: 0,
70 cap: 0,
71 _marker: PhantomData,
72 }
73 }
74
75 pub fn retain_mut(&mut self, f: impl FnMut(&mut T) -> bool) {
84 if self.len == 0 {
85 return;
86 }
87
88 let ptr = self.ptr.as_ptr();
93 let len = self.len as usize;
94 let cap = self.cap as usize;
95 self.cap = 0;
96 self.len = 0;
97
98 let mut vec = unsafe { Vec::from_raw_parts(ptr, len, cap) };
101 vec.retain_mut(f);
102
103 let (new_ptr, new_len, new_cap) = vec.into_raw_parts();
106 debug_assert_eq!(new_cap, cap);
107 self.ptr = unsafe { NonNull::new_unchecked(new_ptr) };
109 self.len = new_len as u8;
110 self.cap = new_cap as u8;
111 }
112
113 #[inline]
114 pub fn len(&self) -> usize {
115 self.len as usize
116 }
117
118 #[inline]
121 pub fn is_empty(&self) -> bool {
122 self.len == 0
123 }
124
125 #[cfg(test)]
127 #[inline]
128 fn capacity(&self) -> usize {
129 self.cap as usize
130 }
131
132 #[inline]
136 fn as_slice(&self) -> &[T] {
137 unsafe { std::slice::from_raw_parts(self.ptr.as_ptr(), self.len()) }
140 }
141
142 #[inline]
143 fn as_mut_slice(&mut self) -> &mut [T] {
144 unsafe { std::slice::from_raw_parts_mut(self.ptr.as_ptr(), self.len()) }
146 }
147
148 pub fn push(&mut self, value: T) {
150 if self.len == self.cap {
151 assert!(
155 (self.len as usize) < MAX as usize,
156 "TinyVec capacity overflow: already at MAX = {MAX}",
157 );
158 self.grow_by_one();
159 }
160 unsafe {
163 ptr::write(self.ptr.as_ptr().add(self.len()), value);
164 }
165 self.len += 1;
166 }
167
168 pub fn swap_remove(&mut self, idx: usize) -> T {
171 let len = self.len();
172 assert!(idx < len, "swap_remove index out of bounds: {idx} >= {len}");
173 unsafe {
175 let last = self.ptr.as_ptr().add(len - 1);
176 let hole = self.ptr.as_ptr().add(idx);
177 let value = ptr::read(hole);
178 if idx != len - 1 {
179 ptr::copy_nonoverlapping(last, hole, 1);
180 }
181 self.len -= 1;
182 value
183 }
184 }
185
186 fn reserve(&mut self, additional: usize) {
191 let needed = self.len() + additional;
192 if needed <= self.cap as usize {
193 return;
194 }
195 let target = needed.next_power_of_two().max(4).min(MAX as usize);
197 self.realloc_to(target);
198 }
199
200 #[cold]
203 #[inline(never)]
204 fn grow_by_one(&mut self) {
205 let doubled = if self.cap == 0 {
206 4
207 } else {
208 (self.cap as usize) * 2
209 };
210 let new_cap = doubled.min(MAX as usize);
211 self.realloc_to(new_cap);
212 }
213
214 fn realloc_to(&mut self, new_cap: usize) {
215 assert!(
216 new_cap <= MAX as usize,
217 "TinyVec capacity overflow: requested {new_cap}, max {MAX}",
218 );
219 if new_cap == self.cap as usize {
220 return;
221 }
222 if size_of::<T>() == 0 {
223 self.cap = new_cap as u8;
225 return;
226 }
227
228 let new_layout = Layout::array::<T>(new_cap).expect("TinyVec layout overflow");
230 let new_ptr = unsafe { alloc(new_layout) } as *mut T;
233 let new_ptr = match NonNull::new(new_ptr) {
234 Some(p) => p,
235 None => handle_alloc_error(new_layout),
236 };
237
238 if self.cap > 0 {
240 unsafe {
243 ptr::copy_nonoverlapping(self.ptr.as_ptr(), new_ptr.as_ptr(), self.len());
244 }
245 self.deallocate_old();
246 }
247
248 self.ptr = new_ptr;
249 self.cap = new_cap as u8;
250 }
251
252 #[inline]
258 fn deallocate_old(&mut self) {
259 if self.cap == 0 || size_of::<T>() == 0 {
260 return;
261 }
262 let old_layout =
263 Layout::array::<T>(self.cap as usize).expect("TinyVec layout was valid when allocated");
264 unsafe {
266 dealloc(self.ptr.as_ptr() as *mut u8, old_layout);
267 }
268 }
269
270 pub fn shrink_to_fit(&mut self) {
272 if (self.len as usize) == (self.cap as usize) {
273 return;
274 }
275 if self.len == 0 {
276 self.deallocate_old();
278 self.ptr = NonNull::dangling();
279 self.cap = 0;
280 return;
281 }
282 let new_cap = self.len as usize;
283 let new_layout = Layout::array::<T>(new_cap).expect("TinyVec layout overflow");
285 let new_ptr = unsafe { alloc(new_layout) } as *mut T;
288 let new_ptr = match NonNull::new(new_ptr) {
289 Some(p) => p,
290 None => handle_alloc_error(new_layout),
291 };
292 unsafe {
294 ptr::copy_nonoverlapping(self.ptr.as_ptr(), new_ptr.as_ptr(), self.len());
295 }
296 self.deallocate_old();
297 self.ptr = new_ptr;
298 self.cap = new_cap as u8;
299 }
300}
301
302impl<T, const MAX: u8> std::ops::Deref for TinyVec<T, MAX> {
306 type Target = [T];
307 fn deref(&self) -> &[T] {
308 self.as_slice()
309 }
310}
311
312impl<T, const MAX: u8> std::ops::DerefMut for TinyVec<T, MAX> {
313 fn deref_mut(&mut self) -> &mut [T] {
314 self.as_mut_slice()
315 }
316}
317
318impl<T, const MAX: u8> TinyVec<T, MAX> {
319 pub fn extend_exact<I>(&mut self, iter: I)
326 where
327 I: IntoIterator<Item = T>,
328 I::IntoIter: ExactSizeIterator,
329 {
330 let iter = iter.into_iter();
331 self.reserve(iter.len());
332 for item in iter {
333 self.push(item);
334 }
335 }
336}
337
338impl<T, const MAX: u8> IntoIterator for TinyVec<T, MAX> {
339 type Item = T;
340 type IntoIter = std::vec::IntoIter<T>;
341
342 fn into_iter(self) -> Self::IntoIter {
343 let me = ManuallyDrop::new(self);
346 unsafe { Vec::from_raw_parts(me.ptr.as_ptr(), me.len as usize, me.cap as usize) }
349 .into_iter()
350 }
351}
352
353impl<'a, T, const MAX: u8> IntoIterator for &'a TinyVec<T, MAX> {
358 type Item = &'a T;
359 type IntoIter = std::slice::Iter<'a, T>;
360 fn into_iter(self) -> std::slice::Iter<'a, T> {
361 self.as_slice().iter()
362 }
363}
364
365impl<'a, T, const MAX: u8> IntoIterator for &'a mut TinyVec<T, MAX> {
366 type Item = &'a mut T;
367 type IntoIter = std::slice::IterMut<'a, T>;
368 fn into_iter(self) -> std::slice::IterMut<'a, T> {
369 self.as_mut_slice().iter_mut()
370 }
371}
372
373impl<T: fmt::Debug, const MAX: u8> fmt::Debug for TinyVec<T, MAX> {
374 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
375 f.debug_list().entries(self.iter()).finish()
376 }
377}
378
379impl<T, const MAX: u8> Drop for TinyVec<T, MAX> {
380 #[inline]
381 fn drop(&mut self) {
382 if self.cap == 0 {
386 return;
387 }
388 if self.len > 0 {
390 unsafe {
392 ptr::drop_in_place(std::ptr::slice_from_raw_parts_mut(
393 self.ptr.as_ptr(),
394 self.len(),
395 ));
396 }
397 }
398 self.deallocate_old();
399 }
400}
401
402impl<T, const MAX: u8> shrink_to_fit::ShrinkToFit for TinyVec<T, MAX> {
403 fn shrink_to_fit(&mut self) {
404 Self::shrink_to_fit(self);
405 }
406}
407
408#[cfg(test)]
409mod tests {
410 use super::*;
411
412 fn from_exact<T, I, const MAX: u8>(iter: I) -> TinyVec<T, MAX>
415 where
416 I: IntoIterator<Item = T>,
417 I::IntoIter: ExactSizeIterator,
418 {
419 let mut v = TinyVec::new();
420 v.extend_exact(iter);
421 v
422 }
423
424 #[test]
425 fn size() {
426 assert_eq!(std::mem::size_of::<TinyVec<u64>>(), 16);
428 assert_eq!(std::mem::size_of::<TinyVec<[u8; 48]>>(), 16);
429 }
430
431 #[test]
432 fn push_iter_swap_remove() {
433 let mut v: TinyVec<u32> = TinyVec::new();
434 assert!(v.is_empty());
435 v.push(10);
436 v.push(20);
437 v.push(30);
438 assert_eq!(v.len(), 3);
439 assert_eq!(v.iter().copied().collect::<Vec<_>>(), vec![10, 20, 30]);
440 let removed = v.swap_remove(0);
441 assert_eq!(removed, 10);
442 assert_eq!(v.iter().copied().collect::<Vec<_>>(), vec![30, 20]);
444 assert_eq!(v[0], 30);
445 assert_eq!(v[1], 20);
446 }
447
448 #[test]
449 fn growth_pattern() {
450 let mut v: TinyVec<u32> = TinyVec::new();
451 for i in 0..32u32 {
452 v.push(i);
453 }
454 assert_eq!(v.len(), 32);
455 let collected: Vec<u32> = v.iter().copied().collect();
456 assert_eq!(collected, (0..32).collect::<Vec<_>>());
457 }
458
459 #[test]
460 fn extend_and_reserve() {
461 let mut v: TinyVec<u32> = TinyVec::new();
462 v.extend_exact(0..10);
463 assert_eq!(v.len(), 10);
464 v.reserve(5);
465 assert!(v.capacity() >= 15);
466 }
467
468 #[test]
469 fn last_mut_and_index_mut() {
470 let mut v: TinyVec<u32> = TinyVec::new();
471 v.push(1);
472 v.push(2);
473 *v.last_mut().unwrap() = 99;
474 assert_eq!(v[1], 99);
475 v[0] = 7;
476 assert_eq!(v[0], 7);
477 }
478
479 #[test]
480 fn drop_runs_on_elements() {
481 use std::sync::atomic::{AtomicUsize, Ordering};
482
483 struct DropCounter<'a>(&'a AtomicUsize);
484 impl<'a> Drop for DropCounter<'a> {
485 fn drop(&mut self) {
486 self.0.fetch_add(1, Ordering::SeqCst);
487 }
488 }
489
490 let count = AtomicUsize::new(0);
491 {
492 let mut v: TinyVec<DropCounter<'_>> = TinyVec::new();
493 v.push(DropCounter(&count));
494 v.push(DropCounter(&count));
495 v.push(DropCounter(&count));
496 }
497 assert_eq!(count.load(Ordering::SeqCst), 3);
498 }
499
500 #[test]
501 fn into_iter_drops_and_yields() {
502 use std::sync::atomic::{AtomicUsize, Ordering};
503
504 struct DropCounter<'a>(&'a AtomicUsize, u32);
505 impl<'a> Drop for DropCounter<'a> {
506 fn drop(&mut self) {
507 self.0.fetch_add(1, Ordering::SeqCst);
508 }
509 }
510
511 let count = AtomicUsize::new(0);
512 let mut v: TinyVec<DropCounter<'_>> = TinyVec::new();
513 v.push(DropCounter(&count, 1));
514 v.push(DropCounter(&count, 2));
515 v.push(DropCounter(&count, 3));
516
517 let mut iter = v.into_iter();
518 assert_eq!(iter.next().unwrap().1, 1);
519 assert_eq!(iter.next().unwrap().1, 2);
520 drop(iter);
522 assert_eq!(count.load(Ordering::SeqCst), 3);
524 }
525
526 #[test]
527 fn shrink_to_fit_releases_buffer() {
528 let mut v: TinyVec<u32> = TinyVec::new();
529 v.extend_exact(0..10);
530 assert!(v.capacity() >= 10);
531 for _ in 0..10 {
532 v.swap_remove(0);
533 }
534 assert!(v.is_empty());
535 v.shrink_to_fit();
536 assert_eq!(v.capacity(), 0);
537 }
538
539 #[test]
540 #[should_panic(expected = "TinyVec capacity overflow")]
541 fn capacity_overflow_panics() {
542 let mut v: TinyVec<u8> = TinyVec::new();
543 for _ in 0..255u32 {
544 v.push(0);
545 }
546 v.push(0);
548 }
549
550 #[test]
553 fn tight_max_caps_growth_exactly() {
554 let mut v: TinyVec<u32, 5> = TinyVec::new();
555 for i in 0..5 {
556 v.push(i);
557 }
558 assert_eq!(v.len(), 5);
559 assert_eq!(v.capacity(), 5);
561 }
562
563 #[test]
564 #[should_panic(expected = "TinyVec capacity overflow")]
565 fn tight_max_panics_at_limit() {
566 let mut v: TinyVec<u32, 3> = TinyVec::new();
567 v.push(0);
568 v.push(1);
569 v.push(2);
570 v.push(3);
572 }
573
574 #[test]
577 fn tight_max_growth_schedule() {
578 let mut v: TinyVec<u32, 10> = TinyVec::new();
579 let mut last_cap = 0;
580 let mut cap_changes = Vec::new();
581 for i in 0..10 {
582 v.push(i);
583 if v.capacity() != last_cap {
584 cap_changes.push(v.capacity());
585 last_cap = v.capacity();
586 }
587 }
588 assert_eq!(cap_changes, vec![4, 8, 10]);
589 }
590
591 #[test]
592 fn retain_mut_basic() {
593 let mut v: TinyVec<u32> = from_exact(0..10);
594 v.retain_mut(|x| *x % 2 == 0);
595 assert_eq!(v.iter().copied().collect::<Vec<_>>(), vec![0, 2, 4, 6, 8]);
596 assert!(v.capacity() >= 5);
598 }
599
600 #[test]
601 fn retain_mut_can_mutate() {
602 let mut v: TinyVec<u32> = from_exact(0..5);
603 v.retain_mut(|x| {
604 *x *= 10;
605 *x != 30
606 });
607 assert_eq!(v.iter().copied().collect::<Vec<_>>(), vec![0, 10, 20, 40]);
608 }
609
610 #[test]
611 fn retain_mut_empty() {
612 let mut v: TinyVec<u32> = TinyVec::new();
613 v.retain_mut(|_| panic!("should not be called for empty"));
614 assert!(v.is_empty());
615 }
616
617 #[test]
618 fn retain_mut_keeps_all() {
619 let mut v: TinyVec<u32> = from_exact(0..5);
620 v.retain_mut(|_| true);
621 assert_eq!(v.iter().copied().collect::<Vec<_>>(), vec![0, 1, 2, 3, 4]);
622 }
623
624 #[test]
625 fn retain_mut_removes_all() {
626 let mut v: TinyVec<u32> = from_exact(0..5);
627 v.retain_mut(|_| false);
628 assert!(v.is_empty());
629 }
630
631 #[test]
633 fn retain_mut_panic_safety() {
634 let result = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| {
635 let mut v: TinyVec<u32> = from_exact(0..10);
636 v.retain_mut(|x| {
637 if *x == 5 {
638 panic!("boom");
639 }
640 true
641 });
642 }));
643 assert!(result.is_err());
644 }
645
646 #[test]
648 fn retain_mut_element_drop_panic() {
649 use std::sync::atomic::{AtomicUsize, Ordering};
650
651 struct PanicyDrop<'a>(u32, &'a AtomicUsize);
652 impl Drop for PanicyDrop<'_> {
653 fn drop(&mut self) {
654 self.1.fetch_add(1, Ordering::SeqCst);
655 if self.0 == 5 && !std::thread::panicking() {
656 panic!("boom from drop");
657 }
658 }
659 }
660
661 let drop_count = AtomicUsize::new(0);
662 let result = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| {
663 let mut v: TinyVec<PanicyDrop<'_>> =
664 from_exact((0..10).map(|i| PanicyDrop(i, &drop_count)));
665 v.retain_mut(|x| x.0 != 5); }));
668 assert!(result.is_err() || drop_count.load(Ordering::SeqCst) > 0);
670 }
671}