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 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 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 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 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 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 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 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 mut list: LinkList<i32> = vec![1, 2, 3].into_iter().collect();
list.clear();
assert!(list.is_empty());
}
#[test]
fn test_uinsertlinknode_dedups() {
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 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 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 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 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 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 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 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 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 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 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 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 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 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");
}
}