use core::{
fmt,
iter::FusedIterator,
marker::PhantomData,
ops::{Bound, RangeBounds},
ptr::NonNull,
};
use crate::{
level_generator::{LevelGenerator, geometric::Geometric},
node::Node,
skip_list::SkipList,
};
impl<T, G: LevelGenerator, const N: usize> SkipList<T, N, G> {
#[inline]
pub fn iter(&self) -> Iter<'_, T, N> {
Iter {
front: unsafe { self.head.as_ref() }.next(),
back: self.tail,
len: self.len,
_marker: PhantomData,
}
}
#[inline]
pub fn iter_mut(&mut self) -> IterMut<'_, T, N> {
IterMut {
front: unsafe { self.head.as_ref().next() },
back: self.tail,
len: self.len,
_marker: PhantomData,
}
}
#[inline]
pub fn range<R: RangeBounds<usize>>(&self, range: R) -> Iter<'_, T, N> {
let start = match range.start_bound() {
Bound::Included(&s) => s,
Bound::Excluded(&s) => s.saturating_add(1),
Bound::Unbounded => 0,
};
let end = match range.end_bound() {
Bound::Included(&e) => e.saturating_add(1),
Bound::Excluded(&e) => e,
Bound::Unbounded => self.len,
};
assert!(
start <= end,
"range start (is {start}) must be ≤ end (is {end})"
);
assert!(
end <= self.len,
"range end (is {end}) must be ≤ len (is {})",
self.len
);
let count = end.saturating_sub(start);
if count == 0 {
return Iter {
front: None,
back: None,
len: 0,
_marker: PhantomData,
};
}
Iter {
front: Some(self.node_ptr_at(start)),
back: Some(self.node_ptr_at(end.saturating_sub(1))),
len: count,
_marker: PhantomData,
}
}
#[inline]
pub fn range_mut<R: RangeBounds<usize>>(&mut self, range: R) -> IterMut<'_, T, N> {
let start = match range.start_bound() {
Bound::Included(&s) => s,
Bound::Excluded(&s) => s.saturating_add(1),
Bound::Unbounded => 0,
};
let end = match range.end_bound() {
Bound::Included(&e) => e.saturating_add(1),
Bound::Excluded(&e) => e,
Bound::Unbounded => self.len,
};
assert!(
start <= end,
"range start (is {start}) must be ≤ end (is {end})"
);
assert!(
end <= self.len,
"range end (is {end}) must be ≤ len (is {})",
self.len
);
let count = end.saturating_sub(start);
if count == 0 {
return IterMut {
front: None,
back: None,
len: 0,
_marker: PhantomData,
};
}
IterMut {
front: Some(self.node_ptr_at(start)),
back: Some(self.node_ptr_at(end.saturating_sub(1))),
len: count,
_marker: PhantomData,
}
}
#[expect(
clippy::expect_used,
reason = "`take_value()` returns None only for the head sentinel, which is never \
in the drain range; the expect fires only on invariant violations"
)]
#[inline]
pub fn drain<R>(&mut self, range: R) -> Drain<'_, T>
where
R: RangeBounds<usize>,
{
let start = match range.start_bound() {
Bound::Included(&s) => s,
Bound::Excluded(&s) => s.saturating_add(1),
Bound::Unbounded => 0,
};
let end = match range.end_bound() {
Bound::Included(&e) => e.saturating_add(1),
Bound::Excluded(&e) => e,
Bound::Unbounded => self.len,
};
assert!(
start <= end,
"drain range start (is {start}) must be ≤ end (is {end})"
);
assert!(
end <= self.len,
"drain range end (is {end}) must be ≤ len (is {})",
self.len
);
let drain_count = end.saturating_sub(start);
let mut drained: Vec<T> = Vec::with_capacity(drain_count);
if drain_count == 0 {
return Drain {
iter: drained.into_iter(),
_marker: PhantomData,
};
}
let mut current_index: usize = 0;
let (new_rank, new_tail) = unsafe {
Node::filter_rebuild(
self.head,
|_cur| {
let in_range = current_index >= start && current_index < end;
current_index = current_index.saturating_add(1);
!in_range
},
|mut boxed| {
drained.push(boxed.take_value().expect("data node has a value"));
},
)
};
self.tail = new_tail;
self.len = new_rank;
Drain {
iter: drained.into_iter(),
_marker: PhantomData,
}
}
#[inline]
pub fn extract_if<F>(&mut self, pred: F) -> ExtractIf<'_, T, G, F, N>
where
F: FnMut(&mut T) -> bool,
{
let current = unsafe { self.head.as_ref().next() };
ExtractIf {
current,
any_removed: false,
list: self,
pred,
}
}
}
impl<'a, T, G: LevelGenerator, const N: usize> IntoIterator for &'a SkipList<T, N, G> {
type Item = &'a T;
type IntoIter = Iter<'a, T, N>;
#[inline]
fn into_iter(self) -> Self::IntoIter {
self.iter()
}
}
impl<'a, T, G: LevelGenerator, const N: usize> IntoIterator for &'a mut SkipList<T, N, G> {
type Item = &'a mut T;
type IntoIter = IterMut<'a, T, N>;
#[inline]
fn into_iter(self) -> Self::IntoIter {
self.iter_mut()
}
}
impl<T, G: LevelGenerator, const N: usize> IntoIterator for SkipList<T, N, G> {
type Item = T;
type IntoIter = IntoIter<T, N, G>;
#[inline]
fn into_iter(self) -> Self::IntoIter {
IntoIter { list: self }
}
}
#[must_use = "iterators are lazy and do nothing unless consumed"]
pub struct Iter<'a, T, const N: usize = 16> {
front: Option<NonNull<Node<T, N>>>,
back: Option<NonNull<Node<T, N>>>,
len: usize,
_marker: PhantomData<&'a T>,
}
unsafe impl<T: Sync, const N: usize> Send for Iter<'_, T, N> {}
unsafe impl<T: Sync, const N: usize> Sync for Iter<'_, T, N> {}
impl<T, const N: usize> Clone for Iter<'_, T, N> {
#[inline]
fn clone(&self) -> Self {
Iter {
front: self.front,
back: self.back,
len: self.len,
_marker: PhantomData,
}
}
}
impl<T: fmt::Debug, const N: usize> fmt::Debug for Iter<'_, T, N> {
#[inline]
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_list().entries(self.clone()).finish()
}
}
impl<'a, T, const N: usize> Iterator for Iter<'a, T, N> {
type Item = &'a T;
#[inline]
fn next(&mut self) -> Option<Self::Item> {
if self.len == 0 {
return None;
}
let front_ptr = self.front?;
let node: &'a Node<T, N> = unsafe { front_ptr.as_ref() };
self.front = node.next();
self.len = self.len.saturating_sub(1);
node.value()
}
#[inline]
fn size_hint(&self) -> (usize, Option<usize>) {
(self.len, Some(self.len))
}
}
impl<'a, T, const N: usize> DoubleEndedIterator for Iter<'a, T, N> {
#[inline]
fn next_back(&mut self) -> Option<Self::Item> {
if self.len == 0 {
return None;
}
let back_ptr = self.back?;
let node: &'a Node<T, N> = unsafe { back_ptr.as_ref() };
self.back = node
.prev()
.filter(|p| unsafe { p.as_ref() }.value().is_some());
self.len = self.len.saturating_sub(1);
node.value()
}
}
impl<T, const N: usize> ExactSizeIterator for Iter<'_, T, N> {}
impl<T, const N: usize> FusedIterator for Iter<'_, T, N> {}
#[must_use = "iterators are lazy and do nothing unless consumed"]
pub struct IterMut<'a, T, const N: usize = 16> {
front: Option<NonNull<Node<T, N>>>,
back: Option<NonNull<Node<T, N>>>,
len: usize,
_marker: PhantomData<&'a mut T>,
}
unsafe impl<T: Send, const N: usize> Send for IterMut<'_, T, N> {}
unsafe impl<T: Sync, const N: usize> Sync for IterMut<'_, T, N> {}
impl<T: fmt::Debug, const N: usize> fmt::Debug for IterMut<'_, T, N> {
#[inline]
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let mut builder = f.debug_list();
let mut node_ptr = self.front;
let mut remaining = self.len;
while remaining > 0 {
let Some(ptr) = node_ptr else { break };
let node = unsafe { ptr.as_ref() };
if let Some(v) = node.value() {
builder.entry(v);
}
node_ptr = node.next();
remaining = remaining.saturating_sub(1);
}
builder.finish()
}
}
impl<'a, T, const N: usize> Iterator for IterMut<'a, T, N> {
type Item = &'a mut T;
#[inline]
fn next(&mut self) -> Option<Self::Item> {
if self.len == 0 {
return None;
}
let mut front_ptr = self.front?;
let node: &'a mut Node<T, N> = unsafe { front_ptr.as_mut() };
self.front = node.next();
self.len = self.len.saturating_sub(1);
node.value_mut()
}
#[inline]
fn size_hint(&self) -> (usize, Option<usize>) {
(self.len, Some(self.len))
}
}
impl<'a, T, const N: usize> DoubleEndedIterator for IterMut<'a, T, N> {
#[inline]
fn next_back(&mut self) -> Option<Self::Item> {
if self.len == 0 {
return None;
}
let mut back_ptr = self.back?;
let node: &'a mut Node<T, N> = unsafe { back_ptr.as_mut() };
self.back = node
.prev()
.filter(|p| unsafe { p.as_ref() }.value().is_some());
self.len = self.len.saturating_sub(1);
node.value_mut()
}
}
impl<T, const N: usize> ExactSizeIterator for IterMut<'_, T, N> {}
impl<T, const N: usize> FusedIterator for IterMut<'_, T, N> {}
#[must_use = "iterators are lazy and do nothing unless consumed"]
pub struct IntoIter<T, const N: usize = 16, G: LevelGenerator = Geometric> {
list: SkipList<T, N, G>,
}
unsafe impl<T: Send, G: LevelGenerator + Send, const N: usize> Send for IntoIter<T, N, G> {}
unsafe impl<T: Sync, G: LevelGenerator + Sync, const N: usize> Sync for IntoIter<T, N, G> {}
impl<T: fmt::Debug, G: LevelGenerator, const N: usize> fmt::Debug for IntoIter<T, N, G> {
#[inline]
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_list().entries(self.list.iter()).finish()
}
}
impl<T, G: LevelGenerator, const N: usize> Iterator for IntoIter<T, N, G> {
type Item = T;
#[inline]
fn next(&mut self) -> Option<Self::Item> {
self.list.pop_front()
}
#[inline]
fn size_hint(&self) -> (usize, Option<usize>) {
(self.list.len(), Some(self.list.len()))
}
}
impl<T, G: LevelGenerator, const N: usize> DoubleEndedIterator for IntoIter<T, N, G> {
#[inline]
fn next_back(&mut self) -> Option<Self::Item> {
self.list.pop_back()
}
}
impl<T, G: LevelGenerator, const N: usize> ExactSizeIterator for IntoIter<T, N, G> {}
impl<T, G: LevelGenerator, const N: usize> FusedIterator for IntoIter<T, N, G> {}
#[must_use = "iterators are lazy and do nothing unless consumed"]
pub struct Drain<'a, T> {
iter: std::vec::IntoIter<T>,
_marker: PhantomData<&'a mut T>,
}
unsafe impl<T: Send> Send for Drain<'_, T> {}
unsafe impl<T: Sync> Sync for Drain<'_, T> {}
impl<T: fmt::Debug> fmt::Debug for Drain<'_, T> {
#[inline]
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_list().entries(self.iter.as_slice()).finish()
}
}
impl<T> Iterator for Drain<'_, T> {
type Item = T;
#[inline]
fn next(&mut self) -> Option<Self::Item> {
self.iter.next()
}
#[inline]
fn size_hint(&self) -> (usize, Option<usize>) {
self.iter.size_hint()
}
}
impl<T> DoubleEndedIterator for Drain<'_, T> {
#[inline]
fn next_back(&mut self) -> Option<Self::Item> {
self.iter.next_back()
}
}
impl<T> ExactSizeIterator for Drain<'_, T> {}
impl<T> FusedIterator for Drain<'_, T> {}
#[must_use = "iterators are lazy and do nothing unless consumed"]
pub struct ExtractIf<
'a,
T,
G: LevelGenerator = Geometric,
F = fn(&mut T) -> bool,
const N: usize = 16,
> where
F: FnMut(&mut T) -> bool,
{
list: &'a mut SkipList<T, N, G>,
current: Option<NonNull<Node<T, N>>>,
any_removed: bool,
pred: F,
}
unsafe impl<T: Send, G: LevelGenerator + Send, F: Send, const N: usize> Send
for ExtractIf<'_, T, G, F, N>
where
F: FnMut(&mut T) -> bool,
{
}
unsafe impl<T: Sync, G: LevelGenerator + Sync, F: Sync, const N: usize> Sync
for ExtractIf<'_, T, G, F, N>
where
F: FnMut(&mut T) -> bool,
{
}
impl<T: fmt::Debug, G: LevelGenerator, F, const N: usize> fmt::Debug for ExtractIf<'_, T, G, F, N>
where
F: FnMut(&mut T) -> bool,
{
#[inline]
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let mut builder = f.debug_list();
let mut ptr = self.current;
while let Some(nn) = ptr {
let node = unsafe { nn.as_ref() };
if let Some(v) = node.value() {
builder.entry(v);
}
ptr = node.next();
}
builder.finish()
}
}
impl<T, G: LevelGenerator, F, const N: usize> Iterator for ExtractIf<'_, T, G, F, N>
where
F: FnMut(&mut T) -> bool,
{
type Item = T;
#[expect(
clippy::unwrap_in_result,
clippy::expect_used,
reason = "`value_mut()` and `take_value()` return None only for the head \
sentinel, which is never reachable via the data-node walk; the \
expect fires only on invariant violations"
)]
#[expect(
clippy::multiple_unsafe_ops_per_block,
reason = "raw-pointer dereference, value_mut(), tail-update read, and pop() \
all touch provably disjoint heap nodes; splitting across blocks \
would require unsafe-crossing raw-pointer variables"
)]
#[inline]
fn next(&mut self) -> Option<T> {
loop {
let current_nn = self.current?;
unsafe {
let current: *mut Node<T, N> = current_nn.as_ptr();
let next_opt = (*current).next();
let value_ref = (*current).value_mut().expect("data node has value");
if (self.pred)(value_ref) {
self.current = next_opt;
self.any_removed = true;
self.list.len = self.list.len.saturating_sub(1);
if self.list.tail == Some(current_nn) {
self.list.tail = (*current).prev().filter(|p| p.as_ref().value().is_some());
}
let mut boxed = (*current).pop();
return Some(boxed.take_value().expect("data node has value"));
}
self.current = next_opt;
}
}
}
#[inline]
fn size_hint(&self) -> (usize, Option<usize>) {
(0, Some(self.list.len))
}
}
impl<T, G: LevelGenerator, F, const N: usize> FusedIterator for ExtractIf<'_, T, G, F, N> where
F: FnMut(&mut T) -> bool
{
}
impl<T, G: LevelGenerator, F, const N: usize> Drop for ExtractIf<'_, T, G, F, N>
where
F: FnMut(&mut T) -> bool,
{
#[inline]
fn drop(&mut self) {
if !self.any_removed {
return;
}
let (_, new_tail) = unsafe { Node::filter_rebuild(self.list.head, |_| true, |_| {}) };
self.list.tail = new_tail;
}
}
#[cfg(test)]
mod tests {
use pretty_assertions::assert_eq;
use super::super::SkipList;
#[test]
fn iter_empty() {
let list = SkipList::<i32>::new();
let mut iter = list.iter();
assert_eq!(iter.next(), None);
assert_eq!(iter.next_back(), None);
}
#[test]
fn iter_single_element() {
let mut list = SkipList::<i32>::new();
list.push_back(42);
let mut iter = list.iter();
assert_eq!(iter.next(), Some(&42));
assert_eq!(iter.next(), None);
}
#[test]
fn iter_single_element_from_back() {
let mut list = SkipList::<i32>::new();
list.push_back(42);
let mut iter = list.iter();
assert_eq!(iter.next_back(), Some(&42));
assert_eq!(iter.next_back(), None);
}
#[test]
fn iter_forward_order() {
let mut list = SkipList::<i32>::with_capacity(1);
list.push_back(1);
list.push_back(2);
list.push_back(3);
let collected: Vec<i32> = list.iter().copied().collect();
assert_eq!(collected, [1, 2, 3]);
}
#[test]
fn iter_backward_order() {
let mut list = SkipList::<i32>::with_capacity(1);
list.push_back(1);
list.push_back(2);
list.push_back(3);
let collected: Vec<i32> = list.iter().copied().rev().collect();
assert_eq!(collected, [3, 2, 1]);
}
#[test]
fn iter_double_ended_alternating() {
let mut list = SkipList::<i32>::with_capacity(1);
for i in 1..=5_i32 {
list.push_back(i);
}
let mut iter = list.iter();
assert_eq!(iter.next(), Some(&1));
assert_eq!(iter.next_back(), Some(&5));
assert_eq!(iter.next(), Some(&2));
assert_eq!(iter.next_back(), Some(&4));
assert_eq!(iter.next(), Some(&3));
assert_eq!(iter.next(), None);
assert_eq!(iter.next_back(), None);
}
#[test]
fn iter_double_ended_meets_in_middle_odd() {
let mut list = SkipList::<i32>::with_capacity(1);
list.push_back(10);
list.push_back(20);
list.push_back(30);
let mut iter = list.iter();
assert_eq!(iter.next(), Some(&10));
assert_eq!(iter.next_back(), Some(&30));
assert_eq!(iter.next(), Some(&20));
assert_eq!(iter.next(), None);
assert_eq!(iter.next_back(), None);
}
#[test]
fn iter_double_ended_meets_in_middle_even() {
let mut list = SkipList::<i32>::with_capacity(1);
list.push_back(10);
list.push_back(20);
list.push_back(30);
list.push_back(40);
let mut iter = list.iter();
assert_eq!(iter.next(), Some(&10));
assert_eq!(iter.next_back(), Some(&40));
assert_eq!(iter.next(), Some(&20));
assert_eq!(iter.next_back(), Some(&30));
assert_eq!(iter.next(), None);
assert_eq!(iter.next_back(), None);
}
#[test]
fn iter_size_hint_decrements() {
let mut list = SkipList::<i32>::with_capacity(1);
list.push_back(1);
list.push_back(2);
list.push_back(3);
let mut iter = list.iter();
assert_eq!(iter.size_hint(), (3, Some(3)));
iter.next();
assert_eq!(iter.size_hint(), (2, Some(2)));
iter.next_back();
assert_eq!(iter.size_hint(), (1, Some(1)));
iter.next();
assert_eq!(iter.size_hint(), (0, Some(0)));
}
#[test]
fn iter_exact_size() {
let mut list = SkipList::<i32>::new();
for i in 0..10_i32 {
list.push_back(i);
}
let mut iter = list.iter();
assert_eq!(iter.len(), 10);
iter.next();
assert_eq!(iter.len(), 9);
iter.next_back();
assert_eq!(iter.len(), 8);
}
#[test]
fn iter_fused_returns_none_repeatedly() {
let mut list = SkipList::<i32>::new();
list.push_back(1);
let mut iter = list.iter();
assert_eq!(iter.next(), Some(&1));
assert_eq!(iter.next(), None);
assert_eq!(iter.next(), None);
assert_eq!(iter.next_back(), None);
assert_eq!(iter.next_back(), None);
}
#[test]
fn iter_clone_yields_same_elements() {
let mut list = SkipList::<i32>::with_capacity(1);
list.push_back(1);
list.push_back(2);
list.push_back(3);
let iter = list.iter();
let clone = iter.clone();
let v1: Vec<i32> = iter.copied().collect();
let v2: Vec<i32> = clone.copied().collect();
assert_eq!(v1, v2);
assert_eq!(v1, [1, 2, 3]);
}
#[test]
fn iter_does_not_consume_list() {
let mut list = SkipList::<i32>::with_capacity(1);
list.push_back(1);
list.push_back(2);
list.push_back(3);
let v1: Vec<i32> = list.iter().copied().collect();
let v2: Vec<i32> = list.iter().copied().collect();
assert_eq!(v1, v2);
assert_eq!(list.len(), 3);
}
#[test]
fn into_iter_for_ref() {
let mut list = SkipList::<i32>::with_capacity(1);
list.push_back(1);
list.push_back(2);
list.push_back(3);
let collected: Vec<i32> = (&list).into_iter().copied().collect();
assert_eq!(collected, [1, 2, 3]);
}
#[test]
fn iter_after_push_front() {
let mut list = SkipList::<i32>::with_capacity(1);
list.push_back(3);
list.push_front(2);
list.push_front(1);
let collected: Vec<i32> = list.iter().copied().collect();
assert_eq!(collected, [1, 2, 3]);
let reversed: Vec<i32> = list.iter().copied().rev().collect();
assert_eq!(reversed, [3, 2, 1]);
}
#[test]
fn iter_after_mutations() {
let mut list = SkipList::<i32>::with_capacity(1);
for i in 1..=5_i32 {
list.push_back(i); }
list.remove(2); list.insert(2, 9); let collected: Vec<i32> = list.iter().copied().collect();
assert_eq!(collected, [1, 2, 9, 4, 5]);
}
#[test]
fn iter_large_list_forward() {
const N: usize = 200;
let mut list = SkipList::<usize>::new();
for i in 0..N {
list.push_back(i);
}
for (i, v) in list.iter().enumerate() {
assert_eq!(*v, i);
}
}
#[test]
fn iter_large_list_backward() {
const N: usize = 200;
let mut list = SkipList::<usize>::new();
for i in 0..N {
list.push_back(i);
}
for (i, v) in list.iter().rev().enumerate() {
assert_eq!(*v, N - 1 - i);
}
}
#[test]
fn iter_mut_empty() {
let mut list = SkipList::<i32>::new();
let mut iter = list.iter_mut();
assert_eq!(iter.next(), None);
assert_eq!(iter.next_back(), None);
}
#[test]
fn iter_mut_single_element() {
let mut list = SkipList::<i32>::new();
list.push_back(42);
let mut iter = list.iter_mut();
assert_eq!(iter.next(), Some(&mut 42));
assert_eq!(iter.next(), None);
}
#[test]
fn iter_mut_single_element_from_back() {
let mut list = SkipList::<i32>::new();
list.push_back(42);
let mut iter = list.iter_mut();
assert_eq!(iter.next_back(), Some(&mut 42));
assert_eq!(iter.next_back(), None);
}
#[test]
#[expect(
clippy::explicit_iter_loop,
reason = "explicitly exercising iter_mut(); the &mut shorthand tests a different code path"
)]
fn iter_mut_modifies_elements() {
let mut list = SkipList::<i32>::with_capacity(1);
list.push_back(1);
list.push_back(2);
list.push_back(3);
for v in list.iter_mut() {
*v *= 10;
}
let collected: Vec<i32> = list.iter().copied().collect();
assert_eq!(collected, [10, 20, 30]);
}
#[test]
fn iter_mut_forward_order() {
let mut list = SkipList::<i32>::with_capacity(1);
list.push_back(1);
list.push_back(2);
list.push_back(3);
let collected: Vec<i32> = list.iter_mut().map(|v| *v).collect();
assert_eq!(collected, [1, 2, 3]);
}
#[test]
fn iter_mut_backward_order() {
let mut list = SkipList::<i32>::with_capacity(1);
list.push_back(1);
list.push_back(2);
list.push_back(3);
let collected: Vec<i32> = list.iter_mut().map(|v| *v).rev().collect();
assert_eq!(collected, [3, 2, 1]);
}
#[test]
fn iter_mut_double_ended_alternating() {
let mut list = SkipList::<i32>::with_capacity(1);
for i in 1..=5_i32 {
list.push_back(i);
}
let mut iter = list.iter_mut();
assert_eq!(iter.next(), Some(&mut 1));
assert_eq!(iter.next_back(), Some(&mut 5));
assert_eq!(iter.next(), Some(&mut 2));
assert_eq!(iter.next_back(), Some(&mut 4));
assert_eq!(iter.next(), Some(&mut 3));
assert_eq!(iter.next(), None);
assert_eq!(iter.next_back(), None);
}
#[test]
fn iter_mut_double_ended_meets_in_middle_odd() {
let mut list = SkipList::<i32>::with_capacity(1);
list.push_back(10);
list.push_back(20);
list.push_back(30);
let mut iter = list.iter_mut();
assert_eq!(iter.next(), Some(&mut 10));
assert_eq!(iter.next_back(), Some(&mut 30));
assert_eq!(iter.next(), Some(&mut 20));
assert_eq!(iter.next(), None);
assert_eq!(iter.next_back(), None);
}
#[test]
fn iter_mut_double_ended_meets_in_middle_even() {
let mut list = SkipList::<i32>::with_capacity(1);
list.push_back(10);
list.push_back(20);
list.push_back(30);
list.push_back(40);
let mut iter = list.iter_mut();
assert_eq!(iter.next(), Some(&mut 10));
assert_eq!(iter.next_back(), Some(&mut 40));
assert_eq!(iter.next(), Some(&mut 20));
assert_eq!(iter.next_back(), Some(&mut 30));
assert_eq!(iter.next(), None);
assert_eq!(iter.next_back(), None);
}
#[test]
fn iter_mut_size_hint_decrements() {
let mut list = SkipList::<i32>::with_capacity(1);
list.push_back(1);
list.push_back(2);
list.push_back(3);
let mut iter = list.iter_mut();
assert_eq!(iter.size_hint(), (3, Some(3)));
iter.next();
assert_eq!(iter.size_hint(), (2, Some(2)));
iter.next_back();
assert_eq!(iter.size_hint(), (1, Some(1)));
iter.next();
assert_eq!(iter.size_hint(), (0, Some(0)));
}
#[test]
fn iter_mut_exact_size() {
let mut list = SkipList::<i32>::new();
for i in 0..10_i32 {
list.push_back(i);
}
let mut iter = list.iter_mut();
assert_eq!(iter.len(), 10);
iter.next();
assert_eq!(iter.len(), 9);
iter.next_back();
assert_eq!(iter.len(), 8);
}
#[test]
fn iter_mut_fused_returns_none_repeatedly() {
let mut list = SkipList::<i32>::new();
list.push_back(1);
let mut iter = list.iter_mut();
assert_eq!(iter.next(), Some(&mut 1));
assert_eq!(iter.next(), None);
assert_eq!(iter.next(), None);
assert_eq!(iter.next_back(), None);
assert_eq!(iter.next_back(), None);
}
#[test]
fn iter_mut_does_not_consume_list_after_drop() {
let mut list = SkipList::<i32>::with_capacity(1);
list.push_back(1);
list.push_back(2);
list.push_back(3);
{
let _iter = list.iter_mut();
}
assert_eq!(list.len(), 3);
let collected: Vec<i32> = list.iter().copied().collect();
assert_eq!(collected, [1, 2, 3]);
}
#[test]
fn into_iter_for_mut_ref() {
let mut list = SkipList::<i32>::with_capacity(1);
list.push_back(1);
list.push_back(2);
list.push_back(3);
let collected: Vec<i32> = (&mut list).into_iter().map(|v| *v).collect();
assert_eq!(collected, [1, 2, 3]);
}
#[test]
fn into_iter_empty() {
let list = SkipList::<i32>::new();
let mut iter = list.into_iter();
assert_eq!(iter.next(), None);
assert_eq!(iter.next_back(), None);
}
#[test]
fn into_iter_single_element() {
let mut list = SkipList::<i32>::new();
list.push_back(42);
let mut iter = list.into_iter();
assert_eq!(iter.next(), Some(42));
assert_eq!(iter.next(), None);
}
#[test]
fn into_iter_single_element_from_back() {
let mut list = SkipList::<i32>::new();
list.push_back(42);
let mut iter = list.into_iter();
assert_eq!(iter.next_back(), Some(42));
assert_eq!(iter.next_back(), None);
}
#[test]
fn into_iter_forward_order() {
let mut list = SkipList::<i32>::with_capacity(1);
list.push_back(1);
list.push_back(2);
list.push_back(3);
let collected: Vec<i32> = list.into_iter().collect();
assert_eq!(collected, [1, 2, 3]);
}
#[test]
fn into_iter_backward_order() {
let mut list = SkipList::<i32>::with_capacity(1);
list.push_back(1);
list.push_back(2);
list.push_back(3);
let collected: Vec<i32> = list.into_iter().rev().collect();
assert_eq!(collected, [3, 2, 1]);
}
#[test]
fn into_iter_double_ended_alternating() {
let mut list = SkipList::<i32>::with_capacity(1);
for i in 1..=5_i32 {
list.push_back(i);
}
let mut iter = list.into_iter();
assert_eq!(iter.next(), Some(1));
assert_eq!(iter.next_back(), Some(5));
assert_eq!(iter.next(), Some(2));
assert_eq!(iter.next_back(), Some(4));
assert_eq!(iter.next(), Some(3));
assert_eq!(iter.next(), None);
assert_eq!(iter.next_back(), None);
}
#[test]
fn into_iter_double_ended_meets_in_middle_even() {
let mut list = SkipList::<i32>::with_capacity(1);
list.push_back(10);
list.push_back(20);
list.push_back(30);
list.push_back(40);
let mut iter = list.into_iter();
assert_eq!(iter.next(), Some(10));
assert_eq!(iter.next_back(), Some(40));
assert_eq!(iter.next(), Some(20));
assert_eq!(iter.next_back(), Some(30));
assert_eq!(iter.next(), None);
assert_eq!(iter.next_back(), None);
}
#[test]
fn into_iter_size_hint_decrements() {
let mut list = SkipList::<i32>::with_capacity(1);
list.push_back(1);
list.push_back(2);
list.push_back(3);
let mut iter = list.into_iter();
assert_eq!(iter.size_hint(), (3, Some(3)));
iter.next();
assert_eq!(iter.size_hint(), (2, Some(2)));
iter.next_back();
assert_eq!(iter.size_hint(), (1, Some(1)));
iter.next();
assert_eq!(iter.size_hint(), (0, Some(0)));
}
#[test]
fn into_iter_exact_size() {
let mut list = SkipList::<i32>::new();
for i in 0..10_i32 {
list.push_back(i);
}
let mut iter = list.into_iter();
assert_eq!(iter.len(), 10);
iter.next();
assert_eq!(iter.len(), 9);
iter.next_back();
assert_eq!(iter.len(), 8);
}
#[test]
fn into_iter_fused_returns_none_repeatedly() {
let mut list = SkipList::<i32>::new();
list.push_back(1);
let mut iter = list.into_iter();
assert_eq!(iter.next(), Some(1));
assert_eq!(iter.next(), None);
assert_eq!(iter.next(), None);
assert_eq!(iter.next_back(), None);
assert_eq!(iter.next_back(), None);
}
#[test]
fn into_iter_drops_remaining_on_drop() {
let mut list = SkipList::<i32>::new();
for i in 0..100_i32 {
list.push_back(i);
}
let mut iter = list.into_iter();
assert_eq!(iter.next(), Some(0));
assert_eq!(iter.next_back(), Some(99));
drop(iter);
}
#[test]
fn into_iter_consuming_via_for_loop() {
let mut list = SkipList::<i32>::with_capacity(1);
list.push_back(10);
list.push_back(20);
list.push_back(30);
let mut sum = 0;
for v in list {
sum += v;
}
assert_eq!(sum, 60);
}
#[test]
fn drain_full_range() {
let mut list = SkipList::<i32>::new();
for i in 1..=5 {
list.push_back(i);
}
let got: Vec<i32> = list.drain(..).collect();
assert_eq!(got, [1, 2, 3, 4, 5]);
assert!(list.is_empty());
}
#[test]
fn drain_empty_range() {
let mut list = SkipList::<i32>::new();
for i in 1..=5 {
list.push_back(i);
}
let got: Vec<i32> = list.drain(2..2).collect();
assert!(got.is_empty());
assert_eq!(list.len(), 5);
let remaining: Vec<i32> = list.iter().copied().collect();
assert_eq!(remaining, [1, 2, 3, 4, 5]);
}
#[test]
fn drain_front() {
let mut list = SkipList::<i32>::new();
for i in 1..=5 {
list.push_back(i);
}
let got: Vec<i32> = list.drain(..2).collect();
assert_eq!(got, [1, 2]);
assert_eq!(list.len(), 3);
let remaining: Vec<i32> = list.iter().copied().collect();
assert_eq!(remaining, [3, 4, 5]);
}
#[test]
fn drain_back() {
let mut list = SkipList::<i32>::new();
for i in 1..=5 {
list.push_back(i);
}
let got: Vec<i32> = list.drain(3..).collect();
assert_eq!(got, [4, 5]);
assert_eq!(list.len(), 3);
let remaining: Vec<i32> = list.iter().copied().collect();
assert_eq!(remaining, [1, 2, 3]);
}
#[test]
fn drain_middle() {
let mut list = SkipList::<i32>::new();
for i in 1..=5 {
list.push_back(i);
}
let got: Vec<i32> = list.drain(1..4).collect();
assert_eq!(got, [2, 3, 4]);
assert_eq!(list.len(), 2);
let remaining: Vec<i32> = list.iter().copied().collect();
assert_eq!(remaining, [1, 5]);
}
#[test]
fn drain_inclusive_range() {
let mut list = SkipList::<i32>::new();
for i in 1..=5 {
list.push_back(i);
}
let got: Vec<i32> = list.drain(1..=3).collect();
assert_eq!(got, [2, 3, 4]);
assert_eq!(list.len(), 2);
}
#[test]
fn drain_double_ended() {
let mut list = SkipList::<i32>::new();
for i in 1..=5 {
list.push_back(i);
}
let mut drain = list.drain(..);
assert_eq!(drain.next(), Some(1));
assert_eq!(drain.next_back(), Some(5));
assert_eq!(drain.next(), Some(2));
assert_eq!(drain.next_back(), Some(4));
assert_eq!(drain.next(), Some(3));
assert_eq!(drain.next(), None);
assert_eq!(drain.next_back(), None);
}
#[test]
fn drain_drop_remaining() {
let mut list = SkipList::<i32>::new();
for i in 1..=5 {
list.push_back(i);
}
{
let mut drain = list.drain(1..4);
assert_eq!(drain.next(), Some(2));
}
assert_eq!(list.len(), 2);
let remaining: Vec<i32> = list.iter().copied().collect();
assert_eq!(remaining, [1, 5]);
}
#[test]
fn drain_len_correct_after() {
let mut list = SkipList::<i32>::new();
for i in 0..10 {
list.push_back(i);
}
drop(list.drain(3..7));
assert_eq!(list.len(), 6);
}
#[test]
fn drain_links_consistent_after() {
let mut list = SkipList::<i32>::new();
for i in 0..10 {
list.push_back(i);
}
drop(list.drain(3..7));
let expected = [0, 1, 2, 7, 8, 9];
for (idx, &v) in expected.iter().enumerate() {
assert_eq!(list.get(idx), Some(&v));
}
assert_eq!(list.get(list.len()), None);
}
#[test]
fn drain_size_hint() {
let mut list = SkipList::<i32>::new();
for i in 1..=5 {
list.push_back(i);
}
let mut drain = list.drain(1..4);
assert_eq!(drain.size_hint(), (3, Some(3)));
drain.next();
assert_eq!(drain.size_hint(), (2, Some(2)));
}
#[test]
fn drain_fused() {
let mut list = SkipList::<i32>::new();
list.push_back(1);
let mut drain = list.drain(..);
assert_eq!(drain.next(), Some(1));
assert_eq!(drain.next(), None);
assert_eq!(drain.next(), None);
assert_eq!(drain.next_back(), None);
}
#[test]
#[expect(
clippy::reversed_empty_ranges,
reason = "Intentional test of invalid range handling in drain()"
)]
#[should_panic(expected = "drain range start")]
fn drain_panics_start_gt_end() {
let mut list = SkipList::<i32>::new();
for i in 0..5 {
list.push_back(i);
}
drop(list.drain(3..1));
}
#[test]
#[should_panic(expected = "drain range end")]
fn drain_panics_end_gt_len() {
let mut list = SkipList::<i32>::new();
for i in 0..5 {
list.push_back(i);
}
drop(list.drain(0..10));
}
#[test]
fn extract_if_empty() {
let mut list = SkipList::<i32>::new();
let extracted: Vec<i32> = list.extract_if(|_| true).collect();
assert!(extracted.is_empty());
assert!(list.is_empty());
}
#[test]
fn extract_if_none_match() {
let mut list = SkipList::<i32>::new();
for i in 1..=5 {
list.push_back(i);
}
let extracted: Vec<i32> = list.extract_if(|_| false).collect();
assert!(extracted.is_empty());
assert_eq!(list.len(), 5);
let remaining: Vec<i32> = list.iter().copied().collect();
assert_eq!(remaining, [1, 2, 3, 4, 5]);
}
#[test]
fn extract_if_all_match() {
let mut list = SkipList::<i32>::new();
for i in 1..=5 {
list.push_back(i);
}
let extracted: Vec<i32> = list.extract_if(|_| true).collect();
assert_eq!(extracted, [1, 2, 3, 4, 5]);
assert!(list.is_empty());
assert_eq!(list.len(), 0);
}
#[test]
fn extract_if_evens() {
let mut list = SkipList::<i32>::new();
for i in 1..=5 {
list.push_back(i);
}
#[expect(
clippy::integer_division_remainder_used,
reason = "clearer to express the intent of extracting even numbers"
)]
let extracted: Vec<i32> = list.extract_if(|x| *x % 2 == 0).collect();
assert_eq!(extracted, [2, 4]);
let remaining: Vec<i32> = list.iter().copied().collect();
assert_eq!(remaining, [1, 3, 5]);
}
#[test]
fn extract_if_preserves_order() {
let mut list = SkipList::<i32>::new();
for i in [5, 1, 4, 2, 3] {
list.push_back(i);
}
let extracted: Vec<i32> = list.extract_if(|x| *x > 3).collect();
assert_eq!(extracted, [5, 4]);
let remaining: Vec<i32> = list.iter().copied().collect();
assert_eq!(remaining, [1, 2, 3]);
}
#[test]
fn extract_if_remaining_in_list() {
let mut list = SkipList::<i32>::new();
for i in 1..=6 {
list.push_back(i);
}
#[expect(
clippy::integer_division_remainder_used,
reason = "clearer to express the intent of extracting odd numbers"
)]
let extracted: Vec<i32> = list.extract_if(|x| *x % 2 != 0).collect();
assert_eq!(extracted, [1, 3, 5]);
assert_eq!(list.len(), 3);
let remaining: Vec<i32> = list.iter().copied().collect();
assert_eq!(remaining, [2, 4, 6]);
}
#[test]
#[expect(
clippy::integer_division_remainder_used,
reason = "clearer to express the intent of extracting multiples of 3"
)]
fn extract_if_links_consistent() {
let mut list = SkipList::<i32>::new();
for i in 0..10 {
list.push_back(i);
}
_ = list.extract_if(|x| *x % 3 == 0).count();
let expected = [1, 2, 4, 5, 7, 8];
assert_eq!(list.len(), expected.len());
for (idx, &v) in expected.iter().enumerate() {
assert_eq!(list.get(idx), Some(&v));
}
assert_eq!(list.get(list.len()), None);
}
#[test]
fn extract_if_drop_early() {
let mut list = SkipList::<i32>::new();
for i in 1..=5 {
list.push_back(i);
}
{
#[expect(
clippy::integer_division_remainder_used,
reason = "clearer to express the intent of extracting even numbers"
)]
let mut it = list.extract_if(|x| *x % 2 == 0);
assert_eq!(it.next(), Some(2));
}
assert_eq!(list.len(), 4);
let remaining: Vec<i32> = list.iter().copied().collect();
assert_eq!(remaining, [1, 3, 4, 5]);
}
#[test]
fn extract_if_tail_updated() {
let mut list = SkipList::<i32>::new();
for i in 1..=4 {
list.push_back(i);
}
let extracted: Vec<i32> = list.extract_if(|x| *x >= 3).collect();
assert_eq!(extracted, [3, 4]);
assert_eq!(list.back(), Some(&2));
}
#[test]
fn extract_if_len_correct() {
let mut list = SkipList::<i32>::new();
for i in 1..=5 {
list.push_back(i);
}
#[expect(
clippy::integer_division_remainder_used,
reason = "clearer to express the intent of extracting even numbers"
)]
let mut it = list.extract_if(|x| *x % 2 == 0);
assert_eq!(it.size_hint(), (0, Some(5)));
assert_eq!(it.next(), Some(2));
assert_eq!(it.size_hint(), (0, Some(4)));
assert_eq!(it.next(), Some(4));
assert_eq!(it.size_hint(), (0, Some(3)));
drop(it);
assert_eq!(list.len(), 3);
}
#[test]
fn extract_if_fused() {
let mut list = SkipList::<i32>::new();
list.push_back(1);
let mut it = list.extract_if(|_| true);
assert_eq!(it.next(), Some(1));
assert_eq!(it.next(), None);
assert_eq!(it.next(), None);
}
#[test]
fn extract_if_mut_predicate() {
let mut list = SkipList::<i32>::new();
for i in 1..=4 {
list.push_back(i);
}
#[expect(
clippy::integer_division_remainder_used,
reason = "clearer to express the intent of modifying even numbers in place and extracting odd numbers"
)]
let extracted: Vec<i32> = list
.extract_if(|x| {
if *x % 2 == 0 {
*x *= 10;
false
} else {
true
}
})
.collect();
assert_eq!(extracted, [1, 3]);
let remaining: Vec<i32> = list.iter().copied().collect();
assert_eq!(remaining, [20, 40]);
}
#[test]
fn range_empty_list() {
let list = SkipList::<i32>::new();
let v: Vec<i32> = list.range(0..0).copied().collect();
assert!(v.is_empty());
}
#[test]
fn range_empty_range() {
let mut list = SkipList::<i32>::new();
for i in 1..=5 {
list.push_back(i);
}
let v: Vec<i32> = list.range(2..2).copied().collect();
assert!(v.is_empty());
}
#[test]
fn range_full() {
let mut list = SkipList::<i32>::new();
for i in 1..=5 {
list.push_back(i);
}
let from_range: Vec<i32> = list.range(..).copied().collect();
let from_iter: Vec<i32> = list.iter().copied().collect();
assert_eq!(from_range, from_iter);
}
#[test]
fn range_half_open() {
let mut list = SkipList::<i32>::new();
for i in 1..=5 {
list.push_back(i);
}
let v: Vec<i32> = list.range(1..4).copied().collect();
assert_eq!(v, [2, 3, 4]);
}
#[test]
fn range_inclusive() {
let mut list = SkipList::<i32>::new();
for i in 1..=5 {
list.push_back(i);
}
let v: Vec<i32> = list.range(1..=3).copied().collect();
assert_eq!(v, [2, 3, 4]);
}
#[test]
fn range_single() {
let mut list = SkipList::<i32>::new();
for i in 1..=5 {
list.push_back(i);
}
let v: Vec<i32> = list.range(2..=2).copied().collect();
assert_eq!(v, [3]);
}
#[test]
fn range_double_ended() {
let mut list = SkipList::<i32>::new();
for i in 1..=5 {
list.push_back(i);
}
let mut it = list.range(1..4);
assert_eq!(it.next(), Some(&2));
assert_eq!(it.next_back(), Some(&4));
assert_eq!(it.next(), Some(&3));
assert_eq!(it.next(), None);
assert_eq!(it.next_back(), None);
}
#[test]
fn range_rev() {
let mut list = SkipList::<i32>::new();
for i in 1..=5 {
list.push_back(i);
}
let v: Vec<i32> = list.range(1..4).copied().rev().collect();
assert_eq!(v, [4, 3, 2]);
}
#[test]
fn range_exact_size() {
let mut list = SkipList::<i32>::new();
for i in 1..=5 {
list.push_back(i);
}
let it = list.range(1..4);
assert_eq!(it.len(), 3);
}
#[test]
fn range_mut_modify() {
let mut list = SkipList::<i32>::new();
for i in 1..=5 {
list.push_back(i);
}
for v in list.range_mut(1..4) {
*v *= 10;
}
let collected: Vec<i32> = list.iter().copied().collect();
assert_eq!(collected, [1, 20, 30, 40, 5]);
}
#[test]
fn range_mut_double_ended() {
let mut list = SkipList::<i32>::new();
for i in 1..=5 {
list.push_back(i);
}
let v: Vec<i32> = list.range_mut(1..4).map(|x| *x).rev().collect();
assert_eq!(v, [4, 3, 2]);
}
#[test]
#[expect(
clippy::reversed_empty_ranges,
reason = "Intentional test of invalid range handling in range()"
)]
#[should_panic(expected = "range start")]
fn range_panic_start_gt_end() {
let mut list = SkipList::<i32>::new();
for i in 1..=5 {
list.push_back(i);
}
drop(list.range(3..1));
}
#[test]
#[should_panic(expected = "range end")]
fn range_panic_end_gt_len() {
let mut list = SkipList::<i32>::new();
for i in 1..=5 {
list.push_back(i);
}
drop(list.range(0..10));
}
}