use std::collections::VecDeque;
pub fn newlinklist() -> LinkList<String> {
LinkList::new()
}
impl<T> Default for LinkList<T> {
fn default() -> Self {
Self::new()
}
}
impl<T> LinkList<T> {
pub fn new() -> Self {
LinkList {
nodes: VecDeque::new(),
flags: 0,
}
}
pub fn is_empty(&self) -> bool {
self.nodes.is_empty()
}
pub fn len(&self) -> usize {
self.nodes.len()
}
pub fn push_front(&mut self, data: T) {
self.nodes.push_front(data);
}
pub fn push_back(&mut self, data: T) {
self.nodes.push_back(data);
}
pub fn pop_front(&mut self) -> Option<T> {
self.nodes.pop_front()
}
pub fn pop_back(&mut self) -> Option<T> {
self.nodes.pop_back()
}
pub fn front(&self) -> Option<&T> {
self.nodes.front()
}
pub fn front_mut(&mut self) -> Option<&mut T> {
self.nodes.front_mut()
}
pub fn back(&self) -> Option<&T> {
self.nodes.back()
}
pub fn back_mut(&mut self) -> Option<&mut T> {
self.nodes.back_mut()
}
pub fn iter(&self) -> std::collections::vec_deque::Iter<'_, T> {
self.nodes.iter()
}
pub fn iter_mut(&mut self) -> std::collections::vec_deque::IterMut<'_, T> {
self.nodes.iter_mut()
}
pub fn append(&mut self, other: &mut LinkList<T>) {
self.nodes.append(&mut other.nodes);
}
pub fn clear(&mut self) {
self.nodes.clear();
}
pub fn to_vec(self) -> Vec<T>
where
T: Clone,
{
self.nodes.into_iter().collect()
}
pub fn firstnode(&self) -> Option<usize> {
if self.nodes.is_empty() {
None
} else {
Some(0)
}
}
pub fn lastnode(&self) -> Option<usize> {
if self.nodes.is_empty() {
None
} else {
Some(self.nodes.len() - 1)
}
}
pub fn nextnode(&self, idx: usize) -> Option<usize> {
if idx + 1 < self.nodes.len() {
Some(idx + 1)
} else {
None
}
}
pub fn prevnode(&self, idx: usize) -> Option<usize> {
if idx > 0 && idx <= self.nodes.len() {
Some(idx - 1)
} else {
None
}
}
pub fn getdata(&self, idx: usize) -> Option<&T> {
self.nodes.get(idx)
}
pub fn setdata(&mut self, idx: usize, data: T) {
if let Some(slot) = self.nodes.get_mut(idx) {
*slot = data;
}
}
pub fn empty(&self) -> bool {
self.nodes.is_empty()
}
pub fn insertlinknode(&mut self, after_idx: usize, data: T) -> usize {
let new_idx = after_idx + 1;
if new_idx >= self.nodes.len() {
self.nodes.push_back(data);
self.nodes.len() - 1
} else {
self.nodes.insert(new_idx, data);
new_idx
}
}
pub fn delete_node(&mut self, idx: usize) -> Option<T> {
self.nodes.remove(idx)
}
pub fn insert_at(&mut self, idx: usize, data: T) {
if idx >= self.nodes.len() {
self.nodes.push_back(data);
} else {
self.nodes.insert(idx, data);
}
}
}
impl<T: Clone> Clone for LinkList<T> {
fn clone(&self) -> Self {
LinkList {
nodes: self.nodes.clone(),
flags: self.flags,
}
}
}
impl<T: std::fmt::Debug> std::fmt::Debug for LinkList<T> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("LinkList")
.field("nodes", &self.nodes)
.field("flags", &self.flags)
.finish()
}
}
impl<T> FromIterator<T> for LinkList<T> {
fn from_iter<I: IntoIterator<Item = T>>(iter: I) -> Self {
let mut list = LinkList::new();
for item in iter {
list.push_back(item);
}
list
}
}
impl<T> IntoIterator for LinkList<T> {
type Item = T;
type IntoIter = std::collections::vec_deque::IntoIter<T>;
fn into_iter(self) -> Self::IntoIter {
self.nodes.into_iter()
}
}
impl<'a, T> IntoIterator for &'a LinkList<T> {
type Item = &'a T;
type IntoIter = std::collections::vec_deque::Iter<'a, T>;
fn into_iter(self) -> Self::IntoIter {
self.nodes.iter()
}
}
pub fn znewlinklist() -> LinkList<String> {
LinkList::new()
}
pub fn insertlinknode<T>(list: &mut LinkList<T>, node: usize, dat: T) -> usize {
list.insertlinknode(node, dat)
}
pub fn zinsertlinknode<T>(list: &mut LinkList<T>, node: usize, dat: T) -> usize {
list.insertlinknode(node, dat)
}
pub fn uinsertlinknode(list: &mut LinkList<String>, node: usize, new: String) -> Option<usize> {
if list.iter().any(|s| s == &new) {
None
} else {
Some(list.insertlinknode(node, new))
}
}
pub fn insertlinklist<T: Clone>(
l: &LinkList<T>,
where_idx: usize,
x: &mut LinkList<T>,
) {
if l.is_empty() {
return;
}
let mut idx = where_idx;
for v in l.iter() {
idx = x.insertlinknode(idx, v.clone());
}
}
pub fn getlinknode<T>(list: &mut LinkList<T>) -> Option<T> {
list.pop_front()
}
pub fn ugetnode<T>(list: &mut LinkList<T>) -> Option<T> {
list.pop_front()
}
pub fn remnode<T>(list: &mut LinkList<T>, nd: usize) -> Option<T> {
list.delete_node(nd)
}
pub fn uremnode<T>(list: &mut LinkList<T>, nd: usize) -> Option<T> {
list.delete_node(nd)
}
pub fn freelinklist<T>(list: &mut LinkList<T>) {
list.clear();
}
pub fn countlinknodes<T>(list: &LinkList<T>) -> usize {
list.len()
}
pub fn rolllist<T>(l: &mut LinkList<T>, nd: usize) {
let len = l.len();
if len > 0 {
let nd = nd % len;
for _ in 0..nd {
if let Some(v) = l.pop_front() {
l.push_back(v);
}
}
}
}
pub fn newsizedlist<T: Default>(size: usize) -> LinkList<T> {
let mut list = LinkList::new();
for _ in 0..size {
list.push_back(T::default());
}
list
}
pub fn joinlists<T>(first: &mut LinkList<T>, second: &mut LinkList<T>) {
first.append(second);
}
pub fn linknodebydatum<T: PartialEq>(list: &LinkList<T>, dat: &T) -> Option<usize> {
list.iter().position(|v| v == dat)
}
pub fn linknodebystring(list: &LinkList<String>, dat: &str) -> Option<usize> {
list.iter().position(|v| v == dat)
}
pub fn hlinklist2array(list: &LinkList<String>) -> Vec<String> {
list.iter().cloned().collect()
}
pub fn zlinklist2array(list: &LinkList<String>) -> Vec<String> {
list.iter().cloned().collect()
}
pub struct LinkList<T> {
pub nodes: VecDeque<T>, pub flags: u32, }
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_new_list() {
let _g = crate::test_util::global_state_lock();
let list: LinkList<i32> = LinkList::new();
assert!(list.is_empty());
assert_eq!(list.len(), 0);
assert_eq!(list.flags, 0);
}
#[test]
fn newsizedlist_preallocates_n_slots() {
let _g = crate::test_util::global_state_lock();
let list: LinkList<i32> = newsizedlist(5);
assert_eq!(
list.len(),
5,
"c:339-341 — newsizedlist(5) must pre-allocate 5 nodes"
);
for v in list.iter() {
assert_eq!(*v, 0, "pre-allocated slots default to 0");
}
let zero_list: LinkList<String> = newsizedlist(0);
assert_eq!(zero_list.len(), 0, "newsizedlist(0) is the same as new()");
}
#[test]
fn test_push_front_back() {
let _g = crate::test_util::global_state_lock();
let mut list = LinkList::new();
list.push_back(1);
list.push_back(2);
list.push_front(0);
assert_eq!(list.front(), Some(&0));
assert_eq!(list.back(), Some(&2));
assert_eq!(list.len(), 3);
}
#[test]
fn test_pop_front_back() {
let _g = crate::test_util::global_state_lock();
let mut list = LinkList::new();
list.push_back(1);
list.push_back(2);
list.push_back(3);
assert_eq!(list.pop_front(), Some(1));
assert_eq!(list.pop_back(), Some(3));
assert_eq!(list.pop_front(), Some(2));
assert_eq!(list.pop_front(), None);
}
#[test]
fn test_iter() {
let _g = crate::test_util::global_state_lock();
let mut list = LinkList::new();
list.push_back(1);
list.push_back(2);
list.push_back(3);
let v: Vec<_> = list.iter().copied().collect();
assert_eq!(v, vec![1, 2, 3]);
}
#[test]
fn test_macro_methods() {
let _g = crate::test_util::global_state_lock();
let mut list: LinkList<String> = LinkList::new();
list.push_back("a".to_string());
list.push_back("b".to_string());
list.push_back("c".to_string());
assert_eq!(list.firstnode(), Some(0));
assert_eq!(list.lastnode(), Some(2));
assert_eq!(list.nextnode(0), Some(1));
assert_eq!(list.nextnode(2), None);
assert_eq!(list.getdata(1).map(String::as_str), Some("b"));
list.setdata(1, "B".to_string());
assert_eq!(list.getdata(1).map(String::as_str), Some("B"));
let new_idx = list.insertlinknode(1, "X".to_string());
assert_eq!(new_idx, 2);
assert_eq!(list.getdata(2).map(String::as_str), Some("X"));
assert_eq!(list.delete_node(2).as_deref(), Some("X"));
assert_eq!(list.getdata(2).map(String::as_str), Some("c"));
}
#[test]
fn test_append() {
let _g = crate::test_util::global_state_lock();
let mut a: LinkList<i32> = vec![1, 2].into_iter().collect();
let mut b: LinkList<i32> = vec![3, 4].into_iter().collect();
a.append(&mut b);
assert!(b.is_empty());
assert_eq!(a.to_vec(), vec![1, 2, 3, 4]);
}
#[test]
fn test_clear() {
let _g = crate::test_util::global_state_lock();
let mut list: LinkList<i32> = vec![1, 2, 3].into_iter().collect();
list.clear();
assert!(list.is_empty());
}
#[test]
fn test_uinsertlinknode_dedups() {
let _g = crate::test_util::global_state_lock();
let mut list: LinkList<String> = LinkList::new();
list.push_back("a".to_string());
assert!(uinsertlinknode(&mut list, 0, "b".to_string()).is_some());
assert!(uinsertlinknode(&mut list, 0, "a".to_string()).is_none());
assert_eq!(list.len(), 2);
}
#[test]
fn joinlists_drains_second_into_first() {
let _g = crate::test_util::global_state_lock();
let mut a: LinkList<i32> = vec![1, 2].into_iter().collect();
let mut b: LinkList<i32> = vec![3, 4, 5].into_iter().collect();
joinlists(&mut a, &mut b);
assert_eq!(a.to_vec(), vec![1, 2, 3, 4, 5]);
assert!(b.is_empty(), "second list must be drained after join");
}
#[test]
fn joinlists_empty_second_is_noop() {
let _g = crate::test_util::global_state_lock();
let mut a: LinkList<i32> = vec![1, 2].into_iter().collect();
let mut b: LinkList<i32> = LinkList::new();
joinlists(&mut a, &mut b);
assert_eq!(a.to_vec(), vec![1, 2]);
assert!(b.is_empty());
}
#[test]
fn joinlists_empty_first_receives_all_of_second() {
let _g = crate::test_util::global_state_lock();
let mut a: LinkList<i32> = LinkList::new();
let mut b: LinkList<i32> = vec![1, 2, 3].into_iter().collect();
joinlists(&mut a, &mut b);
assert_eq!(a.to_vec(), vec![1, 2, 3]);
assert!(b.is_empty());
}
#[test]
fn linknodebydatum_finds_first_match() {
let _g = crate::test_util::global_state_lock();
let list: LinkList<i32> = vec![10, 20, 30, 20].into_iter().collect();
assert_eq!(
linknodebydatum(&list, &20),
Some(1),
"must return FIRST match index"
);
assert_eq!(linknodebydatum(&list, &99), None);
}
#[test]
fn linknodebystring_finds_first_match() {
let _g = crate::test_util::global_state_lock();
let list: LinkList<String> = vec!["a".into(), "b".into(), "a".into()]
.into_iter()
.collect();
assert_eq!(linknodebystring(&list, "a"), Some(0));
assert_eq!(linknodebystring(&list, "b"), Some(1));
assert_eq!(linknodebystring(&list, "x"), None);
}
#[test]
fn hlinklist2array_preserves_order() {
let _g = crate::test_util::global_state_lock();
let list: LinkList<String> = vec!["a".into(), "b".into(), "c".into()]
.into_iter()
.collect();
let arr = hlinklist2array(&list);
assert_eq!(arr, vec!["a".to_string(), "b".to_string(), "c".to_string()]);
}
#[test]
fn countlinknodes_returns_len_for_arbitrary_lists() {
let _g = crate::test_util::global_state_lock();
let empty: LinkList<i32> = LinkList::new();
assert_eq!(
countlinknodes(&empty),
0,
"c:309 — empty list traversal yields 0"
);
let one: LinkList<i32> = vec![42].into_iter().collect();
assert_eq!(countlinknodes(&one), 1);
let many: LinkList<i32> = (0..100).collect();
assert_eq!(countlinknodes(&many), 100);
}
#[test]
fn rolllist_rotates_to_index() {
let _g = crate::test_util::global_state_lock();
let mut list: LinkList<i32> = vec![10, 20, 30, 40].into_iter().collect();
rolllist(&mut list, 2);
assert_eq!(
list.to_vec(),
vec![30, 40, 10, 20],
"c:321 — `list.first = nd` then preceding nodes append at end"
);
}
#[test]
fn rolllist_zero_index_is_identity() {
let _g = crate::test_util::global_state_lock();
let mut list: LinkList<i32> = vec![1, 2, 3].into_iter().collect();
rolllist(&mut list, 0);
assert_eq!(list.to_vec(), vec![1, 2, 3]);
}
#[test]
fn rolllist_wraps_index_modulo_length() {
let _g = crate::test_util::global_state_lock();
let mut list: LinkList<i32> = vec![1, 2, 3].into_iter().collect();
rolllist(&mut list, 4);
assert_eq!(list.to_vec(), vec![2, 3, 1]);
}
#[test]
fn insertlinklist_splices_source_into_dest_after_position() {
let _g = crate::test_util::global_state_lock();
let source: LinkList<i32> = vec![100, 200, 300].into_iter().collect();
let mut dest: LinkList<i32> = vec![10, 20, 30].into_iter().collect();
insertlinklist(&source, 0, &mut dest);
assert_eq!(
dest.to_vec(),
vec![10, 100, 200, 300, 20, 30],
"c:194-202 — source spliced into dest after node 0"
);
assert_eq!(
source.to_vec(),
vec![100, 200, 300],
"c:188-206 — source list is NOT modified (read-only)"
);
}
#[test]
fn insertlinklist_empty_source_is_noop() {
let _g = crate::test_util::global_state_lock();
let source: LinkList<i32> = LinkList::new();
let mut dest: LinkList<i32> = vec![1, 2, 3].into_iter().collect();
insertlinklist(&source, 1, &mut dest);
assert_eq!(
dest.to_vec(),
vec![1, 2, 3],
"c:193-194 — empty l returns early; dest unchanged"
);
}
#[test]
fn insertlinklist_lastnode_append_pattern() {
let _g = crate::test_util::global_state_lock();
let source: LinkList<&str> = vec!["x", "y"].into_iter().collect();
let mut dest: LinkList<&str> = vec!["a", "b", "c"].into_iter().collect();
let last = dest.len() - 1;
insertlinklist(&source, last, &mut dest);
assert_eq!(
dest.to_vec(),
vec!["a", "b", "c", "x", "y"],
"c:188-206 zutil.c:1324 — lastnode anchor → tail-append"
);
}
#[test]
fn linklist_pop_on_empty_returns_none() {
let _g = crate::test_util::global_state_lock();
let mut list: LinkList<i32> = LinkList::new();
assert_eq!(list.pop_front(), None);
assert_eq!(list.pop_back(), None);
}
#[test]
fn linklist_front_back_on_empty_return_none() {
let _g = crate::test_util::global_state_lock();
let list: LinkList<i32> = LinkList::new();
assert!(list.front().is_none());
assert!(list.back().is_none());
}
#[test]
fn countlinknodes_empty_returns_zero() {
let _g = crate::test_util::global_state_lock();
let list: LinkList<i32> = LinkList::new();
assert_eq!(countlinknodes(&list), 0);
}
#[test]
fn countlinknodes_matches_len_for_populated_list() {
let _g = crate::test_util::global_state_lock();
let mut list = LinkList::new();
for i in 0..7 {
list.push_back(i);
}
assert_eq!(countlinknodes(&list), 7);
assert_eq!(countlinknodes(&list), list.len());
}
#[test]
fn joinlists_appends_second_to_first_and_empties_second() {
let _g = crate::test_util::global_state_lock();
let mut first: LinkList<i32> = LinkList::new();
first.push_back(1);
first.push_back(2);
let mut second: LinkList<i32> = LinkList::new();
second.push_back(3);
second.push_back(4);
joinlists(&mut first, &mut second);
assert_eq!(first.len(), 4, "first must absorb second's elements");
assert!(second.is_empty(), "second must be emptied after joinlists");
}
#[test]
fn joinlists_with_empty_second_leaves_first_unchanged() {
let _g = crate::test_util::global_state_lock();
let mut first: LinkList<i32> = LinkList::new();
first.push_back(1);
first.push_back(2);
let len_before = first.len();
let mut second: LinkList<i32> = LinkList::new();
joinlists(&mut first, &mut second);
assert_eq!(first.len(), len_before);
}
#[test]
fn linknodebydatum_finds_existing_element() {
let _g = crate::test_util::global_state_lock();
let mut list = LinkList::new();
list.push_back(10);
list.push_back(20);
list.push_back(30);
assert!(linknodebydatum(&list, &20).is_some());
assert!(linknodebydatum(&list, &99).is_none());
}
#[test]
fn linknodebystring_finds_existing_string() {
let _g = crate::test_util::global_state_lock();
let mut list: LinkList<String> = LinkList::new();
list.push_back("alpha".into());
list.push_back("beta".into());
list.push_back("gamma".into());
assert!(linknodebystring(&list, "beta").is_some());
assert!(linknodebystring(&list, "delta").is_none());
}
#[test]
fn hlinklist2array_preserves_insertion_order() {
let _g = crate::test_util::global_state_lock();
let mut list: LinkList<String> = LinkList::new();
list.push_back("x".into());
list.push_back("y".into());
list.push_back("z".into());
assert_eq!(
hlinklist2array(&list),
vec!["x".to_string(), "y".into(), "z".into()]
);
}
#[test]
fn hlinklist2array_on_empty_returns_empty_vec() {
let _g = crate::test_util::global_state_lock();
let list: LinkList<String> = LinkList::new();
let v = hlinklist2array(&list);
assert!(v.is_empty());
}
#[test]
fn freelinklist_empties_the_list() {
let _g = crate::test_util::global_state_lock();
let mut list = LinkList::new();
for i in 0..5 {
list.push_back(i);
}
assert_eq!(list.len(), 5);
freelinklist(&mut list);
assert!(list.is_empty());
}
#[test]
fn getlinknode_pops_head_returning_value() {
let _g = crate::test_util::global_state_lock();
let mut list = LinkList::new();
list.push_back(1);
list.push_back(2);
list.push_back(3);
assert_eq!(getlinknode(&mut list), Some(1));
assert_eq!(list.len(), 2, "head removed → len down by 1");
assert_eq!(getlinknode(&mut list), Some(2));
assert_eq!(getlinknode(&mut list), Some(3));
assert_eq!(getlinknode(&mut list), None, "empty → None");
}
#[test]
fn linklist_corpus_new_is_empty() {
let l = newlinklist();
assert_eq!(countlinknodes(&l), 0);
assert!(l.is_empty());
}
#[test]
fn linklist_corpus_count_after_many_pushes() {
let mut l = LinkList::<i32>::new();
for i in 0..50 {
l.push_back(i);
}
assert_eq!(countlinknodes(&l), 50);
assert_eq!(l.len(), 50);
}
#[test]
fn linklist_corpus_joinlists_concatenates() {
let mut a = LinkList::<i32>::new();
let mut b = LinkList::<i32>::new();
a.push_back(1);
a.push_back(2);
b.push_back(3);
b.push_back(4);
joinlists(&mut a, &mut b);
assert_eq!(a.len(), 4, "first holds union");
assert!(b.is_empty(), "second emptied");
}
#[test]
fn linklist_corpus_getlinknode_empty_returns_none() {
let mut l = LinkList::<i32>::new();
assert_eq!(getlinknode(&mut l), None);
}
#[test]
fn linklist_corpus_getlinknode_drains_in_fifo_order() {
let mut l = LinkList::<&'static str>::new();
l.push_back("a");
l.push_back("b");
l.push_back("c");
assert_eq!(getlinknode(&mut l), Some("a"));
assert_eq!(getlinknode(&mut l), Some("b"));
assert_eq!(getlinknode(&mut l), Some("c"));
assert_eq!(getlinknode(&mut l), None);
assert!(l.is_empty());
}
#[test]
fn linklist_corpus_linknodebydatum_finds_value() {
let mut l = LinkList::<i32>::new();
l.push_back(10);
l.push_back(20);
l.push_back(30);
assert_eq!(linknodebydatum(&l, &20), Some(1));
assert_eq!(linknodebydatum(&l, &99), None);
}
#[test]
fn newlinklist_returns_empty_pin() {
let l = newlinklist();
assert!(l.is_empty());
assert_eq!(l.len(), 0);
}
#[test]
fn znewlinklist_returns_empty_pin() {
let l = znewlinklist();
assert!(l.is_empty());
}
#[test]
fn countlinknodes_empty_is_zero_pin() {
let l = LinkList::<i32>::new();
assert_eq!(countlinknodes(&l), 0);
}
#[test]
fn countlinknodes_matches_length_pin() {
let mut l = LinkList::<i32>::new();
l.push_back(1);
l.push_back(2);
l.push_back(3);
assert_eq!(countlinknodes(&l), 3);
}
#[test]
fn getlinknode_empty_returns_none_pin() {
let mut l = LinkList::<i32>::new();
assert!(getlinknode(&mut l).is_none());
}
#[test]
fn ugetnode_empty_returns_none_pin() {
let mut l = LinkList::<i32>::new();
assert!(ugetnode(&mut l).is_none());
}
#[test]
fn freelinklist_clears_list_pin() {
let mut l = LinkList::<i32>::new();
l.push_back(1);
l.push_back(2);
freelinklist(&mut l);
assert!(l.is_empty());
}
#[test]
fn linknodebystring_finds_string_pin() {
let mut l = LinkList::<String>::new();
l.push_back("alpha".to_string());
l.push_back("beta".to_string());
l.push_back("gamma".to_string());
assert_eq!(linknodebystring(&l, "beta"), Some(1));
assert_eq!(linknodebystring(&l, "delta"), None);
}
#[test]
fn linknodebystring_first_match_pin() {
let mut l = LinkList::<String>::new();
l.push_back("x".to_string());
l.push_back("x".to_string());
assert_eq!(linknodebystring(&l, "x"), Some(0));
}
#[test]
fn hlinklist2array_preserves_order_pin() {
let mut l = LinkList::<String>::new();
l.push_back("a".to_string());
l.push_back("b".to_string());
l.push_back("c".to_string());
let v = hlinklist2array(&l);
assert_eq!(v, vec!["a", "b", "c"]);
}
#[test]
fn hlinklist2array_empty_returns_empty_vec_pin() {
let l = LinkList::<String>::new();
let v = hlinklist2array(&l);
assert!(v.is_empty());
}
#[test]
fn newsizedlist_zero_returns_empty_pin() {
let l: LinkList<i32> = newsizedlist(0);
assert!(l.is_empty());
}
#[test]
fn uinsertlinknode_dup_returns_none() {
let mut l: LinkList<String> = LinkList::new();
l.push_back("a".to_string());
l.push_back("b".to_string());
let r = uinsertlinknode(&mut l, 0, "a".to_string());
assert_eq!(r, None, "dup must return None");
assert_eq!(l.len(), 2, "list size unchanged");
}
#[test]
fn uinsertlinknode_new_returns_some() {
let mut l: LinkList<String> = LinkList::new();
l.push_back("a".to_string());
let r = uinsertlinknode(&mut l, 0, "b".to_string());
assert!(r.is_some(), "new value must return Some");
assert_eq!(l.len(), 2, "list size incremented");
}
#[test]
fn rolllist_empty_no_panic() {
let mut l: LinkList<i32> = LinkList::new();
rolllist(&mut l, 5);
assert!(l.is_empty());
}
#[test]
fn rolllist_full_length_is_identity() {
let mut l: LinkList<i32> = LinkList::new();
for i in 1..=5 {
l.push_back(i);
}
let before: Vec<i32> = l.iter().copied().collect();
rolllist(&mut l, 5); let after: Vec<i32> = l.iter().copied().collect();
assert_eq!(before, after, "full rotation is identity");
}
#[test]
fn newsizedlist_n_returns_n_default_nodes() {
for n in [1usize, 3, 10, 100] {
let l: LinkList<i32> = newsizedlist(n);
assert_eq!(l.len(), n, "newsizedlist({}) must return {} nodes", n, n);
for v in l.iter() {
assert_eq!(*v, 0, "default i32 = 0");
}
}
}
#[test]
fn linknodebystring_missing_returns_none_pin() {
let mut l: LinkList<String> = LinkList::new();
l.push_back("apple".to_string());
l.push_back("banana".to_string());
assert_eq!(linknodebystring(&l, "cherry"), None);
}
#[test]
fn linknodebystring_case_sensitive() {
let mut l: LinkList<String> = LinkList::new();
l.push_back("APPLE".to_string());
assert_eq!(
linknodebystring(&l, "apple"),
None,
"case mismatch must miss"
);
assert!(linknodebystring(&l, "APPLE").is_some(), "exact case match");
}
#[test]
fn linknodebydatum_missing_returns_none_pin() {
let mut l: LinkList<i32> = LinkList::new();
for i in [1, 2, 3] {
l.push_back(i);
}
assert_eq!(linknodebydatum(&l, &99), None);
}
#[test]
fn zlinklist2array_matches_hlinklist2array() {
let mut l: LinkList<String> = LinkList::new();
for s in ["a", "b", "c", "d"] {
l.push_back(s.to_string());
}
let h = hlinklist2array(&l);
let z = zlinklist2array(&l);
assert_eq!(h, z, "h and z variants must agree");
}
#[test]
fn lookup_fns_are_deterministic() {
let mut l: LinkList<String> = LinkList::new();
for s in ["a", "b", "c"] {
l.push_back(s.to_string());
}
let a = linknodebystring(&l, "b");
for _ in 0..5 {
assert_eq!(linknodebystring(&l, "b"), a);
}
let mut ll: LinkList<i32> = LinkList::new();
for i in [1, 2, 3] {
ll.push_back(i);
}
let b = linknodebydatum(&ll, &2);
for _ in 0..5 {
assert_eq!(linknodebydatum(&ll, &2), b);
}
}
#[test]
fn getlinknode_returns_option_t_type() {
let mut l: LinkList<i32> = LinkList::new();
let _: Option<i32> = getlinknode(&mut l);
}
#[test]
fn getlinknode_empty_returns_none() {
let mut l: LinkList<i32> = LinkList::new();
assert!(getlinknode(&mut l).is_none());
}
#[test]
fn getlinknode_drains_list_to_empty() {
let mut l: LinkList<i32> = LinkList::new();
for i in 1..=5 {
l.push_back(i);
}
for _ in 0..5 {
assert!(getlinknode(&mut l).is_some());
}
assert!(getlinknode(&mut l).is_none(), "after 5 pops → None");
assert!(l.is_empty());
}
#[test]
fn freelinklist_empties_list() {
let mut l: LinkList<i32> = LinkList::new();
for i in 1..=10 {
l.push_back(i);
}
freelinklist(&mut l);
assert!(l.is_empty(), "freelinklist empties");
}
#[test]
fn countlinknodes_returns_usize_type() {
let l: LinkList<i32> = LinkList::new();
let _: usize = countlinknodes(&l);
}
#[test]
fn countlinknodes_empty_returns_zero_pin() {
let l: LinkList<i32> = LinkList::new();
assert_eq!(countlinknodes(&l), 0);
}
#[test]
fn joinlists_associative_on_length() {
let make = |xs: &[i32]| -> LinkList<i32> {
let mut l = LinkList::new();
for &x in xs {
l.push_back(x);
}
l
};
let mut a1 = make(&[1, 2]);
let mut b1 = make(&[3, 4]);
let mut c1 = make(&[5, 6]);
joinlists(&mut a1, &mut b1);
joinlists(&mut a1, &mut c1);
let mut a2 = make(&[1, 2]);
let mut b2 = make(&[3, 4]);
let mut c2 = make(&[5, 6]);
joinlists(&mut b2, &mut c2);
joinlists(&mut a2, &mut b2);
assert_eq!(
a1.len(),
a2.len(),
"joinlists associative: (a+b)+c.len = a+(b+c).len"
);
}
#[test]
fn rolllist_single_element_is_noop() {
let mut l: LinkList<i32> = LinkList::new();
l.push_back(42);
for n in [0usize, 1, 5, 100] {
rolllist(&mut l, n);
assert_eq!(l.len(), 1);
}
}
#[test]
fn newsizedlist_i32_fills_with_default_zero() {
for n in [1usize, 3, 10] {
let l: LinkList<i32> = newsizedlist(n);
assert_eq!(l.len(), n);
for v in l.iter() {
assert_eq!(*v, 0, "i32 default = 0");
}
}
}
#[test]
fn joinlists_single_elem_second_appends() {
let mut a: LinkList<i32> = LinkList::new();
a.push_back(1);
a.push_back(2);
let mut b: LinkList<i32> = LinkList::new();
b.push_back(3);
joinlists(&mut a, &mut b);
assert_eq!(a.len(), 3);
assert!(b.is_empty(), "second emptied after join");
}
#[test]
fn newlinklist_returns_linklist_string_type() {
let _: LinkList<String> = newlinklist();
}
#[test]
fn newlinklist_starts_empty() {
let l = newlinklist();
assert!(l.is_empty(), "new list must be empty");
assert_eq!(l.len(), 0, "new list len = 0");
}
#[test]
fn znewlinklist_starts_empty() {
let l = znewlinklist();
assert!(l.is_empty(), "znewlinklist must start empty");
}
#[test]
fn countlinknodes_returns_usize_pin_alt() {
let l: LinkList<i32> = LinkList::new();
let _: usize = countlinknodes(&l);
}
#[test]
fn countlinknodes_empty_returns_zero_alt() {
let l: LinkList<i32> = LinkList::new();
assert_eq!(countlinknodes(&l), 0);
}
#[test]
fn countlinknodes_matches_list_len() {
for n in [0usize, 1, 3, 10, 100] {
let mut l: LinkList<i32> = LinkList::new();
for i in 0..n {
l.push_back(i as i32);
}
assert_eq!(
countlinknodes(&l),
l.len(),
"countlinknodes must equal list.len() for n={}",
n
);
}
}
#[test]
fn joinlists_empty_into_nonempty_unchanged() {
let mut a: LinkList<i32> = LinkList::new();
a.push_back(1);
a.push_back(2);
let mut b: LinkList<i32> = LinkList::new();
let before_len = a.len();
joinlists(&mut a, &mut b);
assert_eq!(a.len(), before_len, "empty append leaves a unchanged");
}
#[test]
fn joinlists_both_empty_no_op() {
let mut a: LinkList<i32> = LinkList::new();
let mut b: LinkList<i32> = LinkList::new();
joinlists(&mut a, &mut b);
assert!(a.is_empty() && b.is_empty(), "both still empty");
}
#[test]
fn linknodebydatum_missing_returns_none() {
let mut l: LinkList<i32> = LinkList::new();
l.push_back(1);
l.push_back(2);
assert!(linknodebydatum(&l, &999).is_none(), "missing datum → None");
}
#[test]
fn linknodebystring_empty_needle_is_deterministic() {
let mut l: LinkList<String> = LinkList::new();
l.push_back("foo".to_string());
let a = linknodebystring(&l, "");
let b = linknodebystring(&l, "");
assert_eq!(
a.is_some(),
b.is_some(),
"linknodebystring('') must be deterministic"
);
}
#[test]
fn hlinklist2array_returns_vec_string_type() {
let l: LinkList<String> = LinkList::new();
let _: Vec<String> = hlinklist2array(&l);
}
#[test]
fn hlinklist2array_empty_returns_empty_vec() {
let l: LinkList<String> = LinkList::new();
assert!(hlinklist2array(&l).is_empty());
}
#[test]
fn zlinklist2array_length_preserved() {
let mut l: LinkList<String> = LinkList::new();
for i in 0..7 {
l.push_back(format!("item_{}", i));
}
let arr = zlinklist2array(&l);
assert_eq!(arr.len(), 7, "array length = list length");
}
}