Skip to main content

embed_dlist/
lib.rs

1#![allow(rustdoc::redundant_explicit_links)]
2#![cfg_attr(docsrs, feature(doc_cfg))]
3#![cfg_attr(docsrs, allow(unused_attributes))]
4#![cfg_attr(not(feature = "std"), no_std)]
5
6//! An intrusive doubly linked list implementation.
7//!
8//! This module provides `DLinkedList`, a doubly linked list where elements
9//! embed the list nodes themselves. This design offers memory efficiency
10//! and explicit control over allocation, suitable for scenarios like
11//! building LRU caches directly within data structures.
12//!
13//! # Features
14//! - O(1) push and pop from both front and back.
15//! - Generic over pointer types (`Box`, `Arc`, `NonNull`, raw pointers).
16//! - Supports multiple lists for the same item via `Tag`.
17//!
18//! # Example
19//!
20//! ```rust
21//! use embed_dlist::{DLinkedList, DListItem, DListNode};
22//! use core::cell::UnsafeCell;
23//! use std::sync::Arc;
24//! use core::ptr::NonNull;
25//!
26//! struct MyItem {
27//!     id: u32,
28//!     data: String,
29//!     node: UnsafeCell<DListNode<MyItem, ()>>,
30//! }
31//!
32//! impl MyItem {
33//!     fn new(id: u32, data: &str) -> Self {
34//!         MyItem {
35//!             id,
36//!             data: data.to_string(),
37//!             node: UnsafeCell::new(DListNode::default()),
38//!         }
39//!     }
40//! }
41//!
42//! unsafe impl DListItem<()> for MyItem {
43//!     fn get_node(&self) -> &mut DListNode<Self, ()> {
44//!         unsafe { &mut *self.node.get() }
45//!     }
46//! }
47//!
48//! // Using Box<T> (owned pointers)
49//! {
50//!     let mut list = DLinkedList::<Box<MyItem>, ()>::new();
51//!     list.push_back(Box::new(MyItem::new(1, "First")));
52//!     list.push_front(Box::new(MyItem::new(2, "Second")));
53//!     list.push_back(Box::new(MyItem::new(3, "Third")));
54//!     assert_eq!(list.len(), 3);
55//!     assert_eq!(list.pop_front().unwrap().id, 2);
56//!     assert_eq!(list.pop_back().unwrap().id, 3);
57//!     assert_eq!(list.pop_front().unwrap().id, 1);
58//!     assert!(list.is_empty());
59//! }
60//!
61//! // Using Arc<T> (shared ownership)
62//! {
63//!     let mut list = DLinkedList::<Arc<MyItem>, ()>::new();
64//!     list.push_back(Arc::new(MyItem::new(1, "First")));
65//!     list.push_front(Arc::new(MyItem::new(2, "Second")));
66//!     list.push_back(Arc::new(MyItem::new(3, "Third")));
67//!     assert_eq!(list.len(), 3);
68//!     assert_eq!(list.pop_front().unwrap().id, 2);
69//!     assert_eq!(list.pop_back().unwrap().id, 3);
70//!     assert_eq!(list.pop_front().unwrap().id, 1);
71//!     assert!(list.is_empty());
72//! }
73//!
74//! // Using NonNull<T> (raw pointers without ownership)
75//! {
76//!     let mut list = DLinkedList::<NonNull<MyItem>, ()>::new();
77//!     let item1 = Box::leak(Box::new(MyItem::new(1, "First")));
78//!     let item2 = Box::leak(Box::new(MyItem::new(2, "Second")));
79//!     let item3 = Box::leak(Box::new(MyItem::new(3, "Third")));
80//!     list.push_back(NonNull::from(item1));
81//!     list.push_front(NonNull::from(item2));
82//!     list.push_back(NonNull::from(item3));
83//!     assert_eq!(list.len(), 3);
84//!     assert_eq!(unsafe { list.pop_front().unwrap().as_ref().id }, 2);
85//!     assert_eq!(unsafe { list.pop_back().unwrap().as_ref().id }, 3);
86//!     assert_eq!(unsafe { list.pop_front().unwrap().as_ref().id }, 1);
87//!     assert!(list.is_empty());
88//! }
89//! ```
90
91extern crate alloc;
92#[cfg(any(feature = "std", test))]
93extern crate std;
94
95use core::marker::PhantomData;
96use core::{
97    fmt, mem,
98    ptr::{self, null},
99};
100use pointers::Pointer;
101
102/// A trait to return internal mutable DListNode for specified list.
103///
104/// The tag is used to distinguish different DListNodes within the same item,
105/// allowing an item to belong to multiple lists simultaneously.
106/// For only one ownership, you can use `()`.
107///
108/// # Safety
109///
110/// Implementors must ensure `get_node` returns a valid reference to the `DListNode`
111/// embedded within `Self`. Users must use `UnsafeCell` to hold `DListNode` to support
112/// interior mutability required by list operations.
113pub unsafe trait DListItem<Tag>: Sized {
114    fn get_node(&self) -> &mut DListNode<Self, Tag>;
115}
116
117/// The node structure that must be embedded in items to be stored in a `DLinkedList`.
118#[repr(C)]
119pub struct DListNode<T: Sized, Tag> {
120    prev: *const T,
121    next: *const T,
122    _phan: PhantomData<fn(&Tag)>,
123}
124
125unsafe impl<T, Tag> Send for DListNode<T, Tag> {}
126
127impl<T: DListItem<Tag>, Tag> DListNode<T, Tag> {
128    #[inline]
129    fn get_prev<'a>(&self) -> Option<&'a mut DListNode<T, Tag>> {
130        if self.prev.is_null() { None } else { unsafe { Some((*self.prev).get_node()) } }
131    }
132
133    #[inline]
134    fn get_next<'a>(&self) -> Option<&'a mut DListNode<T, Tag>> {
135        if self.next.is_null() { None } else { unsafe { Some((*self.next).get_node()) } }
136    }
137}
138
139impl<T, Tag> Default for DListNode<T, Tag> {
140    #[inline(always)]
141    fn default() -> Self {
142        Self { prev: null(), next: null(), _phan: Default::default() }
143    }
144}
145
146impl<T: DListItem<Tag> + fmt::Debug, Tag> fmt::Debug for DListNode<T, Tag> {
147    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
148        write!(f, "(")?;
149        if !self.prev.is_null() {
150            write!(f, "prev: {:p} ", self.prev)?;
151        } else {
152            write!(f, "prev: none ")?;
153        }
154        if !self.next.is_null() {
155            write!(f, "next: {:p} ", self.next)?;
156        } else {
157            write!(f, "next: none ")?;
158        }
159        write!(f, ")")
160    }
161}
162
163/// An intrusive doubly linked list.
164///
165/// Supports O(1) insertion and removal at both ends.
166#[repr(C)]
167pub struct DLinkedList<P, Tag>
168where
169    P: Pointer,
170    P::Target: DListItem<Tag>,
171{
172    length: usize,
173    head: *const P::Target,
174    tail: *const P::Target,
175    _phan: PhantomData<fn(&Tag)>,
176}
177
178unsafe impl<P, Tag> Send for DLinkedList<P, Tag>
179where
180    P: Pointer,
181    P::Target: DListItem<Tag>,
182{
183}
184
185impl<P: fmt::Debug, Tag> fmt::Debug for DLinkedList<P, Tag>
186where
187    P: Pointer,
188    P::Target: DListItem<Tag>,
189{
190    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
191        write!(f, "{{ length: {} ", self.length)?;
192        if !self.head.is_null() {
193            write!(f, "head: {:?} ", self.head)?;
194        } else {
195            write!(f, "head: none ")?;
196        }
197        if !self.tail.is_null() {
198            write!(f, "tail: {:?} ", self.tail)?;
199        } else {
200            write!(f, "tail: none ")?;
201        }
202        write!(f, "}}")
203    }
204}
205
206impl<P, Tag> DLinkedList<P, Tag>
207where
208    P: Pointer,
209    P::Target: DListItem<Tag>,
210{
211    /// Creates a new, empty doubly linked list.
212    #[inline(always)]
213    pub fn new() -> Self {
214        DLinkedList { length: 0, head: null(), tail: null(), _phan: Default::default() }
215    }
216
217    /// Clears the list, dropping all of its elements if the pointer type `P` owns them.
218    #[inline]
219    pub fn clear(&mut self) {
220        // By repeatedly popping from the front, we drop each element.
221        // If P is an owned pointer (like Box), the element is dropped.
222        // If P is a raw pointer, it's a no-op, but the list is still emptied.
223        while self.pop_front().is_some() {}
224    }
225
226    /// Returns the length of the list as `usize`.
227    #[inline(always)]
228    pub fn len(&self) -> usize {
229        self.length
230    }
231
232    /// Returns `true` if the list contains no elements.
233    #[inline(always)]
234    pub fn is_empty(&self) -> bool {
235        self.length == 0
236    }
237
238    /// Remove a node from the middle of the list
239    ///
240    /// NOTE: Due to we need to support Arc, item should be immutable reference.
241    ///
242    /// # Safety
243    ///
244    /// The item must be already in the list, otherwise will lead to UB.
245    #[inline(always)]
246    pub unsafe fn remove_node(&mut self, item: &P::Target) {
247        let node = item.get_node();
248        if let Some(prev) = node.get_prev() {
249            prev.next = node.next;
250        } else {
251            self.head = node.next;
252        }
253        if let Some(next) = node.get_next() {
254            next.prev = node.prev;
255        } else {
256            self.tail = node.prev;
257        }
258        node.next = null();
259        node.prev = null();
260        self.length -= 1;
261    }
262
263    /// Moves a node to the front of the list (e.g., for LRU updates).
264    ///
265    /// NOTE: Due to we need to support Arc, item should be immutable reference.
266    ///
267    /// # Safety
268    ///
269    /// The item must be in the list, otherwise will lead to UB.
270    #[inline(always)]
271    pub unsafe fn peak(&mut self, item: &P::Target) {
272        assert!(!self.head.is_null());
273        if !self.head.is_null() {
274            let head_node = unsafe { (*self.head).get_node() } as *const DListNode<P::Target, Tag>;
275            if ptr::eq(head_node, item.get_node()) {
276                return;
277            }
278        }
279        unsafe { self.remove_node(item) };
280        self.push_front_ptr(item as *const P::Target);
281    }
282
283    /// Pushes an element to the front of the list.
284    #[inline]
285    pub fn push_front(&mut self, item: P) {
286        let ptr = item.into_raw();
287        self.push_front_ptr(ptr);
288    }
289
290    #[inline]
291    fn push_front_ptr(&mut self, ptr: *const P::Target) {
292        let node = unsafe { (*ptr).get_node() };
293        let head = self.head;
294        node.next = head;
295        node.prev = null();
296
297        if head.is_null() {
298            self.tail = ptr;
299        } else {
300            unsafe {
301                (*head).get_node().prev = ptr;
302            }
303        }
304        self.head = ptr;
305        self.length += 1;
306    }
307
308    /// Pushes an element to the back of the list.
309    #[inline]
310    pub fn push_back(&mut self, item: P) {
311        let node = item.as_ref().get_node();
312        let tail = self.tail;
313        node.prev = tail;
314        node.next = null();
315
316        let ptr = item.into_raw();
317        if tail.is_null() {
318            self.head = ptr;
319        } else {
320            unsafe {
321                (*tail).get_node().next = ptr;
322            }
323        }
324        self.tail = ptr;
325        self.length += 1;
326    }
327
328    /// Removes and returns the element at the front of the list.
329    pub fn pop_front(&mut self) -> Option<P> {
330        if self.head.is_null() {
331            None
332        } else {
333            let head_ptr = self.head;
334            unsafe {
335                let item = &(*head_ptr);
336                self.remove_node(item);
337                Some(P::from_raw(head_ptr))
338            }
339        }
340    }
341
342    /// Removes and returns the element at the back of the list.
343    #[inline]
344    pub fn pop_back(&mut self) -> Option<P> {
345        if self.tail.is_null() {
346            None
347        } else {
348            let tail_ptr = self.tail;
349            unsafe {
350                let item = &(*tail_ptr);
351                self.remove_node(item);
352                Some(P::from_raw(tail_ptr))
353            }
354        }
355    }
356
357    /// Returns a reference to the front element.
358    #[inline]
359    pub fn get_front(&self) -> Option<&P::Target> {
360        if self.head.is_null() { None } else { unsafe { Some(&(*self.head)) } }
361    }
362
363    /// Returns a reference to the back element.
364    #[inline]
365    pub fn get_back(&self) -> Option<&P::Target> {
366        if self.tail.is_null() { None } else { unsafe { Some(&(*self.tail)) } }
367    }
368
369    /// Checks if the given node is the head of the list.
370    #[inline(always)]
371    pub fn is_front(&self, node: &P::Target) -> bool {
372        if self.head.is_null() {
373            false
374        } else {
375            // This comparison is tricky because self.head is *mut HrcWrapper<T>
376            // and node is &mut DListNode<T>.
377            // We need to compare the node address or the wrapper address.
378            // Converting head -> node and comparing addresses of DListNode is safer.
379            ptr::eq(self.head, node)
380        }
381    }
382
383    #[cfg(feature = "std")]
384    pub fn print<U: std::fmt::Debug>(&self) {
385        println!("print list begin! length={}", self.length);
386        let mut ptr = self.head;
387        while !ptr.is_null() {
388            unsafe {
389                // Assuming T can be cast to U for printing, or T implements Debug.
390                // The original code had print<T>, here print<U>.
391                // We'll just print the address for now if T is not Debug?
392                // Or assume T is Debug.
393                // println!("node={:?}", item); // Requires T: Debug
394                ptr = (*ptr).get_node().next;
395            }
396        }
397        println!("print list end:");
398    }
399
400    /// Returns an iterator over the list (borrowed).
401    ///
402    /// # NOTE
403    ///
404    /// If you plan on turn the raw pointer to owned, use drain instead
405    ///
406    /// # Safety
407    ///
408    /// The caller must ensure that the list is not modified in a way that can
409    /// invalidate internal pointers (such as removing elements or dropping
410    /// items) for the duration of the iterator's use.
411    #[inline(always)]
412    pub fn iter<'a>(&'a self) -> DLinkedListIterator<'a, P, Tag> {
413        DLinkedListIterator { list: self, cur: null() }
414    }
415
416    /// Returns a draining iterator that removes items from the list.
417    /// Crucial for cleaning up lists containing owned pointers (like `Box`).
418    ///
419    /// # Note
420    ///
421    /// The iterator removes elements from the **front** of the list (FIFO order),
422    #[inline(always)]
423    pub fn drain<'a>(&'a mut self) -> DLinkedListDrainer<'a, P, Tag> {
424        DLinkedListDrainer { list: self }
425    }
426}
427
428impl<P, Tag> Drop for DLinkedList<P, Tag>
429where
430    P: Pointer,
431    P::Target: DListItem<Tag>,
432{
433    fn drop(&mut self) {
434        // Calling drain will remove all elements from the list and drop them.
435        // The DLinkedListDrainer iterator returns P, which will be dropped
436        // when the iterator is consumed.
437        if mem::needs_drop::<P>() {
438            self.drain().for_each(drop);
439        }
440    }
441}
442
443pub struct DLinkedListIterator<'a, P, Tag>
444where
445    P: Pointer,
446    P::Target: DListItem<Tag>,
447{
448    list: &'a DLinkedList<P, Tag>,
449    cur: *const P::Target,
450}
451
452unsafe impl<'a, P, Tag> Send for DLinkedListIterator<'a, P, Tag>
453where
454    P: Pointer,
455    P::Target: DListItem<Tag>,
456{
457}
458
459impl<'a, P, Tag> Iterator for DLinkedListIterator<'a, P, Tag>
460where
461    P: Pointer,
462    P::Target: DListItem<Tag>,
463{
464    type Item = &'a P::Target;
465
466    fn next(&mut self) -> Option<Self::Item> {
467        if self.cur.is_null() {
468            if self.list.head.is_null() {
469                return None;
470            } else {
471                self.cur = self.list.head;
472            }
473        } else {
474            let next = unsafe { (*self.cur).get_node().next };
475            if next.is_null() {
476                return None;
477            } else {
478                self.cur = next;
479            }
480        }
481        unsafe { Some(&(*self.cur)) }
482    }
483}
484
485pub struct DLinkedListDrainer<'a, P, Tag>
486where
487    P: Pointer,
488    P::Target: DListItem<Tag>,
489{
490    list: &'a mut DLinkedList<P, Tag>,
491}
492
493unsafe impl<'a, P, Tag> Send for DLinkedListDrainer<'a, P, Tag>
494where
495    P: Pointer,
496    P::Target: DListItem<Tag>,
497{
498}
499
500impl<'a, P, Tag> Iterator for DLinkedListDrainer<'a, P, Tag>
501where
502    P: Pointer,
503    P::Target: DListItem<Tag>,
504{
505    type Item = P;
506
507    #[inline]
508    fn next(&mut self) -> Option<P> {
509        self.list.pop_front()
510    }
511}
512
513#[cfg(test)]
514mod tests {
515    use super::*;
516    use std::boxed::Box;
517    use std::cell::UnsafeCell;
518    use std::println;
519    use std::ptr::NonNull;
520    use std::sync::Arc;
521    use std::sync::atomic::{AtomicUsize, Ordering};
522
523    pub struct TestTag;
524
525    #[derive(Debug)]
526    pub struct TestNode {
527        pub value: i64,
528        pub node: UnsafeCell<DListNode<Self, TestTag>>,
529    }
530
531    static ACTIVE_NODE_COUNT: AtomicUsize = AtomicUsize::new(0);
532
533    impl Drop for TestNode {
534        fn drop(&mut self) {
535            ACTIVE_NODE_COUNT.fetch_sub(1, Ordering::SeqCst);
536        }
537    }
538
539    unsafe impl Send for TestNode {}
540
541    unsafe impl DListItem<TestTag> for TestNode {
542        fn get_node(&self) -> &mut DListNode<Self, TestTag> {
543            unsafe { &mut *self.node.get() }
544        }
545    }
546
547    fn new_node(v: i64) -> TestNode {
548        ACTIVE_NODE_COUNT.fetch_add(1, Ordering::SeqCst);
549        TestNode { value: v, node: UnsafeCell::new(DListNode::default()) }
550    }
551
552    #[test]
553    fn test_push_back_box() {
554        let mut l = DLinkedList::<Box<TestNode>, TestTag>::new();
555
556        let node1 = Box::new(new_node(1));
557        l.push_back(node1);
558
559        let node2 = Box::new(new_node(2));
560        l.push_back(node2);
561
562        let node3 = Box::new(new_node(3));
563        l.push_back(node3);
564
565        assert_eq!(3, l.len());
566
567        let mut iter = l.iter();
568        assert_eq!(iter.next().unwrap().value, 1);
569        assert_eq!(iter.next().unwrap().value, 2);
570        assert_eq!(iter.next().unwrap().value, 3);
571        assert!(iter.next().is_none());
572
573        {
574            let mut drain = l.drain();
575            assert_eq!(drain.next().unwrap().value, 1);
576            assert_eq!(drain.next().unwrap().value, 2);
577            assert_eq!(drain.next().unwrap().value, 3);
578            assert!(drain.next().is_none());
579        }
580        assert_eq!(l.len(), 0);
581    }
582
583    #[test]
584    fn test_push_back_arc() {
585        let mut l = DLinkedList::<Arc<TestNode>, TestTag>::new();
586
587        let node1 = Arc::new(new_node(1));
588        l.push_back(node1);
589
590        let node2 = Arc::new(new_node(2));
591        l.push_back(node2);
592
593        let node3 = Arc::new(new_node(3));
594        l.push_back(node3);
595
596        assert_eq!(3, l.len());
597
598        let mut iter = l.iter();
599        assert_eq!(iter.next().unwrap().value, 1);
600        assert_eq!(iter.next().unwrap().value, 2);
601        assert_eq!(iter.next().unwrap().value, 3);
602        assert!(iter.next().is_none());
603
604        {
605            let mut drain = l.drain();
606            assert_eq!(drain.next().unwrap().value, 1);
607            assert_eq!(drain.next().unwrap().value, 2);
608            assert_eq!(drain.next().unwrap().value, 3);
609            assert!(drain.next().is_none());
610        }
611        assert_eq!(l.len(), 0);
612    }
613
614    #[test]
615    fn test_push_front_box() {
616        let mut l = DLinkedList::<Box<TestNode>, TestTag>::new();
617
618        let node3 = Box::new(new_node(3));
619        l.push_front(node3);
620
621        let node2 = Box::new(new_node(2));
622        l.push_front(node2);
623
624        let node1 = Box::new(new_node(1));
625        l.push_front(node1);
626
627        assert_eq!(3, l.len());
628
629        let mut iter = l.iter();
630        assert_eq!(iter.next().unwrap().value, 1);
631        assert_eq!(iter.next().unwrap().value, 2);
632        assert_eq!(iter.next().unwrap().value, 3);
633        assert!(iter.next().is_none());
634
635        {
636            let mut drain = l.drain();
637            assert_eq!(drain.next().unwrap().value, 1);
638            assert_eq!(drain.next().unwrap().value, 2);
639            assert_eq!(drain.next().unwrap().value, 3);
640            assert!(drain.next().is_none());
641        }
642        assert_eq!(l.len(), 0);
643    }
644
645    #[test]
646    fn test_push_front_arc() {
647        let mut l = DLinkedList::<Arc<TestNode>, TestTag>::new();
648
649        let node3 = Arc::new(new_node(3));
650        l.push_front(node3);
651
652        let node2 = Arc::new(new_node(2));
653        l.push_front(node2);
654
655        let node1 = Arc::new(new_node(1));
656        l.push_front(node1);
657
658        assert_eq!(3, l.len());
659
660        let mut iter = l.iter();
661        assert_eq!(iter.next().unwrap().value, 1);
662        assert_eq!(iter.next().unwrap().value, 2);
663        assert_eq!(iter.next().unwrap().value, 3);
664        assert!(iter.next().is_none());
665
666        {
667            let mut drain = l.drain();
668            assert_eq!(drain.next().unwrap().value, 1);
669            assert_eq!(drain.next().unwrap().value, 2);
670            assert_eq!(drain.next().unwrap().value, 3);
671            assert!(drain.next().is_none());
672        }
673        assert_eq!(l.len(), 0);
674    }
675
676    #[test]
677    fn test_pop_back_box() {
678        let mut l = DLinkedList::<Box<TestNode>, TestTag>::new();
679
680        let node1 = Box::new(new_node(1));
681        l.push_back(node1);
682
683        let node2 = Box::new(new_node(2));
684        l.push_back(node2);
685
686        let node3 = Box::new(new_node(3));
687        l.push_back(node3);
688
689        let mut iter = l.iter();
690        assert_eq!(iter.next().unwrap().value, 1);
691        assert_eq!(iter.next().unwrap().value, 2);
692        assert_eq!(iter.next().unwrap().value, 3);
693        assert!(iter.next().is_none());
694
695        let del_node = l.pop_back();
696        assert_eq!(2, l.len());
697        assert!(del_node.is_some());
698        assert_eq!(del_node.unwrap().value, 3);
699
700        let mut iter_remaining = l.iter();
701        assert_eq!(iter_remaining.next().unwrap().value, 1);
702        assert_eq!(iter_remaining.next().unwrap().value, 2);
703        assert!(iter_remaining.next().is_none());
704
705        {
706            let mut drain = l.drain();
707            assert_eq!(drain.next().unwrap().value, 1);
708            assert_eq!(drain.next().unwrap().value, 2);
709            assert!(drain.next().is_none());
710        }
711        assert_eq!(l.len(), 0);
712    }
713
714    #[test]
715    fn test_pop_back_arc() {
716        let mut l = DLinkedList::<Arc<TestNode>, TestTag>::new();
717
718        let node1 = Arc::new(new_node(1));
719        l.push_back(node1);
720
721        let node2 = Arc::new(new_node(2));
722        l.push_back(node2);
723
724        let node3 = Arc::new(new_node(3));
725        l.push_back(node3);
726
727        let mut iter = l.iter();
728        assert_eq!(iter.next().unwrap().value, 1);
729        assert_eq!(iter.next().unwrap().value, 2);
730        assert_eq!(iter.next().unwrap().value, 3);
731        assert!(iter.next().is_none());
732
733        let del_node = l.pop_back();
734        assert_eq!(2, l.len());
735        assert!(del_node.is_some());
736        // Note: The value returned by Arc::from_raw must still be used.
737        assert!(del_node.is_some());
738
739        // Check the order of remaining elements
740        let mut iter = l.iter();
741        assert_eq!(iter.next().unwrap().value, 1);
742        assert_eq!(iter.next().unwrap().value, 2);
743        assert!(iter.next().is_none());
744
745        {
746            let mut drain = l.drain();
747            assert_eq!(drain.next().unwrap().value, 1);
748            assert_eq!(drain.next().unwrap().value, 2);
749            assert!(drain.next().is_none());
750        }
751        assert_eq!(l.len(), 0);
752    }
753
754    #[test]
755    fn test_iter_box() {
756        let mut l = DLinkedList::<Box<TestNode>, TestTag>::new();
757
758        let mut count = 0;
759        for _item in l.iter() {
760            count += 1;
761        }
762        assert_eq!(count, 0);
763
764        let node1 = Box::new(new_node(1));
765        l.push_back(node1);
766
767        let node2 = Box::new(new_node(2));
768        l.push_back(node2);
769
770        let node3 = Box::new(new_node(3));
771        l.push_back(node3);
772
773        count = 0;
774        for item in l.iter() {
775            count += 1;
776            println!("{}", item.value);
777        }
778        assert_eq!(count, 3);
779
780        {
781            let mut drain = l.drain();
782            assert_eq!(drain.next().unwrap().value, 1);
783            assert_eq!(drain.next().unwrap().value, 2);
784            assert_eq!(drain.next().unwrap().value, 3);
785            assert!(drain.next().is_none());
786        }
787        assert_eq!(l.len(), 0);
788    }
789
790    #[test]
791    fn test_iter_arc() {
792        let mut l = DLinkedList::<Arc<TestNode>, TestTag>::new();
793
794        let mut count = 0;
795        for _item in l.iter() {
796            count += 1;
797        }
798        assert_eq!(count, 0);
799
800        let node1 = Arc::new(new_node(1));
801        l.push_back(node1);
802
803        let node2 = Arc::new(new_node(2));
804        l.push_back(node2);
805
806        let node3 = Arc::new(new_node(3));
807        l.push_back(node3);
808
809        // Check order
810        let mut iter = l.iter();
811        assert_eq!(iter.next().unwrap().value, 1);
812        assert_eq!(iter.next().unwrap().value, 2);
813        assert_eq!(iter.next().unwrap().value, 3);
814        assert!(iter.next().is_none());
815
816        {
817            let mut drain = l.drain();
818            assert_eq!(drain.next().unwrap().value, 1);
819            assert_eq!(drain.next().unwrap().value, 2);
820            assert_eq!(drain.next().unwrap().value, 3);
821            assert!(drain.next().is_none());
822        }
823        assert_eq!(l.len(), 0);
824    }
825
826    #[test]
827    fn test_single_element_box() {
828        let mut l = DLinkedList::<Box<TestNode>, TestTag>::new();
829        let node1 = Box::new(new_node(1));
830        l.push_front(node1);
831        let del_node = l.pop_back();
832        assert!(del_node.is_some());
833        assert_eq!(del_node.unwrap().value, 1);
834        assert_eq!(0, l.len());
835        assert!(l.pop_back().is_none());
836
837        let mut l2 = DLinkedList::<Box<TestNode>, TestTag>::new();
838        let node2 = Box::new(new_node(2));
839        l2.push_back(node2);
840        let del_node2 = l2.pop_back();
841        assert!(del_node2.is_some());
842        assert_eq!(del_node2.unwrap().value, 2);
843        assert_eq!(0, l2.len());
844        assert!(l2.pop_back().is_none());
845
846        {
847            let mut drain = l.drain();
848            assert!(drain.next().is_none());
849        }
850        assert_eq!(l.len(), 0);
851
852        {
853            let mut drain = l2.drain();
854            assert!(drain.next().is_none());
855        }
856        assert_eq!(l2.len(), 0);
857    }
858
859    #[test]
860    fn test_single_element_arc() {
861        let mut l = DLinkedList::<Arc<TestNode>, TestTag>::new();
862        let node1 = Arc::new(new_node(1));
863        l.push_front(node1);
864        let del_node = l.pop_back();
865        assert!(del_node.is_some());
866        assert_eq!(0, l.len());
867        assert!(l.pop_back().is_none());
868
869        let mut l2 = DLinkedList::<Arc<TestNode>, TestTag>::new();
870        let node2 = Arc::new(new_node(2));
871        l2.push_back(node2);
872        let del_node2 = l2.pop_back();
873        assert!(del_node2.is_some());
874        assert_eq!(0, l2.len());
875        assert!(l2.pop_back().is_none());
876
877        {
878            let mut drain = l.drain();
879            assert!(drain.next().is_none());
880        }
881        assert_eq!(l.len(), 0);
882
883        {
884            let mut drain = l2.drain();
885            assert!(drain.next().is_none());
886        }
887        assert_eq!(l2.len(), 0);
888    }
889
890    #[test]
891    fn test_drop_box_implementation() {
892        // Reset the counter before the test
893        ACTIVE_NODE_COUNT.store(0, Ordering::SeqCst);
894
895        {
896            let mut l = DLinkedList::<Box<TestNode>, TestTag>::new();
897
898            let node1 = Box::new(new_node(1));
899            l.push_back(node1);
900
901            let node2 = Box::new(new_node(2));
902            l.push_back(node2);
903
904            let node3 = Box::new(new_node(3));
905            l.push_back(node3);
906
907            assert_eq!(l.len(), 3);
908            assert_eq!(ACTIVE_NODE_COUNT.load(Ordering::SeqCst), 3);
909        } // `l` goes out of scope here, triggering DLinkedList's Drop, which drains and drops nodes.
910
911        // All nodes should have been dropped
912        assert_eq!(ACTIVE_NODE_COUNT.load(Ordering::SeqCst), 0);
913    }
914
915    #[test]
916    fn test_raw_pointer_list() {
917        // Reset the counter before the test
918        ACTIVE_NODE_COUNT.store(0, Ordering::SeqCst);
919
920        // Manually create nodes as raw pointers
921        let node1 = Box::into_raw(Box::new(new_node(10)));
922        let node2 = Box::into_raw(Box::new(new_node(20)));
923
924        assert_eq!(ACTIVE_NODE_COUNT.load(Ordering::SeqCst), 2);
925
926        {
927            let mut l = DLinkedList::<*const TestNode, TestTag>::new();
928            l.push_back(node1);
929            l.push_back(node2);
930
931            let mut iter = l.iter();
932            assert_eq!(iter.next().unwrap().value, 10);
933            assert_eq!(iter.next().unwrap().value, 20);
934            assert!(iter.next().is_none());
935        } // l dropped here. Because P is *const TestNode, needs_drop is false, so drain is NOT called.
936
937        // Nodes should still exist
938        assert_eq!(ACTIVE_NODE_COUNT.load(Ordering::SeqCst), 2);
939
940        unsafe {
941            // Check values
942            assert_eq!((*node1).value, 10);
943            assert_eq!((*node2).value, 20);
944
945            // Clean up
946            drop(Box::from_raw(node1));
947            drop(Box::from_raw(node2));
948        }
949        assert_eq!(ACTIVE_NODE_COUNT.load(Ordering::SeqCst), 0);
950    }
951
952    #[test]
953    fn test_non_null_list() {
954        // Reset the counter before the test
955        ACTIVE_NODE_COUNT.store(0, Ordering::SeqCst);
956
957        // Manually create nodes
958        // Box::leak returns &mut T, which helps creating NonNull
959        let node1 = Box::leak(Box::new(new_node(100)));
960        let node2 = Box::leak(Box::new(new_node(200)));
961
962        let ptr1 = NonNull::from(node1);
963        let ptr2 = NonNull::from(node2);
964
965        assert_eq!(ACTIVE_NODE_COUNT.load(Ordering::SeqCst), 2);
966
967        {
968            let mut l = DLinkedList::<NonNull<TestNode>, TestTag>::new();
969            l.push_back(ptr1);
970            l.push_back(ptr2);
971
972            let mut iter = l.iter();
973            assert_eq!(iter.next().unwrap().value, 100);
974            assert_eq!(iter.next().unwrap().value, 200);
975            assert!(iter.next().is_none());
976        } // l dropped here. NonNull doesn't need drop, so no drain.
977
978        // Nodes should still exist
979        assert_eq!(ACTIVE_NODE_COUNT.load(Ordering::SeqCst), 2);
980
981        unsafe {
982            // Clean up
983            drop(Box::from_raw(ptr1.as_ptr()));
984            drop(Box::from_raw(ptr2.as_ptr()));
985        }
986
987        assert_eq!(ACTIVE_NODE_COUNT.load(Ordering::SeqCst), 0);
988    }
989
990    #[test]
991    fn test_clear() {
992        ACTIVE_NODE_COUNT.store(0, Ordering::SeqCst);
993        let mut l = DLinkedList::<Box<TestNode>, TestTag>::new();
994
995        l.push_back(Box::new(new_node(1)));
996        l.push_back(Box::new(new_node(2)));
997        assert_eq!(l.len(), 2);
998        assert_eq!(ACTIVE_NODE_COUNT.load(Ordering::SeqCst), 2);
999
1000        l.clear();
1001
1002        assert!(l.is_empty());
1003        assert_eq!(l.len(), 0);
1004        assert!(l.get_front().is_none());
1005        assert!(l.get_back().is_none());
1006        assert_eq!(ACTIVE_NODE_COUNT.load(Ordering::SeqCst), 0);
1007
1008        // Can still push to the list
1009        l.push_back(Box::new(new_node(3)));
1010        assert_eq!(l.len(), 1);
1011        assert_eq!(ACTIVE_NODE_COUNT.load(Ordering::SeqCst), 1);
1012    }
1013}