Skip to main content

qudit_core/utils/
compact.rs

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