1use std::collections::VecDeque;
23
24pub fn newlinklist() -> LinkList<String> {
31 LinkList::new()
33}
34
35impl<T> Default for LinkList<T> {
36 fn default() -> Self {
37 Self::new()
38 }
39}
40
41impl<T> LinkList<T> {
42 pub fn new() -> Self {
46 LinkList {
48 nodes: VecDeque::new(),
49 flags: 0,
50 }
51 }
52
53 pub fn is_empty(&self) -> bool {
56 self.nodes.is_empty()
58 }
59
60 pub fn len(&self) -> usize {
63 self.nodes.len()
65 }
66
67 pub fn push_front(&mut self, data: T) {
69 self.nodes.push_front(data);
71 }
72
73 pub fn push_back(&mut self, data: T) {
76 self.nodes.push_back(data);
78 }
79
80 pub fn pop_front(&mut self) -> Option<T> {
82 self.nodes.pop_front()
84 }
85
86 pub fn pop_back(&mut self) -> Option<T> {
88 self.nodes.pop_back()
90 }
91
92 pub fn front(&self) -> Option<&T> {
95 self.nodes.front()
96 }
97 pub fn front_mut(&mut self) -> Option<&mut T> {
99 self.nodes.front_mut()
100 }
101
102 pub fn back(&self) -> Option<&T> {
105 self.nodes.back()
106 }
107 pub fn back_mut(&mut self) -> Option<&mut T> {
109 self.nodes.back_mut()
110 }
111 pub fn iter(&self) -> std::collections::vec_deque::Iter<'_, T> {
113 self.nodes.iter()
114 }
115 pub fn iter_mut(&mut self) -> std::collections::vec_deque::IterMut<'_, T> {
117 self.nodes.iter_mut()
118 }
119
120 pub fn append(&mut self, other: &mut LinkList<T>) {
123 self.nodes.append(&mut other.nodes);
125 }
126
127 pub fn clear(&mut self) {
130 self.nodes.clear();
132 }
133 pub fn to_vec(self) -> Vec<T>
135 where
136 T: Clone,
137 {
138 self.nodes.into_iter().collect()
139 }
140
141 pub fn firstnode(&self) -> Option<usize> {
147 if self.nodes.is_empty() {
149 None
150 } else {
151 Some(0)
152 }
153 }
154
155 pub fn lastnode(&self) -> Option<usize> {
157 if self.nodes.is_empty() {
159 None
160 } else {
161 Some(self.nodes.len() - 1)
162 }
163 }
164
165 pub fn nextnode(&self, idx: usize) -> Option<usize> {
167 if idx + 1 < self.nodes.len() {
169 Some(idx + 1)
170 } else {
171 None
172 }
173 }
174
175 pub fn prevnode(&self, idx: usize) -> Option<usize> {
177 if idx > 0 && idx <= self.nodes.len() {
179 Some(idx - 1)
180 } else {
181 None
182 }
183 }
184
185 pub fn getdata(&self, idx: usize) -> Option<&T> {
187 self.nodes.get(idx)
189 }
190
191 pub fn setdata(&mut self, idx: usize, data: T) {
193 if let Some(slot) = self.nodes.get_mut(idx) {
195 *slot = data;
196 }
197 }
198
199 pub fn empty(&self) -> bool {
201 self.nodes.is_empty()
203 }
204
205 pub fn insertlinknode(&mut self, after_idx: usize, data: T) -> usize {
211 let new_idx = after_idx + 1;
213 if new_idx >= self.nodes.len() {
214 self.nodes.push_back(data);
215 self.nodes.len() - 1
216 } else {
217 self.nodes.insert(new_idx, data);
218 new_idx
219 }
220 }
221
222 pub fn delete_node(&mut self, idx: usize) -> Option<T> {
224 self.nodes.remove(idx)
226 }
227
228 pub fn insert_at(&mut self, idx: usize, data: T) {
230 if idx >= self.nodes.len() {
231 self.nodes.push_back(data);
232 } else {
233 self.nodes.insert(idx, data);
234 }
235 }
236}
237
238impl<T: Clone> Clone for LinkList<T> {
239 fn clone(&self) -> Self {
240 LinkList {
241 nodes: self.nodes.clone(),
242 flags: self.flags,
243 }
244 }
245}
246
247impl<T: std::fmt::Debug> std::fmt::Debug for LinkList<T> {
248 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
249 f.debug_struct("LinkList")
250 .field("nodes", &self.nodes)
251 .field("flags", &self.flags)
252 .finish()
253 }
254}
255
256impl<T> FromIterator<T> for LinkList<T> {
257 fn from_iter<I: IntoIterator<Item = T>>(iter: I) -> Self {
258 let mut list = LinkList::new();
259 for item in iter {
260 list.push_back(item);
261 }
262 list
263 }
264}
265
266impl<T> IntoIterator for LinkList<T> {
267 type Item = T;
268 type IntoIter = std::collections::vec_deque::IntoIter<T>;
269
270 fn into_iter(self) -> Self::IntoIter {
271 self.nodes.into_iter()
272 }
273}
274
275impl<'a, T> IntoIterator for &'a LinkList<T> {
276 type Item = &'a T;
277 type IntoIter = std::collections::vec_deque::Iter<'a, T>;
278
279 fn into_iter(self) -> Self::IntoIter {
280 self.nodes.iter()
281 }
282}
283
284pub fn znewlinklist() -> LinkList<String> {
286 LinkList::new()
288}
289
290pub fn insertlinknode<T>(list: &mut LinkList<T>, node: usize, dat: T) -> usize {
293 list.insertlinknode(node, dat)
295}
296
297pub fn zinsertlinknode<T>(list: &mut LinkList<T>, node: usize, dat: T) -> usize {
299 list.insertlinknode(node, dat)
300}
301
302pub fn uinsertlinknode(list: &mut LinkList<String>, node: usize, new: String) -> Option<usize> {
304 if list.iter().any(|s| s == &new) {
305 None
306 } else {
307 Some(list.insertlinknode(node, new))
308 }
309}
310
311pub fn insertlinklist<T: Clone>(
322 l: &LinkList<T>,
324 where_idx: usize,
325 x: &mut LinkList<T>,
326) {
327 if l.is_empty() {
328 return;
330 }
331 let mut idx = where_idx;
332 for v in l.iter() {
333 idx = x.insertlinknode(idx, v.clone());
335 }
336}
337
338pub fn getlinknode<T>(list: &mut LinkList<T>) -> Option<T> {
341 list.pop_front()
343}
344
345pub fn ugetnode<T>(list: &mut LinkList<T>) -> Option<T> {
348 list.pop_front()
350}
351
352pub fn remnode<T>(list: &mut LinkList<T>, nd: usize) -> Option<T> {
355 list.delete_node(nd)
357}
358
359pub fn uremnode<T>(list: &mut LinkList<T>, nd: usize) -> Option<T> {
361 list.delete_node(nd)
363}
364
365pub fn freelinklist<T>(list: &mut LinkList<T>) {
369 list.clear();
371}
372
373pub fn countlinknodes<T>(list: &LinkList<T>) -> usize {
376 list.len()
378}
379
380pub fn rolllist<T>(l: &mut LinkList<T>, nd: usize) {
383 let len = l.len();
385 if len > 0 {
386 let nd = nd % len;
387 for _ in 0..nd {
388 if let Some(v) = l.pop_front() {
389 l.push_back(v);
390 }
391 }
392 }
393}
394
395pub fn newsizedlist<T: Default>(size: usize) -> LinkList<T> {
407 let mut list = LinkList::new();
409 for _ in 0..size {
410 list.push_back(T::default());
412 }
413 list
414}
415
416pub fn joinlists<T>(first: &mut LinkList<T>, second: &mut LinkList<T>) {
418 first.append(second);
420}
421
422pub fn linknodebydatum<T: PartialEq>(list: &LinkList<T>, dat: &T) -> Option<usize> {
424 list.iter().position(|v| v == dat)
426}
427
428pub fn linknodebystring(list: &LinkList<String>, dat: &str) -> Option<usize> {
430 list.iter().position(|v| v == dat)
432}
433
434pub fn hlinklist2array(list: &LinkList<String>) -> Vec<String> {
437 list.iter().cloned().collect()
439}
440
441pub fn zlinklist2array(list: &LinkList<String>) -> Vec<String> {
444 list.iter().cloned().collect()
446}
447
448pub struct LinkList<T> {
451 pub nodes: VecDeque<T>, pub flags: u32, }
454
455#[cfg(test)]
456mod tests {
457 use super::*;
458
459 #[test]
460 fn test_new_list() {
461 let _g = crate::test_util::global_state_lock();
462 let list: LinkList<i32> = LinkList::new();
463 assert!(list.is_empty());
464 assert_eq!(list.len(), 0);
465 assert_eq!(list.flags, 0);
466 }
467
468 #[test]
473 fn newsizedlist_preallocates_n_slots() {
474 let _g = crate::test_util::global_state_lock();
475 let list: LinkList<i32> = newsizedlist(5);
476 assert_eq!(
477 list.len(),
478 5,
479 "c:339-341 — newsizedlist(5) must pre-allocate 5 nodes"
480 );
481 for v in list.iter() {
483 assert_eq!(*v, 0, "pre-allocated slots default to 0");
484 }
485
486 let zero_list: LinkList<String> = newsizedlist(0);
487 assert_eq!(zero_list.len(), 0, "newsizedlist(0) is the same as new()");
488 }
489
490 #[test]
491 fn test_push_front_back() {
492 let _g = crate::test_util::global_state_lock();
493 let mut list = LinkList::new();
494 list.push_back(1);
495 list.push_back(2);
496 list.push_front(0);
497 assert_eq!(list.front(), Some(&0));
498 assert_eq!(list.back(), Some(&2));
499 assert_eq!(list.len(), 3);
500 }
501
502 #[test]
503 fn test_pop_front_back() {
504 let _g = crate::test_util::global_state_lock();
505 let mut list = LinkList::new();
506 list.push_back(1);
507 list.push_back(2);
508 list.push_back(3);
509 assert_eq!(list.pop_front(), Some(1));
510 assert_eq!(list.pop_back(), Some(3));
511 assert_eq!(list.pop_front(), Some(2));
512 assert_eq!(list.pop_front(), None);
513 }
514
515 #[test]
516 fn test_iter() {
517 let _g = crate::test_util::global_state_lock();
518 let mut list = LinkList::new();
519 list.push_back(1);
520 list.push_back(2);
521 list.push_back(3);
522 let v: Vec<_> = list.iter().copied().collect();
523 assert_eq!(v, vec![1, 2, 3]);
524 }
525
526 #[test]
527 fn test_macro_methods() {
528 let _g = crate::test_util::global_state_lock();
529 let mut list: LinkList<String> = LinkList::new();
530 list.push_back("a".to_string());
531 list.push_back("b".to_string());
532 list.push_back("c".to_string());
533
534 assert_eq!(list.firstnode(), Some(0));
535 assert_eq!(list.lastnode(), Some(2));
536 assert_eq!(list.nextnode(0), Some(1));
537 assert_eq!(list.nextnode(2), None);
538 assert_eq!(list.getdata(1).map(String::as_str), Some("b"));
539 list.setdata(1, "B".to_string());
540 assert_eq!(list.getdata(1).map(String::as_str), Some("B"));
541 let new_idx = list.insertlinknode(1, "X".to_string());
542 assert_eq!(new_idx, 2);
543 assert_eq!(list.getdata(2).map(String::as_str), Some("X"));
544 assert_eq!(list.delete_node(2).as_deref(), Some("X"));
545 assert_eq!(list.getdata(2).map(String::as_str), Some("c"));
546 }
547
548 #[test]
549 fn test_append() {
550 let _g = crate::test_util::global_state_lock();
551 let mut a: LinkList<i32> = vec![1, 2].into_iter().collect();
552 let mut b: LinkList<i32> = vec![3, 4].into_iter().collect();
553 a.append(&mut b);
554 assert!(b.is_empty());
555 assert_eq!(a.to_vec(), vec![1, 2, 3, 4]);
556 }
557
558 #[test]
559 fn test_clear() {
560 let _g = crate::test_util::global_state_lock();
561 let mut list: LinkList<i32> = vec![1, 2, 3].into_iter().collect();
562 list.clear();
563 assert!(list.is_empty());
564 }
565
566 #[test]
567 fn test_uinsertlinknode_dedups() {
568 let _g = crate::test_util::global_state_lock();
569 let mut list: LinkList<String> = LinkList::new();
570 list.push_back("a".to_string());
571 assert!(uinsertlinknode(&mut list, 0, "b".to_string()).is_some());
572 assert!(uinsertlinknode(&mut list, 0, "a".to_string()).is_none());
573 assert_eq!(list.len(), 2);
574 }
575
576 #[test]
580 fn joinlists_drains_second_into_first() {
581 let _g = crate::test_util::global_state_lock();
582 let mut a: LinkList<i32> = vec![1, 2].into_iter().collect();
583 let mut b: LinkList<i32> = vec![3, 4, 5].into_iter().collect();
584 joinlists(&mut a, &mut b);
585 assert_eq!(a.to_vec(), vec![1, 2, 3, 4, 5]);
586 assert!(b.is_empty(), "second list must be drained after join");
587 }
588
589 #[test]
592 fn joinlists_empty_second_is_noop() {
593 let _g = crate::test_util::global_state_lock();
594 let mut a: LinkList<i32> = vec![1, 2].into_iter().collect();
595 let mut b: LinkList<i32> = LinkList::new();
596 joinlists(&mut a, &mut b);
597 assert_eq!(a.to_vec(), vec![1, 2]);
598 assert!(b.is_empty());
599 }
600
601 #[test]
605 fn joinlists_empty_first_receives_all_of_second() {
606 let _g = crate::test_util::global_state_lock();
607 let mut a: LinkList<i32> = LinkList::new();
608 let mut b: LinkList<i32> = vec![1, 2, 3].into_iter().collect();
609 joinlists(&mut a, &mut b);
610 assert_eq!(a.to_vec(), vec![1, 2, 3]);
611 assert!(b.is_empty());
612 }
613
614 #[test]
617 fn linknodebydatum_finds_first_match() {
618 let _g = crate::test_util::global_state_lock();
619 let list: LinkList<i32> = vec![10, 20, 30, 20].into_iter().collect();
620 assert_eq!(
621 linknodebydatum(&list, &20),
622 Some(1),
623 "must return FIRST match index"
624 );
625 assert_eq!(linknodebydatum(&list, &99), None);
626 }
627
628 #[test]
631 fn linknodebystring_finds_first_match() {
632 let _g = crate::test_util::global_state_lock();
633 let list: LinkList<String> = vec!["a".into(), "b".into(), "a".into()]
634 .into_iter()
635 .collect();
636 assert_eq!(linknodebystring(&list, "a"), Some(0));
637 assert_eq!(linknodebystring(&list, "b"), Some(1));
638 assert_eq!(linknodebystring(&list, "x"), None);
639 }
640
641 #[test]
644 fn hlinklist2array_preserves_order() {
645 let _g = crate::test_util::global_state_lock();
646 let list: LinkList<String> = vec!["a".into(), "b".into(), "c".into()]
647 .into_iter()
648 .collect();
649 let arr = hlinklist2array(&list);
650 assert_eq!(arr, vec!["a".to_string(), "b".to_string(), "c".to_string()]);
651 }
652
653 #[test]
656 fn countlinknodes_returns_len_for_arbitrary_lists() {
657 let _g = crate::test_util::global_state_lock();
658 let empty: LinkList<i32> = LinkList::new();
659 assert_eq!(
660 countlinknodes(&empty),
661 0,
662 "c:309 — empty list traversal yields 0"
663 );
664 let one: LinkList<i32> = vec![42].into_iter().collect();
665 assert_eq!(countlinknodes(&one), 1);
666 let many: LinkList<i32> = (0..100).collect();
667 assert_eq!(countlinknodes(&many), 100);
668 }
669
670 #[test]
675 fn rolllist_rotates_to_index() {
676 let _g = crate::test_util::global_state_lock();
677 let mut list: LinkList<i32> = vec![10, 20, 30, 40].into_iter().collect();
679 rolllist(&mut list, 2);
680 assert_eq!(
681 list.to_vec(),
682 vec![30, 40, 10, 20],
683 "c:321 — `list.first = nd` then preceding nodes append at end"
684 );
685 }
686
687 #[test]
690 fn rolllist_zero_index_is_identity() {
691 let _g = crate::test_util::global_state_lock();
692 let mut list: LinkList<i32> = vec![1, 2, 3].into_iter().collect();
693 rolllist(&mut list, 0);
694 assert_eq!(list.to_vec(), vec![1, 2, 3]);
695 }
696
697 #[test]
701 fn rolllist_wraps_index_modulo_length() {
702 let _g = crate::test_util::global_state_lock();
703 let mut list: LinkList<i32> = vec![1, 2, 3].into_iter().collect();
704 rolllist(&mut list, 4);
706 assert_eq!(list.to_vec(), vec![2, 3, 1]);
707 }
708
709 #[test]
718 fn insertlinklist_splices_source_into_dest_after_position() {
719 let _g = crate::test_util::global_state_lock();
720 let source: LinkList<i32> = vec![100, 200, 300].into_iter().collect();
723 let mut dest: LinkList<i32> = vec![10, 20, 30].into_iter().collect();
724 insertlinklist(&source, 0, &mut dest);
725 assert_eq!(
726 dest.to_vec(),
727 vec![10, 100, 200, 300, 20, 30],
728 "c:194-202 — source spliced into dest after node 0"
729 );
730 assert_eq!(
731 source.to_vec(),
732 vec![100, 200, 300],
733 "c:188-206 — source list is NOT modified (read-only)"
734 );
735 }
736
737 #[test]
741 fn insertlinklist_empty_source_is_noop() {
742 let _g = crate::test_util::global_state_lock();
743 let source: LinkList<i32> = LinkList::new();
744 let mut dest: LinkList<i32> = vec![1, 2, 3].into_iter().collect();
745 insertlinklist(&source, 1, &mut dest);
746 assert_eq!(
747 dest.to_vec(),
748 vec![1, 2, 3],
749 "c:193-194 — empty l returns early; dest unchanged"
750 );
751 }
752
753 #[test]
759 fn insertlinklist_lastnode_append_pattern() {
760 let _g = crate::test_util::global_state_lock();
761 let source: LinkList<&str> = vec!["x", "y"].into_iter().collect();
762 let mut dest: LinkList<&str> = vec!["a", "b", "c"].into_iter().collect();
763 let last = dest.len() - 1;
764 insertlinklist(&source, last, &mut dest);
765 assert_eq!(
766 dest.to_vec(),
767 vec!["a", "b", "c", "x", "y"],
768 "c:188-206 zutil.c:1324 — lastnode anchor → tail-append"
769 );
770 }
771
772 #[test]
779 fn linklist_pop_on_empty_returns_none() {
780 let _g = crate::test_util::global_state_lock();
781 let mut list: LinkList<i32> = LinkList::new();
782 assert_eq!(list.pop_front(), None);
783 assert_eq!(list.pop_back(), None);
784 }
785
786 #[test]
788 fn linklist_front_back_on_empty_return_none() {
789 let _g = crate::test_util::global_state_lock();
790 let list: LinkList<i32> = LinkList::new();
791 assert!(list.front().is_none());
792 assert!(list.back().is_none());
793 }
794
795 #[test]
797 fn countlinknodes_empty_returns_zero() {
798 let _g = crate::test_util::global_state_lock();
799 let list: LinkList<i32> = LinkList::new();
800 assert_eq!(countlinknodes(&list), 0);
801 }
802
803 #[test]
805 fn countlinknodes_matches_len_for_populated_list() {
806 let _g = crate::test_util::global_state_lock();
807 let mut list = LinkList::new();
808 for i in 0..7 {
809 list.push_back(i);
810 }
811 assert_eq!(countlinknodes(&list), 7);
812 assert_eq!(countlinknodes(&list), list.len());
813 }
814
815 #[test]
817 fn joinlists_appends_second_to_first_and_empties_second() {
818 let _g = crate::test_util::global_state_lock();
819 let mut first: LinkList<i32> = LinkList::new();
820 first.push_back(1);
821 first.push_back(2);
822 let mut second: LinkList<i32> = LinkList::new();
823 second.push_back(3);
824 second.push_back(4);
825
826 joinlists(&mut first, &mut second);
827
828 assert_eq!(first.len(), 4, "first must absorb second's elements");
829 assert!(second.is_empty(), "second must be emptied after joinlists");
830 }
831
832 #[test]
834 fn joinlists_with_empty_second_leaves_first_unchanged() {
835 let _g = crate::test_util::global_state_lock();
836 let mut first: LinkList<i32> = LinkList::new();
837 first.push_back(1);
838 first.push_back(2);
839 let len_before = first.len();
840 let mut second: LinkList<i32> = LinkList::new();
841
842 joinlists(&mut first, &mut second);
843 assert_eq!(first.len(), len_before);
844 }
845
846 #[test]
849 fn linknodebydatum_finds_existing_element() {
850 let _g = crate::test_util::global_state_lock();
851 let mut list = LinkList::new();
852 list.push_back(10);
853 list.push_back(20);
854 list.push_back(30);
855 assert!(linknodebydatum(&list, &20).is_some());
856 assert!(linknodebydatum(&list, &99).is_none());
857 }
858
859 #[test]
861 fn linknodebystring_finds_existing_string() {
862 let _g = crate::test_util::global_state_lock();
863 let mut list: LinkList<String> = LinkList::new();
864 list.push_back("alpha".into());
865 list.push_back("beta".into());
866 list.push_back("gamma".into());
867 assert!(linknodebystring(&list, "beta").is_some());
868 assert!(linknodebystring(&list, "delta").is_none());
869 }
870
871 #[test]
873 fn hlinklist2array_preserves_insertion_order() {
874 let _g = crate::test_util::global_state_lock();
875 let mut list: LinkList<String> = LinkList::new();
876 list.push_back("x".into());
877 list.push_back("y".into());
878 list.push_back("z".into());
879 assert_eq!(
880 hlinklist2array(&list),
881 vec!["x".to_string(), "y".into(), "z".into()]
882 );
883 }
884
885 #[test]
887 fn hlinklist2array_on_empty_returns_empty_vec() {
888 let _g = crate::test_util::global_state_lock();
889 let list: LinkList<String> = LinkList::new();
890 let v = hlinklist2array(&list);
891 assert!(v.is_empty());
892 }
893
894 #[test]
896 fn freelinklist_empties_the_list() {
897 let _g = crate::test_util::global_state_lock();
898 let mut list = LinkList::new();
899 for i in 0..5 {
900 list.push_back(i);
901 }
902 assert_eq!(list.len(), 5);
903 freelinklist(&mut list);
904 assert!(list.is_empty());
905 }
906
907 #[test]
909 fn getlinknode_pops_head_returning_value() {
910 let _g = crate::test_util::global_state_lock();
911 let mut list = LinkList::new();
912 list.push_back(1);
913 list.push_back(2);
914 list.push_back(3);
915 assert_eq!(getlinknode(&mut list), Some(1));
916 assert_eq!(list.len(), 2, "head removed → len down by 1");
917 assert_eq!(getlinknode(&mut list), Some(2));
918 assert_eq!(getlinknode(&mut list), Some(3));
919 assert_eq!(getlinknode(&mut list), None, "empty → None");
920 }
921
922 #[test]
926 fn linklist_corpus_new_is_empty() {
927 let l = newlinklist();
928 assert_eq!(countlinknodes(&l), 0);
929 assert!(l.is_empty());
930 }
931
932 #[test]
934 fn linklist_corpus_count_after_many_pushes() {
935 let mut l = LinkList::<i32>::new();
936 for i in 0..50 {
937 l.push_back(i);
938 }
939 assert_eq!(countlinknodes(&l), 50);
940 assert_eq!(l.len(), 50);
941 }
942
943 #[test]
945 fn linklist_corpus_joinlists_concatenates() {
946 let mut a = LinkList::<i32>::new();
947 let mut b = LinkList::<i32>::new();
948 a.push_back(1);
949 a.push_back(2);
950 b.push_back(3);
951 b.push_back(4);
952 joinlists(&mut a, &mut b);
953 assert_eq!(a.len(), 4, "first holds union");
954 assert!(b.is_empty(), "second emptied");
955 }
956
957 #[test]
959 fn linklist_corpus_getlinknode_empty_returns_none() {
960 let mut l = LinkList::<i32>::new();
961 assert_eq!(getlinknode(&mut l), None);
962 }
963
964 #[test]
966 fn linklist_corpus_getlinknode_drains_in_fifo_order() {
967 let mut l = LinkList::<&'static str>::new();
968 l.push_back("a");
969 l.push_back("b");
970 l.push_back("c");
971 assert_eq!(getlinknode(&mut l), Some("a"));
972 assert_eq!(getlinknode(&mut l), Some("b"));
973 assert_eq!(getlinknode(&mut l), Some("c"));
974 assert_eq!(getlinknode(&mut l), None);
975 assert!(l.is_empty());
976 }
977
978 #[test]
980 fn linklist_corpus_linknodebydatum_finds_value() {
981 let mut l = LinkList::<i32>::new();
982 l.push_back(10);
983 l.push_back(20);
984 l.push_back(30);
985 assert_eq!(linknodebydatum(&l, &20), Some(1));
986 assert_eq!(linknodebydatum(&l, &99), None);
987 }
988
989 #[test]
995 fn newlinklist_returns_empty_pin() {
996 let l = newlinklist();
997 assert!(l.is_empty());
998 assert_eq!(l.len(), 0);
999 }
1000
1001 #[test]
1003 fn znewlinklist_returns_empty_pin() {
1004 let l = znewlinklist();
1005 assert!(l.is_empty());
1006 }
1007
1008 #[test]
1010 fn countlinknodes_empty_is_zero_pin() {
1011 let l = LinkList::<i32>::new();
1012 assert_eq!(countlinknodes(&l), 0);
1013 }
1014
1015 #[test]
1017 fn countlinknodes_matches_length_pin() {
1018 let mut l = LinkList::<i32>::new();
1019 l.push_back(1);
1020 l.push_back(2);
1021 l.push_back(3);
1022 assert_eq!(countlinknodes(&l), 3);
1023 }
1024
1025 #[test]
1027 fn getlinknode_empty_returns_none_pin() {
1028 let mut l = LinkList::<i32>::new();
1029 assert!(getlinknode(&mut l).is_none());
1030 }
1031
1032 #[test]
1034 fn ugetnode_empty_returns_none_pin() {
1035 let mut l = LinkList::<i32>::new();
1036 assert!(ugetnode(&mut l).is_none());
1037 }
1038
1039 #[test]
1041 fn freelinklist_clears_list_pin() {
1042 let mut l = LinkList::<i32>::new();
1043 l.push_back(1);
1044 l.push_back(2);
1045 freelinklist(&mut l);
1046 assert!(l.is_empty());
1047 }
1048
1049 #[test]
1051 fn linknodebystring_finds_string_pin() {
1052 let mut l = LinkList::<String>::new();
1053 l.push_back("alpha".to_string());
1054 l.push_back("beta".to_string());
1055 l.push_back("gamma".to_string());
1056 assert_eq!(linknodebystring(&l, "beta"), Some(1));
1057 assert_eq!(linknodebystring(&l, "delta"), None);
1058 }
1059
1060 #[test]
1062 fn linknodebystring_first_match_pin() {
1063 let mut l = LinkList::<String>::new();
1064 l.push_back("x".to_string());
1065 l.push_back("x".to_string());
1066 assert_eq!(linknodebystring(&l, "x"), Some(0));
1067 }
1068
1069 #[test]
1071 fn hlinklist2array_preserves_order_pin() {
1072 let mut l = LinkList::<String>::new();
1073 l.push_back("a".to_string());
1074 l.push_back("b".to_string());
1075 l.push_back("c".to_string());
1076 let v = hlinklist2array(&l);
1077 assert_eq!(v, vec!["a", "b", "c"]);
1078 }
1079
1080 #[test]
1082 fn hlinklist2array_empty_returns_empty_vec_pin() {
1083 let l = LinkList::<String>::new();
1084 let v = hlinklist2array(&l);
1085 assert!(v.is_empty());
1086 }
1087
1088 #[test]
1090 fn newsizedlist_zero_returns_empty_pin() {
1091 let l: LinkList<i32> = newsizedlist(0);
1092 assert!(l.is_empty());
1093 }
1094
1095 #[test]
1103 fn uinsertlinknode_dup_returns_none() {
1104 let mut l: LinkList<String> = LinkList::new();
1105 l.push_back("a".to_string());
1106 l.push_back("b".to_string());
1107 let r = uinsertlinknode(&mut l, 0, "a".to_string());
1108 assert_eq!(r, None, "dup must return None");
1109 assert_eq!(l.len(), 2, "list size unchanged");
1110 }
1111
1112 #[test]
1114 fn uinsertlinknode_new_returns_some() {
1115 let mut l: LinkList<String> = LinkList::new();
1116 l.push_back("a".to_string());
1117 let r = uinsertlinknode(&mut l, 0, "b".to_string());
1118 assert!(r.is_some(), "new value must return Some");
1119 assert_eq!(l.len(), 2, "list size incremented");
1120 }
1121
1122 #[test]
1124 fn rolllist_empty_no_panic() {
1125 let mut l: LinkList<i32> = LinkList::new();
1126 rolllist(&mut l, 5);
1127 assert!(l.is_empty());
1128 }
1129
1130 #[test]
1132 fn rolllist_full_length_is_identity() {
1133 let mut l: LinkList<i32> = LinkList::new();
1134 for i in 1..=5 {
1135 l.push_back(i);
1136 }
1137 let before: Vec<i32> = l.iter().copied().collect();
1138 rolllist(&mut l, 5); let after: Vec<i32> = l.iter().copied().collect();
1140 assert_eq!(before, after, "full rotation is identity");
1141 }
1142
1143 #[test]
1145 fn newsizedlist_n_returns_n_default_nodes() {
1146 for n in [1usize, 3, 10, 100] {
1147 let l: LinkList<i32> = newsizedlist(n);
1148 assert_eq!(l.len(), n, "newsizedlist({}) must return {} nodes", n, n);
1149 for v in l.iter() {
1150 assert_eq!(*v, 0, "default i32 = 0");
1151 }
1152 }
1153 }
1154
1155 #[test]
1157 fn linknodebystring_missing_returns_none_pin() {
1158 let mut l: LinkList<String> = LinkList::new();
1159 l.push_back("apple".to_string());
1160 l.push_back("banana".to_string());
1161 assert_eq!(linknodebystring(&l, "cherry"), None);
1162 }
1163
1164 #[test]
1166 fn linknodebystring_case_sensitive() {
1167 let mut l: LinkList<String> = LinkList::new();
1168 l.push_back("APPLE".to_string());
1169 assert_eq!(
1170 linknodebystring(&l, "apple"),
1171 None,
1172 "case mismatch must miss"
1173 );
1174 assert!(linknodebystring(&l, "APPLE").is_some(), "exact case match");
1175 }
1176
1177 #[test]
1179 fn linknodebydatum_missing_returns_none_pin() {
1180 let mut l: LinkList<i32> = LinkList::new();
1181 for i in [1, 2, 3] {
1182 l.push_back(i);
1183 }
1184 assert_eq!(linknodebydatum(&l, &99), None);
1185 }
1186
1187 #[test]
1190 fn zlinklist2array_matches_hlinklist2array() {
1191 let mut l: LinkList<String> = LinkList::new();
1192 for s in ["a", "b", "c", "d"] {
1193 l.push_back(s.to_string());
1194 }
1195 let h = hlinklist2array(&l);
1196 let z = zlinklist2array(&l);
1197 assert_eq!(h, z, "h and z variants must agree");
1198 }
1199
1200 #[test]
1202 fn lookup_fns_are_deterministic() {
1203 let mut l: LinkList<String> = LinkList::new();
1204 for s in ["a", "b", "c"] {
1205 l.push_back(s.to_string());
1206 }
1207 let a = linknodebystring(&l, "b");
1208 for _ in 0..5 {
1209 assert_eq!(linknodebystring(&l, "b"), a);
1210 }
1211 let mut ll: LinkList<i32> = LinkList::new();
1212 for i in [1, 2, 3] {
1213 ll.push_back(i);
1214 }
1215 let b = linknodebydatum(&ll, &2);
1216 for _ in 0..5 {
1217 assert_eq!(linknodebydatum(&ll, &2), b);
1218 }
1219 }
1220
1221 #[test]
1230 fn getlinknode_returns_option_t_type() {
1231 let mut l: LinkList<i32> = LinkList::new();
1232 let _: Option<i32> = getlinknode(&mut l);
1233 }
1234
1235 #[test]
1237 fn getlinknode_empty_returns_none() {
1238 let mut l: LinkList<i32> = LinkList::new();
1239 assert!(getlinknode(&mut l).is_none());
1240 }
1241
1242 #[test]
1244 fn getlinknode_drains_list_to_empty() {
1245 let mut l: LinkList<i32> = LinkList::new();
1246 for i in 1..=5 {
1247 l.push_back(i);
1248 }
1249 for _ in 0..5 {
1250 assert!(getlinknode(&mut l).is_some());
1251 }
1252 assert!(getlinknode(&mut l).is_none(), "after 5 pops → None");
1253 assert!(l.is_empty());
1254 }
1255
1256 #[test]
1258 fn freelinklist_empties_list() {
1259 let mut l: LinkList<i32> = LinkList::new();
1260 for i in 1..=10 {
1261 l.push_back(i);
1262 }
1263 freelinklist(&mut l);
1264 assert!(l.is_empty(), "freelinklist empties");
1265 }
1266
1267 #[test]
1269 fn countlinknodes_returns_usize_type() {
1270 let l: LinkList<i32> = LinkList::new();
1271 let _: usize = countlinknodes(&l);
1272 }
1273
1274 #[test]
1276 fn countlinknodes_empty_returns_zero_pin() {
1277 let l: LinkList<i32> = LinkList::new();
1278 assert_eq!(countlinknodes(&l), 0);
1279 }
1280
1281 #[test]
1283 fn joinlists_associative_on_length() {
1284 let make = |xs: &[i32]| -> LinkList<i32> {
1285 let mut l = LinkList::new();
1286 for &x in xs {
1287 l.push_back(x);
1288 }
1289 l
1290 };
1291 let mut a1 = make(&[1, 2]);
1293 let mut b1 = make(&[3, 4]);
1294 let mut c1 = make(&[5, 6]);
1295 joinlists(&mut a1, &mut b1);
1296 joinlists(&mut a1, &mut c1);
1297
1298 let mut a2 = make(&[1, 2]);
1300 let mut b2 = make(&[3, 4]);
1301 let mut c2 = make(&[5, 6]);
1302 joinlists(&mut b2, &mut c2);
1303 joinlists(&mut a2, &mut b2);
1304
1305 assert_eq!(
1306 a1.len(),
1307 a2.len(),
1308 "joinlists associative: (a+b)+c.len = a+(b+c).len"
1309 );
1310 }
1311
1312 #[test]
1314 fn rolllist_single_element_is_noop() {
1315 let mut l: LinkList<i32> = LinkList::new();
1316 l.push_back(42);
1317 for n in [0usize, 1, 5, 100] {
1318 rolllist(&mut l, n);
1319 assert_eq!(l.len(), 1);
1320 }
1321 }
1322
1323 #[test]
1325 fn newsizedlist_i32_fills_with_default_zero() {
1326 for n in [1usize, 3, 10] {
1327 let l: LinkList<i32> = newsizedlist(n);
1328 assert_eq!(l.len(), n);
1329 for v in l.iter() {
1330 assert_eq!(*v, 0, "i32 default = 0");
1331 }
1332 }
1333 }
1334
1335 #[test]
1337 fn joinlists_single_elem_second_appends() {
1338 let mut a: LinkList<i32> = LinkList::new();
1339 a.push_back(1);
1340 a.push_back(2);
1341 let mut b: LinkList<i32> = LinkList::new();
1342 b.push_back(3);
1343 joinlists(&mut a, &mut b);
1344 assert_eq!(a.len(), 3);
1345 assert!(b.is_empty(), "second emptied after join");
1346 }
1347
1348 #[test]
1357 fn newlinklist_returns_linklist_string_type() {
1358 let _: LinkList<String> = newlinklist();
1359 }
1360
1361 #[test]
1363 fn newlinklist_starts_empty() {
1364 let l = newlinklist();
1365 assert!(l.is_empty(), "new list must be empty");
1366 assert_eq!(l.len(), 0, "new list len = 0");
1367 }
1368
1369 #[test]
1371 fn znewlinklist_starts_empty() {
1372 let l = znewlinklist();
1373 assert!(l.is_empty(), "znewlinklist must start empty");
1374 }
1375
1376 #[test]
1378 fn countlinknodes_returns_usize_pin_alt() {
1379 let l: LinkList<i32> = LinkList::new();
1380 let _: usize = countlinknodes(&l);
1381 }
1382
1383 #[test]
1385 fn countlinknodes_empty_returns_zero_alt() {
1386 let l: LinkList<i32> = LinkList::new();
1387 assert_eq!(countlinknodes(&l), 0);
1388 }
1389
1390 #[test]
1392 fn countlinknodes_matches_list_len() {
1393 for n in [0usize, 1, 3, 10, 100] {
1394 let mut l: LinkList<i32> = LinkList::new();
1395 for i in 0..n {
1396 l.push_back(i as i32);
1397 }
1398 assert_eq!(
1399 countlinknodes(&l),
1400 l.len(),
1401 "countlinknodes must equal list.len() for n={}",
1402 n
1403 );
1404 }
1405 }
1406
1407 #[test]
1409 fn joinlists_empty_into_nonempty_unchanged() {
1410 let mut a: LinkList<i32> = LinkList::new();
1411 a.push_back(1);
1412 a.push_back(2);
1413 let mut b: LinkList<i32> = LinkList::new();
1414 let before_len = a.len();
1415 joinlists(&mut a, &mut b);
1416 assert_eq!(a.len(), before_len, "empty append leaves a unchanged");
1417 }
1418
1419 #[test]
1421 fn joinlists_both_empty_no_op() {
1422 let mut a: LinkList<i32> = LinkList::new();
1423 let mut b: LinkList<i32> = LinkList::new();
1424 joinlists(&mut a, &mut b);
1425 assert!(a.is_empty() && b.is_empty(), "both still empty");
1426 }
1427
1428 #[test]
1430 fn linknodebydatum_missing_returns_none() {
1431 let mut l: LinkList<i32> = LinkList::new();
1432 l.push_back(1);
1433 l.push_back(2);
1434 assert!(linknodebydatum(&l, &999).is_none(), "missing datum → None");
1435 }
1436
1437 #[test]
1439 fn linknodebystring_empty_needle_is_deterministic() {
1440 let mut l: LinkList<String> = LinkList::new();
1441 l.push_back("foo".to_string());
1442 let a = linknodebystring(&l, "");
1443 let b = linknodebystring(&l, "");
1444 assert_eq!(
1445 a.is_some(),
1446 b.is_some(),
1447 "linknodebystring('') must be deterministic"
1448 );
1449 }
1450
1451 #[test]
1453 fn hlinklist2array_returns_vec_string_type() {
1454 let l: LinkList<String> = LinkList::new();
1455 let _: Vec<String> = hlinklist2array(&l);
1456 }
1457
1458 #[test]
1460 fn hlinklist2array_empty_returns_empty_vec() {
1461 let l: LinkList<String> = LinkList::new();
1462 assert!(hlinklist2array(&l).is_empty());
1463 }
1464
1465 #[test]
1467 fn zlinklist2array_length_preserved() {
1468 let mut l: LinkList<String> = LinkList::new();
1469 for i in 0..7 {
1470 l.push_back(format!("item_{}", i));
1471 }
1472 let arr = zlinklist2array(&l);
1473 assert_eq!(arr.len(), 7, "array length = list length");
1474 }
1475}