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}