1#![no_std]
2
3extern 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
173pub 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 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 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 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 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 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 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 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 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 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 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 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 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 position.move_next(self);
705
706 let value = self.chunks[current.chunk].remove(current.slot)?;
707 self.len -= 1;
708
709 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 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 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 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 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 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 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 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 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 #[inline]
914 pub const fn len(&self) -> usize {
915 const { assert!(N >= crate::MIN_CHUNK_CAPACITY) };
916
917 self.len
918 }
919
920 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 pub fn spare_capacity(&self) -> usize {
958 const { assert!(N >= crate::MIN_CHUNK_CAPACITY) };
959
960 self.capacity() - self.len()
961 }
962
963 pub fn shrink(&mut self) {
981 const { assert!(N >= crate::MIN_CHUNK_CAPACITY) };
982
983 self.compact_from(0);
984 }
985
986 #[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 #[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 #[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 #[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 #[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 #[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 #[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 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 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 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 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 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}