Skip to main content

array_list/
lib.rs

1#![no_std]
2
3//! # array_list
4//!
5//! `array_list` provides an ordered collection backed by fixed-capacity chunks.
6//! It offers sequence operations, iterators, and cursors while avoiding one
7//! allocation per element.
8//!
9//! ## Features
10//! - Ordered sequence with index-based element access.
11//! - Chunked storage with less per-element pointer overhead than a traditional
12//!   linked list.
13//! - Shared, mutable, and owning iterators.
14//! - Cursor and mutable cursor APIs for moving around the list and editing near
15//!   the cursor.
16//! - `#![no_std]` support with `alloc`.
17//!
18//! ## Quick Start
19//! ```rust
20//! use array_list::ArrayList;
21//!
22//! let mut list: ArrayList<i32, 8> = ArrayList::from([1, 2, 4]);
23//!
24//! list.insert(2, 3);
25//! list.push_front(0);
26//! list.push_back(5);
27//!
28//! assert_eq!(list, [0, 1, 2, 3, 4, 5]);
29//!
30//! for value in &mut list {
31//!     *value *= 2;
32//! }
33//!
34//! assert_eq!(list.iter().copied().collect::<Vec<_>>(), [0, 2, 4, 6, 8, 10]);
35//! ```
36//!
37//! ## When To Use It
38//! `array_list` is useful when you want an ordered sequence that supports indexed
39//! access, stable iteration order, and cursor-local edits without allocating one
40//! node per element.
41//!
42//! It is not a drop-in replacement for `Vec`. Index lookup may need to scan
43//! chunks when the list is not densely packed, and insertions/removals inside a
44//! chunk can move elements within that chunk.
45//!
46//! Use `Vec` when you primarily push/pop at the back and need dense contiguous
47//! storage. Use `ArrayList` when cursor-local edits and chunked growth are a
48//! better fit than a single contiguous allocation. Use `LinkedList` only when
49//! its exact node-based semantics are required.
50//!
51//! ## API Overview
52//! - Build lists with [`ArrayList::new`], [`ArrayList::from`], `collect`,
53//!   `extend`, or [`ArrayList::append`].
54//! - Edit at the ends with [`ArrayList::push_front`],
55//!   [`ArrayList::push_back`], [`ArrayList::pop_front`], and
56//!   [`ArrayList::pop_back`].
57//! - Edit by index with [`ArrayList::insert`], [`ArrayList::remove`],
58//!   [`ArrayList::get`], and [`ArrayList::get_mut`].
59//! - Traverse with [`ArrayList::iter`], [`ArrayList::iter_mut`],
60//!   [`IntoIter`], or the `IntoIterator` implementations for `ArrayList`,
61//!   `&ArrayList`, and `&mut ArrayList`.
62//! - Navigate and edit near a position with [`Cursor`] and [`CursorMut`].
63//! - Inspect storage with [`ArrayList::capacity`],
64//!   [`ArrayList::spare_capacity`], and [`ArrayList::shrink`].
65//!
66//! ## Storage Model
67//! `ArrayList<T, N>` stores elements in chunks that can each hold up to `N`
68//! elements. The logical order is independent from internal chunk boundaries:
69//! iteration and indexing see one continuous sequence.
70//!
71//! Middle insertions and removals can leave spare capacity inside chunks. After
72//! a middle removal that leaves the edited chunk non-empty, or after a middle
73//! insertion that splits a full chunk, the edited chunk is locally refilled up
74//! to half capacity from immediate sibling chunks when those siblings contain
75//! more than half capacity. Siblings at or below half capacity are left
76//! untouched, so edit-heavy workloads can still become fragmented. Use
77//! [`ArrayList::spare_capacity`] to inspect unused chunk slots and
78//! [`ArrayList::shrink`] to compact elements toward the front.
79//!
80//! This is a local minimum-occupancy heuristic, not a global invariant. The
81//! minimum is `N / 2` using integer division, so odd capacities round down.
82//! Refill only touches the edited chunk and its immediate siblings, preferring
83//! bounded local movement over globally dense storage. Inserting into a full
84//! middle chunk splits that chunk locally. Front/back pushes and pops keep their
85//! direct boundary behavior, so edge chunks may be less than half full.
86//!
87//! ## Chunk Capacity
88//! The second type parameter is the maximum number of elements per chunk.
89//! Capacity must be at least 4. Smaller chunk sizes are rejected at compile time
90//! by constructors and operations because this data structure is designed around
91//! multi-element chunks and a local half-full occupancy heuristic.
92//!
93//! Chunk size has a large effect on performance. Small capacities reduce the
94//! maximum amount moved inside one chunk, but they also create many more chunks,
95//! more boundary crossings, more allocations, and more metadata to scan. Larger
96//! capacities improve locality and reduce chunk count, which is especially
97//! important for cursor-local edits, but middle insertions and removals can move
98//! more elements within the edited chunk and its immediate siblings.
99//!
100//! Very small capacities are mostly useful for stress-testing chunk boundaries.
101//! For general use, prefer capacities large enough to amortize chunk overhead.
102//! Values in the 32-64 range are usually more representative than the minimum
103//! supported size; mutation-heavy workloads often benefit from the larger end of
104//! that range.
105//!
106//! Keeping edited chunks at least half full where possible reduces the chance of
107//! many tiny chunks after repeated mutations. The tradeoff is that the list may
108//! contain more chunks than a fully compacted layout, so locating an indexed
109//! element can require scanning more chunk metadata until
110//! [`ArrayList::shrink`] is called.
111//!
112//! ## Performance Notes
113//! The exact cost depends on chunk occupancy and the chosen chunk capacity:
114//! - [`ArrayList::len`] and [`ArrayList::is_empty`] are constant time.
115//! - End pushes and pops usually touch only one edge chunk.
116//! - [`ArrayList::get`], [`ArrayList::get_mut`], [`ArrayList::insert`], and
117//!   [`ArrayList::remove`] locate elements by scanning chunk metadata unless
118//!   the list is densely packed.
119//! - Middle insertion/removal may move elements within the edited chunk and its
120//!   immediate siblings.
121//! - Iteration is in logical order and does not expose chunk boundaries.
122//!
123//! Call [`ArrayList::shrink`] after edit-heavy phases if a compact front-filled
124//! layout is more important than preserving spare chunk slots for future edits.
125//!
126//! ## Example
127//! ```rust
128//! use array_list::ArrayList;
129//!
130//! let mut list: ArrayList<i64, 6> = ArrayList::new();
131//! list.push_back(2);
132//! list.push_front(0);
133//! list.insert(1, 1);
134//!
135//! assert_eq!(list.front(), Some(&0));
136//! assert_eq!(list.get(1), Some(&1));
137//! assert_eq!(list.back(), Some(&2));
138//!
139//! assert_eq!(list.remove(1), Some(1));
140//! assert_eq!(list.pop_back(), Some(2));
141//! assert_eq!(list.pop_front(), Some(0));
142//! ```
143
144extern crate alloc;
145
146#[cfg(test)]
147extern crate std;
148
149mod cursor;
150mod cursor_mut;
151mod into_iter;
152mod iter;
153mod iter_mut;
154mod position;
155
156pub use cursor::Cursor;
157pub use cursor_mut::CursorMut;
158pub use into_iter::IntoIter;
159pub use iter::Iter;
160pub use iter_mut::IterMut;
161
162const MIN_CHUNK_CAPACITY: usize = 4;
163
164use alloc::collections::VecDeque;
165
166use core::cmp::Ordering;
167use core::hash::{Hash, Hasher};
168
169use cap_vec::CapVec;
170
171use crate::position::Position;
172
173/// A dynamic ordered sequence stored as fixed-capacity chunks.
174///
175/// # Features
176/// - **Chunked storage**: each chunk can hold up to `N` elements, reducing
177///   allocation overhead compared to a traditional linked list.
178/// - **Sequence operations**: supports front, back, indexed, iterator, and
179///   cursor-based access.
180/// - **Local editing**: mutable cursors can insert and remove near their current
181///   position while keeping track of the logical element when possible.
182///
183/// # Type Parameters
184/// - `T`: The type of elements stored in the list.
185/// - `N`: The maximum number of elements that each chunk can hold.
186///
187/// `N` must be at least 4. Smaller chunk sizes are rejected at compile time by
188/// constructors and operations because this data structure is designed around
189/// multi-element chunks and a local half-full occupancy heuristic.
190///
191/// Chunk size is a performance tuning parameter. Small chunks reduce the maximum
192/// movement within any one chunk, but they increase chunk count, allocation
193/// count, boundary crossings, and indexed lookup metadata. Larger chunks reduce
194/// that overhead and can improve cursor-local mutation performance, at the cost
195/// of moving more elements within the edited chunk when a middle insertion or
196/// removal occurs. Capacities around 32-64 are usually a better starting point
197/// for real workloads than the minimum supported size.
198///
199/// # Fragmentation
200/// Middle insertions and removals may leave spare capacity inside chunks. After
201/// a middle removal that leaves the edited chunk non-empty, or after a middle
202/// insertion that splits a full chunk, the edited chunk is locally refilled up
203/// to half capacity from immediate sibling chunks when those siblings contain
204/// more than half capacity. Siblings at or below half capacity are left
205/// untouched.
206///
207/// This is a local minimum-occupancy heuristic, not a global invariant. The
208/// minimum is `N / 2` using integer division, so odd capacities round down.
209/// Front/back pushes and pops keep their direct boundary behavior, so edge
210/// chunks may be less than half full. Use [`shrink`](Self::shrink) when
211/// explicit front compaction is useful.
212///
213/// # Example
214/// ```rust
215/// use array_list::ArrayList;
216///
217/// let mut list: ArrayList<i64, 6> = ArrayList::new();
218/// list.push_back(3);
219/// list.push_front(1);
220/// list.insert(1, 2);
221///
222/// assert!(!list.is_empty());
223/// assert_eq!(list.len(), 3);
224///
225/// assert_eq!(list.pop_front(), Some(1));
226/// assert_eq!(list.pop_front(), Some(2));
227/// assert_eq!(list.pop_front(), Some(3));
228/// ```
229///
230/// ```compile_fail
231/// use array_list::ArrayList;
232///
233/// let mut list: ArrayList<i32, 3> = ArrayList::new();
234/// list.push_back(1);
235/// ```
236pub struct ArrayList<T, const N: usize> {
237    chunks: VecDeque<CapVec<T, N>>,
238    len: usize,
239}
240
241impl<T, const N: usize, const M: usize> From<[T; M]> for ArrayList<T, N> {
242    fn from(values: [T; M]) -> Self {
243        const { assert!(N >= crate::MIN_CHUNK_CAPACITY) };
244
245        values.into_iter().collect()
246    }
247}
248
249impl<T, const N: usize> FromIterator<T> for ArrayList<T, N> {
250    fn from_iter<I: IntoIterator<Item = T>>(iter: I) -> Self {
251        const { assert!(N >= crate::MIN_CHUNK_CAPACITY) };
252
253        let mut this = Self::new();
254        this.extend(iter);
255        this
256    }
257}
258
259impl<T, const N: usize> Extend<T> for ArrayList<T, N> {
260    fn extend<I: IntoIterator<Item = T>>(&mut self, iter: I) {
261        const { assert!(N >= crate::MIN_CHUNK_CAPACITY) };
262
263        let mut iter = iter.into_iter();
264
265        let (lower_bound, _) = iter.size_hint();
266        if lower_bound > 0 {
267            let tail_spare = self
268                .chunks
269                .back()
270                .map_or(0, |chunk| N.saturating_sub(chunk.len()));
271            let new_chunks = lower_bound.saturating_sub(tail_spare).div_ceil(N);
272            self.chunks.reserve(new_chunks);
273        }
274
275        if let Some(chunk) = self.chunks.back_mut() {
276            let old_len = chunk.len();
277            chunk.extend(&mut iter);
278            self.len += chunk.len() - old_len;
279        }
280
281        while let Some(value) = iter.next() {
282            let mut chunk = CapVec::new();
283            chunk.push(value).unwrap_or_unreachable();
284            chunk.extend(&mut iter);
285            self.len += chunk.len();
286            self.chunks.push_back(chunk);
287        }
288    }
289}
290
291impl<'a, T, const N: usize> Extend<&'a T> for ArrayList<T, N>
292where
293    T: Clone,
294{
295    fn extend<I: IntoIterator<Item = &'a T>>(&mut self, iter: I) {
296        const { assert!(N >= crate::MIN_CHUNK_CAPACITY) };
297
298        self.extend(iter.into_iter().cloned());
299    }
300}
301
302impl<T, const N: usize> Default for ArrayList<T, N> {
303    fn default() -> Self {
304        const { assert!(N >= crate::MIN_CHUNK_CAPACITY) };
305
306        Self::new()
307    }
308}
309
310impl<T, const N: usize> ArrayList<T, N> {
311    /// Creates a new, empty `ArrayList` with no elements and no allocated chunks.
312    ///
313    /// # Example
314    /// ```rust
315    /// use array_list::ArrayList;
316    ///
317    /// let list: ArrayList<i64, 6> = ArrayList::new();
318    ///
319    /// assert!(list.is_empty());
320    /// ```
321    pub const fn new() -> Self {
322        const { assert!(N >= crate::MIN_CHUNK_CAPACITY) };
323
324        Self {
325            chunks: VecDeque::new(),
326            len: 0,
327        }
328    }
329
330    /// Adds an element to the front of the `ArrayList`.
331    ///
332    /// The element is inserted at the beginning of the list, shifting existing elements
333    /// forward if necessary. If the first chunk is full, a new one will be allocated to
334    /// accommodate the element.
335    ///
336    /// # Example
337    /// ```rust
338    /// use array_list::ArrayList;
339    ///
340    /// let mut list: ArrayList<i64, 6> = ArrayList::new();
341    /// list.push_front(10);
342    /// list.push_front(20);
343    ///
344    /// assert_eq!(list.len(), 2);
345    ///
346    /// assert_eq!(list.pop_front(), Some(20));
347    /// assert_eq!(list.pop_front(), Some(10));
348    /// ```
349    pub fn push_front(&mut self, value: T) {
350        const { assert!(N >= crate::MIN_CHUNK_CAPACITY) };
351
352        match self.chunks.front_mut() {
353            Some(chunk) if chunk.len() < N => chunk.insert(0, value).unwrap_or_unreachable(),
354            _ => {
355                let mut chunk = CapVec::new();
356                chunk.push(value).unwrap_or_unreachable();
357                self.chunks.push_front(chunk);
358            }
359        }
360
361        self.len += 1;
362    }
363
364    /// Adds an element to the back of the `ArrayList`.
365    ///
366    /// The element is inserted at the end of the list.
367    /// If the last chunk is full, a new one will be allocated to
368    /// accommodate the element.
369    ///
370    /// # Example
371    /// ```rust
372    /// use array_list::ArrayList;
373    ///
374    /// let mut list: ArrayList<i64, 6> = ArrayList::new();
375    /// list.push_back(10);
376    /// list.push_back(20);
377    ///
378    /// assert_eq!(list.len(), 2);
379    ///
380    /// assert_eq!(list.pop_back(), Some(20));
381    /// assert_eq!(list.pop_back(), Some(10));
382    /// ```
383    pub fn push_back(&mut self, value: T) {
384        const { assert!(N >= crate::MIN_CHUNK_CAPACITY) };
385
386        match self.chunks.back_mut() {
387            Some(chunk) if chunk.len() < N => chunk.push(value).unwrap_or_unreachable(),
388            _ => {
389                let mut chunk = CapVec::new();
390                chunk.push(value).unwrap_or_unreachable();
391                self.chunks.push_back(chunk);
392            }
393        }
394
395        self.len += 1;
396    }
397
398    /// Inserts an element at `index`, shifting that element and all later
399    /// elements to the right.
400    ///
401    /// If the target chunk is full, insertion splits that chunk locally. When a
402    /// middle insertion splits a full chunk, the edited chunk may be refilled up
403    /// to half capacity from immediate sibling chunks that contain more than
404    /// half capacity.
405    /// Inserting at [`len`](Self::len) is equivalent to
406    /// [`push_back`](Self::push_back).
407    ///
408    /// # Panics
409    /// - Panics if the `index` is out of bounds (greater than the list's current length).
410    ///
411    /// # Examples
412    /// ```
413    /// use array_list::ArrayList;
414    ///
415    /// let mut list: ArrayList<i64, 4> = ArrayList::new();
416    /// list.push_back(10);
417    /// list.push_back(30);
418    /// list.insert(1, 20);
419    ///
420    /// assert_eq!(list.get(0), Some(&10));
421    /// assert_eq!(list.get(1), Some(&20));
422    /// assert_eq!(list.get(2), Some(&30));
423    /// ```
424    pub fn insert(&mut self, index: usize, value: T) {
425        const { assert!(N >= crate::MIN_CHUNK_CAPACITY) };
426
427        assert!(index <= self.len());
428
429        if index == 0 {
430            self.push_front(value);
431            return;
432        }
433
434        if index == self.len {
435            self.push_back(value);
436            return;
437        }
438
439        let mut position = self.position_at(index).unwrap();
440        self.insert_before_position(&mut position, value);
441    }
442
443    /// Inserts `value` before `position` and keeps `position` pointing at the
444    /// same logical element, now shifted right by the inserted value.
445    ///
446    /// `position` must point at an existing element. This helper is used for
447    /// middle insertions only; front insertions are handled by the direct
448    /// `push_front` path. When the target chunk is full, the chunk is split
449    /// before insertion; if the edited chunk is under the local minimum after
450    /// insertion, nearby siblings may refill it. `position` is adjusted across
451    /// those storage moves so it still names the original element.
452    fn insert_before_position(&mut self, position: &mut Position, value: T) {
453        const { assert!(N >= crate::MIN_CHUNK_CAPACITY) };
454
455        assert!(position.element < self.len);
456        assert!(position.chunk < self.chunks.len());
457        assert!(position.slot < self.chunks[position.chunk].len());
458
459        if position.element == 0 {
460            self.push_front(value);
461            *position = Position::front(self);
462            position.move_next(self);
463            return;
464        }
465
466        let target_chunk_was_full = self.chunks[position.chunk].len() >= N;
467
468        if target_chunk_was_full {
469            let split_at = Ord::max(position.slot, Self::local_min_occupancy());
470            self.split_chunk_at(position.chunk, split_at);
471
472            if position.slot >= split_at {
473                position.chunk += 1;
474                position.slot -= split_at;
475            }
476        }
477
478        let inserted = *position;
479        position.element += 1;
480        position.slot += 1;
481
482        let chunk = &mut self.chunks[inserted.chunk];
483        chunk.insert(inserted.slot, value).unwrap_or_unreachable();
484        self.len += 1;
485
486        if target_chunk_was_full {
487            self.refill_chunk_to_local_min_occupancy(inserted.chunk, position);
488        }
489    }
490
491    /// Inserts `value` after `position` and keeps `position` pointing at the
492    /// same logical element.
493    ///
494    /// `position` must point at an existing element. The back edge is handled
495    /// directly with `push_back`. Otherwise, inserting after the current element
496    /// is equivalent to inserting before the next element, so this temporarily
497    /// moves `position` forward, delegates to `insert_before_position`, then
498    /// walks back over the shifted target and the inserted value.
499    fn insert_after_position(&mut self, position: &mut Position, value: T) {
500        const { assert!(N >= crate::MIN_CHUNK_CAPACITY) };
501
502        assert!(position.element < self.len);
503        assert!(position.chunk < self.chunks.len());
504        assert!(position.slot < self.chunks[position.chunk].len());
505
506        if (position.element + 1) == self.len {
507            self.push_back(value);
508            return;
509        }
510
511        position.move_next(self);
512        self.insert_before_position(position, value);
513
514        position.move_prev(self);
515        position.move_prev(self);
516    }
517
518    /// Moves all elements from `other` to the back of this list.
519    ///
520    /// This preserves the logical order of both lists. When the tail chunk of
521    /// this list has spare capacity, elements are first drained from the head of
522    /// `other` to fill that boundary chunk; remaining chunks are then moved
523    /// wholesale. After this operation, `other` is empty.
524    ///
525    /// # Example
526    /// ```rust
527    /// use array_list::ArrayList;
528    ///
529    /// let mut list1: ArrayList<i32, 4> = ArrayList::new();
530    /// list1.push_back(1);
531    /// list1.push_back(2);
532    ///
533    /// let mut list2: ArrayList<i32, 4> = ArrayList::new();
534    /// list2.push_back(3);
535    /// list2.push_back(4);
536    ///
537    /// list1.append(&mut list2);
538    ///
539    /// assert_eq!(list1.len(), 4);
540    /// assert_eq!(list1.get(0), Some(&1));
541    /// assert_eq!(list1.get(1), Some(&2));
542    /// assert_eq!(list1.get(2), Some(&3));
543    /// assert_eq!(list1.get(3), Some(&4));
544    /// ```
545    pub fn append(&mut self, other: &mut Self) {
546        const { assert!(N >= crate::MIN_CHUNK_CAPACITY) };
547
548        if let Some(tail) = self.chunks.back_mut() {
549            while tail.len() < N {
550                let Some(head) = other.chunks.front_mut() else {
551                    break;
552                };
553
554                let items_to_take = (N - tail.len()).min(head.len());
555                if items_to_take > 0 {
556                    tail.extend(head.drain(..items_to_take));
557                }
558
559                if head.is_empty() {
560                    other.chunks.pop_front();
561                }
562            }
563        }
564
565        self.chunks.append(&mut other.chunks);
566        self.len += other.len;
567        other.len = 0;
568    }
569
570    /// Removes and returns the first element of the `ArrayList`, if any.
571    /// If the list is empty, it returns `None`.
572    ///
573    /// # Examples
574    /// ```
575    /// use array_list::ArrayList;
576    ///
577    /// let mut list: ArrayList<i64, 4> = ArrayList::new();
578    /// list.push_front(10);
579    /// list.push_front(20);
580    ///
581    /// assert_eq!(list.pop_front(), Some(20));
582    /// assert_eq!(list.pop_front(), Some(10));
583    /// assert_eq!(list.pop_front(), None);
584    /// ```
585    pub fn pop_front(&mut self) -> Option<T> {
586        const { assert!(N >= crate::MIN_CHUNK_CAPACITY) };
587
588        let chunk = self.chunks.front_mut()?;
589
590        let value = chunk.remove(0);
591        if chunk.is_empty() {
592            self.chunks.pop_front();
593        }
594
595        self.len -= 1;
596        value
597    }
598
599    /// Removes and returns the last element of the `ArrayList`, if any.
600    /// If the list is empty, it returns `None`.
601    ///
602    /// # Examples
603    /// ```
604    /// use array_list::ArrayList;
605    ///
606    /// let mut list: ArrayList<i64, 4> = ArrayList::new();
607    /// list.push_back(10);
608    /// list.push_back(20);
609    ///
610    /// assert_eq!(list.pop_back(), Some(20));
611    /// assert_eq!(list.pop_back(), Some(10));
612    /// assert_eq!(list.pop_back(), None);
613    /// ```
614    pub fn pop_back(&mut self) -> Option<T> {
615        const { assert!(N >= crate::MIN_CHUNK_CAPACITY) };
616
617        let chunk = self.chunks.back_mut()?;
618
619        let value = chunk.pop();
620        if chunk.is_empty() {
621            self.chunks.pop_back();
622        }
623
624        self.len -= 1;
625        value
626    }
627
628    /// Removes and returns the element at `index`.
629    ///
630    /// Elements after `index` keep their relative order. After a middle removal
631    /// that leaves the edited chunk non-empty, that chunk may be refilled up to
632    /// half capacity from immediate sibling chunks that contain more than half
633    /// capacity.
634    ///
635    /// # Examples
636    /// ```
637    /// use array_list::ArrayList;
638    ///
639    /// let mut list: ArrayList<i64, 4> = ArrayList::new();
640    /// list.push_back(10);
641    /// list.push_back(20);
642    /// list.push_back(30);
643    /// list.push_back(40);
644    /// list.push_back(50);
645    ///
646    /// assert_eq!(list.remove(1), Some(20));
647    /// assert_eq!(list.get(1), Some(&30));
648    /// assert_eq!(list.len(), 4);
649    ///
650    /// assert_eq!(list.remove(10), None);
651    /// ```
652    pub fn remove(&mut self, index: usize) -> Option<T> {
653        const { assert!(N >= crate::MIN_CHUNK_CAPACITY) };
654
655        if index >= self.len {
656            return None;
657        }
658
659        if index == 0 {
660            return self.pop_front();
661        }
662
663        if index == self.len - 1 {
664            return self.pop_back();
665        }
666
667        let mut position = self.position_at(index).unwrap();
668        self.remove_at_position(&mut position)
669    }
670
671    /// Removes and returns the element at `position`.
672    ///
673    /// `position` must point at an existing element. After removal, it is
674    /// updated to the next logical element, or to the ghost position when the
675    /// removed element was the back element. If a middle removal leaves the
676    /// edited chunk empty, that chunk is removed. Otherwise, the edited chunk
677    /// may be locally refilled from siblings; `position` is adjusted across
678    /// those storage moves and across empty chunk removal.
679    fn remove_at_position(&mut self, position: &mut Position) -> Option<T> {
680        const { assert!(N >= crate::MIN_CHUNK_CAPACITY) };
681
682        assert!(position.element < self.len);
683        assert!(position.chunk < self.chunks.len());
684        assert!(position.slot < self.chunks[position.chunk].len());
685
686        let current = *position;
687
688        // Edge removals delegate to the direct pop paths, then normalize the
689        // cursor position to the documented post-removal location.
690        if current.element == 0 {
691            let value = self.pop_front()?;
692            *position = Position::front(self);
693            return Some(value);
694        }
695
696        if current.element == self.len - 1 {
697            let value = self.pop_back()?;
698            *position = Position::ghost(self);
699            return Some(value);
700        }
701
702        // Reuse `position` as the tracked successor before changing storage,
703        // while the old chunk/slot coordinates are still valid.
704        position.move_next(self);
705
706        let value = self.chunks[current.chunk].remove(current.slot)?;
707        self.len -= 1;
708
709        // The successor takes the removed element's logical index. Its slot
710        // only changes here when it was stored in the edited chunk.
711        position.element = current.element;
712        if position.chunk == current.chunk {
713            position.slot = current.slot;
714        }
715
716        if self.chunks[current.chunk].is_empty() {
717            self.chunks.remove(current.chunk);
718            // If the tracked successor is after the removed empty chunk, its
719            // chunk index shifts left with the remaining storage.
720            if position.chunk > current.chunk {
721                position.chunk -= 1;
722            }
723        } else {
724            self.refill_chunk_to_local_min_occupancy(current.chunk, position);
725        }
726
727        Some(value)
728    }
729
730    /// Removes all elements from the `ArrayList`, effectively making it empty.
731    ///
732    /// # Example
733    /// ```rust
734    /// use array_list::ArrayList;
735    ///
736    /// let mut list: ArrayList<i32, 4> = ArrayList::new();
737    /// list.push_back(1);
738    /// list.push_back(2);
739    /// list.push_back(3);
740    ///
741    /// assert_eq!(list.len(), 3);
742    ///
743    /// list.clear();
744    ///
745    /// assert_eq!(list.len(), 0);
746    /// assert!(list.is_empty());
747    /// assert_eq!(list.front(), None);
748    /// assert_eq!(list.back(), None);
749    /// ```
750    pub fn clear(&mut self) {
751        const { assert!(N >= crate::MIN_CHUNK_CAPACITY) };
752
753        self.chunks.clear();
754        self.len = 0;
755    }
756
757    /// Returns a reference to the first element of the `ArrayList`, if any.
758    ///
759    /// # Examples
760    /// ```
761    /// use array_list::ArrayList;
762    ///
763    /// let mut list: ArrayList<i64, 4> = ArrayList::new();
764    /// list.push_back(10);
765    /// list.push_back(20);
766    ///
767    /// assert_eq!(list.front(), Some(&10));
768    ///
769    /// list.pop_front();
770    /// assert_eq!(list.front(), Some(&20));
771    ///
772    /// list.pop_front();
773    /// assert_eq!(list.front(), None);
774    /// ```
775    pub fn front(&self) -> Option<&T> {
776        const { assert!(N >= crate::MIN_CHUNK_CAPACITY) };
777
778        self.chunks.front().and_then(|chunk| chunk.first())
779    }
780
781    /// Returns a mutable reference to the first element of the `ArrayList`, if any.
782    ///
783    /// # Examples
784    /// ```
785    /// use array_list::ArrayList;
786    ///
787    /// let mut list: ArrayList<i64, 4> = ArrayList::new();
788    /// list.push_back(10);
789    /// list.push_back(20);
790    ///
791    /// assert_eq!(list.front_mut(), Some(&mut 10));
792    ///
793    /// list.pop_front();
794    /// assert_eq!(list.front_mut(), Some(&mut 20));
795    ///
796    /// list.pop_front();
797    /// assert_eq!(list.front_mut(), None);
798    /// ```
799    pub fn front_mut(&mut self) -> Option<&mut T> {
800        const { assert!(N >= crate::MIN_CHUNK_CAPACITY) };
801
802        self.chunks.front_mut().and_then(|chunk| chunk.first_mut())
803    }
804
805    /// Returns a reference to the last element of the `ArrayList`, if any.
806    ///
807    /// # Examples
808    /// ```
809    /// use array_list::ArrayList;
810    ///
811    /// let mut list: ArrayList<i64, 4> = ArrayList::new();
812    /// list.push_back(10);
813    /// list.push_back(20);
814    ///
815    /// assert_eq!(list.back(), Some(&20));
816    ///
817    /// list.pop_back();
818    /// assert_eq!(list.back(), Some(&10));
819    ///
820    /// list.pop_back();
821    /// assert_eq!(list.back(), None);
822    /// ```
823    pub fn back(&self) -> Option<&T> {
824        const { assert!(N >= crate::MIN_CHUNK_CAPACITY) };
825
826        self.chunks.back().and_then(|chunk| chunk.last())
827    }
828
829    /// Returns a mutable reference to the last element of the `ArrayList`, if any.
830    ///
831    /// # Examples
832    /// ```
833    /// use array_list::ArrayList;
834    ///
835    /// let mut list: ArrayList<i64, 4> = ArrayList::new();
836    /// list.push_back(10);
837    /// list.push_back(20);
838    ///
839    /// assert_eq!(list.back_mut(), Some(&mut 20));
840    ///
841    /// list.pop_back();
842    /// assert_eq!(list.back_mut(), Some(&mut 10));
843    ///
844    /// list.pop_back();
845    /// assert_eq!(list.back_mut(), None);
846    /// ```
847    pub fn back_mut(&mut self) -> Option<&mut T> {
848        const { assert!(N >= crate::MIN_CHUNK_CAPACITY) };
849
850        self.chunks.back_mut().and_then(|chunk| chunk.last_mut())
851    }
852
853    /// Returns a reference to the element at `index`, if any.
854    ///
855    /// Index lookup scans chunk metadata to find the chunk containing `index`.
856    /// Fragmented lists may require scanning more chunks than compact lists.
857    ///
858    /// # Examples
859    /// ```
860    /// use array_list::ArrayList;
861    ///
862    /// let mut list: ArrayList<i64, 4> = ArrayList::new();
863    /// list.push_back(10);
864    /// list.push_back(20);
865    ///
866    /// assert_eq!(list.get(0), Some(&10));
867    /// assert_eq!(list.get(1), Some(&20));
868    /// assert_eq!(list.get(2), None); // Out of bounds
869    /// ```
870    pub fn get(&self, index: usize) -> Option<&T> {
871        const { assert!(N >= crate::MIN_CHUNK_CAPACITY) };
872
873        let position = self.position_at(index)?;
874        self.chunks[position.chunk].get(position.slot)
875    }
876
877    /// Returns a mutable reference to the element at `index`, if any.
878    ///
879    /// Index lookup scans chunk metadata to find the chunk containing `index`.
880    /// Fragmented lists may require scanning more chunks than compact lists.
881    ///
882    /// # Examples
883    /// ```
884    /// use array_list::ArrayList;
885    ///
886    /// let mut list: ArrayList<i64, 4> = ArrayList::new();
887    /// list.push_back(10);
888    /// list.push_back(20);
889    ///
890    /// assert_eq!(list.get_mut(0), Some(&mut 10));
891    /// assert_eq!(list.get_mut(1), Some(&mut 20));
892    /// assert_eq!(list.get_mut(2), None); // Out of bounds
893    /// ```
894    pub fn get_mut(&mut self, index: usize) -> Option<&mut T> {
895        const { assert!(N >= crate::MIN_CHUNK_CAPACITY) };
896
897        let position = self.position_at(index)?;
898        self.chunks[position.chunk].get_mut(position.slot)
899    }
900
901    /// Returns the number of elements currently stored in the `ArrayList`.
902    ///
903    /// # Example
904    /// ```rust
905    /// use array_list::ArrayList;
906    ///
907    /// let mut list: ArrayList<i64, 6> = ArrayList::new();
908    /// list.push_back(1);
909    /// list.push_back(2);
910    ///
911    /// assert_eq!(list.len(), 2);
912    /// ```
913    #[inline]
914    pub const fn len(&self) -> usize {
915        const { assert!(N >= crate::MIN_CHUNK_CAPACITY) };
916
917        self.len
918    }
919
920    /// Returns the total number of elements that can fit in the currently allocated chunks.
921    ///
922    /// This is the sum of the capacity of every internal chunk. It is always at
923    /// least [`len`](Self::len), but it may be larger after edits until the list
924    /// is compacted with [`shrink`](Self::shrink).
925    ///
926    /// # Example
927    /// ```rust
928    /// use array_list::ArrayList;
929    ///
930    /// let mut list: ArrayList<i32, 4> = ArrayList::new();
931    /// assert_eq!(list.capacity(), 0);
932    ///
933    /// list.push_back(1);
934    /// assert!(list.capacity() >= list.len());
935    /// ```
936    pub fn capacity(&self) -> usize {
937        const { assert!(N >= crate::MIN_CHUNK_CAPACITY) };
938
939        self.chunks.iter().map(CapVec::capacity).sum()
940    }
941
942    /// Returns the number of unused element slots in allocated chunks.
943    ///
944    /// This is [`capacity`](Self::capacity) minus [`len`](Self::len). A larger
945    /// value means the list has more spare chunk storage, usually after middle
946    /// edits, front-heavy insertions, or uneven appends.
947    ///
948    /// # Example
949    /// ```rust
950    /// use array_list::ArrayList;
951    ///
952    /// let mut list: ArrayList<i32, 4> = ArrayList::from([1, 2, 3, 4, 5]);
953    /// list.remove(1);
954    ///
955    /// assert_eq!(list.spare_capacity(), list.capacity() - list.len());
956    /// ```
957    pub fn spare_capacity(&self) -> usize {
958        const { assert!(N >= crate::MIN_CHUNK_CAPACITY) };
959
960        self.capacity() - self.len()
961    }
962
963    /// Compacts elements toward the front of the list.
964    ///
965    /// This preserves element order and length. It can reduce spare capacity
966    /// after removals or uneven insertions by filling earlier chunks from later
967    /// chunks and removing chunks that become empty. It does not guarantee that
968    /// all allocation capacity held by the internal `VecDeque` is released.
969    ///
970    /// # Example
971    /// ```rust
972    /// use array_list::ArrayList;
973    ///
974    /// let mut list: ArrayList<i32, 4> = ArrayList::from([1, 2, 3]);
975    /// list.remove(1);
976    /// list.shrink();
977    ///
978    /// assert_eq!(list, [1, 3]);
979    /// ```
980    pub fn shrink(&mut self) {
981        const { assert!(N >= crate::MIN_CHUNK_CAPACITY) };
982
983        self.compact_from(0);
984    }
985
986    /// Checks if the `ArrayList` is empty.
987    ///
988    /// # Example
989    /// ```rust
990    /// use array_list::ArrayList;
991    ///
992    /// let mut list: ArrayList<i64, 6> = ArrayList::new();
993    /// assert!(list.is_empty());
994    ///
995    /// list.push_back(1);
996    /// assert!(!list.is_empty());
997    /// ```
998    #[inline]
999    pub const fn is_empty(&self) -> bool {
1000        const { assert!(N >= crate::MIN_CHUNK_CAPACITY) };
1001
1002        self.len == 0
1003    }
1004
1005    /// Provides an iterator over the list's elements.
1006    ///
1007    /// # Examples
1008    /// ```
1009    /// use array_list::ArrayList;
1010    ///
1011    /// let mut list: ArrayList<_, 4> = ArrayList::new();
1012    /// list.push_back(0);
1013    /// list.push_back(1);
1014    /// list.push_back(2);
1015    ///
1016    /// let mut iter = list.iter();
1017    /// assert_eq!(iter.next(), Some(&0));
1018    /// assert_eq!(iter.next(), Some(&1));
1019    /// assert_eq!(iter.next(), Some(&2));
1020    /// assert_eq!(iter.next(), None);
1021    /// ```
1022    #[inline]
1023    pub fn iter(&self) -> Iter<'_, T, N> {
1024        const { assert!(N >= crate::MIN_CHUNK_CAPACITY) };
1025
1026        Iter::from_list(self)
1027    }
1028
1029    /// Provides a mutable iterator over the list's elements.
1030    ///
1031    /// # Examples
1032    /// ```
1033    /// use array_list::ArrayList;
1034    ///
1035    /// let mut list: ArrayList<_, 4> = ArrayList::new();
1036    /// list.push_back(0);
1037    /// list.push_back(1);
1038    /// list.push_back(2);
1039    ///
1040    /// let mut iter = list.iter_mut();
1041    /// assert_eq!(iter.next(), Some(&mut 0));
1042    /// assert_eq!(iter.next(), Some(&mut 1));
1043    /// assert_eq!(iter.next(), Some(&mut 2));
1044    /// assert_eq!(iter.next(), None);
1045    /// ```
1046    #[inline]
1047    pub fn iter_mut(&mut self) -> IterMut<'_, T, N> {
1048        const { assert!(N >= crate::MIN_CHUNK_CAPACITY) };
1049
1050        IterMut::from_list(self)
1051    }
1052
1053    /// Provides a read-only cursor at the front element.
1054    ///
1055    /// The cursor points to the ghost non-element if the list is empty.
1056    ///
1057    /// # Example
1058    /// ```rust
1059    /// use array_list::ArrayList;
1060    ///
1061    /// let list: ArrayList<i32, 4> = ArrayList::from([1, 2]);
1062    /// let cursor = list.cursor_front();
1063    ///
1064    /// assert_eq!(cursor.index(), Some(0));
1065    /// assert_eq!(cursor.current(), Some(&1));
1066    ///
1067    /// let empty: ArrayList<i32, 4> = ArrayList::new();
1068    /// assert_eq!(empty.cursor_front().index(), None);
1069    /// ```
1070    #[inline]
1071    pub fn cursor_front(&self) -> Cursor<'_, T, N> {
1072        const { assert!(N >= crate::MIN_CHUNK_CAPACITY) };
1073
1074        Cursor::from_front(self)
1075    }
1076
1077    /// Provides a read-only cursor at the back element.
1078    ///
1079    /// The cursor points to the ghost non-element if the list is empty.
1080    ///
1081    /// # Example
1082    /// ```rust
1083    /// use array_list::ArrayList;
1084    ///
1085    /// let list: ArrayList<i32, 4> = ArrayList::from([1, 2]);
1086    /// let cursor = list.cursor_back();
1087    ///
1088    /// assert_eq!(cursor.index(), Some(1));
1089    /// assert_eq!(cursor.current(), Some(&2));
1090    ///
1091    /// let empty: ArrayList<i32, 4> = ArrayList::new();
1092    /// assert_eq!(empty.cursor_back().index(), None);
1093    /// ```
1094    #[inline]
1095    pub fn cursor_back(&self) -> Cursor<'_, T, N> {
1096        const { assert!(N >= crate::MIN_CHUNK_CAPACITY) };
1097
1098        Cursor::from_back(self)
1099    }
1100
1101    /// Provides a mutable cursor at the front element.
1102    ///
1103    /// The cursor points to the ghost non-element if the list is empty.
1104    ///
1105    /// # Example
1106    /// ```rust
1107    /// use array_list::ArrayList;
1108    ///
1109    /// let mut list: ArrayList<i32, 4> = ArrayList::from([1, 2]);
1110    /// let mut cursor = list.cursor_front_mut();
1111    ///
1112    /// assert_eq!(cursor.index(), Some(0));
1113    /// assert_eq!(cursor.current(), Some(&mut 1));
1114    ///
1115    /// let mut empty: ArrayList<i32, 4> = ArrayList::new();
1116    /// assert_eq!(empty.cursor_front_mut().index(), None);
1117    /// ```
1118    #[inline]
1119    pub fn cursor_front_mut(&mut self) -> CursorMut<'_, T, N> {
1120        const { assert!(N >= crate::MIN_CHUNK_CAPACITY) };
1121
1122        CursorMut::from_front(self)
1123    }
1124
1125    /// Provides a mutable cursor at the back element.
1126    ///
1127    /// The cursor points to the ghost non-element if the list is empty.
1128    ///
1129    /// # Example
1130    /// ```rust
1131    /// use array_list::ArrayList;
1132    ///
1133    /// let mut list: ArrayList<i32, 4> = ArrayList::from([1, 2]);
1134    /// let mut cursor = list.cursor_back_mut();
1135    ///
1136    /// assert_eq!(cursor.index(), Some(1));
1137    /// assert_eq!(cursor.current(), Some(&mut 2));
1138    ///
1139    /// let mut empty: ArrayList<i32, 4> = ArrayList::new();
1140    /// assert_eq!(empty.cursor_back_mut().index(), None);
1141    /// ```
1142    #[inline]
1143    pub fn cursor_back_mut(&mut self) -> CursorMut<'_, T, N> {
1144        const { assert!(N >= crate::MIN_CHUNK_CAPACITY) };
1145
1146        CursorMut::from_back(self)
1147    }
1148
1149    fn position_at(&self, mut index: usize) -> Option<Position> {
1150        const { assert!(N >= crate::MIN_CHUNK_CAPACITY) };
1151
1152        let element = index;
1153
1154        if index >= self.len() {
1155            return None;
1156        }
1157
1158        if self.chunks.len() == 1 || self.chunks.len().checked_mul(N) == Some(self.len) {
1159            return Some(Position {
1160                element,
1161                chunk: index / N,
1162                slot: index % N,
1163            });
1164        }
1165
1166        if index <= self.len() / 2 {
1167            for (chunk_index, chunk) in self.chunks.iter().enumerate() {
1168                let chunk_len = chunk.len();
1169                if index < chunk_len {
1170                    return Some(Position {
1171                        element,
1172                        chunk: chunk_index,
1173                        slot: index,
1174                    });
1175                }
1176
1177                index -= chunk_len;
1178            }
1179
1180            return None;
1181        }
1182
1183        let mut remaining_len = self.len();
1184        for chunk_index in (0..self.chunks.len()).rev() {
1185            remaining_len -= self.chunks[chunk_index].len();
1186
1187            if index >= remaining_len {
1188                return Some(Position {
1189                    element,
1190                    chunk: chunk_index,
1191                    slot: index - remaining_len,
1192                });
1193            }
1194        }
1195
1196        None
1197    }
1198
1199    fn split_chunk_at(&mut self, chunk_index: usize, split_at: usize) {
1200        const { assert!(N >= crate::MIN_CHUNK_CAPACITY) };
1201
1202        let mut next = CapVec::new();
1203        let chunk = &mut self.chunks[chunk_index];
1204        next.extend(chunk.drain(split_at..));
1205
1206        self.chunks.insert(chunk_index + 1, next);
1207    }
1208
1209    const fn local_min_occupancy() -> usize {
1210        N / 2
1211    }
1212
1213    /// Refills `chunk_index` up to the local minimum occupancy when possible.
1214    ///
1215    /// This is a local repair step used after middle insertions split a chunk
1216    /// and after middle removals shrink a non-empty chunk. It only pulls from
1217    /// immediate siblings while those siblings remain above the local minimum
1218    /// occupancy, preferring the previous sibling before the next sibling.
1219    /// `tracked` is a position that must continue to point at the same logical
1220    /// element while values move across chunk boundaries.
1221    fn refill_chunk_to_local_min_occupancy(&mut self, chunk_index: usize, tracked: &mut Position) {
1222        const { assert!(N >= crate::MIN_CHUNK_CAPACITY) };
1223
1224        let min_occupancy = Self::local_min_occupancy();
1225        if chunk_index >= self.chunks.len() {
1226            return;
1227        }
1228
1229        if chunk_index > 0 {
1230            let previous_chunk = chunk_index - 1;
1231
1232            // Pull from the previous sibling first. Its last element becomes
1233            // the new first element of the edited chunk, preserving order.
1234            while self.chunks[chunk_index].len() < min_occupancy
1235                && self.chunks[previous_chunk].len() > min_occupancy
1236            {
1237                let moved_slot = self.chunks[previous_chunk].len() - 1;
1238                let value = self.chunks[previous_chunk].pop().unwrap();
1239
1240                // Keep `tracked` on the same logical element when that element
1241                // is moved, or when prepending shifts slots in the edited chunk.
1242                if tracked.chunk == previous_chunk && tracked.slot == moved_slot {
1243                    tracked.chunk = chunk_index;
1244                    tracked.slot = 0;
1245                } else if tracked.chunk == chunk_index {
1246                    tracked.slot += 1;
1247                }
1248
1249                self.chunks[chunk_index]
1250                    .insert(0, value)
1251                    .unwrap_or_unreachable();
1252            }
1253        }
1254
1255        let next_chunk = chunk_index + 1;
1256        if next_chunk < self.chunks.len() {
1257            // Then pull from the next sibling. Its first element becomes the
1258            // new last element of the edited chunk.
1259            while self.chunks[chunk_index].len() < min_occupancy
1260                && self.chunks[next_chunk].len() > min_occupancy
1261            {
1262                let target_slot = self.chunks[chunk_index].len();
1263                let value = self.chunks[next_chunk].remove(0).unwrap();
1264
1265                // The moved first element changes chunks; later elements in
1266                // the next sibling shift left by one slot.
1267                if tracked.chunk == next_chunk {
1268                    if tracked.slot == 0 {
1269                        tracked.chunk = chunk_index;
1270                        tracked.slot = target_slot;
1271                    } else {
1272                        tracked.slot -= 1;
1273                    }
1274                }
1275
1276                self.chunks[chunk_index].push(value).unwrap_or_unreachable();
1277            }
1278        }
1279    }
1280
1281    fn compact_from(&mut self, chunk_index: usize) {
1282        const { assert!(N >= crate::MIN_CHUNK_CAPACITY) };
1283
1284        if self.chunks.len() <= 1 {
1285            return;
1286        }
1287
1288        let mut chunk_index = chunk_index.min(self.chunks.len() - 1);
1289
1290        while chunk_index + 1 < self.chunks.len() {
1291            if self.chunks[chunk_index].len() >= N {
1292                chunk_index += 1;
1293                continue;
1294            }
1295
1296            while self.chunks[chunk_index].len() < N && chunk_index + 1 < self.chunks.len() {
1297                let mut source = self.chunks.remove(chunk_index + 1).unwrap();
1298                let missing = N - self.chunks[chunk_index].len();
1299                let take = missing.min(source.len());
1300
1301                if take > 0 {
1302                    self.chunks[chunk_index].extend(source.drain(..take));
1303                }
1304
1305                if !source.is_empty() {
1306                    self.chunks.insert(chunk_index + 1, source);
1307                }
1308            }
1309
1310            chunk_index += 1;
1311        }
1312    }
1313}
1314
1315impl<T: Clone, const N: usize> Clone for ArrayList<T, N> {
1316    fn clone(&self) -> Self {
1317        const { assert!(N >= crate::MIN_CHUNK_CAPACITY) };
1318
1319        Self {
1320            chunks: self.chunks.clone(),
1321            len: self.len,
1322        }
1323    }
1324}
1325
1326impl<T, const N: usize, const M: usize> PartialEq<[T; M]> for ArrayList<T, N>
1327where
1328    T: PartialEq,
1329{
1330    fn eq(&self, other: &[T; M]) -> bool {
1331        const { assert!(N >= crate::MIN_CHUNK_CAPACITY) };
1332
1333        self.len() == other.len() && self.iter().eq(other)
1334    }
1335}
1336
1337impl<T, const N: usize> PartialEq<&[T]> for ArrayList<T, N>
1338where
1339    T: PartialEq,
1340{
1341    fn eq(&self, other: &&[T]) -> bool {
1342        const { assert!(N >= crate::MIN_CHUNK_CAPACITY) };
1343
1344        self.len() == other.len() && self.iter().eq(other.iter())
1345    }
1346}
1347
1348impl<T, const N: usize> PartialEq<[T]> for ArrayList<T, N>
1349where
1350    T: PartialEq,
1351{
1352    fn eq(&self, other: &[T]) -> bool {
1353        const { assert!(N >= crate::MIN_CHUNK_CAPACITY) };
1354
1355        self.len() == other.len() && self.iter().eq(other)
1356    }
1357}
1358
1359impl<T, const N: usize> PartialEq for ArrayList<T, N>
1360where
1361    T: PartialEq,
1362{
1363    fn eq(&self, other: &Self) -> bool {
1364        const { assert!(N >= crate::MIN_CHUNK_CAPACITY) };
1365
1366        self.len() == other.len() && self.iter().eq(other)
1367    }
1368}
1369
1370impl<T, const N: usize> Eq for ArrayList<T, N> where T: Eq {}
1371
1372impl<T, const N: usize> PartialOrd for ArrayList<T, N>
1373where
1374    T: PartialOrd,
1375{
1376    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
1377        const { assert!(N >= crate::MIN_CHUNK_CAPACITY) };
1378
1379        self.iter().partial_cmp(other)
1380    }
1381}
1382
1383impl<T, const N: usize> Ord for ArrayList<T, N>
1384where
1385    T: Ord,
1386{
1387    #[inline]
1388    fn cmp(&self, other: &Self) -> Ordering {
1389        const { assert!(N >= crate::MIN_CHUNK_CAPACITY) };
1390
1391        self.iter().cmp(other)
1392    }
1393}
1394
1395impl<T, const N: usize> Hash for ArrayList<T, N>
1396where
1397    T: Hash,
1398{
1399    fn hash<H: Hasher>(&self, state: &mut H) {
1400        const { assert!(N >= crate::MIN_CHUNK_CAPACITY) };
1401
1402        state.write_usize(self.len());
1403        self.iter().for_each(|v| v.hash(state));
1404    }
1405}
1406
1407impl<T, const N: usize> core::fmt::Debug for ArrayList<T, N>
1408where
1409    T: core::fmt::Debug,
1410{
1411    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
1412        const { assert!(N >= crate::MIN_CHUNK_CAPACITY) };
1413
1414        f.debug_list().entries(self.chunks.iter()).finish()
1415    }
1416}
1417
1418impl<T, const N: usize> IntoIterator for ArrayList<T, N> {
1419    type Item = T;
1420    type IntoIter = IntoIter<T, N>;
1421
1422    fn into_iter(self) -> Self::IntoIter {
1423        const { assert!(N >= crate::MIN_CHUNK_CAPACITY) };
1424
1425        IntoIter::from_list(self)
1426    }
1427}
1428
1429impl<'a, T, const N: usize> IntoIterator for &'a ArrayList<T, N> {
1430    type Item = &'a T;
1431    type IntoIter = Iter<'a, T, N>;
1432
1433    fn into_iter(self) -> Self::IntoIter {
1434        const { assert!(N >= crate::MIN_CHUNK_CAPACITY) };
1435
1436        Iter::from_list(self)
1437    }
1438}
1439
1440impl<'a, T, const N: usize> IntoIterator for &'a mut ArrayList<T, N> {
1441    type Item = &'a mut T;
1442    type IntoIter = IterMut<'a, T, N>;
1443
1444    fn into_iter(self) -> Self::IntoIter {
1445        const { assert!(N >= crate::MIN_CHUNK_CAPACITY) };
1446
1447        self.iter_mut()
1448    }
1449}
1450
1451trait UnwrapExt {
1452    type Output;
1453
1454    fn unwrap_or_unreachable(self) -> Self::Output;
1455}
1456
1457impl<T, E> UnwrapExt for Result<T, E> {
1458    type Output = T;
1459
1460    fn unwrap_or_unreachable(self) -> Self::Output {
1461        match self {
1462            Ok(value) => value,
1463            Err(_) => unreachable!(),
1464        }
1465    }
1466}
1467
1468#[cfg(all(test, not(miri)))]
1469mod tests {
1470    use super::{ArrayList, Cursor, UnwrapExt};
1471    use alloc::collections::VecDeque;
1472    use alloc::rc::Rc;
1473    use alloc::vec::Vec;
1474    use cap_vec::CapVec;
1475    use core::cell::Cell;
1476    use core::cmp::Ordering;
1477    use core::hash::{Hash, Hasher};
1478    use proptest::prelude::*;
1479
1480    fn values<const N: usize>(list: &ArrayList<i32, N>) -> Vec<i32> {
1481        list.iter().copied().collect()
1482    }
1483
1484    fn chunk_lengths<const N: usize>(list: &ArrayList<i32, N>) -> Vec<usize> {
1485        list.chunks.iter().map(|chunk| chunk.len()).collect()
1486    }
1487
1488    fn usize_chunk<const N: usize>(values: impl IntoIterator<Item = usize>) -> CapVec<usize, N> {
1489        let mut chunk = CapVec::new();
1490        for value in values {
1491            chunk.push(value).unwrap_or_unreachable();
1492        }
1493        chunk
1494    }
1495
1496    fn assert_matches_model<const N: usize>(list: &ArrayList<i32, N>, model: &[i32]) {
1497        assert_eq!(list.len(), model.len());
1498        assert_eq!(list.is_empty(), model.is_empty());
1499        assert_eq!(values(list), model);
1500        assert_eq!(list.iter().count(), model.len());
1501        assert!(list.capacity() >= list.len());
1502        assert_eq!(list.spare_capacity(), list.capacity() - list.len());
1503        assert_eq!(list.front(), model.first());
1504        assert_eq!(list.back(), model.last());
1505        assert_eq!(list.get(model.len()), None);
1506        assert!(list.chunks.iter().all(|chunk| !chunk.is_empty()));
1507        assert!(list.chunks.iter().all(|chunk| chunk.len() <= N));
1508        assert_eq!(
1509            list.chunks.iter().map(|chunk| chunk.len()).sum::<usize>(),
1510            list.len()
1511        );
1512
1513        for (index, value) in model.iter().enumerate() {
1514            assert_eq!(list.get(index), Some(value));
1515        }
1516    }
1517
1518    macro_rules! check_capacities {
1519        ($check:ident) => {{
1520            $check::<4>();
1521            $check::<8>();
1522            $check::<16>();
1523        }};
1524    }
1525
1526    #[derive(Clone, Debug)]
1527    enum ModelOp {
1528        PushFront(i32),
1529        PushBack(i32),
1530        PopFront,
1531        PopBack,
1532        Insert { index: usize, value: i32 },
1533        Remove { index: usize },
1534        Clear,
1535        Shrink,
1536    }
1537
1538    fn model_op_strategy() -> impl Strategy<Value = ModelOp> {
1539        prop_oneof![
1540            any::<i8>().prop_map(|value| ModelOp::PushFront(value.into())),
1541            any::<i8>().prop_map(|value| ModelOp::PushBack(value.into())),
1542            Just(ModelOp::PopFront),
1543            Just(ModelOp::PopBack),
1544            (0usize..32, any::<i8>()).prop_map(|(index, value)| ModelOp::Insert {
1545                index,
1546                value: value.into()
1547            }),
1548            (0usize..32).prop_map(|index| ModelOp::Remove { index }),
1549            Just(ModelOp::Clear),
1550            Just(ModelOp::Shrink),
1551        ]
1552    }
1553
1554    fn apply_model_ops<const N: usize>(ops: &[ModelOp]) {
1555        let mut list = ArrayList::<i32, N>::new();
1556        let mut model = Vec::new();
1557
1558        assert_matches_model(&list, &model);
1559
1560        for op in ops {
1561            match *op {
1562                ModelOp::PushFront(value) => {
1563                    list.push_front(value);
1564                    model.insert(0, value);
1565                }
1566                ModelOp::PushBack(value) => {
1567                    list.push_back(value);
1568                    model.push(value);
1569                }
1570                ModelOp::PopFront => {
1571                    let expected = (!model.is_empty()).then(|| model.remove(0));
1572                    assert_eq!(list.pop_front(), expected);
1573                }
1574                ModelOp::PopBack => {
1575                    assert_eq!(list.pop_back(), model.pop());
1576                }
1577                ModelOp::Insert { index, value } => {
1578                    let index = if model.is_empty() {
1579                        0
1580                    } else {
1581                        index % (model.len() + 1)
1582                    };
1583                    list.insert(index, value);
1584                    model.insert(index, value);
1585                }
1586                ModelOp::Remove { index } => {
1587                    let expected = (index < model.len()).then(|| model.remove(index));
1588                    assert_eq!(list.remove(index), expected);
1589                }
1590                ModelOp::Clear => {
1591                    list.clear();
1592                    model.clear();
1593                }
1594                ModelOp::Shrink => {
1595                    list.shrink();
1596                }
1597            }
1598
1599            assert_matches_model(&list, &model);
1600        }
1601    }
1602
1603    #[derive(Clone, Debug)]
1604    enum CursorModelOp {
1605        MoveNext,
1606        MovePrev,
1607        InsertBefore(i32),
1608        InsertAfter(i32),
1609        PushFront(i32),
1610        PushBack(i32),
1611        PopFront,
1612        PopBack,
1613        RemoveCurrent,
1614    }
1615
1616    fn cursor_model_op_strategy() -> impl Strategy<Value = CursorModelOp> {
1617        prop_oneof![
1618            Just(CursorModelOp::MoveNext),
1619            Just(CursorModelOp::MovePrev),
1620            any::<i8>().prop_map(|value| CursorModelOp::InsertBefore(value.into())),
1621            any::<i8>().prop_map(|value| CursorModelOp::InsertAfter(value.into())),
1622            any::<i8>().prop_map(|value| CursorModelOp::PushFront(value.into())),
1623            any::<i8>().prop_map(|value| CursorModelOp::PushBack(value.into())),
1624            Just(CursorModelOp::PopFront),
1625            Just(CursorModelOp::PopBack),
1626            Just(CursorModelOp::RemoveCurrent),
1627        ]
1628    }
1629
1630    fn model_move_next(cursor: &mut Option<usize>, len: usize) {
1631        *cursor = match *cursor {
1632            None => (len > 0).then_some(0),
1633            Some(index) if index + 1 < len => Some(index + 1),
1634            Some(_) => None,
1635        };
1636    }
1637
1638    fn model_move_prev(cursor: &mut Option<usize>, len: usize) {
1639        *cursor = match *cursor {
1640            None => len.checked_sub(1),
1641            Some(0) => None,
1642            Some(index) => Some(index - 1),
1643        };
1644    }
1645
1646    fn apply_cursor_model_ops<const N: usize>(ops: &[CursorModelOp]) {
1647        let mut list = ArrayList::<i32, N>::from([0, 1, 2, 3]);
1648        let mut model = Vec::from([0, 1, 2, 3]);
1649        let mut model_cursor = Some(0usize);
1650
1651        for op in ops {
1652            let actual_index = {
1653                let mut cursor = list.cursor_front_mut();
1654                for _ in 0..model_cursor.unwrap_or(model.len()) {
1655                    cursor.move_next();
1656                }
1657
1658                match *op {
1659                    CursorModelOp::MoveNext => {
1660                        cursor.move_next();
1661                        model_move_next(&mut model_cursor, model.len());
1662                    }
1663                    CursorModelOp::MovePrev => {
1664                        cursor.move_prev();
1665                        model_move_prev(&mut model_cursor, model.len());
1666                    }
1667                    CursorModelOp::InsertBefore(value) => {
1668                        cursor.insert_before(value);
1669                        let index = model_cursor.unwrap_or(model.len());
1670                        model.insert(index, value);
1671                        if let Some(cursor_index) = &mut model_cursor {
1672                            *cursor_index += 1;
1673                        }
1674                    }
1675                    CursorModelOp::InsertAfter(value) => {
1676                        cursor.insert_after(value);
1677                        let index = model_cursor.map_or(0, |index| index + 1);
1678                        model.insert(index, value);
1679                    }
1680                    CursorModelOp::PushFront(value) => {
1681                        cursor.push_front(value);
1682                        model.insert(0, value);
1683                        if let Some(cursor_index) = &mut model_cursor {
1684                            *cursor_index += 1;
1685                        }
1686                    }
1687                    CursorModelOp::PushBack(value) => {
1688                        cursor.push_back(value);
1689                        model.push(value);
1690                    }
1691                    CursorModelOp::PopFront => {
1692                        let expected = (!model.is_empty()).then(|| model.remove(0));
1693                        assert_eq!(cursor.pop_front(), expected);
1694                        if let Some(cursor_index) = &mut model_cursor {
1695                            *cursor_index = cursor_index.saturating_sub(1);
1696                        }
1697                        if model_cursor.is_some_and(|index| index >= model.len()) {
1698                            model_cursor = None;
1699                        }
1700                    }
1701                    CursorModelOp::PopBack => {
1702                        assert_eq!(cursor.pop_back(), model.pop());
1703                        if model_cursor.is_some_and(|index| index >= model.len()) {
1704                            model_cursor = None;
1705                        }
1706                    }
1707                    CursorModelOp::RemoveCurrent => {
1708                        let expected = model_cursor.map(|index| model.remove(index));
1709                        assert_eq!(cursor.remove_current(), expected);
1710                        if model_cursor.is_some_and(|index| index >= model.len()) {
1711                            model_cursor = None;
1712                        }
1713                    }
1714                };
1715
1716                cursor.index()
1717            };
1718
1719            assert_eq!(actual_index, model_cursor);
1720            assert_matches_model(&list, &model);
1721        }
1722    }
1723
1724    #[derive(Clone, Copy, Debug)]
1725    enum ReadOnlyCursorModelOp {
1726        MoveNext,
1727        MovePrev,
1728    }
1729
1730    fn read_only_cursor_model_op_strategy() -> impl Strategy<Value = ReadOnlyCursorModelOp> {
1731        prop_oneof![
1732            Just(ReadOnlyCursorModelOp::MoveNext),
1733            Just(ReadOnlyCursorModelOp::MovePrev),
1734        ]
1735    }
1736
1737    fn assert_cursor_matches_model<const N: usize>(
1738        cursor: &Cursor<'_, i32, N>,
1739        model: &[i32],
1740        model_cursor: Option<usize>,
1741    ) {
1742        assert_eq!(cursor.index(), model_cursor);
1743        assert_eq!(cursor.current(), model_cursor.map(|index| &model[index]));
1744        assert_eq!(cursor.front(), model.first());
1745        assert_eq!(cursor.back(), model.last());
1746        assert_eq!(cursor.as_list().len(), model.len());
1747
1748        let expected_next =
1749            model_cursor.map_or_else(|| model.first(), |index| model.get(index.saturating_add(1)));
1750        let expected_prev = match model_cursor {
1751            None => model.last(),
1752            Some(0) => None,
1753            Some(index) => model.get(index - 1),
1754        };
1755
1756        assert_eq!(cursor.peek_next(), expected_next);
1757        assert_eq!(cursor.peek_prev(), expected_prev);
1758    }
1759
1760    fn apply_read_only_cursor_model_ops<const N: usize>(ops: &[ReadOnlyCursorModelOp]) {
1761        let list = ArrayList::<i32, N>::from([0, 1, 2, 3, 4, 5, 6, 7, 8, 9]);
1762        let model = Vec::from([0, 1, 2, 3, 4, 5, 6, 7, 8, 9]);
1763        let mut cursor = list.cursor_front();
1764        let mut model_cursor = Some(0usize);
1765
1766        assert_cursor_matches_model(&cursor, &model, model_cursor);
1767
1768        for op in ops {
1769            match op {
1770                ReadOnlyCursorModelOp::MoveNext => {
1771                    cursor.move_next();
1772                    model_move_next(&mut model_cursor, model.len());
1773                }
1774                ReadOnlyCursorModelOp::MovePrev => {
1775                    cursor.move_prev();
1776                    model_move_prev(&mut model_cursor, model.len());
1777                }
1778            }
1779
1780            assert_cursor_matches_model(&cursor, &model, model_cursor);
1781        }
1782    }
1783
1784    #[derive(Clone, Copy, Debug)]
1785    enum IteratorModelOp {
1786        Next,
1787        NextBack,
1788        Nth(usize),
1789        NthBack(usize),
1790    }
1791
1792    fn iterator_model_op_strategy() -> impl Strategy<Value = IteratorModelOp> {
1793        prop_oneof![
1794            Just(IteratorModelOp::Next),
1795            Just(IteratorModelOp::NextBack),
1796            (0usize..8).prop_map(IteratorModelOp::Nth),
1797            (0usize..8).prop_map(IteratorModelOp::NthBack),
1798        ]
1799    }
1800
1801    fn model_nth(model: &mut VecDeque<i32>, n: usize) -> Option<i32> {
1802        if n >= model.len() {
1803            model.clear();
1804            return None;
1805        }
1806
1807        for _ in 0..n {
1808            model.pop_front();
1809        }
1810
1811        model.pop_front()
1812    }
1813
1814    fn model_nth_back(model: &mut VecDeque<i32>, n: usize) -> Option<i32> {
1815        if n >= model.len() {
1816            model.clear();
1817            return None;
1818        }
1819
1820        for _ in 0..n {
1821            model.pop_back();
1822        }
1823
1824        model.pop_back()
1825    }
1826
1827    fn apply_iter_model_ops<const N: usize>(ops: &[IteratorModelOp]) {
1828        let list = ArrayList::<i32, N>::from([0, 1, 2, 3, 4, 5, 6, 7, 8, 9]);
1829        let mut iter = list.iter();
1830        let mut model = VecDeque::from([0, 1, 2, 3, 4, 5, 6, 7, 8, 9]);
1831
1832        for op in ops {
1833            let expected = match *op {
1834                IteratorModelOp::Next => model.pop_front(),
1835                IteratorModelOp::NextBack => model.pop_back(),
1836                IteratorModelOp::Nth(n) => model_nth(&mut model, n),
1837                IteratorModelOp::NthBack(n) => model_nth_back(&mut model, n),
1838            };
1839
1840            let actual = match *op {
1841                IteratorModelOp::Next => iter.next().copied(),
1842                IteratorModelOp::NextBack => iter.next_back().copied(),
1843                IteratorModelOp::Nth(n) => iter.nth(n).copied(),
1844                IteratorModelOp::NthBack(n) => iter.nth_back(n).copied(),
1845            };
1846
1847            assert_eq!(actual, expected);
1848        }
1849
1850        assert_eq!(
1851            iter.copied().collect::<Vec<_>>(),
1852            model.into_iter().collect::<Vec<_>>()
1853        );
1854    }
1855
1856    fn apply_iter_mut_model_ops<const N: usize>(ops: &[IteratorModelOp]) {
1857        let mut list = ArrayList::<i32, N>::from([0, 1, 2, 3, 4, 5, 6, 7, 8, 9]);
1858        let mut iter = list.iter_mut();
1859        let mut model = VecDeque::from([0, 1, 2, 3, 4, 5, 6, 7, 8, 9]);
1860
1861        for op in ops {
1862            let expected = match *op {
1863                IteratorModelOp::Next => model.pop_front(),
1864                IteratorModelOp::NextBack => model.pop_back(),
1865                IteratorModelOp::Nth(n) => model_nth(&mut model, n),
1866                IteratorModelOp::NthBack(n) => model_nth_back(&mut model, n),
1867            };
1868
1869            let actual = match *op {
1870                IteratorModelOp::Next => iter.next().map(|value| {
1871                    *value += 100;
1872                    *value - 100
1873                }),
1874                IteratorModelOp::NextBack => iter.next_back().map(|value| {
1875                    *value += 100;
1876                    *value - 100
1877                }),
1878                IteratorModelOp::Nth(n) => iter.nth(n).map(|value| {
1879                    *value += 100;
1880                    *value - 100
1881                }),
1882                IteratorModelOp::NthBack(n) => iter.nth_back(n).map(|value| {
1883                    *value += 100;
1884                    *value - 100
1885                }),
1886            };
1887
1888            assert_eq!(actual, expected);
1889        }
1890
1891        assert_eq!(
1892            iter.map(|value| *value).collect::<Vec<_>>(),
1893            model.into_iter().collect::<Vec<_>>()
1894        );
1895    }
1896
1897    fn apply_into_iter_model_ops<const N: usize>(ops: &[IteratorModelOp]) {
1898        let list = ArrayList::<i32, N>::from([0, 1, 2, 3, 4, 5, 6, 7, 8, 9]);
1899        let mut iter = list.into_iter();
1900        let mut model = VecDeque::from([0, 1, 2, 3, 4, 5, 6, 7, 8, 9]);
1901
1902        for op in ops {
1903            let expected = match *op {
1904                IteratorModelOp::Next => model.pop_front(),
1905                IteratorModelOp::NextBack => model.pop_back(),
1906                IteratorModelOp::Nth(n) => model_nth(&mut model, n),
1907                IteratorModelOp::NthBack(n) => model_nth_back(&mut model, n),
1908            };
1909
1910            let actual = match *op {
1911                IteratorModelOp::Next => iter.next(),
1912                IteratorModelOp::NextBack => iter.next_back(),
1913                IteratorModelOp::Nth(n) => iter.nth(n),
1914                IteratorModelOp::NthBack(n) => iter.nth_back(n),
1915            };
1916
1917            assert_eq!(actual, expected);
1918        }
1919
1920        assert_eq!(
1921            iter.collect::<Vec<_>>(),
1922            model.into_iter().collect::<Vec<_>>()
1923        );
1924    }
1925
1926    #[derive(Default)]
1927    struct RecordingHasher {
1928        bytes: Vec<u8>,
1929    }
1930
1931    impl Hasher for RecordingHasher {
1932        fn write(&mut self, bytes: &[u8]) {
1933            self.bytes.extend_from_slice(bytes);
1934        }
1935
1936        fn finish(&self) -> u64 {
1937            self.bytes.len() as u64
1938        }
1939    }
1940
1941    #[derive(Debug)]
1942    struct DropProbe {
1943        value: i32,
1944        drops: Rc<Cell<usize>>,
1945    }
1946
1947    impl DropProbe {
1948        fn new(value: i32, drops: &Rc<Cell<usize>>) -> Self {
1949            Self {
1950                value,
1951                drops: Rc::clone(drops),
1952            }
1953        }
1954    }
1955
1956    impl Drop for DropProbe {
1957        fn drop(&mut self) {
1958            self.drops.set(self.drops.get() + 1);
1959        }
1960    }
1961
1962    fn drop_probe_list<const N: usize>(
1963        drops: &Rc<Cell<usize>>,
1964        len: i32,
1965    ) -> ArrayList<DropProbe, N> {
1966        (0..len).map(|value| DropProbe::new(value, drops)).collect()
1967    }
1968
1969    #[test]
1970    fn default_and_new_start_empty_without_allocated_chunks() {
1971        fn check<const N: usize>() {
1972            let list = ArrayList::<i32, N>::new();
1973            let default = ArrayList::<i32, N>::default();
1974
1975            assert!(list.is_empty());
1976            assert_eq!(list.len(), 0);
1977            assert_eq!(list.capacity(), 0);
1978            assert_eq!(list.front(), None);
1979            assert_eq!(list.back(), None);
1980            assert!(default.is_empty());
1981        }
1982
1983        check_capacities!(check);
1984    }
1985
1986    #[test]
1987    fn push_and_pop_work_across_chunks() {
1988        fn check<const N: usize>() {
1989            let mut list = ArrayList::<i32, N>::new();
1990
1991            list.push_back(2);
1992            list.push_front(1);
1993            list.push_back(3);
1994
1995            assert_eq!(values(&list), [1, 2, 3]);
1996            assert!(list.chunks.iter().all(|chunk| chunk.len() <= N));
1997            assert_eq!(list.pop_front(), Some(1));
1998            assert_eq!(list.pop_back(), Some(3));
1999            assert_eq!(list.pop_back(), Some(2));
2000            assert_eq!(list.pop_back(), None);
2001            assert!(list.is_empty());
2002            assert_eq!(list.capacity(), 0);
2003        }
2004
2005        check_capacities!(check);
2006    }
2007
2008    #[test]
2009    fn push_front_reuses_spare_front_chunk_capacity() {
2010        fn check<const N: usize>() {
2011            let mut list = ArrayList::<i32, N>::new();
2012
2013            list.push_front(3);
2014            list.push_front(2);
2015            list.push_front(1);
2016
2017            assert_eq!(values(&list), [1, 2, 3]);
2018            assert!(list.chunks.iter().all(|chunk| chunk.len() <= N));
2019            assert_eq!(list.front(), Some(&1));
2020            assert_eq!(list.back(), Some(&3));
2021        }
2022
2023        check_capacities!(check);
2024    }
2025
2026    #[test]
2027    fn insert_covers_front_middle_back_and_chunk_spill() {
2028        fn check<const N: usize>() {
2029            let mut list = ArrayList::<i32, N>::from([10, 20, 40, 50]);
2030
2031            list.insert(0, 0);
2032            list.insert(3, 30);
2033            list.insert(list.len(), 60);
2034
2035            assert_eq!(values(&list), [0, 10, 20, 30, 40, 50, 60]);
2036            assert!(list.chunks.iter().all(|chunk| chunk.len() <= N));
2037        }
2038
2039        check_capacities!(check);
2040    }
2041
2042    #[test]
2043    fn insert_without_split_does_not_refill_from_siblings() {
2044        fn check<const N: usize>() {
2045            let min = N / 2;
2046            let chunks = VecDeque::from([
2047                usize_chunk::<N>(0..N),
2048                usize_chunk::<N>(100..101),
2049                usize_chunk::<N>(200..(200 + min)),
2050            ]);
2051            let len = chunks.iter().map(CapVec::len).sum();
2052            let mut list = ArrayList { chunks, len };
2053
2054            list.insert(N, usize::MAX);
2055
2056            assert_eq!(list.get(N), Some(&usize::MAX));
2057            assert_eq!(
2058                list.chunks.iter().map(CapVec::len).collect::<Vec<_>>(),
2059                [N, 2, min]
2060            );
2061        }
2062
2063        check_capacities!(check);
2064    }
2065
2066    #[test]
2067    fn insert_split_refills_underfull_chunk_from_sibling_above_min() {
2068        fn check<const N: usize>() {
2069            let min = N / 2;
2070            let chunks = VecDeque::from([
2071                usize_chunk::<N>(0..N),
2072                usize_chunk::<N>(100..(100 + N)),
2073                usize_chunk::<N>(200..(200 + min)),
2074            ]);
2075            let len = chunks.iter().map(CapVec::len).sum();
2076            let mut list = ArrayList { chunks, len };
2077            let index = (N * 2) - 1;
2078
2079            list.insert(index, usize::MAX);
2080
2081            assert_eq!(list.get(index), Some(&usize::MAX));
2082            assert_eq!(
2083                list.chunks.iter().map(CapVec::len).collect::<Vec<_>>(),
2084                [N, min + 1, min, min]
2085            );
2086        }
2087
2088        check_capacities!(check);
2089    }
2090
2091    #[test]
2092    fn insert_splits_full_chunk_locally() {
2093        fn check<const N: usize>() {
2094            let mut list = (0..(N * 2)).collect::<ArrayList<usize, N>>();
2095
2096            list.insert(N - 1, usize::MAX);
2097
2098            assert_eq!(list.get(N - 1), Some(&usize::MAX));
2099            assert_eq!(list.iter().copied().count(), (N * 2) + 1);
2100            assert!(list.chunks.iter().all(|chunk| !chunk.is_empty()));
2101            assert!(list.chunks.iter().all(|chunk| chunk.len() <= N));
2102        }
2103
2104        check_capacities!(check);
2105    }
2106
2107    #[test]
2108    fn insert_leaves_siblings_at_min_untouched() {
2109        fn check<const N: usize>() {
2110            let min = N / 2;
2111            let chunks = VecDeque::from([
2112                usize_chunk::<N>(0..min),
2113                usize_chunk::<N>(100..101),
2114                usize_chunk::<N>(200..(200 + min)),
2115            ]);
2116            let len = chunks.iter().map(CapVec::len).sum();
2117            let mut list = ArrayList { chunks, len };
2118            let index = min;
2119
2120            list.insert(index, usize::MAX);
2121
2122            assert_eq!(
2123                list.chunks.iter().map(CapVec::len).collect::<Vec<_>>(),
2124                [min, 2, min]
2125            );
2126            assert_eq!(list.get(index), Some(&usize::MAX));
2127        }
2128
2129        check_capacities!(check);
2130    }
2131
2132    #[test]
2133    fn cursor_insert_before_keeps_cursor_on_element_spilled_to_next_chunk() {
2134        fn check<const N: usize>() {
2135            let mut list = (0..(N * 2)).collect::<ArrayList<usize, N>>();
2136
2137            {
2138                let mut cursor = list.cursor_front_mut();
2139                for _ in 0..(N - 1) {
2140                    cursor.move_next();
2141                }
2142
2143                cursor.insert_before(usize::MAX);
2144
2145                assert_eq!(cursor.current(), Some(&mut (N - 1)));
2146            }
2147
2148            let expected = (0..(N - 1))
2149                .chain(core::iter::once(usize::MAX))
2150                .chain((N - 1)..(N * 2))
2151                .collect::<Vec<_>>();
2152
2153            assert_eq!(list.iter().copied().collect::<Vec<_>>(), expected);
2154        }
2155
2156        check_capacities!(check);
2157    }
2158
2159    #[test]
2160    fn cursor_insert_after_keeps_cursor_on_element_shifted_to_previous_chunk() {
2161        fn check<const N: usize>() {
2162            let chunks = VecDeque::from([
2163                usize_chunk::<N>(0..(N - 1)),
2164                usize_chunk::<N>(100..(100 + N)),
2165                usize_chunk::<N>(200..(200 + N)),
2166            ]);
2167            let len = chunks.iter().map(CapVec::len).sum();
2168            let mut list = ArrayList { chunks, len };
2169
2170            {
2171                let mut cursor = list.cursor_front_mut();
2172                for _ in 0..(N - 1) {
2173                    cursor.move_next();
2174                }
2175
2176                cursor.insert_after(usize::MAX);
2177
2178                assert_eq!(cursor.current(), Some(&mut 100));
2179            }
2180
2181            let expected = (0..(N - 1))
2182                .chain(core::iter::once(100))
2183                .chain(core::iter::once(usize::MAX))
2184                .chain(101..(100 + N))
2185                .chain(200..(200 + N))
2186                .collect::<Vec<_>>();
2187
2188            assert_eq!(list.iter().copied().collect::<Vec<_>>(), expected);
2189        }
2190
2191        check_capacities!(check);
2192    }
2193
2194    #[test]
2195    fn cursor_insert_after_tracks_current_moved_by_refill_from_previous_sibling() {
2196        fn check<const N: usize>() {
2197            let mut list = (0..N).collect::<ArrayList<usize, N>>();
2198
2199            {
2200                let mut cursor = list.cursor_front_mut();
2201                for _ in 0..(N - 2) {
2202                    cursor.move_next();
2203                }
2204
2205                cursor.insert_after(usize::MAX);
2206
2207                assert_eq!(cursor.current().map(|value| *value), Some(N - 2));
2208                assert_eq!(cursor.peek_next().map(|value| *value), Some(usize::MAX));
2209            }
2210
2211            let expected = (0..(N - 1))
2212                .chain(core::iter::once(usize::MAX))
2213                .chain((N - 1)..N)
2214                .collect::<Vec<_>>();
2215
2216            assert_eq!(list.iter().copied().collect::<Vec<_>>(), expected);
2217        }
2218
2219        check_capacities!(check);
2220    }
2221
2222    #[test]
2223    fn cursor_remove_current_tracks_next_moved_by_refill_from_next_sibling() {
2224        fn check<const N: usize>() {
2225            let min = N / 2;
2226            let chunks = VecDeque::from([
2227                usize_chunk::<N>(0..min),
2228                usize_chunk::<N>(100..101),
2229                usize_chunk::<N>(200..(200 + N)),
2230            ]);
2231            let len = chunks.iter().map(CapVec::len).sum();
2232            let mut list = ArrayList { chunks, len };
2233
2234            {
2235                let mut cursor = list.cursor_front_mut();
2236                for _ in 0..min {
2237                    cursor.move_next();
2238                }
2239
2240                assert_eq!(cursor.remove_current(), Some(100));
2241                assert_eq!(cursor.current(), Some(&mut 200));
2242            }
2243
2244            let expected = (0..min).chain(200..(200 + N)).collect::<Vec<_>>();
2245            assert_eq!(list.iter().copied().collect::<Vec<_>>(), expected);
2246        }
2247
2248        check_capacities!(check);
2249    }
2250
2251    #[test]
2252    fn insert_panics_when_index_is_greater_than_len() {
2253        fn check<const N: usize>() {
2254            let out = std::panic::catch_unwind(|| {
2255                let mut list = ArrayList::<i32, N>::from([1, 2, 3]);
2256                list.insert(4, 4);
2257            });
2258
2259            assert!(out.is_err());
2260        }
2261
2262        check_capacities!(check);
2263    }
2264
2265    #[test]
2266    fn remove_covers_edges_middle_and_out_of_bounds() {
2267        fn check<const N: usize>() {
2268            let mut list = ArrayList::<i32, N>::from([0, 1, 2, 3, 4, 5, 6]);
2269
2270            assert_eq!(list.remove(0), Some(0));
2271            assert_eq!(list.remove(5), Some(6));
2272            assert_eq!(list.remove(2), Some(3));
2273            assert_eq!(list.remove(99), None);
2274
2275            assert_eq!(values(&list), [1, 2, 4, 5]);
2276            assert_eq!(list.len(), 4);
2277            assert!(list.chunks.iter().all(|chunk| chunk.len() <= N));
2278        }
2279
2280        check_capacities!(check);
2281    }
2282
2283    #[test]
2284    fn repeated_middle_removals_preserve_order_and_chunk_bounds() {
2285        fn check<const N: usize>() {
2286            let mut list = (0..(N * 3)).collect::<ArrayList<usize, N>>();
2287
2288            for _ in 0..N {
2289                assert!(list.remove(N).is_some());
2290            }
2291
2292            assert_eq!(list.len(), N * 2);
2293            assert_eq!(
2294                list.iter().copied().collect::<Vec<_>>(),
2295                (0..N).chain((N * 2)..(N * 3)).collect::<Vec<_>>()
2296            );
2297            assert!(list.chunks.iter().all(|chunk| !chunk.is_empty()));
2298            assert!(list.chunks.iter().all(|chunk| chunk.len() <= N));
2299        }
2300
2301        check_capacities!(check);
2302    }
2303
2304    #[test]
2305    fn remove_refills_underfull_chunk_from_sibling_above_min() {
2306        fn check<const N: usize>() {
2307            let min = N / 2;
2308            let chunks = VecDeque::from([
2309                usize_chunk::<N>(0..N),
2310                usize_chunk::<N>(100..(100 + min)),
2311                usize_chunk::<N>(200..(200 + min)),
2312            ]);
2313            let len = chunks.iter().map(CapVec::len).sum();
2314            let mut list = ArrayList { chunks, len };
2315
2316            assert_eq!(list.remove(N), Some(100));
2317
2318            let expected_values = (0..N)
2319                .chain(101..(100 + min))
2320                .chain(200..(200 + min))
2321                .collect::<Vec<_>>();
2322
2323            assert_eq!(list.iter().copied().collect::<Vec<_>>(), expected_values);
2324            assert_eq!(
2325                list.chunks.iter().map(CapVec::len).collect::<Vec<_>>(),
2326                [N - 1, min, min]
2327            );
2328        }
2329
2330        check_capacities!(check);
2331    }
2332
2333    #[test]
2334    fn remove_leaves_siblings_at_min_untouched() {
2335        fn check<const N: usize>() {
2336            let min = N / 2;
2337            let chunks = VecDeque::from([
2338                usize_chunk::<N>(0..min),
2339                usize_chunk::<N>(100..(100 + min)),
2340                usize_chunk::<N>(200..(200 + min)),
2341            ]);
2342            let len = chunks.iter().map(CapVec::len).sum();
2343            let mut list = ArrayList { chunks, len };
2344
2345            assert_eq!(list.remove(min), Some(100));
2346
2347            assert_eq!(
2348                list.chunks.iter().map(CapVec::len).collect::<Vec<_>>(),
2349                [min, min - 1, min]
2350            );
2351            assert_eq!(
2352                list.iter().copied().collect::<Vec<_>>(),
2353                (0..min)
2354                    .chain(101..(100 + min))
2355                    .chain(200..(200 + min))
2356                    .collect::<Vec<_>>()
2357            );
2358        }
2359
2360        check_capacities!(check);
2361    }
2362
2363    #[test]
2364    fn get_and_get_mut_cross_chunk_boundaries() {
2365        fn check<const N: usize>() {
2366            let mut list = ArrayList::<i32, N>::from([1, 2, 3, 4, 5]);
2367
2368            assert_eq!(list.get(0), Some(&1));
2369            assert_eq!(list.get(2), Some(&3));
2370            assert_eq!(list.get(4), Some(&5));
2371            assert_eq!(list.get(5), None);
2372
2373            *list.get_mut(3).unwrap() = 40;
2374            assert_eq!(values(&list), [1, 2, 3, 40, 5]);
2375        }
2376
2377        check_capacities!(check);
2378    }
2379
2380    #[test]
2381    fn append_moves_all_chunks_and_empties_source() {
2382        fn check<const N: usize>() {
2383            let mut left = ArrayList::<i32, N>::from([1, 2, 3]);
2384            let mut right = ArrayList::<i32, N>::from([4, 5]);
2385
2386            left.append(&mut right);
2387
2388            assert_eq!(values(&left), [1, 2, 3, 4, 5]);
2389            assert!(right.is_empty());
2390            assert_eq!(right.capacity(), 0);
2391            assert!(left.chunks.iter().all(|chunk| chunk.len() <= N));
2392        }
2393
2394        check_capacities!(check);
2395    }
2396
2397    #[test]
2398    fn append_compacts_sparse_boundary_chunks() {
2399        fn check<const N: usize>() {
2400            let mut left = (0..(N + 1)).collect::<ArrayList<usize, N>>();
2401            let mut right = ((N + 1)..(N * 2)).collect::<ArrayList<usize, N>>();
2402
2403            left.append(&mut right);
2404
2405            assert_eq!(
2406                left.iter().copied().collect::<Vec<_>>(),
2407                (0..(N * 2)).collect::<Vec<_>>()
2408            );
2409            assert!(right.is_empty());
2410            assert_eq!(right.capacity(), 0);
2411            assert_eq!(left.spare_capacity(), 0);
2412        }
2413
2414        check_capacities!(check);
2415    }
2416
2417    #[test]
2418    fn clear_removes_elements_and_allocated_chunks() {
2419        fn check<const N: usize>() {
2420            let mut list = ArrayList::<i32, N>::from([1, 2, 3, 4]);
2421
2422            list.clear();
2423
2424            assert!(list.is_empty());
2425            assert_eq!(list.capacity(), 0);
2426            assert_eq!(list.pop_front(), None);
2427            assert_eq!(chunk_lengths(&list), Vec::<usize>::new());
2428        }
2429
2430        check_capacities!(check);
2431    }
2432
2433    #[test]
2434    fn shrink_compacts_sparse_chunks_without_reordering() {
2435        fn check<const N: usize>() {
2436            let mut list = ArrayList::<i32, N>::from([0, 1, 2, 3, 4, 5, 6, 7]);
2437
2438            assert_eq!(list.remove(1), Some(1));
2439            assert_eq!(list.remove(2), Some(3));
2440
2441            list.shrink();
2442
2443            assert_eq!(values(&list), [0, 2, 4, 5, 6, 7]);
2444            assert!(list.chunks.iter().all(|chunk| chunk.len() <= N));
2445        }
2446
2447        check_capacities!(check);
2448    }
2449
2450    #[test]
2451    fn from_array_collect_and_extend_fill_chunks_across_capacities() {
2452        fn check<const N: usize>() {
2453            let from_array = ArrayList::<i32, N>::from([1, 2, 3, 4, 5]);
2454            let collected = (1..=5).collect::<ArrayList<_, N>>();
2455            let mut extended = ArrayList::<i32, N>::from([1]);
2456            extended.extend([2, 3, 4, 5]);
2457            extended.extend([6, 7].iter());
2458
2459            assert_eq!(values(&from_array), [1, 2, 3, 4, 5]);
2460            assert_eq!(values(&collected), [1, 2, 3, 4, 5]);
2461            assert_eq!(values(&extended), [1, 2, 3, 4, 5, 6, 7]);
2462            assert!(from_array.chunks.iter().all(|chunk| chunk.len() <= N));
2463            assert!(collected.chunks.iter().all(|chunk| chunk.len() <= N));
2464            assert!(extended.chunks.iter().all(|chunk| chunk.len() <= N));
2465        }
2466
2467        check_capacities!(check);
2468    }
2469
2470    #[test]
2471    fn clone_debug_equality_ordering_and_hash_are_sequence_based() {
2472        fn check<const N: usize>() {
2473            let list = ArrayList::<i32, N>::from([1, 2, 3]);
2474            let clone = list.clone();
2475            let greater = ArrayList::<i32, N>::from([1, 2, 4]);
2476            let different_chunking = {
2477                let mut list = ArrayList::<i32, N>::new();
2478                list.extend([1, 2, 3]);
2479                list
2480            };
2481
2482            assert_eq!(list, clone);
2483            assert_eq!(list, [1, 2, 3]);
2484            assert_eq!(list, &[1, 2, 3][..]);
2485            assert_eq!(list.partial_cmp(&greater), Some(Ordering::Less));
2486            assert_eq!(list.cmp(&clone), Ordering::Equal);
2487            assert_eq!(different_chunking, [1, 2, 3]);
2488            assert!(alloc::format!("{list:?}").contains('1'));
2489
2490            let mut left_hasher = RecordingHasher::default();
2491            let mut right_hasher = RecordingHasher::default();
2492            list.hash(&mut left_hasher);
2493            clone.hash(&mut right_hasher);
2494            assert_eq!(left_hasher.bytes, right_hasher.bytes);
2495        }
2496
2497        check_capacities!(check);
2498    }
2499
2500    #[test]
2501    fn mutable_front_and_back_allow_in_place_updates() {
2502        fn check<const N: usize>() {
2503            let mut list = ArrayList::<i32, N>::from([1, 2, 3]);
2504
2505            *list.front_mut().unwrap() = 10;
2506            *list.back_mut().unwrap() = 30;
2507
2508            assert_eq!(values(&list), [10, 2, 30]);
2509        }
2510
2511        check_capacities!(check);
2512    }
2513
2514    #[test]
2515    fn mixed_operations_work_for_required_capacities() {
2516        fn check<const N: usize>() {
2517            let mut list = ArrayList::<i32, N>::new();
2518
2519            for value in 0..10 {
2520                list.push_back(value);
2521            }
2522
2523            list.insert(0, -1);
2524            list.insert(6, 99);
2525            list.insert(list.len(), 10);
2526
2527            assert_eq!(list.remove(6), Some(99));
2528            assert_eq!(list.pop_front(), Some(-1));
2529            assert_eq!(list.pop_back(), Some(10));
2530            assert_eq!(list.get(0), Some(&0));
2531            assert_eq!(list.get(9), Some(&9));
2532            assert_eq!(list.get(10), None);
2533
2534            list.shrink();
2535
2536            assert_eq!(values(&list), [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]);
2537            assert!(list.capacity() >= list.len());
2538            assert!(list.chunks.iter().all(|chunk| chunk.len() <= N));
2539        }
2540
2541        check_capacities!(check);
2542    }
2543
2544    #[test]
2545    fn clear_drops_each_element_once_for_required_capacities() {
2546        fn check<const N: usize>() {
2547            let drops = Rc::new(Cell::new(0));
2548            let mut list = drop_probe_list::<N>(&drops, 10);
2549
2550            list.clear();
2551
2552            assert_eq!(drops.get(), 10);
2553            assert!(list.is_empty());
2554            drop(list);
2555            assert_eq!(drops.get(), 10);
2556        }
2557
2558        check_capacities!(check);
2559    }
2560
2561    #[test]
2562    fn remove_and_pop_drop_removed_elements_once_for_required_capacities() {
2563        fn check<const N: usize>() {
2564            let drops = Rc::new(Cell::new(0));
2565            let mut list = drop_probe_list::<N>(&drops, 6);
2566
2567            let removed = list.remove(2).unwrap();
2568            assert_eq!(removed.value, 2);
2569            assert_eq!(drops.get(), 0);
2570            drop(removed);
2571            assert_eq!(drops.get(), 1);
2572
2573            let front = list.pop_front().unwrap();
2574            assert_eq!(front.value, 0);
2575            drop(front);
2576            assert_eq!(drops.get(), 2);
2577
2578            let back = list.pop_back().unwrap();
2579            assert_eq!(back.value, 5);
2580            drop(back);
2581            assert_eq!(drops.get(), 3);
2582
2583            drop(list);
2584            assert_eq!(drops.get(), 6);
2585        }
2586
2587        check_capacities!(check);
2588    }
2589
2590    #[test]
2591    fn append_moves_elements_without_dropping_for_required_capacities() {
2592        fn check<const N: usize>() {
2593            let drops = Rc::new(Cell::new(0));
2594            let mut left = drop_probe_list::<N>(&drops, 3);
2595            let mut right = (3..7)
2596                .map(|value| DropProbe::new(value, &drops))
2597                .collect::<ArrayList<_, N>>();
2598
2599            left.append(&mut right);
2600
2601            assert_eq!(drops.get(), 0);
2602            assert!(right.is_empty());
2603            drop(right);
2604            assert_eq!(drops.get(), 0);
2605            drop(left);
2606            assert_eq!(drops.get(), 7);
2607        }
2608
2609        check_capacities!(check);
2610    }
2611
2612    #[test]
2613    fn shrink_reorders_storage_without_dropping_for_required_capacities() {
2614        fn check<const N: usize>() {
2615            let drops = Rc::new(Cell::new(0));
2616            let mut list = drop_probe_list::<N>(&drops, 9);
2617
2618            drop(list.remove(1));
2619            drop(list.remove(3));
2620            assert_eq!(drops.get(), 2);
2621
2622            list.shrink();
2623
2624            assert_eq!(drops.get(), 2);
2625            drop(list);
2626            assert_eq!(drops.get(), 9);
2627        }
2628
2629        check_capacities!(check);
2630    }
2631
2632    #[test]
2633    fn partially_consumed_into_iter_drops_remaining_elements_for_required_capacities() {
2634        fn check<const N: usize>() {
2635            let drops = Rc::new(Cell::new(0));
2636            let list = drop_probe_list::<N>(&drops, 6);
2637            let mut iter = list.into_iter();
2638
2639            let first = iter.next().unwrap();
2640            assert_eq!(first.value, 0);
2641            drop(first);
2642            assert_eq!(drops.get(), 1);
2643
2644            let last = iter.next_back().unwrap();
2645            assert_eq!(last.value, 5);
2646            drop(last);
2647            assert_eq!(drops.get(), 2);
2648
2649            drop(iter);
2650            assert_eq!(drops.get(), 6);
2651        }
2652
2653        check_capacities!(check);
2654    }
2655
2656    #[test]
2657    fn cursor_remove_current_drops_returned_element_once_for_required_capacities() {
2658        fn check<const N: usize>() {
2659            let drops = Rc::new(Cell::new(0));
2660            let mut list = drop_probe_list::<N>(&drops, 4);
2661            let removed = {
2662                let mut cursor = list.cursor_front_mut();
2663
2664                cursor.move_next();
2665                cursor.remove_current().unwrap()
2666            };
2667
2668            assert_eq!(removed.value, 1);
2669            assert_eq!(drops.get(), 0);
2670            drop(removed);
2671            assert_eq!(drops.get(), 1);
2672            drop(list);
2673            assert_eq!(drops.get(), 4);
2674        }
2675
2676        check_capacities!(check);
2677    }
2678
2679    proptest! {
2680        #![proptest_config(ProptestConfig::with_cases(128))]
2681
2682        #[test]
2683        fn model_based_collection_ops_match_vec(
2684            ops in prop::collection::vec(model_op_strategy(), 0..128)
2685        ) {
2686            apply_model_ops::<4>(&ops);
2687            apply_model_ops::<8>(&ops);
2688            apply_model_ops::<16>(&ops);
2689        }
2690
2691        #[test]
2692        fn model_based_read_only_cursor_ops_match_indexed_vec_cursor(
2693            ops in prop::collection::vec(read_only_cursor_model_op_strategy(), 0..256)
2694        ) {
2695            apply_read_only_cursor_model_ops::<4>(&ops);
2696            apply_read_only_cursor_model_ops::<8>(&ops);
2697            apply_read_only_cursor_model_ops::<16>(&ops);
2698        }
2699
2700        #[test]
2701        fn model_based_cursor_mut_ops_match_indexed_vec_cursor(
2702            ops in prop::collection::vec(cursor_model_op_strategy(), 0..128)
2703        ) {
2704            apply_cursor_model_ops::<4>(&ops);
2705            apply_cursor_model_ops::<8>(&ops);
2706            apply_cursor_model_ops::<16>(&ops);
2707        }
2708
2709        #[test]
2710        fn model_based_shared_iterator_ops_match_vec_deque(
2711            ops in prop::collection::vec(iterator_model_op_strategy(), 0..128)
2712        ) {
2713            apply_iter_model_ops::<4>(&ops);
2714            apply_iter_model_ops::<8>(&ops);
2715            apply_iter_model_ops::<16>(&ops);
2716        }
2717
2718        #[test]
2719        fn model_based_mutable_iterator_ops_match_vec_deque(
2720            ops in prop::collection::vec(iterator_model_op_strategy(), 0..128)
2721        ) {
2722            apply_iter_mut_model_ops::<4>(&ops);
2723            apply_iter_mut_model_ops::<8>(&ops);
2724            apply_iter_mut_model_ops::<16>(&ops);
2725        }
2726
2727        #[test]
2728        fn model_based_owning_iterator_ops_match_vec_deque(
2729            ops in prop::collection::vec(iterator_model_op_strategy(), 0..128)
2730        ) {
2731            apply_into_iter_model_ops::<4>(&ops);
2732            apply_into_iter_model_ops::<8>(&ops);
2733            apply_into_iter_model_ops::<16>(&ops);
2734        }
2735    }
2736}
2737
2738#[cfg(all(test, miri))]
2739mod miri_tests {
2740    use super::ArrayList;
2741    use alloc::rc::Rc;
2742    use alloc::vec::Vec;
2743    use core::cell::Cell;
2744
2745    macro_rules! check_capacities {
2746        ($check:ident) => {{
2747            $check::<4>();
2748            $check::<8>();
2749            $check::<16>();
2750        }};
2751    }
2752
2753    fn values<const N: usize>(list: &ArrayList<i32, N>) -> Vec<i32> {
2754        list.iter().copied().collect()
2755    }
2756
2757    #[derive(Debug)]
2758    struct DropProbe {
2759        value: i32,
2760        drops: Rc<Cell<usize>>,
2761    }
2762
2763    impl DropProbe {
2764        fn new(value: i32, drops: &Rc<Cell<usize>>) -> Self {
2765            Self {
2766                value,
2767                drops: Rc::clone(drops),
2768            }
2769        }
2770    }
2771
2772    impl Drop for DropProbe {
2773        fn drop(&mut self) {
2774            self.drops.set(self.drops.get() + 1);
2775        }
2776    }
2777
2778    fn drop_probe_list<const N: usize>(
2779        drops: &Rc<Cell<usize>>,
2780        values: impl IntoIterator<Item = i32>,
2781    ) -> ArrayList<DropProbe, N> {
2782        values
2783            .into_iter()
2784            .map(|value| DropProbe::new(value, drops))
2785            .collect()
2786    }
2787
2788    #[test]
2789    fn miri_drop_paths_cover_remove_append_shrink_and_into_iter() {
2790        fn check<const N: usize>() {
2791            let drops = Rc::new(Cell::new(0));
2792            let mut list = drop_probe_list::<N>(&drops, 0..6);
2793            let mut extra = drop_probe_list::<N>(&drops, 6..9);
2794
2795            let removed = list.remove(2).unwrap();
2796            assert_eq!(removed.value, 2);
2797            assert_eq!(drops.get(), 0);
2798            drop(removed);
2799            assert_eq!(drops.get(), 1);
2800
2801            list.append(&mut extra);
2802            drop(extra);
2803            assert_eq!(drops.get(), 1);
2804
2805            list.shrink();
2806            assert_eq!(drops.get(), 1);
2807
2808            let mut iter = list.into_iter();
2809            let first = iter.next().unwrap();
2810            assert_eq!(first.value, 0);
2811            drop(first);
2812            assert_eq!(drops.get(), 2);
2813            drop(iter);
2814            assert_eq!(drops.get(), 9);
2815        }
2816
2817        check_capacities!(check);
2818    }
2819
2820    #[test]
2821    fn miri_cursor_mut_paths_cover_mut_refs_inserts_and_removal() {
2822        fn check<const N: usize>() {
2823            let mut list = ArrayList::<i32, N>::from([0, 1, 2, 3, 4, 5, 6, 7]);
2824
2825            {
2826                let mut cursor = list.cursor_front_mut();
2827                *cursor.current().unwrap() = 10;
2828                *cursor.peek_next().unwrap() = 20;
2829                cursor.move_next();
2830                cursor.insert_before(15);
2831                cursor.insert_after(25);
2832                assert_eq!(cursor.index(), Some(2));
2833                assert_eq!(cursor.remove_current(), Some(20));
2834                *cursor.front_mut().unwrap() += 1;
2835                *cursor.back_mut().unwrap() += 1;
2836            }
2837
2838            assert_eq!(values(&list), [11, 15, 25, 2, 3, 4, 5, 6, 8]);
2839        }
2840
2841        check_capacities!(check);
2842    }
2843
2844    #[test]
2845    fn miri_iterator_paths_cover_shared_mutable_and_owning_iterators() {
2846        fn check<const N: usize>() {
2847            let mut list = ArrayList::<i32, N>::from([0, 1, 2, 3, 4, 5, 6, 7]);
2848
2849            {
2850                let mut iter = list.iter_mut();
2851                *iter.next().unwrap() += 10;
2852                *iter.next_back().unwrap() += 10;
2853                *iter.nth(1).unwrap() += 10;
2854                *iter.nth_back(1).unwrap() += 10;
2855            }
2856
2857            assert_eq!(values(&list), [10, 1, 12, 3, 4, 15, 6, 17]);
2858
2859            let mut iter = list.iter();
2860            assert_eq!(iter.next(), Some(&10));
2861            assert_eq!(iter.nth_back(2), Some(&15));
2862            assert_eq!(iter.next_back(), Some(&4));
2863
2864            let mut into_iter = list.into_iter();
2865            assert_eq!(into_iter.next(), Some(10));
2866            assert_eq!(into_iter.next_back(), Some(17));
2867            assert_eq!(into_iter.nth(2), Some(3));
2868            assert_eq!(into_iter.nth_back(1), Some(15));
2869        }
2870
2871        check_capacities!(check);
2872    }
2873
2874    #[test]
2875    fn miri_read_only_cursor_paths_cover_ghost_and_cross_chunk_moves() {
2876        fn check<const N: usize>() {
2877            let mut list = ArrayList::<i32, N>::from([0, 1, 2, 3, 4, 5, 6, 7]);
2878            assert_eq!(list.remove(1), Some(1));
2879            assert_eq!(list.remove(4), Some(5));
2880            list.shrink();
2881
2882            let mut cursor = list.cursor_front();
2883            assert_eq!(cursor.current(), Some(&0));
2884            cursor.move_prev();
2885            assert_eq!(cursor.current(), None);
2886            assert_eq!(cursor.peek_prev(), Some(&7));
2887            assert_eq!(cursor.peek_next(), Some(&0));
2888            cursor.move_prev();
2889            assert_eq!(cursor.current(), Some(&7));
2890            cursor.move_next();
2891            assert_eq!(cursor.current(), None);
2892            cursor.move_next();
2893            assert_eq!(cursor.current(), Some(&0));
2894        }
2895
2896        check_capacities!(check);
2897    }
2898}