Skip to main content

radixdb_core/
compact_vec.rs

1// Copyright 2026 RadixDB Contributors
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//     http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15//! CompactVec - A 16-byte vector optimized for Row storage
16//!
17//! Standard `Vec<T>` is 24 bytes (ptr + len + cap as usize).
18//! `CompactVec<T>` is 16 bytes (ptr + packed len/cap as u32).
19//!
20//! Benefits:
21//! - 33% smaller than Vec (16 vs 24 bytes)
22//! - O(1) len() access (unlike ThinVec which requires dereference)
23//! - Faster moves due to smaller size
24//! - Supports up to 4 billion elements (u32::MAX)
25
26use std::alloc::{alloc, dealloc, realloc, Layout};
27use std::fmt;
28use std::iter::FromIterator;
29use std::mem::{self, ManuallyDrop};
30use std::ops::{Deref, DerefMut, Index, IndexMut};
31use std::ptr::{self, NonNull};
32use std::slice;
33
34/// A compact vector that uses 16 bytes instead of Vec's 24 bytes.
35/// Stores length and capacity as u32 (max 4 billion elements).
36pub struct CompactVec<T> {
37    ptr: NonNull<T>,
38    /// Packed length (low 32 bits) and capacity (high 32 bits)
39    len_cap: u64,
40}
41
42// SAFETY: CompactVec has the same thread-safety as Vec - it can be sent
43// between threads if T can be sent, as it owns its data exclusively.
44unsafe impl<T: Send> Send for CompactVec<T> {}
45// SAFETY: CompactVec can be shared between threads if T can be shared,
46// as it only provides shared access to its elements through &self methods.
47unsafe impl<T: Sync> Sync for CompactVec<T> {}
48
49impl<T> CompactVec<T> {
50    const MAX_CAPACITY: usize = u32::MAX as usize;
51
52    #[track_caller]
53    fn assert_capacity_representable(capacity: usize) {
54        assert!(
55            capacity <= Self::MAX_CAPACITY,
56            "CompactVec capacity exceeds u32::MAX"
57        );
58    }
59
60    /// Pack length and capacity into a single u64
61    #[inline(always)]
62    const fn pack(len: u32, cap: u32) -> u64 {
63        (len as u64) | ((cap as u64) << 32)
64    }
65
66    /// Unpack length from len_cap
67    #[inline(always)]
68    const fn unpack_len(len_cap: u64) -> u32 {
69        len_cap as u32
70    }
71
72    /// Unpack capacity from len_cap
73    #[inline(always)]
74    const fn unpack_cap(len_cap: u64) -> u32 {
75        (len_cap >> 32) as u32
76    }
77
78    /// Creates an empty CompactVec.
79    #[inline]
80    pub const fn new() -> Self {
81        Self {
82            ptr: NonNull::dangling(),
83            len_cap: 0,
84        }
85    }
86
87    /// Creates a CompactVec with the specified capacity.
88    #[inline]
89    pub fn with_capacity(capacity: usize) -> Self {
90        Self::assert_capacity_representable(capacity);
91        if capacity == 0 {
92            return Self::new();
93        }
94
95        let cap = capacity as u32;
96
97        if mem::size_of::<T>() == 0 {
98            return Self {
99                ptr: NonNull::dangling(),
100                len_cap: Self::pack(0, cap),
101            };
102        }
103
104        // Allocate memory
105        let layout = Layout::array::<T>(cap as usize).unwrap();
106        // SAFETY: Layout is valid (non-zero size, proper alignment for T).
107        let ptr = unsafe { alloc(layout) as *mut T };
108
109        if ptr.is_null() {
110            std::alloc::handle_alloc_error(layout);
111        }
112
113        Self {
114            // SAFETY: We just checked that ptr is not null above.
115            ptr: unsafe { NonNull::new_unchecked(ptr) },
116            len_cap: Self::pack(0, cap),
117        }
118    }
119
120    /// Returns the number of elements in the vector.
121    #[inline(always)]
122    pub const fn len(&self) -> usize {
123        Self::unpack_len(self.len_cap) as usize
124    }
125
126    /// Returns true if the vector contains no elements.
127    #[inline(always)]
128    pub const fn is_empty(&self) -> bool {
129        Self::unpack_len(self.len_cap) == 0
130    }
131
132    /// Returns the capacity of the vector.
133    #[inline(always)]
134    pub const fn capacity(&self) -> usize {
135        Self::unpack_cap(self.len_cap) as usize
136    }
137
138    /// Set the length.
139    ///
140    /// # Safety
141    ///
142    /// - `new_len` must be less than or equal to `capacity()`
143    /// - The elements at `old_len..new_len` must be initialized (if growing)
144    /// - The elements at `new_len..old_len` will NOT be dropped (if shrinking)
145    #[inline(always)]
146    pub unsafe fn set_len(&mut self, new_len: usize) {
147        let cap = Self::unpack_cap(self.len_cap);
148        self.len_cap = Self::pack(new_len as u32, cap);
149    }
150
151    /// Returns a raw pointer to the vector's buffer.
152    #[inline(always)]
153    pub fn as_ptr(&self) -> *const T {
154        self.ptr.as_ptr()
155    }
156
157    /// Returns a raw mutable pointer to the vector's buffer.
158    #[inline(always)]
159    pub fn as_mut_ptr(&mut self) -> *mut T {
160        self.ptr.as_ptr()
161    }
162
163    /// Appends an element to the back of the vector.
164    #[inline]
165    pub fn push(&mut self, value: T) {
166        // Unpack once instead of calling len() and capacity() separately
167        let len = Self::unpack_len(self.len_cap) as usize;
168        let cap = Self::unpack_cap(self.len_cap) as usize;
169
170        if len == cap {
171            self.grow();
172        }
173
174        // SAFETY: After grow(), we have capacity > len, so ptr.add(len) is valid.
175        // The memory at that location is uninitialized but allocated for T.
176        unsafe {
177            ptr::write(self.ptr.as_ptr().add(len), value);
178            self.set_len(len + 1);
179        }
180    }
181
182    /// Removes the last element from the vector and returns it.
183    #[inline]
184    pub fn pop(&mut self) -> Option<T> {
185        let len = self.len();
186        if len == 0 {
187            return None;
188        }
189
190        // SAFETY: len > 0, so len - 1 is a valid index. The element at that
191        // position is initialized. After read, we decrement len so the moved
192        // element won't be dropped again.
193        unsafe {
194            self.set_len(len - 1);
195            Some(ptr::read(self.ptr.as_ptr().add(len - 1)))
196        }
197    }
198
199    /// Clears the vector, removing all values.
200    #[inline]
201    pub fn clear(&mut self) {
202        let len = self.len();
203        if len == 0 {
204            return;
205        }
206
207        // SAFETY: All elements [0..len] are initialized. Publish the empty
208        // state before invoking user Drop code so unwinding cannot expose an
209        // already-dropped element through the vector's bookkeeping.
210        unsafe {
211            self.set_len(0);
212            ptr::drop_in_place(ptr::slice_from_raw_parts_mut(self.ptr.as_ptr(), len));
213        }
214    }
215
216    /// Reserves capacity for at least `additional` more elements.
217    #[inline]
218    pub fn reserve(&mut self, additional: usize) {
219        // Unpack once
220        let len = Self::unpack_len(self.len_cap) as usize;
221        let cap = Self::unpack_cap(self.len_cap) as usize;
222        let required = len
223            .checked_add(additional)
224            .expect("CompactVec capacity exceeds usize::MAX");
225        Self::assert_capacity_representable(required);
226
227        if required > cap {
228            self.realloc(required);
229        }
230    }
231
232    /// Grow the vector (double capacity or start at 4)
233    fn grow(&mut self) {
234        let cap = self.capacity();
235        let new_cap = if cap == 0 {
236            4
237        } else {
238            assert!(
239                cap < Self::MAX_CAPACITY,
240                "CompactVec capacity exceeds u32::MAX"
241            );
242            cap.saturating_mul(2).min(Self::MAX_CAPACITY)
243        };
244
245        self.realloc(new_cap);
246    }
247
248    /// Reallocate to new capacity
249    fn realloc(&mut self, new_cap: usize) {
250        Self::assert_capacity_representable(new_cap);
251        let len = self.len();
252        let old_cap = self.capacity();
253        let new_cap = new_cap as u32;
254
255        if mem::size_of::<T>() == 0 {
256            // ZST - no actual allocation needed
257            self.len_cap = Self::pack(len as u32, new_cap);
258            return;
259        }
260
261        let new_layout = Layout::array::<T>(new_cap as usize).unwrap();
262
263        let new_ptr = if old_cap == 0 {
264            // Fresh allocation
265            // SAFETY: new_layout is valid (non-zero size, proper alignment).
266            unsafe { alloc(new_layout) as *mut T }
267        } else {
268            // Realloc existing
269            let old_layout = Layout::array::<T>(old_cap).unwrap();
270            // SAFETY: self.ptr was allocated with old_layout, and new_layout.size()
271            // is valid. The allocator will copy existing data to new location.
272            unsafe {
273                realloc(self.ptr.as_ptr() as *mut u8, old_layout, new_layout.size()) as *mut T
274            }
275        };
276
277        if new_ptr.is_null() {
278            std::alloc::handle_alloc_error(new_layout);
279        }
280
281        // SAFETY: We just checked that new_ptr is not null above.
282        self.ptr = unsafe { NonNull::new_unchecked(new_ptr) };
283        self.len_cap = Self::pack(len as u32, new_cap);
284    }
285
286    /// Truncates the vector, keeping the first `len` elements.
287    #[inline]
288    pub fn truncate(&mut self, len: usize) {
289        let current_len = self.len();
290        if len >= current_len {
291            return;
292        }
293
294        // SAFETY: Elements [len..current_len] are initialized. Publish the new
295        // length before invoking user Drop code so unwinding cannot make the
296        // truncated tail visible again.
297        unsafe {
298            let remaining = current_len - len;
299            self.set_len(len);
300            ptr::drop_in_place(ptr::slice_from_raw_parts_mut(
301                self.ptr.as_ptr().add(len),
302                remaining,
303            ));
304        }
305    }
306
307    /// Removes and returns the element at position `index`, shifting all elements after it.
308    #[inline]
309    pub fn remove(&mut self, index: usize) -> T {
310        let len = self.len();
311        assert!(index < len, "removal index out of bounds");
312
313        // SAFETY: index < len is asserted above, so the element is valid.
314        // After reading, we shift remaining elements and decrement length.
315        unsafe {
316            let ptr = self.ptr.as_ptr().add(index);
317            let value = ptr::read(ptr);
318
319            // Shift elements down
320            ptr::copy(ptr.add(1), ptr, len - index - 1);
321            self.set_len(len - 1);
322
323            value
324        }
325    }
326
327    /// Removes an element from the vector and returns it, replacing it with the last element.
328    #[inline]
329    pub fn swap_remove(&mut self, index: usize) -> T {
330        let len = self.len();
331        assert!(index < len, "swap_remove index out of bounds");
332
333        // SAFETY: index < len is asserted above. We read the element at index,
334        // then copy the last element to fill the gap, and decrement length.
335        unsafe {
336            let ptr = self.ptr.as_ptr();
337            let value = ptr::read(ptr.add(index));
338
339            // Copy last element to the removed position (if not removing last)
340            if index < len - 1 {
341                ptr::copy_nonoverlapping(ptr.add(len - 1), ptr.add(index), 1);
342            }
343
344            self.set_len(len - 1);
345            value
346        }
347    }
348
349    /// Inserts an element at position `index`, shifting all elements after it to the right.
350    ///
351    /// # Panics
352    /// Panics if `index > len`.
353    #[inline]
354    pub fn insert(&mut self, index: usize, element: T) {
355        let len = self.len();
356        assert!(index <= len, "insertion index out of bounds");
357
358        // Ensure we have capacity for one more element
359        if len == self.capacity() {
360            self.grow();
361        }
362
363        // SAFETY: index <= len is asserted above. After grow(), capacity > len.
364        // We shift elements right to make room, then write the new element.
365        unsafe {
366            let ptr = self.ptr.as_ptr().add(index);
367
368            // Shift elements to the right
369            if index < len {
370                ptr::copy(ptr, ptr.add(1), len - index);
371            }
372
373            // Write the new element
374            ptr::write(ptr, element);
375            self.set_len(len + 1);
376        }
377    }
378
379    /// Retains only the elements specified by the predicate.
380    ///
381    /// Removes all elements `e` such that `f(&e)` returns `false`.
382    /// This method operates in place, visiting each element exactly once in the
383    /// original order, and preserves the order of the retained elements.
384    #[inline]
385    pub fn retain<F>(&mut self, mut f: F)
386    where
387        F: FnMut(&T) -> bool,
388    {
389        let original_len = self.len();
390        if original_len == 0 {
391            return;
392        }
393
394        struct BackshiftOnDrop<'a, T> {
395            vec: &'a mut CompactVec<T>,
396            original_len: usize,
397            processed_len: usize,
398            deleted_count: usize,
399        }
400
401        impl<T> Drop for BackshiftOnDrop<'_, T> {
402            fn drop(&mut self) {
403                // SAFETY: The processed prefix contains `deleted_count` holes.
404                // The unprocessed tail is still fully initialized. Shift that
405                // tail over the holes and publish the exact surviving length,
406                // including when predicate or element Drop unwinds.
407                unsafe {
408                    if self.deleted_count > 0 {
409                        let base = self.vec.ptr.as_ptr();
410                        ptr::copy(
411                            base.add(self.processed_len),
412                            base.add(self.processed_len - self.deleted_count),
413                            self.original_len - self.processed_len,
414                        );
415                    }
416                    self.vec.set_len(self.original_len - self.deleted_count);
417                }
418            }
419        }
420
421        // SAFETY: The guard owns bookkeeping until it restores the exact
422        // surviving length. This prevents CompactVec::drop from observing a
423        // partially processed prefix during unwinding.
424        unsafe {
425            self.set_len(0);
426        }
427        let mut guard = BackshiftOnDrop {
428            vec: self,
429            original_len,
430            processed_len: 0,
431            deleted_count: 0,
432        };
433
434        while guard.processed_len < original_len {
435            // SAFETY: processed_len is inside the original initialized range.
436            unsafe {
437                let current = guard.vec.ptr.as_ptr().add(guard.processed_len);
438                if f(&*current) {
439                    if guard.deleted_count > 0 {
440                        ptr::copy_nonoverlapping(current, current.sub(guard.deleted_count), 1);
441                    }
442                    guard.processed_len += 1;
443                } else {
444                    // Retire the element in bookkeeping before invoking Drop.
445                    guard.processed_len += 1;
446                    guard.deleted_count += 1;
447                    ptr::drop_in_place(current);
448                }
449            }
450        }
451    }
452
453    /// Extends the vector with elements from an iterator.
454    #[inline]
455    pub fn extend<I: IntoIterator<Item = T>>(&mut self, iter: I) {
456        let iter = iter.into_iter();
457        let (lower, upper) = iter.size_hint();
458
459        // If exact size is known, write directly with bounds protection
460        if Some(lower) == upper && lower > 0 {
461            self.reserve(lower);
462            let original_len = self.len();
463            let cap = self.capacity();
464
465            // RAII guard for panic safety: if iter.next() panics, we set the length
466            // to the number of successfully written elements so Drop can clean up.
467            struct ExtendGuard<'a, T> {
468                vec: &'a mut CompactVec<T>,
469                written_count: usize,
470            }
471
472            impl<T> Drop for ExtendGuard<'_, T> {
473                fn drop(&mut self) {
474                    // SAFETY: written_count tracks how many elements were successfully
475                    // written before a panic. Setting len to this value ensures Drop
476                    // will clean up exactly those elements. This is only reached on panic
477                    // (normal path uses mem::forget).
478                    unsafe {
479                        self.vec.set_len(self.written_count);
480                    }
481                }
482            }
483
484            let mut guard = ExtendGuard {
485                vec: self,
486                written_count: original_len,
487            };
488
489            // SAFETY:
490            // - reserve(lower) guarantees capacity for `lower` more elements
491            // - We add bounds check (len < cap) to protect against malicious iterators
492            //   that yield more elements than size_hint promised
493            // - If iter.next() panics, guard drops and sets len, ensuring cleanup
494            unsafe {
495                let ptr = guard.vec.ptr.as_ptr();
496                for item in iter {
497                    if guard.written_count >= cap {
498                        // Iterator lied about size - fall back to safe push
499                        // Guard already has correct written_count, push updates len
500                        let count = guard.written_count;
501                        guard.vec.set_len(count);
502                        guard.vec.push(item);
503                        guard.written_count = guard.vec.len();
504                        continue;
505                    }
506                    ptr::write(ptr.add(guard.written_count), item);
507                    guard.written_count += 1;
508                }
509            }
510
511            // Success! Set final length and forget the guard
512            let final_len = guard.written_count;
513            mem::forget(guard);
514            // SAFETY: final_len equals the number of elements written by the loop.
515            // reserve() ensured capacity, and the loop wrote exactly final_len elements.
516            unsafe {
517                self.set_len(final_len);
518            }
519        } else {
520            // Fallback for unknown size - push is already panic-safe
521            self.reserve(lower);
522            for item in iter {
523                self.push(item);
524            }
525        }
526    }
527
528    /// Extend from a slice, cloning each element.
529    ///
530    /// This is faster than `extend(slice.iter().cloned())` because it avoids
531    /// the `Cloned` iterator adapter overhead. Profile shows the adapter adds
532    /// 7x overhead vs actual clone cost.
533    ///
534    /// OPTIMIZATION: Uses pointer increment instead of indexed access to reduce
535    /// per-element overhead from enumerate() + ptr.add(i).
536    #[inline]
537    pub fn extend_clone(&mut self, slice: &[T])
538    where
539        T: Clone,
540    {
541        let slice_len = slice.len();
542        if slice_len == 0 {
543            return;
544        }
545        self.reserve(slice_len);
546        let original_len = self.len();
547
548        // RAII guard for panic safety: if clone() panics, we set the length
549        // to the number of successfully cloned elements so Drop can clean up.
550        struct ExtendCloneGuard<'a, T> {
551            vec: &'a mut CompactVec<T>,
552            written_count: usize,
553        }
554
555        impl<T> Drop for ExtendCloneGuard<'_, T> {
556            fn drop(&mut self) {
557                // SAFETY: written_count tracks how many elements were successfully
558                // cloned before a panic. Setting len to this value ensures Drop
559                // will clean up exactly those elements. This is only reached on panic
560                // (normal path uses mem::forget).
561                unsafe {
562                    self.vec.set_len(self.written_count);
563                }
564            }
565        }
566
567        let mut guard = ExtendCloneGuard {
568            vec: self,
569            written_count: original_len,
570        };
571
572        // SAFETY: reserve() guarantees capacity for slice_len more elements
573        // If clone() panics, guard drops and sets len, ensuring cleanup
574        unsafe {
575            let mut dst = guard.vec.ptr.as_ptr().add(original_len);
576            for item in slice {
577                ptr::write(dst, item.clone());
578                guard.written_count += 1;
579                dst = dst.add(1);
580            }
581        }
582
583        // Success! Set final length and forget the guard
584        let final_len = guard.written_count;
585        mem::forget(guard);
586        // SAFETY: final_len equals original_len + slice_len. reserve() ensured capacity,
587        // and the loop successfully cloned all slice_len elements.
588        unsafe {
589            self.set_len(final_len);
590        }
591    }
592
593    /// Returns a slice containing all elements.
594    #[inline(always)]
595    pub fn as_slice(&self) -> &[T] {
596        // SAFETY: ptr is valid and aligned, and len() elements are initialized.
597        unsafe { slice::from_raw_parts(self.ptr.as_ptr(), self.len()) }
598    }
599
600    /// Returns a mutable slice containing all elements.
601    #[inline(always)]
602    pub fn as_mut_slice(&mut self) -> &mut [T] {
603        // SAFETY: ptr is valid and aligned, len elements are initialized
604        unsafe { &mut *ptr::slice_from_raw_parts_mut(self.ptr.as_ptr(), self.len()) }
605    }
606
607    /// Returns an iterator over the vector.
608    #[inline]
609    pub fn iter(&self) -> slice::Iter<'_, T> {
610        self.as_slice().iter()
611    }
612
613    /// Returns a mutable iterator over the vector.
614    #[inline]
615    pub fn iter_mut(&mut self) -> slice::IterMut<'_, T> {
616        self.as_mut_slice().iter_mut()
617    }
618
619    /// Drains elements from `start` to end, returning an iterator.
620    /// Elements are removed from the vector.
621    #[inline]
622    pub fn drain(&mut self, range: std::ops::RangeFrom<usize>) -> Drain<'_, T> {
623        let start = range.start;
624        let len = self.len();
625        assert!(start <= len, "drain start index out of bounds");
626
627        Drain {
628            vec: self,
629            start,
630            current: start,
631            end: len,
632        }
633    }
634
635    /// Gets a reference to an element.
636    #[inline(always)]
637    pub fn get(&self, index: usize) -> Option<&T> {
638        if index < self.len() {
639            // SAFETY: index < len is checked above, so the element is valid.
640            unsafe { Some(&*self.ptr.as_ptr().add(index)) }
641        } else {
642            None
643        }
644    }
645
646    /// Gets a mutable reference to an element.
647    #[inline(always)]
648    pub fn get_mut(&mut self, index: usize) -> Option<&mut T> {
649        if index < self.len() {
650            // SAFETY: index < len is checked above, so the element is valid.
651            unsafe { Some(&mut *self.ptr.as_ptr().add(index)) }
652        } else {
653            None
654        }
655    }
656
657    /// Converts the vector into a standard Vec.
658    #[inline]
659    pub fn into_vec(self) -> Vec<T> {
660        let len = self.len();
661        let cap = self.capacity();
662
663        if cap == 0 {
664            mem::forget(self);
665            return Vec::new();
666        }
667
668        let ptr = self.ptr.as_ptr();
669        mem::forget(self);
670
671        if mem::size_of::<T>() == 0 {
672            // SAFETY: ZST elements require no allocation. The dangling pointer
673            // is aligned and `len` elements are logically initialized.
674            return unsafe { Vec::from_raw_parts(ptr, len, len) };
675        }
676
677        // SAFETY: ptr was allocated by the global allocator with the given capacity,
678        // len elements are initialized, and we've forgotten self to prevent double-free.
679        unsafe { Vec::from_raw_parts(ptr, len, cap) }
680    }
681
682    /// Converts the vector into a boxed slice.
683    #[inline]
684    pub fn into_boxed_slice(self) -> Box<[T]> {
685        self.into_vec().into_boxed_slice()
686    }
687
688    /// Creates a CompactVec from a standard Vec.
689    #[inline]
690    pub fn from_vec(vec: Vec<T>) -> Self {
691        Self::assert_capacity_representable(vec.len());
692        if mem::size_of::<T>() == 0 {
693            let len = vec.len() as u32;
694            let mut vec = ManuallyDrop::new(vec);
695            return Self {
696                ptr: unsafe { NonNull::new_unchecked(vec.as_mut_ptr()) },
697                len_cap: Self::pack(len, len),
698            };
699        }
700        Self::assert_capacity_representable(vec.capacity());
701        let len = vec.len() as u32;
702        let cap = vec.capacity() as u32;
703
704        if cap == 0 {
705            mem::forget(vec);
706            return Self::new();
707        }
708
709        let mut vec = ManuallyDrop::new(vec);
710        let ptr = vec.as_mut_ptr();
711
712        Self {
713            // SAFETY: Vec always has a non-null pointer when capacity > 0.
714            ptr: unsafe { NonNull::new_unchecked(ptr) },
715            len_cap: Self::pack(len, cap),
716        }
717    }
718}
719
720impl<T: Clone> CompactVec<T> {
721    /// Resizes the vector to `new_len`, filling with clones of `value`.
722    pub fn resize(&mut self, new_len: usize, value: T) {
723        let len = self.len();
724
725        if new_len > len {
726            self.reserve(new_len - len);
727            for _ in len..new_len {
728                self.push(value.clone());
729            }
730        } else {
731            self.truncate(new_len);
732        }
733    }
734}
735
736impl<T> Drop for CompactVec<T> {
737    fn drop(&mut self) {
738        if self.capacity() == 0 {
739            return;
740        }
741
742        // Drop all elements
743        let len = self.len();
744        if len > 0 {
745            // SAFETY: All len elements are initialized and valid for dropping.
746            unsafe {
747                ptr::drop_in_place(ptr::slice_from_raw_parts_mut(self.ptr.as_ptr(), len));
748            }
749        }
750
751        // Deallocate memory
752        if mem::size_of::<T>() > 0 {
753            let layout = Layout::array::<T>(self.capacity()).unwrap();
754            // SAFETY: ptr was allocated with this layout and capacity > 0.
755            unsafe {
756                dealloc(self.ptr.as_ptr() as *mut u8, layout);
757            }
758        }
759    }
760}
761
762impl<T: Clone> Clone for CompactVec<T> {
763    fn clone(&self) -> Self {
764        let len = self.len();
765        if len == 0 {
766            return Self::new();
767        }
768
769        let mut new_vec = Self::with_capacity(len);
770
771        // RAII guard for panic safety: if clone() panics, we set the length
772        // to the number of successfully cloned elements so Drop can clean up.
773        struct CloneGuard<'a, T> {
774            vec: &'a mut CompactVec<T>,
775            cloned_count: usize,
776        }
777
778        impl<T> Drop for CloneGuard<'_, T> {
779            fn drop(&mut self) {
780                // SAFETY: cloned_count tracks how many elements were successfully
781                // cloned before a panic. Setting len to this value ensures Drop
782                // will clean up exactly those elements. This is only reached on panic
783                // (normal path uses mem::forget).
784                unsafe {
785                    self.vec.set_len(self.cloned_count);
786                }
787            }
788        }
789
790        let mut guard = CloneGuard {
791            vec: &mut new_vec,
792            cloned_count: 0,
793        };
794
795        // SAFETY:
796        // - with_capacity(len) guarantees capacity >= len
797        // - We write elements to indices 0..len
798        // - If clone() panics, guard drops and sets len to cloned_count,
799        //   ensuring proper cleanup of partially cloned elements
800        unsafe {
801            let src = self.ptr.as_ptr();
802            let dst = guard.vec.ptr.as_ptr();
803            for i in 0..len {
804                ptr::write(dst.add(i), (*src.add(i)).clone());
805                guard.cloned_count += 1;
806            }
807        }
808
809        // Success! Set final length and forget the guard (prevent double-set)
810        let cloned = guard.cloned_count;
811        mem::forget(guard);
812        // SAFETY: cloned equals len (the number of elements in self).
813        // with_capacity(len) ensured capacity, and all len elements were cloned.
814        unsafe {
815            new_vec.set_len(cloned);
816        }
817        new_vec
818    }
819}
820
821impl<T> Default for CompactVec<T> {
822    #[inline]
823    fn default() -> Self {
824        Self::new()
825    }
826}
827
828impl<T: fmt::Debug> fmt::Debug for CompactVec<T> {
829    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
830        f.debug_list().entries(self.iter()).finish()
831    }
832}
833
834impl<T> Deref for CompactVec<T> {
835    type Target = [T];
836
837    #[inline(always)]
838    fn deref(&self) -> &[T] {
839        self.as_slice()
840    }
841}
842
843impl<T> DerefMut for CompactVec<T> {
844    #[inline(always)]
845    fn deref_mut(&mut self) -> &mut [T] {
846        self.as_mut_slice()
847    }
848}
849
850impl<T> Index<usize> for CompactVec<T> {
851    type Output = T;
852
853    #[inline(always)]
854    fn index(&self, index: usize) -> &T {
855        &self.as_slice()[index]
856    }
857}
858
859impl<T> IndexMut<usize> for CompactVec<T> {
860    #[inline(always)]
861    fn index_mut(&mut self, index: usize) -> &mut T {
862        &mut self.as_mut_slice()[index]
863    }
864}
865
866impl<T> Index<std::ops::Range<usize>> for CompactVec<T> {
867    type Output = [T];
868
869    #[inline(always)]
870    fn index(&self, range: std::ops::Range<usize>) -> &[T] {
871        &self.as_slice()[range]
872    }
873}
874
875impl<T> Index<std::ops::RangeFrom<usize>> for CompactVec<T> {
876    type Output = [T];
877
878    #[inline(always)]
879    fn index(&self, range: std::ops::RangeFrom<usize>) -> &[T] {
880        &self.as_slice()[range]
881    }
882}
883
884impl<T> Index<std::ops::RangeTo<usize>> for CompactVec<T> {
885    type Output = [T];
886
887    #[inline(always)]
888    fn index(&self, range: std::ops::RangeTo<usize>) -> &[T] {
889        &self.as_slice()[range]
890    }
891}
892
893impl<T> Index<std::ops::RangeFull> for CompactVec<T> {
894    type Output = [T];
895
896    #[inline(always)]
897    fn index(&self, _range: std::ops::RangeFull) -> &[T] {
898        self.as_slice()
899    }
900}
901
902impl<T> FromIterator<T> for CompactVec<T> {
903    fn from_iter<I: IntoIterator<Item = T>>(iter: I) -> Self {
904        let iter = iter.into_iter();
905        let (lower, upper) = iter.size_hint();
906
907        // If exact size is known, write directly with bounds protection
908        if Some(lower) == upper && lower > 0 {
909            let mut vec = Self::with_capacity(lower);
910            let cap = vec.capacity();
911
912            // RAII guard for panic safety: if iter.next() panics, we set the length
913            // to the number of successfully written elements so Drop can clean up.
914            struct FromIterGuard<'a, T> {
915                vec: &'a mut CompactVec<T>,
916                written_count: usize,
917            }
918
919            impl<T> Drop for FromIterGuard<'_, T> {
920                fn drop(&mut self) {
921                    // SAFETY: written_count tracks how many elements were successfully
922                    // written before a panic. Setting len to this value ensures Drop
923                    // will clean up exactly those elements. This is only reached on panic
924                    // (normal path uses mem::forget).
925                    unsafe {
926                        self.vec.set_len(self.written_count);
927                    }
928                }
929            }
930
931            let mut guard = FromIterGuard {
932                vec: &mut vec,
933                written_count: 0,
934            };
935
936            // SAFETY:
937            // - with_capacity(lower) guarantees capacity >= lower
938            // - We add bounds check (len < cap) to protect against malicious iterators
939            //   that yield more elements than size_hint promised
940            // - If iter.next() panics, guard drops and sets len, ensuring cleanup
941            unsafe {
942                let ptr = guard.vec.ptr.as_ptr();
943                for item in iter {
944                    if guard.written_count >= cap {
945                        // Iterator lied about size - fall back to safe push
946                        let count = guard.written_count;
947                        guard.vec.set_len(count);
948                        guard.vec.push(item);
949                        guard.written_count = guard.vec.len();
950                        continue;
951                    }
952                    ptr::write(ptr.add(guard.written_count), item);
953                    guard.written_count += 1;
954                }
955            }
956
957            // Success! Set final length and forget the guard
958            let final_len = guard.written_count;
959            mem::forget(guard);
960            // SAFETY: final_len equals the number of elements written by the loop.
961            // with_capacity() ensured capacity, and the loop wrote exactly final_len elements.
962            unsafe {
963                vec.set_len(final_len);
964            }
965            vec
966        } else {
967            // Fallback for unknown size - push is already panic-safe
968            let mut vec = Self::with_capacity(lower);
969            for item in iter {
970                vec.push(item);
971            }
972            vec
973        }
974    }
975}
976
977impl<T> IntoIterator for CompactVec<T> {
978    type Item = T;
979    type IntoIter = IntoIter<T>;
980
981    fn into_iter(self) -> IntoIter<T> {
982        IntoIter::new(self)
983    }
984}
985
986impl<'a, T> IntoIterator for &'a CompactVec<T> {
987    type Item = &'a T;
988    type IntoIter = slice::Iter<'a, T>;
989
990    fn into_iter(self) -> slice::Iter<'a, T> {
991        self.iter()
992    }
993}
994
995impl<'a, T> IntoIterator for &'a mut CompactVec<T> {
996    type Item = &'a mut T;
997    type IntoIter = slice::IterMut<'a, T>;
998
999    fn into_iter(self) -> slice::IterMut<'a, T> {
1000        self.iter_mut()
1001    }
1002}
1003
1004impl<T: PartialEq> PartialEq for CompactVec<T> {
1005    fn eq(&self, other: &Self) -> bool {
1006        self.as_slice() == other.as_slice()
1007    }
1008}
1009
1010impl<T: Eq> Eq for CompactVec<T> {}
1011
1012impl<T> From<Vec<T>> for CompactVec<T> {
1013    fn from(vec: Vec<T>) -> Self {
1014        Self::from_vec(vec)
1015    }
1016}
1017
1018impl<T> From<CompactVec<T>> for Vec<T> {
1019    fn from(vec: CompactVec<T>) -> Self {
1020        vec.into_vec()
1021    }
1022}
1023
1024/// Drain iterator for CompactVec.
1025/// Removes elements from the vector as they are iterated.
1026pub struct Drain<'a, T> {
1027    vec: &'a mut CompactVec<T>,
1028    start: usize,
1029    current: usize,
1030    end: usize,
1031}
1032
1033impl<'a, T> Iterator for Drain<'a, T> {
1034    type Item = T;
1035
1036    #[inline]
1037    fn next(&mut self) -> Option<T> {
1038        if self.current < self.end {
1039            // SAFETY: current < end <= original len, so the element is valid.
1040            // After reading, we increment current so it won't be read again.
1041            let item = unsafe { ptr::read(self.vec.ptr.as_ptr().add(self.current)) };
1042            self.current += 1;
1043            Some(item)
1044        } else {
1045            None
1046        }
1047    }
1048
1049    fn size_hint(&self) -> (usize, Option<usize>) {
1050        let remaining = self.end - self.current;
1051        (remaining, Some(remaining))
1052    }
1053}
1054
1055impl<'a, T> ExactSizeIterator for Drain<'a, T> {
1056    fn len(&self) -> usize {
1057        self.end - self.current
1058    }
1059}
1060
1061impl<'a, T> Drop for Drain<'a, T> {
1062    fn drop(&mut self) {
1063        // Drop any remaining elements not yet consumed
1064        while self.current < self.end {
1065            // SAFETY: Elements [current..end] are initialized but not yet consumed.
1066            unsafe {
1067                ptr::drop_in_place(self.vec.ptr.as_ptr().add(self.current));
1068            }
1069            self.current += 1;
1070        }
1071
1072        // SAFETY: Elements [0..start] are still valid, elements [start..end] have
1073        // been consumed or dropped, so we set len to start.
1074        unsafe {
1075            self.vec.set_len(self.start);
1076        }
1077    }
1078}
1079
1080/// Owning iterator for CompactVec.
1081pub struct IntoIter<T> {
1082    vec: CompactVec<T>,
1083    index: usize,
1084}
1085
1086impl<T> IntoIter<T> {
1087    fn new(vec: CompactVec<T>) -> Self {
1088        Self { vec, index: 0 }
1089    }
1090}
1091
1092impl<T> Iterator for IntoIter<T> {
1093    type Item = T;
1094
1095    fn next(&mut self) -> Option<T> {
1096        if self.index < self.vec.len() {
1097            // SAFETY: index < len, so the element is valid. After reading,
1098            // we increment index so it won't be read again.
1099            let item = unsafe { ptr::read(self.vec.ptr.as_ptr().add(self.index)) };
1100            self.index += 1;
1101            Some(item)
1102        } else {
1103            None
1104        }
1105    }
1106
1107    fn size_hint(&self) -> (usize, Option<usize>) {
1108        let remaining = self.vec.len() - self.index;
1109        (remaining, Some(remaining))
1110    }
1111}
1112
1113impl<T> ExactSizeIterator for IntoIter<T> {
1114    fn len(&self) -> usize {
1115        self.vec.len() - self.index
1116    }
1117}
1118
1119impl<T> Drop for IntoIter<T> {
1120    fn drop(&mut self) {
1121        let len = self.vec.len();
1122        if self.index < len {
1123            // SAFETY:
1124            // - Elements [index..len] have not been read/moved out yet
1125            // - They are valid initialized elements that need dropping
1126            // - After drop_in_place, we set len=0 to prevent double-drop
1127            unsafe {
1128                let remaining = len - self.index;
1129                ptr::drop_in_place(ptr::slice_from_raw_parts_mut(
1130                    self.vec.ptr.as_ptr().add(self.index),
1131                    remaining,
1132                ));
1133            }
1134        }
1135
1136        // SAFETY: All elements are now dropped, set len=0 to prevent double-drop
1137        unsafe {
1138            self.vec.set_len(0);
1139        }
1140    }
1141}
1142
1143/// Creates a [`CompactVec`] containing the arguments.
1144///
1145/// `compact_vec!` allows creating a `CompactVec` with the same syntax as `vec![]`:
1146///
1147/// ```ignore
1148/// let v = compact_vec![1, 2, 3];
1149/// assert_eq!(v.as_slice(), &[1, 2, 3]);
1150/// ```
1151#[macro_export]
1152macro_rules! compact_vec {
1153    () => {
1154        $crate::CompactVec::new()
1155    };
1156    ($($elem:expr),+ $(,)?) => {{
1157        // Use array to get count at compile time, then collect
1158        let arr = [$($elem),+];
1159        let mut vec = $crate::CompactVec::with_capacity(arr.len());
1160        for elem in arr {
1161            vec.push(elem);
1162        }
1163        vec
1164    }};
1165}
1166
1167#[cfg(test)]
1168mod tests {
1169    use super::*;
1170
1171    struct PanicOnFirstDrop {
1172        panicked: std::rc::Rc<std::cell::Cell<bool>>,
1173    }
1174
1175    impl Drop for PanicOnFirstDrop {
1176        fn drop(&mut self) {
1177            if !self.panicked.replace(true) {
1178                panic!("intentional drop panic");
1179            }
1180        }
1181    }
1182
1183    fn panic_drop_vec(len: usize) -> std::mem::ManuallyDrop<CompactVec<PanicOnFirstDrop>> {
1184        let panicked = std::rc::Rc::new(std::cell::Cell::new(false));
1185        std::mem::ManuallyDrop::new(
1186            (0..len)
1187                .map(|_| PanicOnFirstDrop {
1188                    panicked: std::rc::Rc::clone(&panicked),
1189                })
1190                .collect(),
1191        )
1192    }
1193
1194    #[test]
1195    fn test_mutation_state_before_unwind_compact_vec_clear() {
1196        let mut vec = panic_drop_vec(3);
1197        let result = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| vec.clear()));
1198
1199        assert!(result.is_err());
1200        assert_eq!(vec.len(), 0, "clear must publish empty state before Drop");
1201    }
1202
1203    #[test]
1204    fn test_mutation_state_before_unwind_compact_vec_truncate() {
1205        let mut vec = panic_drop_vec(3);
1206        let result = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| vec.truncate(1)));
1207
1208        assert!(result.is_err());
1209        assert_eq!(vec.len(), 1, "truncate must publish new length before Drop");
1210    }
1211
1212    #[test]
1213    fn test_mutation_state_before_unwind_compact_vec_retain() {
1214        let mut vec: CompactVec<i32> = [0, 1, 2].into_iter().collect();
1215        let result = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| {
1216            vec.retain(|value| match *value {
1217                0 => false,
1218                1 => panic!("intentional predicate panic"),
1219                _ => true,
1220            });
1221        }));
1222
1223        assert!(result.is_err());
1224        assert_eq!(vec.as_slice(), &[1, 2]);
1225    }
1226
1227    #[test]
1228    fn test_size() {
1229        assert_eq!(std::mem::size_of::<CompactVec<u8>>(), 16);
1230        assert_eq!(std::mem::size_of::<CompactVec<u64>>(), 16);
1231        assert_eq!(std::mem::size_of::<Vec<u8>>(), 24);
1232    }
1233
1234    #[test]
1235    fn test_basic_operations() {
1236        let mut vec = CompactVec::new();
1237        assert!(vec.is_empty());
1238        assert_eq!(vec.len(), 0);
1239
1240        vec.push(1);
1241        vec.push(2);
1242        vec.push(3);
1243
1244        assert_eq!(vec.len(), 3);
1245        assert_eq!(vec[0], 1);
1246        assert_eq!(vec[1], 2);
1247        assert_eq!(vec[2], 3);
1248
1249        assert_eq!(vec.pop(), Some(3));
1250        assert_eq!(vec.len(), 2);
1251    }
1252
1253    #[test]
1254    fn test_with_capacity() {
1255        let vec: CompactVec<i32> = CompactVec::with_capacity(100);
1256        assert!(vec.is_empty());
1257        assert!(vec.capacity() >= 100);
1258    }
1259
1260    #[cfg(target_pointer_width = "64")]
1261    #[test]
1262    fn test_capacity_above_u32_is_rejected_without_allocation() {
1263        let unrepresentable = u32::MAX as usize + 1;
1264
1265        assert!(std::panic::catch_unwind(|| {
1266            let _ = CompactVec::<()>::with_capacity(unrepresentable);
1267        })
1268        .is_err());
1269
1270        assert!(std::panic::catch_unwind(|| {
1271            let mut vec = CompactVec::<()>::new();
1272            vec.reserve(unrepresentable);
1273        })
1274        .is_err());
1275
1276        assert_eq!(Vec::<()>::new().capacity(), usize::MAX);
1277        let compact = CompactVec::from_vec(Vec::<()>::new());
1278        assert!(compact.is_empty());
1279    }
1280
1281    #[test]
1282    fn zst_capacity_conversion_and_growth_are_allocation_free() {
1283        let mut compact = CompactVec::<()>::with_capacity(2);
1284        assert_eq!(compact.capacity(), 2);
1285        compact.push(());
1286        compact.push(());
1287        compact.push(());
1288        assert_eq!(compact.len(), 3);
1289        assert!(compact.capacity() >= 3);
1290
1291        let standard = compact.into_vec();
1292        assert_eq!(standard.len(), 3);
1293        assert_eq!(standard.capacity(), usize::MAX);
1294
1295        let round_trip = CompactVec::from_vec(standard);
1296        assert_eq!(round_trip.len(), 3);
1297        assert_eq!(round_trip.into_vec().len(), 3);
1298    }
1299
1300    #[test]
1301    fn test_clone() {
1302        let mut vec = CompactVec::new();
1303        vec.push(1);
1304        vec.push(2);
1305        vec.push(3);
1306
1307        let cloned = vec.clone();
1308        assert_eq!(vec.as_slice(), cloned.as_slice());
1309    }
1310
1311    #[test]
1312    fn test_iteration() {
1313        let mut vec = CompactVec::new();
1314        vec.push(1);
1315        vec.push(2);
1316        vec.push(3);
1317
1318        let sum: i32 = vec.iter().sum();
1319        assert_eq!(sum, 6);
1320
1321        let collected: Vec<i32> = vec.into_iter().collect();
1322        assert_eq!(collected, vec![1, 2, 3]);
1323    }
1324
1325    #[test]
1326    fn test_from_iterator() {
1327        let vec: CompactVec<i32> = (0..5).collect();
1328        assert_eq!(vec.len(), 5);
1329        assert_eq!(vec.as_slice(), &[0, 1, 2, 3, 4]);
1330    }
1331
1332    #[test]
1333    fn test_extend() {
1334        let mut vec = CompactVec::new();
1335        vec.push(1);
1336        vec.extend(vec![2, 3, 4]);
1337        assert_eq!(vec.as_slice(), &[1, 2, 3, 4]);
1338    }
1339
1340    #[test]
1341    fn test_truncate() {
1342        let mut vec: CompactVec<i32> = (0..10).collect();
1343        vec.truncate(5);
1344        assert_eq!(vec.len(), 5);
1345        assert_eq!(vec.as_slice(), &[0, 1, 2, 3, 4]);
1346    }
1347
1348    #[test]
1349    fn test_clear() {
1350        let mut vec: CompactVec<i32> = (0..10).collect();
1351        let cap = vec.capacity();
1352        vec.clear();
1353        assert!(vec.is_empty());
1354        assert_eq!(vec.capacity(), cap); // Capacity preserved
1355    }
1356
1357    #[test]
1358    fn test_swap_remove() {
1359        let mut vec = CompactVec::new();
1360        vec.push(1);
1361        vec.push(2);
1362        vec.push(3);
1363
1364        assert_eq!(vec.swap_remove(0), 1);
1365        assert_eq!(vec.as_slice(), &[3, 2]);
1366    }
1367
1368    #[test]
1369    fn test_into_vec_and_back() {
1370        let compact: CompactVec<i32> = (0..5).collect();
1371        let std_vec: Vec<i32> = compact.into_vec();
1372        assert_eq!(std_vec, vec![0, 1, 2, 3, 4]);
1373
1374        let compact_again = CompactVec::from_vec(std_vec);
1375        assert_eq!(compact_again.as_slice(), &[0, 1, 2, 3, 4]);
1376    }
1377
1378    #[test]
1379    fn test_with_strings() {
1380        let mut vec = CompactVec::new();
1381        vec.push(String::from("hello"));
1382        vec.push(String::from("world"));
1383
1384        assert_eq!(vec[0], "hello");
1385        assert_eq!(vec[1], "world");
1386
1387        let cloned = vec.clone();
1388        assert_eq!(cloned[0], "hello");
1389    }
1390
1391    /// Test panic safety in Clone implementation
1392    #[test]
1393    fn test_clone_panic_safety() {
1394        use std::sync::atomic::{AtomicUsize, Ordering};
1395
1396        static DROP_COUNT: AtomicUsize = AtomicUsize::new(0);
1397        static CLONE_COUNT: AtomicUsize = AtomicUsize::new(0);
1398
1399        #[derive(Debug)]
1400        struct PanicOnThirdClone(usize);
1401
1402        impl Clone for PanicOnThirdClone {
1403            fn clone(&self) -> Self {
1404                let count = CLONE_COUNT.fetch_add(1, Ordering::SeqCst);
1405                if count == 2 {
1406                    panic!("Intentional panic on third clone");
1407                }
1408                PanicOnThirdClone(self.0)
1409            }
1410        }
1411
1412        impl Drop for PanicOnThirdClone {
1413            fn drop(&mut self) {
1414                DROP_COUNT.fetch_add(1, Ordering::SeqCst);
1415            }
1416        }
1417
1418        // Reset counters
1419        DROP_COUNT.store(0, Ordering::SeqCst);
1420        CLONE_COUNT.store(0, Ordering::SeqCst);
1421
1422        let mut vec = CompactVec::new();
1423        vec.push(PanicOnThirdClone(1));
1424        vec.push(PanicOnThirdClone(2));
1425        vec.push(PanicOnThirdClone(3));
1426        vec.push(PanicOnThirdClone(4));
1427
1428        // Try to clone - should panic on third element
1429        let result = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| {
1430            let _cloned = vec.clone();
1431        }));
1432
1433        assert!(result.is_err(), "Should have panicked");
1434
1435        // Verify panic safety: 2 successfully cloned elements should be dropped
1436        // by the CloneGuard when the panic unwinds
1437        let drops_from_cleanup = DROP_COUNT.load(Ordering::SeqCst);
1438        assert_eq!(
1439            drops_from_cleanup, 2,
1440            "Should have dropped 2 successfully cloned elements, got {}",
1441            drops_from_cleanup
1442        );
1443
1444        // Now drop the original vec (4 elements)
1445        drop(vec);
1446        let total_drops = DROP_COUNT.load(Ordering::SeqCst);
1447        assert_eq!(
1448            total_drops, 6,
1449            "Total drops should be 6 (2 from cleanup + 4 from original), got {}",
1450            total_drops
1451        );
1452    }
1453
1454    /// Test panic safety in extend_clone implementation
1455    #[test]
1456    fn test_extend_clone_panic_safety() {
1457        use std::sync::atomic::{AtomicUsize, Ordering};
1458
1459        static DROP_COUNT: AtomicUsize = AtomicUsize::new(0);
1460        static CLONE_COUNT: AtomicUsize = AtomicUsize::new(0);
1461
1462        #[derive(Debug)]
1463        struct PanicOnThirdClone(usize);
1464
1465        impl Clone for PanicOnThirdClone {
1466            fn clone(&self) -> Self {
1467                let count = CLONE_COUNT.fetch_add(1, Ordering::SeqCst);
1468                if count == 2 {
1469                    panic!("Intentional panic on third clone");
1470                }
1471                PanicOnThirdClone(self.0)
1472            }
1473        }
1474
1475        impl Drop for PanicOnThirdClone {
1476            fn drop(&mut self) {
1477                DROP_COUNT.fetch_add(1, Ordering::SeqCst);
1478            }
1479        }
1480
1481        // Reset counters
1482        DROP_COUNT.store(0, Ordering::SeqCst);
1483        CLONE_COUNT.store(0, Ordering::SeqCst);
1484
1485        // Create source slice (won't be dropped, just borrowed)
1486        let source = [
1487            PanicOnThirdClone(1),
1488            PanicOnThirdClone(2),
1489            PanicOnThirdClone(3),
1490            PanicOnThirdClone(4),
1491        ];
1492
1493        let mut vec: CompactVec<PanicOnThirdClone> = CompactVec::new();
1494
1495        // Try to extend_clone - should panic on third element
1496        let result = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| {
1497            vec.extend_clone(&source);
1498        }));
1499
1500        assert!(result.is_err(), "Should have panicked");
1501
1502        // The guard has set vec's length to 2 (the successfully cloned elements)
1503        // Now when we drop vec, those 2 elements should be properly dropped
1504        assert_eq!(
1505            vec.len(),
1506            2,
1507            "Guard should have set length to 2 (elements cloned before panic)"
1508        );
1509
1510        // Drop vec - this should drop the 2 elements the guard accounted for
1511        drop(vec);
1512        let drops_after_vec_drop = DROP_COUNT.load(Ordering::SeqCst);
1513        assert_eq!(
1514            drops_after_vec_drop, 2,
1515            "Should have dropped 2 successfully cloned elements when vec dropped, got {}",
1516            drops_after_vec_drop
1517        );
1518
1519        // Drop source (4 elements)
1520        drop(source);
1521        let total_drops = DROP_COUNT.load(Ordering::SeqCst);
1522        assert_eq!(
1523            total_drops, 6,
1524            "Total drops should be 6 (2 from vec + 4 from source), got {}",
1525            total_drops
1526        );
1527    }
1528
1529    /// Test panic safety in from_iter implementation
1530    #[test]
1531    fn test_from_iter_panic_safety() {
1532        use std::sync::atomic::{AtomicUsize, Ordering};
1533
1534        static DROP_COUNT: AtomicUsize = AtomicUsize::new(0);
1535
1536        #[derive(Debug)]
1537        #[allow(dead_code)] // Field used to give struct a non-zero size
1538        struct PanicOnThirdNext(usize);
1539
1540        impl Drop for PanicOnThirdNext {
1541            fn drop(&mut self) {
1542                DROP_COUNT.fetch_add(1, Ordering::SeqCst);
1543            }
1544        }
1545
1546        // An iterator that panics on the third next() call
1547        struct PanickingIter {
1548            current: usize,
1549            max: usize,
1550        }
1551
1552        impl Iterator for PanickingIter {
1553            type Item = PanicOnThirdNext;
1554
1555            fn next(&mut self) -> Option<Self::Item> {
1556                if self.current >= self.max {
1557                    return None;
1558                }
1559                self.current += 1;
1560                if self.current == 3 {
1561                    panic!("Intentional panic on third next()");
1562                }
1563                Some(PanicOnThirdNext(self.current))
1564            }
1565
1566            fn size_hint(&self) -> (usize, Option<usize>) {
1567                let remaining = self.max - self.current;
1568                (remaining, Some(remaining))
1569            }
1570        }
1571
1572        impl ExactSizeIterator for PanickingIter {}
1573
1574        // Reset counter
1575        DROP_COUNT.store(0, Ordering::SeqCst);
1576
1577        // Try to collect - should panic on third element
1578        let result = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| {
1579            let _vec: CompactVec<PanicOnThirdNext> = PanickingIter { current: 0, max: 5 }.collect();
1580        }));
1581
1582        assert!(result.is_err(), "Should have panicked");
1583
1584        // Verify panic safety: 2 successfully written elements should be dropped
1585        let drops_after_panic = DROP_COUNT.load(Ordering::SeqCst);
1586        assert_eq!(
1587            drops_after_panic, 2,
1588            "Should have dropped 2 successfully written elements, got {}",
1589            drops_after_panic
1590        );
1591    }
1592}