qudit_core/utils/compact.rs
1use super::LimitedSizeVec;
2use super::storage::CompactStorage;
3use std::any::TypeId;
4use std::hash::Hash;
5
6const INLINE_CAPACITY: usize = 7;
7
8/// A space-efficient vector that stores small collections inline and transitions to heap allocation when needed.
9///
10/// `CompactVec` optimizes memory usage by storing up to INLINE_CAPACITY elements directly inline without heap allocation,
11/// automatically transitioning to heap storage when the capacity is exceeded or when inline storage
12/// cannot represent certain values.
13///
14/// # Examples
15///
16/// ```
17/// # use qudit_core::CompactVec;
18/// let mut vec: CompactVec<i8> = CompactVec::new();
19/// vec.push(1);
20/// vec.push(2);
21/// vec.push(3);
22/// assert_eq!(vec.len(), 3);
23/// assert!(vec.is_inline());
24/// ```
25#[derive(Debug, Clone)]
26pub enum CompactVec<T: CompactStorage> {
27 /// Inline storage for up to INLINE_CAPACITY elements.
28 Inline([T::InlineType; INLINE_CAPACITY], u8),
29
30 /// Heap storage for more than INLINE_CAPACITY elements.
31 Heap(LimitedSizeVec<T>),
32}
33
34impl<T: CompactStorage> CompactVec<T> {
35 /// Creates a new empty `CompactVec` using inline storage.
36 ///
37 /// The vector starts with inline storage and can hold up to INLINE_CAPACITY elements
38 /// before transitioning to heap allocation.
39 ///
40 /// # Examples
41 ///
42 /// ```
43 /// # use qudit_core::CompactVec;
44 /// let vec: CompactVec<i8> = CompactVec::new();
45 /// assert_eq!(vec.len(), 0);
46 /// assert!(vec.is_inline());
47 /// ```
48 #[inline]
49 pub fn new() -> Self {
50 CompactVec::Inline([T::InlineType::default(); INLINE_CAPACITY], 0)
51 }
52
53 /// Transitions the vector from inline storage to heap storage.
54 ///
55 /// This method converts all inline-stored elements to their full representation
56 /// and moves them to a heap-allocated vector. It's called automatically when
57 /// inline storage is insufficient (either due to capacity or representation limits).
58 ///
59 /// Returns a mutable reference to the heap vector for immediate use.
60 #[inline]
61 fn transition_to_heap(&mut self) -> &mut LimitedSizeVec<T> {
62 match self {
63 CompactVec::Inline(storage, length) => {
64 let mut heap_vec = LimitedSizeVec::new();
65 for i in 0..*length {
66 heap_vec.push(T::from_inline(storage[i as usize]));
67 }
68 *self = CompactVec::Heap(heap_vec);
69 match self {
70 CompactVec::Heap(vec) => vec,
71 _ => unreachable!(),
72 }
73 }
74 CompactVec::Heap(vec) => vec,
75 }
76 }
77
78 /// Fast push for types where conversion is infallible (i8, u8)
79 /// Appends an element to the back of the collection without checking conversion validity.
80 ///
81 /// This method provides optimal performance for types with infallible inline conversions
82 /// (such as `i8` and `u8`) by skipping runtime conversion checks.
83 ///
84 /// # Safety
85 ///
86 /// This method should only be used with types where `T::CONVERSION_INFALLIBLE` is true.
87 /// Using it with other types may cause debug assertions to fail.
88 ///
89 /// # Examples
90 ///
91 /// ```
92 /// # use qudit_core::CompactVec;
93 /// let mut vec: CompactVec<i8> = CompactVec::new();
94 /// vec.push_unchecked(42);
95 /// vec.push_unchecked(-10);
96 /// assert_eq!(vec.len(), 2);
97 /// ```
98 #[inline]
99 pub fn push_unchecked(&mut self, value: T) {
100 debug_assert!(
101 T::CONVERSION_INFALLIBLE,
102 "push_unchecked only valid for infallible types"
103 );
104
105 match self {
106 CompactVec::Inline(storage, length) => {
107 if (*length as usize) < INLINE_CAPACITY {
108 storage[*length as usize] = T::to_inline_unchecked(value);
109 *length += 1;
110 } else {
111 self.transition_to_heap().push(value);
112 }
113 }
114 CompactVec::Heap(vec) => {
115 vec.push(value);
116 }
117 }
118 }
119
120 /// Appends an element to the back of the collection.
121 ///
122 /// If the vector is using inline storage and has capacity, the element is stored inline.
123 /// If inline storage cannot represent the value or is full, the vector transitions to heap storage.
124 ///
125 /// # Examples
126 ///
127 /// ```
128 /// # use qudit_core::CompactVec;
129 /// let mut vec: CompactVec<i8> = CompactVec::new();
130 /// vec.push(1);
131 /// vec.push(2);
132 /// assert_eq!(vec.len(), 2);
133 /// ```
134 #[inline]
135 pub fn push(&mut self, value: T) {
136 // Fast path for infallible conversions
137 if T::CONVERSION_INFALLIBLE {
138 self.push_unchecked(value);
139 return;
140 }
141
142 match self {
143 CompactVec::Inline(storage, length) => {
144 if (*length as usize) < INLINE_CAPACITY {
145 match T::to_inline(value) {
146 Ok(inline_value) => {
147 storage[*length as usize] = inline_value;
148 *length += 1;
149 }
150 Err(original_value) => {
151 self.transition_to_heap().push(original_value);
152 }
153 }
154 } else {
155 self.transition_to_heap().push(value);
156 }
157 }
158 CompactVec::Heap(vec) => {
159 vec.push(value);
160 }
161 }
162 }
163
164 /// Removes the last element from the vector and returns it, or `None` if empty.
165 ///
166 /// # Examples
167 ///
168 /// ```
169 /// # use qudit_core::CompactVec;
170 /// let mut vec: CompactVec<i8> = CompactVec::new();
171 /// vec.push(1);
172 /// vec.push(2);
173 /// assert_eq!(vec.pop(), Some(2));
174 /// assert_eq!(vec.pop(), Some(1));
175 /// assert_eq!(vec.pop(), None);
176 /// ```
177 #[inline]
178 pub fn pop(&mut self) -> Option<T> {
179 match self {
180 CompactVec::Inline(storage, length) => {
181 if *length > 0 {
182 *length -= 1;
183 Some(T::from_inline(storage[*length as usize]))
184 } else {
185 None
186 }
187 }
188 CompactVec::Heap(vec) => vec.pop(),
189 }
190 }
191
192 /// Returns the number of elements in the vector.
193 ///
194 /// # Examples
195 ///
196 /// ```
197 /// # use qudit_core::CompactVec;
198 /// let mut vec: CompactVec<i8> = CompactVec::new();
199 /// assert_eq!(vec.len(), 0);
200 /// vec.push(1);
201 /// assert_eq!(vec.len(), 1);
202 /// ```
203 #[inline]
204 pub fn len(&self) -> usize {
205 match self {
206 CompactVec::Inline(_, length) => *length as usize,
207 CompactVec::Heap(vec) => vec.len(),
208 }
209 }
210
211 /// Returns `true` if the vector contains no elements.
212 ///
213 /// # Examples
214 ///
215 /// ```
216 /// # use qudit_core::CompactVec;
217 /// let mut vec: CompactVec<i8> = CompactVec::new();
218 /// assert!(vec.is_empty());
219 /// vec.push(1);
220 /// assert!(!vec.is_empty());
221 /// ```
222 #[inline]
223 pub fn is_empty(&self) -> bool {
224 self.len() == 0
225 }
226
227 /// Returns a copy of the element at the given index, or `None` if the index is out of bounds.
228 ///
229 /// # Examples
230 ///
231 /// ```
232 /// # use qudit_core::CompactVec;
233 /// let mut vec: CompactVec<i8> = CompactVec::new();
234 /// vec.push(10);
235 /// vec.push(20);
236 /// assert_eq!(vec.get(0), Some(10));
237 /// assert_eq!(vec.get(1), Some(20));
238 /// assert_eq!(vec.get(2), None);
239 /// ```
240 #[inline]
241 pub fn get(&self, index: usize) -> Option<T> {
242 match self {
243 CompactVec::Inline(storage, length) => {
244 if index < *length as usize {
245 Some(T::from_inline(storage[index]))
246 } else {
247 None
248 }
249 }
250 CompactVec::Heap(vec) => vec.get(index).copied(),
251 }
252 }
253
254 /// Returns a copy of the element at the given index without bounds checking.
255 ///
256 /// This provides optimal performance when the caller can guarantee the index is valid.
257 ///
258 /// # Safety
259 ///
260 /// Calling this method with an out-of-bounds index is undefined behavior,
261 /// even with a safe type `T`.
262 ///
263 /// # Examples
264 ///
265 /// ```
266 /// # use qudit_core::CompactVec;
267 /// let mut vec: CompactVec<i8> = CompactVec::new();
268 /// vec.push(42);
269 /// unsafe {
270 /// assert_eq!(vec.get_unchecked(0), 42);
271 /// }
272 /// ```
273 #[inline]
274 pub unsafe fn get_unchecked(&self, index: usize) -> T {
275 unsafe {
276 match self {
277 CompactVec::Inline(storage, _) => T::from_inline(*storage.get_unchecked(index)),
278 CompactVec::Heap(vec) => *vec.get_unchecked(index),
279 }
280 }
281 }
282
283 /// Returns `true` if the vector is currently using inline storage.
284 ///
285 /// This can be useful for performance-sensitive code that needs to know
286 /// whether operations will involve heap allocation or inline array access.
287 ///
288 /// # Examples
289 ///
290 /// ```
291 /// # use qudit_core::CompactVec;
292 /// let mut vec: CompactVec<i8> = CompactVec::new();
293 /// assert!(vec.is_inline());
294 ///
295 /// // Still inline after adding elements
296 /// for i in 0..7 {
297 /// vec.push(i);
298 /// }
299 /// assert!(vec.is_inline());
300 ///
301 /// // Transitions to heap when capacity is exceeded
302 /// vec.push(7);
303 /// assert!(!vec.is_inline());
304 /// ```
305 #[inline]
306 pub fn is_inline(&self) -> bool {
307 matches!(self, CompactVec::Inline(_, _))
308 }
309
310 /// Returns the total capacity of the vector.
311 ///
312 /// For inline storage, this is always INLINE_CAPACITY. For heap storage, this returns
313 /// the current heap capacity which may be larger than the length.
314 ///
315 /// # Examples
316 ///
317 /// ```
318 /// # use qudit_core::CompactVec;
319 /// let vec: CompactVec<i8> = CompactVec::new();
320 /// assert_eq!(vec.capacity(), 7);
321 ///
322 /// let mut vec: CompactVec<i8> = CompactVec::new();
323 /// for i in 0..8 { // Force transition to heap
324 /// vec.push(i);
325 /// }
326 /// assert!(vec.capacity() >= 8); // Heap capacity may be larger
327 /// ```
328 #[inline]
329 pub fn capacity(&self) -> usize {
330 match self {
331 CompactVec::Inline(_, _) => INLINE_CAPACITY,
332 CompactVec::Heap(vec) => vec.capacity(),
333 }
334 }
335
336 /// Returns the vector's contents as a slice.
337 ///
338 /// This method provides zero-cost slice access for types where `T` and `T::InlineType`
339 /// are the same (such as `i8` and `u8`). For other types, it panics since the
340 /// inline storage cannot be directly interpreted as a slice of `T`.
341 ///
342 /// # Panics
343 ///
344 /// Panics if `T` and `T::InlineType` are different types, as conversion would be required.
345 /// Use `iter()` instead for such types.
346 ///
347 /// # Examples
348 ///
349 /// ```
350 /// # use qudit_core::CompactVec;
351 /// let mut vec: CompactVec<i8> = CompactVec::new();
352 /// vec.push(1);
353 /// vec.push(2);
354 /// vec.push(3);
355 /// let slice = vec.as_slice();
356 /// assert_eq!(slice, &[1, 2, 3]);
357 /// ```
358 #[inline]
359 pub fn as_slice(&self) -> &[T] {
360 // Check if T and T::InlineType are the same type (zero-cost conversion)
361 if TypeId::of::<T>() == TypeId::of::<T::InlineType>() {
362 match self {
363 CompactVec::Inline(storage, length) => {
364 unsafe {
365 // Safe because T == T::InlineType
366 let ptr = storage.as_ptr() as *const T;
367 std::slice::from_raw_parts(ptr, *length as usize)
368 }
369 }
370 CompactVec::Heap(vec) => vec.as_slice(),
371 }
372 } else {
373 // TODO: transition to HEAP, then return slice
374 panic!(
375 "Cannot get slice from inline storage for non-zero-cost types - use iter() instead"
376 )
377 }
378 }
379
380 /// Removes and returns the element at position `index`, shifting all elements after it to the left.
381 ///
382 /// # Panics
383 /// Panics if `index` is out of bounds.
384 #[inline]
385 pub fn remove(&mut self, index: usize) -> T {
386 if index >= self.len() {
387 panic!(
388 "removal index (is {}) should be < len (is {})",
389 index,
390 self.len()
391 );
392 }
393
394 match self {
395 CompactVec::Inline(storage, length) => {
396 let result = T::from_inline(storage[index]);
397 // Shift elements left
398 for i in index..(*length as usize - 1) {
399 storage[i] = storage[i + 1];
400 }
401 *length -= 1;
402 result
403 }
404 CompactVec::Heap(vec) => vec.remove(index),
405 }
406 }
407
408 /// Inserts an element at position `index`, shifting all elements after it to the right.
409 ///
410 /// # Panics
411 /// Panics if `index > len`.
412 #[inline]
413 pub fn insert(&mut self, index: usize, element: T) {
414 if index > self.len() {
415 panic!(
416 "insertion index (is {}) should be <= len (is {})",
417 index,
418 self.len()
419 );
420 }
421
422 match self {
423 CompactVec::Inline(storage, length) => {
424 if (*length as usize) >= INLINE_CAPACITY || T::to_inline(element).is_err() {
425 self.transition_to_heap().insert(index, element);
426 } else {
427 // Shift elements right
428 for i in (index..*length as usize).rev() {
429 storage[i + 1] = storage[i];
430 }
431 storage[index] = T::to_inline(element).unwrap_or_else(|_| unreachable!());
432 *length += 1;
433 }
434 }
435 CompactVec::Heap(vec) => vec.insert(index, element),
436 }
437 }
438
439 /// Shortens the vector, keeping the first `len` elements and dropping the rest.
440 ///
441 /// If `len` is greater than the vector's current length, this has no effect.
442 #[inline]
443 pub fn truncate(&mut self, len: usize) {
444 match self {
445 CompactVec::Inline(_, length) => {
446 if len < *length as usize {
447 *length = len as u8;
448 }
449 }
450 CompactVec::Heap(vec) => vec.truncate(len),
451 }
452 }
453
454 /// Resizes the vector to the given length.
455 ///
456 /// If `new_len` is greater than `len`, the vector is extended with clones of `value`.
457 /// If `new_len` is less than `len`, the vector is truncated.
458 #[inline]
459 pub fn resize(&mut self, new_len: usize, value: T) {
460 let current_len = self.len();
461 if new_len > current_len {
462 for _ in current_len..new_len {
463 self.push(value);
464 }
465 } else {
466 self.truncate(new_len);
467 }
468 }
469
470 /// Extends the vector by cloning elements from a slice.
471 ///
472 /// All elements from the slice are appended to the vector in order.
473 /// If the vector is using inline storage and the additional elements
474 /// cause it to exceed capacity or cannot be represented inline,
475 /// it will transition to heap storage automatically.
476 ///
477 /// # Examples
478 ///
479 /// ```
480 /// # use qudit_core::CompactVec;
481 /// let mut vec: CompactVec<i8> = CompactVec::new();
482 /// vec.extend_from_slice(&[1, 2, 3]);
483 /// assert_eq!(vec.len(), 3);
484 ///
485 /// vec.extend_from_slice(&[4, 5]);
486 /// assert_eq!(vec.len(), 5);
487 /// ```
488 #[inline]
489 pub fn extend_from_slice(&mut self, other: &[T]) {
490 for item in other {
491 self.push(*item);
492 }
493 }
494
495 /// Reserves capacity for at least `additional` more elements.
496 ///
497 /// For inline storage, this will transition to heap if the requested
498 /// additional capacity would exceed the inline capacity of INLINE_CAPACITY elements.
499 /// For heap storage, this forwards the call to the underlying vector's
500 /// reserve method.
501 ///
502 /// # Examples
503 ///
504 /// ```
505 /// # use qudit_core::CompactVec;
506 /// let mut vec: CompactVec<i8> = CompactVec::new();
507 /// vec.reserve(10); // This will transition to heap since 10 > INLINE_CAPACITY
508 /// assert!(!vec.is_inline());
509 /// assert!(vec.capacity() >= 10);
510 /// ```
511 #[inline]
512 pub fn reserve(&mut self, additional: usize) {
513 match self {
514 CompactVec::Inline(_, _) => {
515 let new_capacity = self.len() + additional;
516
517 if self.capacity() >= new_capacity {
518 return;
519 }
520
521 if new_capacity > INLINE_CAPACITY {
522 self.transition_to_heap().reserve(additional);
523 }
524 }
525 CompactVec::Heap(vec) => vec.reserve(additional),
526 }
527 }
528
529 /// Clears the vector, removing all elements but keeping allocated capacity.
530 ///
531 /// For inline storage, this resets the length to 0 without changing the storage mode.
532 /// For heap storage, this forwards the call to the underlying vector, which clears
533 /// all elements but preserves the allocated heap capacity.
534 ///
535 /// # Examples
536 ///
537 /// ```
538 /// # use qudit_core::CompactVec;
539 /// let mut vec: CompactVec<i8> = CompactVec::new();
540 /// vec.push(1);
541 /// vec.push(2);
542 /// vec.push(3);
543 /// assert_eq!(vec.len(), 3);
544 ///
545 /// vec.clear();
546 /// assert_eq!(vec.len(), 0);
547 /// assert!(vec.is_empty());
548 /// ```
549 #[inline]
550 pub fn clear(&mut self) {
551 match self {
552 CompactVec::Inline(_, length) => *length = 0,
553 CompactVec::Heap(vec) => vec.clear(),
554 }
555 }
556
557 /// Returns `true` if the vector contains an element equal to `value`.
558 ///
559 /// # Examples
560 ///
561 /// ```
562 /// # use qudit_core::CompactVec;
563 /// let mut vec: CompactVec<i8> = CompactVec::new();
564 /// vec.push(1);
565 /// vec.push(2);
566 /// vec.push(3);
567 ///
568 /// assert!(vec.contains(&1));
569 /// assert!(!vec.contains(&4));
570 /// ```
571 #[inline]
572 pub fn contains(&self, value: &T) -> bool
573 where
574 T: PartialEq,
575 {
576 match self {
577 CompactVec::Inline(storage, length) => {
578 for i in 0..*length as usize {
579 if T::from_inline(storage[i]) == *value {
580 return true;
581 }
582 }
583 false
584 }
585 CompactVec::Heap(vec) => vec.contains(value),
586 }
587 }
588
589 /// Sorts the vector in-place using the natural ordering of elements.
590 ///
591 /// This uses insertion sort for inline storage (which is efficient for small arrays)
592 /// and delegates to the underlying vector's sort method for heap storage.
593 ///
594 /// # Examples
595 ///
596 /// ```
597 /// # use qudit_core::CompactVec;
598 /// let mut vec: CompactVec<i8> = CompactVec::new();
599 /// vec.extend_from_slice(&[3, 1, 4, 1, 5]);
600 /// vec.sort();
601 /// assert_eq!(vec.as_slice(), &[1, 1, 3, 4, 5]);
602 /// ```
603 #[inline]
604 pub fn sort(&mut self)
605 where
606 T: Ord,
607 {
608 match self {
609 CompactVec::Inline(storage, length) => {
610 if *length <= 1 {
611 return;
612 }
613
614 for i in 1..*length {
615 let mut j = i as usize;
616 while j > 0 && T::from_inline(storage[j - 1]) > T::from_inline(storage[j]) {
617 storage.swap(j - 1, j);
618 j -= 1;
619 }
620 }
621 }
622 CompactVec::Heap(vec) => vec.sort(),
623 }
624 }
625
626 /// Takes ownership of the vector's contents, leaving the original empty.
627 ///
628 /// This is equivalent to `std::mem::replace(self, CompactVec::new())` but more explicit.
629 /// The original vector is left in a new, empty state (using inline storage).
630 ///
631 /// # Examples
632 ///
633 /// ```
634 /// # use qudit_core::CompactVec;
635 /// let mut vec: CompactVec<i8> = CompactVec::new();
636 /// vec.extend_from_slice(&[1, 2, 3]);
637 ///
638 /// let taken = vec.take();
639 /// assert_eq!(taken.len(), 3);
640 /// assert_eq!(vec.len(), 0);
641 /// assert!(vec.is_empty());
642 /// ```
643 #[inline]
644 pub fn take(&mut self) -> Self {
645 std::mem::take(self)
646 }
647
648 /// Returns a mutable reference to the element at the given index, or `None` if out of bounds.
649 ///
650 /// For inline storage with non-zero-cost type conversions, this method will transition
651 /// the vector to heap storage to provide mutable access. For zero-cost conversions
652 /// (where `T` and `T::InlineType` are the same), it provides direct mutable access
653 /// to the inline storage.
654 ///
655 /// # Examples
656 ///
657 /// ```
658 /// # use qudit_core::CompactVec;
659 /// let mut vec: CompactVec<i8> = CompactVec::new();
660 /// vec.push(10);
661 /// vec.push(20);
662 ///
663 /// if let Some(elem) = vec.get_mut(1) {
664 /// *elem = 25;
665 /// }
666 /// assert_eq!(vec.get(1), Some(25));
667 /// ```
668 #[inline]
669 pub fn get_mut(&mut self, index: usize) -> Option<&mut T> {
670 // Check if T and T::InlineType are the same type (zero-cost conversion)
671 match self {
672 CompactVec::Inline(storage, length) => {
673 if index < *length as usize {
674 if TypeId::of::<T>() == TypeId::of::<T::InlineType>() {
675 unsafe {
676 // Safe because T == T::InlineType
677 let ptr = storage.as_mut_ptr() as *mut T;
678 Some(&mut *ptr.add(index))
679 }
680 } else {
681 // We need to transition to heap for mutable access
682 self.transition_to_heap().get_mut(index)
683 }
684 } else {
685 None
686 }
687 }
688 CompactVec::Heap(vec) => vec.get_mut(index),
689 }
690 }
691
692 /// Returns a mutable reference to an element without bounds checking.
693 ///
694 /// For inline storage with non-zero-cost type conversions, this method will transition
695 /// the vector to heap storage to provide mutable access. For zero-cost conversions,
696 /// it provides direct unsafe mutable access to the inline storage.
697 ///
698 /// # Safety
699 ///
700 /// Calling this method with an out-of-bounds index is undefined behavior,
701 /// even with a safe type `T`.
702 ///
703 /// # Examples
704 ///
705 /// ```
706 /// # use qudit_core::CompactVec;
707 /// let mut vec: CompactVec<i8> = CompactVec::new();
708 /// vec.push(42);
709 /// unsafe {
710 /// *vec.get_mut_unchecked(0) = 100;
711 /// assert_eq!(vec.get(0), Some(100));
712 /// }
713 /// ```
714 #[inline]
715 pub unsafe fn get_mut_unchecked(&mut self, index: usize) -> &mut T {
716 unsafe {
717 // Check if T and T::InlineType are the same type (zero-cost conversion)
718 match self {
719 CompactVec::Inline(storage, _) => {
720 if TypeId::of::<T>() == TypeId::of::<T::InlineType>() {
721 // Safe because T == T::InlineType and caller guarantees bounds
722 let ptr = storage.as_mut_ptr() as *mut T;
723 &mut *ptr.add(index)
724 } else {
725 self.transition_to_heap().get_mut_unchecked(index)
726 }
727 }
728 CompactVec::Heap(vec) => vec.get_mut_unchecked(index),
729 }
730 }
731 }
732
733 /// Returns the vector's contents as a mutable slice.
734 ///
735 /// For inline storage with non-zero-cost type conversions, this method will transition
736 /// the vector to heap storage to provide mutable slice access. For zero-cost conversions
737 /// (where `T` and `T::InlineType` are the same), it provides direct mutable access
738 /// to the inline storage as a slice.
739 ///
740 /// # Examples
741 ///
742 /// ```
743 /// # use qudit_core::CompactVec;
744 /// let mut vec: CompactVec<i8> = CompactVec::new();
745 /// vec.extend_from_slice(&[1, 2, 3]);
746 ///
747 /// let slice = vec.as_slice_mut();
748 /// slice[1] = 10;
749 /// assert_eq!(vec.get(1), Some(10));
750 /// ```
751 #[inline]
752 pub fn as_slice_mut(&mut self) -> &mut [T] {
753 // Check if T and T::InlineType are the same type (zero-cost conversion)
754 match self {
755 CompactVec::Inline(storage, length) => {
756 if TypeId::of::<T>() == TypeId::of::<T::InlineType>() {
757 unsafe {
758 // Safe because T == T::InlineType
759 let ptr = storage.as_mut_ptr() as *mut T;
760 std::slice::from_raw_parts_mut(ptr, *length as usize)
761 }
762 } else {
763 self.transition_to_heap().as_mut()
764 }
765 }
766 CompactVec::Heap(vec) => vec.as_mut(),
767 }
768 }
769
770 /// Returns an iterator over the vector's elements.
771 ///
772 /// This iterator is optimized for inline storage, avoiding heap allocations
773 /// and providing efficient element access for small collections.
774 ///
775 /// # Examples
776 ///
777 /// ```
778 /// # use qudit_core::CompactVec;
779 /// let mut vec: CompactVec<i8> = CompactVec::new();
780 /// vec.extend_from_slice(&[1, 2, 3]);
781 ///
782 /// let sum: i8 = vec.iter().sum();
783 /// assert_eq!(sum, 6);
784 ///
785 /// for (i, value) in vec.iter().enumerate() {
786 /// println!("Element {}: {}", i, value);
787 /// }
788 /// ```
789 #[inline]
790 pub fn iter(&self) -> CompactVecIter<'_, T> {
791 match self {
792 CompactVec::Inline(storage, length) => CompactVecIter::Inline(storage, 0, *length),
793 CompactVec::Heap(vec) => CompactVecIter::Heap(vec.iter()),
794 }
795 }
796}
797
798impl<T: CompactStorage> Default for CompactVec<T> {
799 /// Creates an empty `CompactVec<T>`.
800 ///
801 /// This is equivalent to `CompactVec::new()`.
802 #[inline]
803 fn default() -> Self {
804 Self::new()
805 }
806}
807
808/// An iterator over the elements of a `CompactVec`.
809///
810/// This iterator is optimized to handle both inline and heap storage modes efficiently.
811/// It's created by calling `iter()` on a `CompactVec`.
812#[derive(Debug, Clone)]
813pub enum CompactVecIter<'a, T: CompactStorage> {
814 /// Iterator over inline storage elements.
815 ///
816 /// Contains: (storage reference, current index, total length)
817 Inline(&'a [T::InlineType; INLINE_CAPACITY], u8, u8),
818 /// Iterator over heap storage elements.
819 Heap(std::slice::Iter<'a, T>),
820}
821
822impl<'a, T: CompactStorage> Iterator for CompactVecIter<'a, T> {
823 type Item = T;
824
825 #[inline]
826 fn next(&mut self) -> Option<Self::Item> {
827 match self {
828 CompactVecIter::Inline(storage, index, length) => {
829 if *index < *length {
830 let result = T::from_inline(storage[*index as usize]);
831 *index += 1;
832 Some(result)
833 } else {
834 None
835 }
836 }
837 CompactVecIter::Heap(iter) => iter.next().copied(),
838 }
839 }
840
841 #[inline]
842 fn size_hint(&self) -> (usize, Option<usize>) {
843 match self {
844 CompactVecIter::Inline(_, index, length) => {
845 let remaining = (*length - *index) as usize;
846 (remaining, Some(remaining))
847 }
848 CompactVecIter::Heap(iter) => iter.size_hint(),
849 }
850 }
851}
852
853impl<'a, T: CompactStorage> ExactSizeIterator for CompactVecIter<'a, T> {}
854
855impl<T> AsMut<[T]> for CompactVec<T>
856where
857 T: CompactStorage,
858{
859 /// Returns a mutable slice of the vector's contents.
860 ///
861 /// This delegates to `as_slice_mut()`.
862 #[inline]
863 fn as_mut(&mut self) -> &mut [T] {
864 self.as_slice_mut()
865 }
866}
867
868/// Enables converting a `Vec<T>` into a `CompactVec<T>`.
869impl<T> From<Vec<T>> for CompactVec<T>
870where
871 T: CompactStorage,
872{
873 /// Creates a `CompactVec` from a standard `Vec`.
874 ///
875 /// All elements are moved from the source vector. If the vector has INLINE_CAPACITY or fewer
876 /// elements and they can all be represented inline, the result will use inline storage.
877 /// Otherwise, it will use heap storage.
878 ///
879 /// # Examples
880 ///
881 /// ```
882 /// # use qudit_core::CompactVec;
883 /// let vec = vec![1i8, 2, 3];
884 /// let compact: CompactVec<i8> = vec.into();
885 /// assert_eq!(compact.len(), 3);
886 /// assert!(compact.is_inline());
887 /// ```
888 #[inline]
889 fn from(vec: Vec<T>) -> Self {
890 if vec.len() > INLINE_CAPACITY {
891 Self::Heap(LimitedSizeVec::from(vec))
892 } else {
893 let mut compact_vec = Self::new();
894 for item in vec {
895 compact_vec.push(item);
896 }
897 compact_vec
898 }
899 }
900}
901
902/// Enables converting a fixed-size array `[T; N]` into a `CompactVec<T>`.
903impl<T, const N: usize> From<[T; N]> for CompactVec<T>
904where
905 T: CompactStorage,
906{
907 /// Creates a `CompactVec` from a fixed-size array.
908 ///
909 /// # Examples
910 ///
911 /// ```
912 /// # use qudit_core::CompactVec;
913 /// let array = [1i8, 2, 3, 4, 5];
914 /// let compact: CompactVec<i8> = array.into();
915 /// assert_eq!(compact.len(), 5);
916 /// ```
917 #[inline]
918 fn from(array: [T; N]) -> Self {
919 let mut compact_vec = Self::new();
920 for item in array {
921 compact_vec.push(item);
922 }
923 compact_vec
924 }
925}
926
927/// Enables converting a fixed-size array `[T; N]` into a `CompactVec<T>`.
928impl<T, const N: usize> From<&[T; N]> for CompactVec<T>
929where
930 T: CompactStorage,
931{
932 /// Creates a `CompactVec` from a fixed-size array.
933 ///
934 /// # Examples
935 ///
936 /// ```
937 /// # use qudit_core::CompactVec;
938 /// let array = [1i8, 2, 3, 4, 5];
939 /// let compact: CompactVec<i8> = array.into();
940 /// assert_eq!(compact.len(), 5);
941 /// ```
942 #[inline]
943 fn from(array: &[T; N]) -> Self {
944 let mut compact_vec = Self::new();
945 for item in array {
946 compact_vec.push(*item);
947 }
948 compact_vec
949 }
950}
951
952/// Enables converting a slice `&[T]` into a `CompactVec<T>`.
953impl<T> From<&[T]> for CompactVec<T>
954where
955 T: CompactStorage + Clone,
956{
957 /// Creates a `CompactVec` from a slice by cloning all elements.
958 ///
959 /// # Examples
960 ///
961 /// ```
962 /// # use qudit_core::CompactVec;
963 /// let slice = &[1i8, 2, 3];
964 /// let compact: CompactVec<i8> = slice.into();
965 /// assert_eq!(compact.len(), 3);
966 /// ```
967 #[inline]
968 fn from(slice: &[T]) -> Self {
969 let mut compact_vec = Self::new();
970 for item in slice {
971 compact_vec.push(*item);
972 }
973 compact_vec
974 }
975}
976
977/// Enables converting a `&Vec<T>` into a `CompactVec<T>`.
978impl<T> From<&Vec<T>> for CompactVec<T>
979where
980 T: CompactStorage + Clone,
981{
982 /// Creates a `CompactVec` from a vector reference by cloning all elements.
983 ///
984 /// This delegates to the `&[T]` implementation.
985 #[inline]
986 fn from(vec: &Vec<T>) -> Self {
987 Self::from(vec.as_slice())
988 }
989}
990
991/// Enables converting a `CompactVec<T>` into a standard `Vec<T>`.
992impl<T> From<CompactVec<T>> for Vec<T>
993where
994 T: CompactStorage,
995{
996 /// Creates a standard `Vec` from a `CompactVec`.
997 ///
998 /// For inline storage, a new vector is allocated and all elements are copied.
999 /// For heap storage, the underlying vector is returned directly when possible.
1000 ///
1001 /// # Examples
1002 ///
1003 /// ```
1004 /// # use qudit_core::CompactVec;
1005 /// let mut compact: CompactVec<i8> = CompactVec::new();
1006 /// compact.extend_from_slice(&[1, 2, 3]);
1007 ///
1008 /// let vec: Vec<i8> = compact.into();
1009 /// assert_eq!(vec, vec![1, 2, 3]);
1010 /// ```
1011 #[inline]
1012 fn from(compact_vec: CompactVec<T>) -> Self {
1013 match compact_vec {
1014 CompactVec::Inline(storage, length) => {
1015 let mut vec = Vec::with_capacity(length as usize);
1016 for i in 0..length {
1017 vec.push(T::from_inline(storage[i as usize]));
1018 }
1019 vec
1020 }
1021 CompactVec::Heap(vec) => vec.into(),
1022 }
1023 }
1024}
1025
1026impl<T: CompactStorage + Hash> Hash for CompactVec<T> {
1027 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
1028 for item in self.iter() {
1029 item.hash(state);
1030 }
1031 }
1032}
1033
1034impl<T: CompactStorage + PartialEq> PartialEq for CompactVec<T> {
1035 fn eq(&self, other: &Self) -> bool {
1036 if self.len() != other.len() {
1037 return false;
1038 }
1039
1040 self.iter().zip(other.iter()).all(|(a, b)| a == b)
1041 }
1042}
1043
1044impl<T: CompactStorage + Eq> Eq for CompactVec<T> {}
1045
1046/// An owning iterator over the elements of a `CompactVec`.
1047///
1048/// This iterator moves elements out of the vector, consuming it in the process.
1049/// It's created by calling `into_iter()` on a `CompactVec` or by using a `for` loop.
1050/// Like `CompactVecIter`, it's optimized to handle both inline and heap storage modes.
1051pub enum CompactVecIntoIter<T: CompactStorage> {
1052 /// Iterator that moves out of inline storage elements.
1053 ///
1054 /// Contains: (storage array, current index, total length)
1055 Inline([T::InlineType; INLINE_CAPACITY], u8, u8),
1056 /// Iterator that moves out of heap storage elements.
1057 Heap(<LimitedSizeVec<T> as IntoIterator>::IntoIter),
1058}
1059
1060impl<T: CompactStorage> Iterator for CompactVecIntoIter<T> {
1061 type Item = T;
1062
1063 #[inline]
1064 fn next(&mut self) -> Option<Self::Item> {
1065 match self {
1066 CompactVecIntoIter::Inline(storage, index, length) => {
1067 if *index < *length {
1068 let result = T::from_inline(storage[*index as usize]);
1069 *index += 1;
1070 Some(result)
1071 } else {
1072 None
1073 }
1074 }
1075 CompactVecIntoIter::Heap(iter) => iter.next(),
1076 }
1077 }
1078
1079 #[inline]
1080 fn size_hint(&self) -> (usize, Option<usize>) {
1081 match self {
1082 CompactVecIntoIter::Inline(_, index, length) => {
1083 let remaining = (*length - *index) as usize;
1084 (remaining, Some(remaining))
1085 }
1086 CompactVecIntoIter::Heap(iter) => iter.size_hint(),
1087 }
1088 }
1089}
1090
1091impl<T: CompactStorage> ExactSizeIterator for CompactVecIntoIter<T> {}
1092
1093impl<T: CompactStorage> FromIterator<T> for CompactVec<T> {
1094 fn from_iter<I: IntoIterator<Item = T>>(iter: I) -> Self {
1095 let iter = iter.into_iter();
1096 let (min_len, max_len) = iter.size_hint();
1097
1098 if let Some(len) = max_len {
1099 if len <= INLINE_CAPACITY {
1100 // If the known size fits within inline capacity:
1101 // For types with infallible inline conversions (e.g., i8, u8),
1102 // we can directly populate the inline array for maximum performance.
1103 if T::CONVERSION_INFALLIBLE {
1104 let mut storage = [T::InlineType::default(); INLINE_CAPACITY];
1105 let mut i = 0;
1106 for next in iter {
1107 storage[i] = T::to_inline_unchecked(next);
1108 i += 1;
1109 }
1110 return CompactVec::Inline(storage, i as u8);
1111 }
1112 // For types with fallible inline conversions, even if the size fits,
1113 // we cannot pre-populate without checking each item. In this case,
1114 // we fall through to the general `push` loop, which handles conversions
1115 // and potential transitions to heap as needed.
1116 } else {
1117 // If the known size exceeds inline capacity, it will definitely be a heap-allocated vector.
1118 // We collect all elements directly into a LimitedSizeVec, leveraging its FromIterator
1119 // implementation which uses the size hint for efficient allocation.
1120 return CompactVec::Heap(iter.collect::<LimitedSizeVec<T>>());
1121 }
1122 } else {
1123 // If the exact size is unknown, but the lower bound suggests it's likely to be large,
1124 // we start with a heap-allocated vector to avoid multiple reallocations during inline-to-heap transition.
1125 if min_len > INLINE_CAPACITY {
1126 // Collect into a LimitedSizeVec. Its FromIterator will use min_len for initial capacity.
1127 return CompactVec::Heap(iter.collect::<LimitedSizeVec<T>>());
1128 }
1129 }
1130
1131 // Default path: This covers cases where a specialized path wasn't taken,
1132 let mut compact_vec = Self::new();
1133 for item in iter {
1134 compact_vec.push(item);
1135 }
1136 compact_vec
1137 }
1138}
1139
1140/// Enables using `CompactVec` as a mutable slice through the `AsMut` trait.
1141impl<T> IntoIterator for CompactVec<T>
1142where
1143 T: CompactStorage,
1144{
1145 type Item = T;
1146 type IntoIter = CompactVecIntoIter<T>;
1147
1148 /// Creates an owning iterator that consumes the vector.
1149 ///
1150 /// # Examples
1151 ///
1152 /// ```
1153 /// # use qudit_core::CompactVec;
1154 /// let mut vec: CompactVec<i8> = CompactVec::new();
1155 /// vec.extend_from_slice(&[1, 2, 3]);
1156 ///
1157 /// let doubled: Vec<i8> = vec.into_iter().map(|x| x * 2).collect();
1158 /// assert_eq!(doubled, vec![2, 4, 6]);
1159 /// ```
1160 #[inline]
1161 fn into_iter(self) -> Self::IntoIter {
1162 match self {
1163 CompactVec::Inline(storage, length) => CompactVecIntoIter::Inline(storage, 0, length),
1164 CompactVec::Heap(vec) => CompactVecIntoIter::Heap(vec.into_iter()),
1165 }
1166 }
1167}
1168
1169impl<'a, T> IntoIterator for &'a CompactVec<T>
1170where
1171 T: CompactStorage,
1172{
1173 type Item = T;
1174 type IntoIter = CompactVecIter<'a, T>;
1175
1176 /// Creates an iterator over references to the vector's elements.
1177 ///
1178 /// This delegates to `iter()`.
1179 #[inline]
1180 fn into_iter(self) -> Self::IntoIter {
1181 self.iter()
1182 }
1183}
1184
1185impl<'a, T> IntoIterator for &'a mut CompactVec<T>
1186where
1187 T: CompactStorage,
1188{
1189 type Item = &'a mut T;
1190 type IntoIter = std::slice::IterMut<'a, T>;
1191
1192 /// Creates an iterator over mutable references to the vector's elements.
1193 ///
1194 /// For inline storage with non-zero-cost conversions, this will transition
1195 /// the vector to heap storage.
1196 #[inline]
1197 fn into_iter(self) -> Self::IntoIter {
1198 self.as_slice_mut().iter_mut()
1199 }
1200}
1201
1202// Specialized implementations for zero-cost conversions (T == T::InlineType)
1203// These provide optimal performance for i8 and u8 types.
1204/// Enables treating `CompactVec<i8>` as a slice through the `Deref` trait.
1205///
1206/// This implementation is only available for `i8` because it has zero-cost
1207/// conversion with its inline type.
1208impl std::ops::Deref for CompactVec<i8> {
1209 type Target = [i8];
1210
1211 /// Returns a slice view of the vector's contents.
1212 ///
1213 /// This provides zero-cost access to the underlying storage.
1214 #[inline]
1215 fn deref(&self) -> &Self::Target {
1216 match self {
1217 CompactVec::Inline(storage, length) => unsafe {
1218 std::slice::from_raw_parts(storage.as_ptr(), *length as usize)
1219 },
1220 CompactVec::Heap(vec) => vec.as_slice(),
1221 }
1222 }
1223}
1224
1225/// Enables treating `CompactVec<u8>` as a slice through the `Deref` trait.
1226///
1227/// This implementation is only available for `u8` because it has zero-cost
1228/// conversion with its inline type.
1229impl std::ops::Deref for CompactVec<u8> {
1230 type Target = [u8];
1231
1232 /// Returns a slice view of the vector's contents.
1233 ///
1234 /// This provides zero-cost access to the underlying storage.
1235 #[inline]
1236 fn deref(&self) -> &Self::Target {
1237 match self {
1238 CompactVec::Inline(storage, length) => unsafe {
1239 std::slice::from_raw_parts(storage.as_ptr(), *length as usize)
1240 },
1241 CompactVec::Heap(vec) => vec.as_slice(),
1242 }
1243 }
1244}
1245
1246/// Enables indexing `CompactVec<i8>` with `[]` syntax.
1247impl std::ops::Index<usize> for CompactVec<i8> {
1248 type Output = i8;
1249
1250 /// Returns a reference to the element at the given index.
1251 ///
1252 /// # Panics
1253 ///
1254 /// Panics if the index is out of bounds.
1255 #[inline]
1256 fn index(&self, index: usize) -> &Self::Output {
1257 match self {
1258 CompactVec::Inline(storage, length) => {
1259 if index >= *length as usize {
1260 panic!(
1261 "index out of bounds: the len is {} but the index is {}",
1262 *length, index
1263 );
1264 }
1265 &storage[index]
1266 }
1267 CompactVec::Heap(vec) => &vec[index],
1268 }
1269 }
1270}
1271
1272/// Enables indexing `CompactVec<u8>` with `[]` syntax.
1273impl std::ops::Index<usize> for CompactVec<u8> {
1274 type Output = u8;
1275
1276 /// Returns a reference to the element at the given index.
1277 ///
1278 /// # Panics
1279 ///
1280 /// Panics if the index is out of bounds.
1281 #[inline]
1282 fn index(&self, index: usize) -> &Self::Output {
1283 match self {
1284 CompactVec::Inline(storage, length) => {
1285 if index >= *length as usize {
1286 panic!(
1287 "index out of bounds: the len is {} but the index is {}",
1288 *length, index
1289 );
1290 }
1291 &storage[index]
1292 }
1293 CompactVec::Heap(vec) => &vec[index],
1294 }
1295 }
1296}
1297
1298/// Enables using `CompactVec<i8>` where `&[i8]` is expected.
1299impl AsRef<[i8]> for CompactVec<i8> {
1300 /// Returns a slice view of the vector's contents.
1301 #[inline]
1302 fn as_ref(&self) -> &[i8] {
1303 self.as_slice()
1304 }
1305}
1306
1307/// Enables using `CompactVec<u8>` where `&[u8]` is expected.
1308impl AsRef<[u8]> for CompactVec<u8> {
1309 /// Returns a slice view of the vector's contents.
1310 #[inline]
1311 fn as_ref(&self) -> &[u8] {
1312 self.as_slice()
1313 }
1314}
1315
1316#[cfg(test)]
1317mod tests {
1318 use super::*;
1319
1320 // Helper function to create a test CompactVec with known elements
1321 fn test_vec_with_elements<T: CompactStorage + Clone>(elements: &[T]) -> CompactVec<T> {
1322 let mut vec: CompactVec<T> = CompactVec::new();
1323 for elem in elements {
1324 vec.push(*elem);
1325 }
1326 vec
1327 }
1328
1329 #[test]
1330 fn test_new() {
1331 let vec: CompactVec<i8> = CompactVec::new();
1332 assert_eq!(vec.len(), 0);
1333 assert!(vec.is_empty());
1334 assert!(vec.is_inline());
1335 assert_eq!(vec.capacity(), INLINE_CAPACITY);
1336 }
1337
1338 #[test]
1339 fn test_default() {
1340 let vec: CompactVec<i8> = CompactVec::default();
1341 assert_eq!(vec.len(), 0);
1342 assert!(vec.is_empty());
1343 assert!(vec.is_inline());
1344 }
1345
1346 #[test]
1347 fn test_push_inline() {
1348 let mut vec: CompactVec<i8> = CompactVec::new();
1349
1350 // Test pushing elements within inline capacity
1351 for i in 0..INLINE_CAPACITY as i8 {
1352 vec.push(i);
1353 assert_eq!(vec.len(), (i + 1) as usize);
1354 assert!(vec.is_inline());
1355 assert_eq!(vec.get(i as usize), Some(i));
1356 }
1357
1358 assert_eq!(vec.len(), INLINE_CAPACITY);
1359 assert!(vec.is_inline());
1360 }
1361
1362 #[test]
1363 fn test_push_transition_to_heap() {
1364 let mut vec: CompactVec<i8> = CompactVec::new();
1365
1366 // Fill inline storage
1367 for i in 0..INLINE_CAPACITY as i8 {
1368 vec.push(i);
1369 }
1370 assert!(vec.is_inline());
1371
1372 // This should trigger transition to heap
1373 vec.push(INLINE_CAPACITY as i8);
1374 assert!(!vec.is_inline());
1375 assert_eq!(vec.len(), INLINE_CAPACITY + 1);
1376 assert!(vec.capacity() > INLINE_CAPACITY);
1377
1378 // Verify all elements are still accessible
1379 for i in 0..=INLINE_CAPACITY as i8 {
1380 assert_eq!(vec.get(i as usize), Some(i));
1381 }
1382 }
1383
1384 #[test]
1385 fn test_push_unchecked() {
1386 let mut vec: CompactVec<i8> = CompactVec::new();
1387
1388 vec.push_unchecked(42);
1389 vec.push_unchecked(-10);
1390
1391 assert_eq!(vec.len(), 2);
1392 assert_eq!(vec.get(0), Some(42));
1393 assert_eq!(vec.get(1), Some(-10));
1394 }
1395
1396 #[test]
1397 fn test_pop() {
1398 let mut vec: CompactVec<i8> = CompactVec::new();
1399
1400 // Pop from empty vector
1401 assert_eq!(vec.pop(), None);
1402
1403 // Push some elements and pop them
1404 vec.push(1);
1405 vec.push(2);
1406 vec.push(3);
1407
1408 assert_eq!(vec.pop(), Some(3));
1409 assert_eq!(vec.len(), 2);
1410 assert_eq!(vec.pop(), Some(2));
1411 assert_eq!(vec.pop(), Some(1));
1412 assert_eq!(vec.len(), 0);
1413 assert_eq!(vec.pop(), None);
1414 }
1415
1416 #[test]
1417 fn test_get_and_bounds() {
1418 let vec = test_vec_with_elements(&[1i8, 2, 3]);
1419
1420 assert_eq!(vec.get(0), Some(1));
1421 assert_eq!(vec.get(1), Some(2));
1422 assert_eq!(vec.get(2), Some(3));
1423 assert_eq!(vec.get(3), None);
1424 assert_eq!(vec.get(100), None);
1425 }
1426
1427 #[test]
1428 fn test_get_unchecked() {
1429 let vec = test_vec_with_elements(&[42i8, -10, 100]);
1430
1431 unsafe {
1432 assert_eq!(vec.get_unchecked(0), 42);
1433 assert_eq!(vec.get_unchecked(1), -10);
1434 assert_eq!(vec.get_unchecked(2), 100);
1435 }
1436 }
1437
1438 #[test]
1439 fn test_capacity() {
1440 let mut vec: CompactVec<i8> = CompactVec::new();
1441 assert_eq!(vec.capacity(), INLINE_CAPACITY);
1442
1443 // Fill to capacity
1444 for i in 0..INLINE_CAPACITY as i8 {
1445 vec.push(i);
1446 }
1447 assert_eq!(vec.capacity(), INLINE_CAPACITY);
1448
1449 // Transition to heap
1450 vec.push(INLINE_CAPACITY as i8);
1451 assert!(vec.capacity() > INLINE_CAPACITY);
1452 }
1453
1454 #[test]
1455 fn test_remove() {
1456 let mut vec = test_vec_with_elements(&[1i8, 2, 3, 4, 5]);
1457
1458 // Remove from middle
1459 assert_eq!(vec.remove(2), 3);
1460 assert_eq!(vec.len(), 4);
1461 assert_eq!(vec.get(2), Some(4));
1462
1463 // Remove first element
1464 assert_eq!(vec.remove(0), 1);
1465 assert_eq!(vec.len(), 3);
1466 assert_eq!(vec.get(0), Some(2));
1467
1468 // Remove last element
1469 assert_eq!(vec.remove(2), 5);
1470 assert_eq!(vec.len(), 2);
1471 }
1472
1473 #[test]
1474 #[should_panic(expected = "removal index")]
1475 fn test_remove_out_of_bounds() {
1476 let mut vec = test_vec_with_elements(&[1i8, 2, 3]);
1477 vec.remove(3);
1478 }
1479
1480 #[test]
1481 fn test_insert() {
1482 let mut vec = test_vec_with_elements(&[1i8, 3, 4]);
1483
1484 // Insert at middle
1485 vec.insert(1, 2);
1486 assert_eq!(vec.len(), 4);
1487 assert_eq!(vec.get(0), Some(1));
1488 assert_eq!(vec.get(1), Some(2));
1489 assert_eq!(vec.get(2), Some(3));
1490 assert_eq!(vec.get(3), Some(4));
1491
1492 // Insert at beginning
1493 vec.insert(0, 0);
1494 assert_eq!(vec.len(), 5);
1495 assert_eq!(vec.get(0), Some(0));
1496
1497 // Insert at end
1498 vec.insert(5, 5);
1499 assert_eq!(vec.len(), 6);
1500 assert_eq!(vec.get(5), Some(5));
1501 }
1502
1503 #[test]
1504 #[should_panic(expected = "insertion index")]
1505 fn test_insert_out_of_bounds() {
1506 let mut vec = test_vec_with_elements(&[1i8, 2, 3]);
1507 vec.insert(4, 42);
1508 }
1509
1510 #[test]
1511 fn test_truncate() {
1512 let mut vec = test_vec_with_elements(&[1i8, 2, 3, 4, 5]);
1513
1514 vec.truncate(3);
1515 assert_eq!(vec.len(), 3);
1516 assert_eq!(vec.get(2), Some(3));
1517 assert_eq!(vec.get(3), None);
1518
1519 // Truncate to larger size should have no effect
1520 vec.truncate(10);
1521 assert_eq!(vec.len(), 3);
1522
1523 // Truncate to 0
1524 vec.truncate(0);
1525 assert_eq!(vec.len(), 0);
1526 assert!(vec.is_empty());
1527 }
1528
1529 #[test]
1530 fn test_resize() {
1531 let mut vec = test_vec_with_elements(&[1i8, 2, 3]);
1532
1533 // Resize larger
1534 vec.resize(5, 42);
1535 assert_eq!(vec.len(), 5);
1536 assert_eq!(vec.get(3), Some(42));
1537 assert_eq!(vec.get(4), Some(42));
1538
1539 // Resize smaller
1540 vec.resize(2, 99);
1541 assert_eq!(vec.len(), 2);
1542 assert_eq!(vec.get(1), Some(2));
1543 assert_eq!(vec.get(2), None);
1544 }
1545
1546 #[test]
1547 fn test_extend_from_slice() {
1548 let mut vec = test_vec_with_elements(&[1i8, 2]);
1549
1550 vec.extend_from_slice(&[3, 4, 5]);
1551 assert_eq!(vec.len(), 5);
1552 assert_eq!(vec.get(2), Some(3));
1553 assert_eq!(vec.get(3), Some(4));
1554 assert_eq!(vec.get(4), Some(5));
1555
1556 // Extend to force heap transition
1557 vec.extend_from_slice(&[6, 7, 8]);
1558 assert_eq!(vec.len(), 8);
1559 assert!(!vec.is_inline());
1560 }
1561
1562 #[test]
1563 fn test_reserve() {
1564 let mut vec: CompactVec<i8> = CompactVec::new();
1565
1566 // Reserve within inline capacity
1567 vec.reserve(5);
1568 assert!(vec.is_inline());
1569
1570 // Reserve beyond inline capacity
1571 vec.reserve(10);
1572 assert!(!vec.is_inline());
1573 assert!(vec.capacity() >= 10);
1574 }
1575
1576 #[test]
1577 fn test_clear() {
1578 let mut vec = test_vec_with_elements(&[1i8, 2, 3, 4, 5]);
1579 let was_inline = vec.is_inline();
1580
1581 vec.clear();
1582 assert_eq!(vec.len(), 0);
1583 assert!(vec.is_empty());
1584 assert_eq!(vec.is_inline(), was_inline); // Storage mode should remain the same
1585 }
1586
1587 #[test]
1588 fn test_contains_method() {
1589 let mut vec: CompactVec<i8> = CompactVec::new();
1590 vec.push(1);
1591 vec.push(2);
1592 vec.push(3);
1593
1594 assert!(vec.contains(&1));
1595 assert!(vec.contains(&2));
1596 assert!(vec.contains(&3));
1597 assert!(!vec.contains(&4));
1598 assert!(!vec.contains(&0));
1599 }
1600
1601 #[test]
1602 fn test_sort() {
1603 let mut vec = test_vec_with_elements(&[3i8, 1, 4, 1, 5]);
1604
1605 vec.sort();
1606 assert_eq!(vec.get(0), Some(1));
1607 assert_eq!(vec.get(1), Some(1));
1608 assert_eq!(vec.get(2), Some(3));
1609 assert_eq!(vec.get(3), Some(4));
1610 assert_eq!(vec.get(4), Some(5));
1611 }
1612
1613 #[test]
1614 fn test_take() {
1615 let mut vec = test_vec_with_elements(&[1i8, 2, 3]);
1616
1617 let taken = vec.take();
1618 assert_eq!(taken.len(), 3);
1619 assert_eq!(vec.len(), 0);
1620 assert!(vec.is_empty());
1621 assert!(vec.is_inline());
1622 }
1623
1624 #[test]
1625 fn test_as_slice_i8() {
1626 let vec = test_vec_with_elements(&[1i8, 2, 3]);
1627 let slice = vec.as_slice();
1628 assert_eq!(slice, &[1, 2, 3]);
1629 }
1630
1631 #[test]
1632 fn test_get_mut_i8() {
1633 let mut vec = test_vec_with_elements(&[10i8, 20, 30]);
1634
1635 if let Some(elem) = vec.get_mut(1) {
1636 *elem = 25;
1637 }
1638 assert_eq!(vec.get(1), Some(25));
1639 }
1640
1641 #[test]
1642 fn test_get_mut_unchecked_i8() {
1643 let mut vec = test_vec_with_elements(&[42i8]);
1644
1645 unsafe {
1646 *vec.get_mut_unchecked(0) = 100;
1647 }
1648 assert_eq!(vec.get(0), Some(100));
1649 }
1650
1651 #[test]
1652 fn test_as_slice_mut_i8() {
1653 let mut vec = test_vec_with_elements(&[1i8, 2, 3]);
1654
1655 let slice = vec.as_slice_mut();
1656 slice[1] = 10;
1657 assert_eq!(vec.get(1), Some(10));
1658 }
1659
1660 #[test]
1661 fn test_iter() {
1662 let vec = test_vec_with_elements(&[1i8, 2, 3, 4, 5]);
1663
1664 let collected: Vec<i8> = vec.iter().collect();
1665 assert_eq!(collected, vec![1, 2, 3, 4, 5]);
1666
1667 let sum: i8 = vec.iter().sum();
1668 assert_eq!(sum, 15);
1669 }
1670
1671 #[test]
1672 fn test_iter_size_hint() {
1673 let vec = test_vec_with_elements(&[1i8, 2, 3]);
1674 let mut iter = vec.iter();
1675
1676 assert_eq!(iter.size_hint(), (3, Some(3)));
1677 iter.next();
1678 assert_eq!(iter.size_hint(), (2, Some(2)));
1679 }
1680
1681 #[test]
1682 fn test_into_iter() {
1683 let vec = test_vec_with_elements(&[1i8, 2, 3]);
1684
1685 let collected: Vec<i8> = vec.into_iter().collect();
1686 assert_eq!(collected, vec![1, 2, 3]);
1687 }
1688
1689 #[test]
1690 fn test_into_iter_ref() {
1691 let vec = test_vec_with_elements(&[1i8, 2, 3]);
1692
1693 let collected: Vec<i8> = (&vec).into_iter().collect();
1694 assert_eq!(collected, vec![1, 2, 3]);
1695 assert_eq!(vec.len(), 3); // Original should still exist
1696 }
1697
1698 #[test]
1699 fn test_into_iter_mut() {
1700 let mut vec = test_vec_with_elements(&[1i8, 2, 3]);
1701
1702 for elem in &mut vec {
1703 *elem *= 2;
1704 }
1705
1706 assert_eq!(vec.get(0), Some(2));
1707 assert_eq!(vec.get(1), Some(4));
1708 assert_eq!(vec.get(2), Some(6));
1709 }
1710
1711 #[test]
1712 fn test_from_vec() {
1713 let vec = vec![1i8, 2, 3, 4, 5];
1714 let compact: CompactVec<i8> = vec.into();
1715
1716 assert_eq!(compact.len(), 5);
1717 assert!(compact.is_inline());
1718 assert_eq!(compact.get(0), Some(1));
1719 assert_eq!(compact.get(4), Some(5));
1720 }
1721
1722 #[test]
1723 fn test_from_array() {
1724 let array = [1i8, 2, 3, 4, 5];
1725 let compact: CompactVec<i8> = array.into();
1726
1727 assert_eq!(compact.len(), 5);
1728 assert_eq!(compact.get(0), Some(1));
1729 assert_eq!(compact.get(4), Some(5));
1730 }
1731
1732 #[test]
1733 fn test_from_array_ref() {
1734 let array = [1i8, 2, 3, 4, 5];
1735 let compact: CompactVec<i8> = (&array).into();
1736
1737 assert_eq!(compact.len(), 5);
1738 assert_eq!(compact.get(0), Some(1));
1739 assert_eq!(compact.get(4), Some(5));
1740 }
1741
1742 #[test]
1743 fn test_from_slice() {
1744 let slice = &[1i8, 2, 3];
1745 let compact: CompactVec<i8> = slice.into();
1746
1747 assert_eq!(compact.len(), 3);
1748 assert_eq!(compact.get(0), Some(1));
1749 assert_eq!(compact.get(2), Some(3));
1750 }
1751
1752 #[test]
1753 fn test_into_vec() {
1754 let compact = test_vec_with_elements(&[1i8, 2, 3]);
1755 let vec: Vec<i8> = compact.into();
1756
1757 assert_eq!(vec, vec![1, 2, 3]);
1758 }
1759
1760 #[test]
1761 fn test_deref_i8() {
1762 let vec = test_vec_with_elements(&[1i8, 2, 3]);
1763 let slice: &[i8] = &vec; // Uses Deref
1764
1765 assert_eq!(slice, &[1, 2, 3]);
1766 }
1767
1768 #[test]
1769 fn test_index_i8() {
1770 let vec = test_vec_with_elements(&[10i8, 20, 30]);
1771
1772 assert_eq!(vec[0], 10);
1773 assert_eq!(vec[1], 20);
1774 assert_eq!(vec[2], 30);
1775 }
1776
1777 #[test]
1778 #[should_panic(expected = "index out of bounds")]
1779 fn test_index_out_of_bounds() {
1780 let vec = test_vec_with_elements(&[1i8, 2, 3]);
1781 let _ = vec[3];
1782 }
1783
1784 #[test]
1785 fn test_as_ref_i8() {
1786 let vec = test_vec_with_elements(&[1i8, 2, 3]);
1787 let slice: &[i8] = vec.as_ref();
1788
1789 assert_eq!(slice, &[1, 2, 3]);
1790 }
1791
1792 #[test]
1793 fn test_as_mut_trait() {
1794 let mut vec = test_vec_with_elements(&[1i8, 2, 3]);
1795 let slice: &mut [i8] = vec.as_mut();
1796
1797 slice[1] = 42;
1798 assert_eq!(vec.get(1), Some(42));
1799 }
1800
1801 #[test]
1802 fn test_heap_operations() {
1803 let mut vec: CompactVec<i8> = CompactVec::new();
1804
1805 // Fill beyond inline capacity to force heap
1806 for i in 0..10 {
1807 vec.push(i);
1808 }
1809
1810 assert!(!vec.is_inline());
1811 assert_eq!(vec.len(), 10);
1812
1813 // Test operations on heap storage
1814 assert_eq!(vec.pop(), Some(9));
1815 assert_eq!(vec.get(5), Some(5));
1816
1817 vec.insert(5, 42);
1818 assert_eq!(vec.get(5), Some(42));
1819
1820 let removed = vec.remove(5);
1821 assert_eq!(removed, 42);
1822 }
1823
1824 #[test]
1825 fn test_empty_operations() {
1826 let mut vec: CompactVec<i8> = CompactVec::new();
1827
1828 assert_eq!(vec.pop(), None);
1829 assert_eq!(vec.get(0), None);
1830 assert!(vec.is_empty());
1831 assert_eq!(vec.len(), 0);
1832
1833 let iter_count = vec.iter().count();
1834 assert_eq!(iter_count, 0);
1835 }
1836
1837 #[test]
1838 fn test_clone() {
1839 let vec = test_vec_with_elements(&[1i8, 2, 3]);
1840 let cloned = vec.clone();
1841
1842 assert_eq!(vec.len(), cloned.len());
1843 assert_eq!(vec.is_inline(), cloned.is_inline());
1844
1845 for i in 0..vec.len() {
1846 assert_eq!(vec.get(i), cloned.get(i));
1847 }
1848 }
1849
1850 #[test]
1851 fn test_u8_specialization() {
1852 let mut vec: CompactVec<u8> = CompactVec::new();
1853 vec.extend_from_slice(&[1u8, 2, 3]);
1854
1855 // Test u8 specific deref
1856 let slice: &[u8] = &vec;
1857 assert_eq!(slice, &[1u8, 2, 3]);
1858
1859 // Test u8 indexing
1860 assert_eq!(vec[1], 2u8);
1861
1862 // Test u8 as_ref
1863 let slice: &[u8] = vec.as_ref();
1864 assert_eq!(slice, &[1u8, 2, 3]);
1865 }
1866
1867 #[test]
1868 fn test_debug() {
1869 let vec = test_vec_with_elements(&[1i8, 2, 3]);
1870 let debug_str = format!("{:?}", vec);
1871
1872 // Just ensure it doesn't panic and produces some output
1873 assert!(!debug_str.is_empty());
1874 }
1875
1876 #[test]
1877 fn test_from_iterator() {
1878 let iter = 0..5;
1879 let vec: CompactVec<i8> = iter.collect();
1880 assert_eq!(vec.len(), 5);
1881 assert_eq!(vec.as_slice(), &[0, 1, 2, 3, 4]);
1882
1883 let empty_iter: std::vec::IntoIter<i8> = Vec::new().into_iter();
1884 let empty_vec: CompactVec<i8> = empty_iter.collect();
1885 assert_eq!(empty_vec.len(), 0);
1886 }
1887
1888 #[test]
1889 fn test_transition_preserves_order() {
1890 let mut vec: CompactVec<i8> = CompactVec::new();
1891
1892 // Add elements that will fill inline storage
1893 for i in 0..INLINE_CAPACITY {
1894 vec.push((i * 10) as i8);
1895 }
1896 assert!(vec.is_inline());
1897
1898 // Force transition to heap
1899 vec.push((INLINE_CAPACITY * 10) as i8);
1900 assert!(!vec.is_inline());
1901
1902 // Verify all elements are in correct order
1903 for i in 0..=INLINE_CAPACITY {
1904 assert_eq!(vec.get(i), Some((i as i8) * 10));
1905 }
1906 }
1907}