Skip to main content

fbl/
doubly_linked_list.rs

1// Copyright 2026 The Fuchsia Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5use crate::ptr_traits::{ManagedPtr, PtrTraits};
6use crate::sentinel::{is_sentinel_ptr, make_sentinel};
7use crate::size_tracker::{NonTrackingSize, SizeTracker, TrackingSize};
8use crate::tag::DefaultObjectTag;
9use core::cell::UnsafeCell;
10use core::pin::Pin;
11use pin_init::{PinInit, pin_data, pin_init, pinned_drop};
12
13/// A node in a doubly linked list.
14#[repr(C)]
15pub struct DoublyLinkedListNode<T> {
16    /// The next element in the list.
17    pub next: UnsafeCell<*mut T>,
18    /// The previous element in the list.
19    pub prev: UnsafeCell<*mut T>,
20}
21
22impl<T> DoublyLinkedListNode<T> {
23    /// Creates a new, unlinked node.
24    pub const fn new() -> Self {
25        Self {
26            next: UnsafeCell::new(core::ptr::null_mut()),
27            prev: UnsafeCell::new(core::ptr::null_mut()),
28        }
29    }
30
31    /// Returns true if the node is currently in a list.
32    pub fn in_container(&self) -> bool {
33        // SAFETY: `self.next.get()` returns a valid pointer to the inner field of `self.next`
34        // which is a validly allocated UnsafeCell inside `self`.
35        !unsafe { *self.next.get() }.is_null()
36    }
37
38    fn get_next(&self) -> *mut T {
39        // SAFETY: `self.next.get()` is a valid pointer to `self.next` which is owned by `self`.
40        unsafe { *self.next.get() }
41    }
42
43    fn set_next(&self, next: *mut T) {
44        // SAFETY: `self.next.get()` is a valid, writable pointer to `self.next` owned by `self`.
45        // UnsafeCell allows interior mutability through a shared reference.
46        unsafe {
47            *self.next.get() = next;
48        }
49    }
50
51    fn get_prev(&self) -> *mut T {
52        // SAFETY: `self.prev.get()` is a valid pointer to `self.prev` which is owned by `self`.
53        unsafe { *self.prev.get() }
54    }
55
56    fn set_prev(&self, prev: *mut T) {
57        // SAFETY: `self.prev.get()` is a valid, writable pointer to `self.prev` owned by `self`.
58        // UnsafeCell allows interior mutability through a shared reference.
59        unsafe {
60            *self.prev.get() = prev;
61        }
62    }
63}
64
65impl<T> core::fmt::Debug for DoublyLinkedListNode<T> {
66    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
67        f.debug_struct("DoublyLinkedListNode").field("in_container", &self.in_container()).finish()
68    }
69}
70
71impl<T> Default for DoublyLinkedListNode<T> {
72    fn default() -> Self {
73        Self::new()
74    }
75}
76
77// Static asserts for layout verification.
78::zr::static_assert!(
79    core::mem::size_of::<DoublyLinkedListNode<()>>() == 2 * core::mem::size_of::<*mut ()>()
80);
81::zr::static_assert!(
82    core::mem::align_of::<DoublyLinkedListNode<()>>() == core::mem::align_of::<*mut ()>()
83);
84
85impl<T> Drop for DoublyLinkedListNode<T> {
86    fn drop(&mut self) {
87        debug_assert!(!self.in_container(), "Object destroyed while still in container");
88    }
89}
90
91/// Trait that types must implement to be contained in a `DoublyLinkedList`.
92pub trait DoublyLinkedListContainable<T, Tag = DefaultObjectTag> {
93    /// Returns a reference to the list node.
94    fn get_node(&self) -> &DoublyLinkedListNode<T>;
95}
96
97/// An intrusive doubly linked list container supporting custom ownership semantics, constant-time
98/// operations, and circular-like node layout.
99///
100/// ### Bookkeeping & Memory Storage
101///
102/// The bookkeeping storage (`DoublyLinkedListNode`) required to link elements exists directly
103/// on the objects themselves. This intrusive pattern eliminates the need for runtime bookkeeping
104/// allocations/deallocations when adding or removing members to/from the container.
105///
106/// The list stores pointers to the objects, not the objects themselves, and is parameterized
107/// based on the specific pointer wrapper to be stored (`P`). Supported pointer wrappers are:
108///
109/// * `*mut T`       : Raw unmanaged pointers.
110/// * `UniquePtr<T>` : Unique managed pointers.
111/// * `RefPtr<T>`    : Shared managed pointers to reference-counted objects.
112///
113/// ### Lifecycle Management
114///
115/// * **Managed Pointers (`UniquePtr`/`RefPtr`)**: The list holds ownership references of elements
116///   and follows the rules of the respective smart pointer. Clearing the list or dropping it out of
117///   scope automatically releases references, which may destruct the elements if it was their last
118///   reference.
119///
120/// * **Unmanaged Pointers (`*mut T`)**: The list performs no lifecycle management. It is up to the
121///   caller to ensure elements outlive the list and are freed correctly. As a safety check, a list
122///   of unmanaged pointers will panic/debug-assert if it is dropped with elements still inside.
123///
124/// ### Ring Layout & Sentinel
125///
126/// Nodes are arranged in a circular-like ring structure:
127///
128/// * `head` stores a sentinel value (a pointer to the container itself) when the list is empty.
129/// * For non-empty lists, the `next` pointer of the tail node points to the sentinel, and the
130///   `prev` pointer of the head node points to the tail node. This allows constant-time O(1) tail
131///   lookup and bidirectionality.
132/// * Because the sentinel points back to the container's own memory address, the `DoublyLinkedList`
133///   container **must be pinned in memory** (typically via `pin_init::stack_pin_init!`) and cannot
134///   be safely moved after initialization.
135///
136/// ### Additional Functionality over SinglyLinkedList
137///
138/// * O(1) `push_back`, `pop_back`, and `back` operations.
139/// * The ability to `insert` (before an element) in addition to `insert_after`.
140/// * The ability to `erase` (by reference or iterator) in addition to `erase_next`.
141/// * Bidirectional iteration support.
142///
143/// ### Multiple List Participation
144///
145/// Objects may exist on multiple lists simultaneously through the use of custom `Tag` classes
146/// implementing `DoublyLinkedListContainable` multiple times.
147///
148/// ---
149///
150/// ### Example: Simple list of unmanaged raw pointers
151///
152/// ```rust
153/// # use fbl::{DoublyLinkedList, DoublyLinkedListNode, stack_pin_init, pin_init::PinInit};
154/// #[derive(fbl::DoublyLinkedListContainable)]
155/// struct Foo {
156///     value: i32,
157///     #[dll_node]
158///     node: DoublyLinkedListNode<Foo>,
159/// }
160///
161/// impl Foo {
162///     fn new(value: i32) -> Self {
163///         Self { value, node: DoublyLinkedListNode::new() }
164///     }
165/// }
166///
167/// unsafe {
168///     stack_pin_init!(let mut list = DoublyLinkedList::<*mut Foo>::new());
169///     let list = list.get_unchecked_mut();
170///
171///     list.push_front(Box::into_raw(Box::new(Foo::new(1))));
172///     list.push_back(Box::into_raw(Box::new(Foo::new(2))));
173///
174///     for foo in list.iter() {
175///         println!("Value: {}", foo.value);
176///     }
177///
178///     while let Some(foo_ptr) = list.pop_front() {
179///         let _ = Box::from_raw(foo_ptr);
180///     }
181/// }
182/// ```
183///
184/// ### Example: Simple list of unique managed pointers
185///
186/// ```rust
187/// use fbl::{DoublyLinkedList, DoublyLinkedListNode, UniquePtr, stack_pin_init};
188///
189/// #[derive(fbl::DoublyLinkedListContainable, fbl::Recyclable)]
190/// struct Foo {
191///     value: i32,
192///     #[dll_node]
193///     node: DoublyLinkedListNode<Foo>,
194/// }
195///
196/// impl Foo {
197///     fn new(value: i32) -> Self {
198///         Self { value, node: DoublyLinkedListNode::new() }
199///     }
200/// }
201///
202/// stack_pin_init!(let mut list = DoublyLinkedList::<UniquePtr<Foo>>::new());
203/// let list = list.get_unchecked_mut();
204///
205/// list.push_front(UniquePtr::try_new(Foo::new(1)).unwrap());
206/// list.push_back(UniquePtr::try_new(Foo::new(2)).unwrap());
207///
208/// for foo in list.iter() {
209///     println!("Value: {}", foo.value);
210/// }
211///
212/// // Clearing the list automatically drops unique pointers and reclaims their memory!
213/// list.clear();
214/// ```
215///
216/// ### Example: Shared objects in multiple lists simultaneously using Tags
217///
218/// ```rust
219/// use fbl::{DoublyLinkedList, DoublyLinkedListNode, RefPtr, stack_pin_init};
220///
221/// struct TagA;
222/// struct TagB;
223///
224/// #[fbl::ref_counted]
225/// #[derive(fbl::DoublyLinkedListContainable)]
226/// struct Foo {
227///     value: i32,
228///     #[dll_node(TagA)]
229///     node_a: DoublyLinkedListNode<Foo>,
230///     #[dll_node(TagA)]
231///     node_b: DoublyLinkedListNode<Foo>,
232/// }
233///
234/// stack_pin_init!(let mut list_a = DoublyLinkedList::<RefPtr<Foo>, TagA>::new());
235/// stack_pin_init!(let mut list_b = DoublyLinkedList::<RefPtr<Foo>, TagB>::new());
236/// let list_a = list_a.get_unchecked_mut();
237/// let list_b = list_b.get_unchecked_mut();
238///
239/// let foo = fbl::make_ref_counted!(Foo {
240///     value: 42,
241///     node_a: DoublyLinkedListNode::new(),
242///     node_b: DoublyLinkedListNode::new(),
243/// }).unwrap();
244///
245/// list_a.push_back(foo.clone());
246/// list_b.push_back(foo);
247/// ```
248#[repr(C)]
249#[pin_data(PinnedDrop)]
250pub struct DoublyLinkedList<P, Tag = DefaultObjectTag, S = NonTrackingSize>
251where
252    P: PtrTraits,
253    P::Target: DoublyLinkedListContainable<P::Target, Tag>,
254    S: SizeTracker,
255{
256    /// Pointer to the first element of the list.
257    ///
258    /// # Link Structure
259    ///
260    /// Nodes in the list are arranged in a circular-like ring structure using a sentinel:
261    /// * For a non-empty list, the `next` pointer of each node points to the next element,
262    ///   and the `next` pointer of the **tail** node points to the **sentinel** (which is
263    ///   a pointer back to this `DoublyLinkedList` container itself).
264    /// * The `prev` pointer of each node points to the previous element.
265    ///
266    /// # Empty List Value
267    ///
268    /// When the list is empty, this `head` pointer holds the **sentinel** value (a pointer
269    /// to the container itself).
270    ///
271    /// # Tail Pointer Location
272    ///
273    /// The tail pointer of the list is located in the `prev` field of the **head** node's
274    /// list node (`head->prev`), which can be accessed or updated via `self.get_tail()` and
275    /// `self.set_tail()`.
276    head: *mut P::Target,
277
278    /// The size tracker for the list, supporting either O(N) or O(1) size operations
279    /// depending on the `S` parameter (e.g., `NonTrackingSize` or `TrackingSize`).
280    size: S,
281
282    /// Marker to ensure the list container is pinned in memory. Pinning is required
283    /// because the sentinel pointer points back to the container's own memory address,
284    /// meaning the list cannot be safely moved once initialized.
285    #[pin]
286    _pin: core::marker::PhantomPinned,
287
288    _phantom: core::marker::PhantomData<(P, Tag)>,
289}
290
291impl<P, Tag, S> DoublyLinkedList<P, Tag, S>
292where
293    P: PtrTraits,
294    P::Target: DoublyLinkedListContainable<P::Target, Tag>,
295    S: SizeTracker,
296{
297    /// Creates a new, empty list.
298    pub fn new() -> impl PinInit<Self, core::convert::Infallible> {
299        pin_init!(&this in Self {
300            head: make_sentinel(this.as_ptr()),
301            size: S::INIT,
302            _pin: core::marker::PhantomPinned,
303            _phantom: core::marker::PhantomData,
304        })
305    }
306
307    fn get_sentinel(&self) -> *mut P::Target {
308        make_sentinel(self as *const Self as *mut Self)
309    }
310
311    fn get_tail(&self) -> *mut P::Target {
312        if self.is_empty() {
313            self.get_sentinel()
314        } else {
315            // SAFETY: `self.head` is a valid, aligned pointer to an element in the list.
316            // Reading `prev` from its node returns a valid pointer (either another node or
317            // sentinel).
318            unsafe { *(*self.head).get_node().prev.get() }
319        }
320    }
321
322    /// # Safety
323    ///
324    /// The caller must ensure that the list is not empty.
325    unsafe fn set_tail(&self, tail: *mut P::Target) {
326        debug_assert!(!self.is_empty());
327        // SAFETY: `self.head` is a valid, aligned pointer to an element in the list.
328        // Writing to its `prev` node UnsafeCell is safe because we have exclusive or shared access
329        // and interior mutability is allowed.
330        unsafe {
331            *(*self.head).get_node().prev.get() = tail;
332        }
333    }
334
335    /// # Safety
336    ///
337    /// The caller must ensure that `ptr` is a valid, aligned, and dereferenceable pointer
338    /// to an initialized `P::Target` object that is alive for `'a`.
339    unsafe fn get_node_ref<'a>(&self, ptr: *mut P::Target) -> &'a DoublyLinkedListNode<P::Target> {
340        let _ = self;
341        // SAFETY: The caller guarantees `ptr` is valid, aligned, and dereferenceable.
342        unsafe { &(*ptr) }.get_node()
343    }
344
345    /// Returns true if the list is empty.
346    pub fn is_empty(&self) -> bool {
347        is_sentinel_ptr(self.head)
348    }
349
350    /// Returns a reference to the first element of the list, or `None` if it is empty.
351    pub fn front(&self) -> Option<&P::Target> {
352        if self.is_empty() { None } else { unsafe { Some(&*self.head) } }
353    }
354
355    /// Returns a reference to the last element of the list, or `None` if it is empty.
356    pub fn back(&self) -> Option<&P::Target> {
357        let tail = self.get_tail();
358        if is_sentinel_ptr(tail) { None } else { unsafe { Some(&*tail) } }
359    }
360
361    /// Pushes an element to the front of the list.
362    ///
363    /// # Panics
364    ///
365    /// Panics if the object is already in a container.
366    pub fn push_front(&mut self, ptr: P)
367    where
368        P: ManagedPtr,
369    {
370        // SAFETY: `P` is a `ManagedPtr`, which guarantees that the pointer is valid and that the
371        // object will outlive its reference from this list.
372        unsafe { self.push_front_raw(ptr) }
373    }
374
375    /// Pushes an element to the front of the list.
376    ///
377    /// # Panics
378    ///
379    /// Panics if the object is already in a container.
380    ///
381    /// # Safety
382    ///
383    /// The caller must ensure that `ptr` is a valid pointer to a `T` and that the object outlives
384    /// the reference from the list.
385    pub unsafe fn push_front_raw(&mut self, ptr: P) {
386        let head = self.head;
387        let mut cursor = CursorMut { list: self, current: head };
388        // SAFETY: `ptr` is valid and not in container (asserted inside insert_before_raw).
389        unsafe {
390            cursor.insert_before_raw(ptr);
391        }
392    }
393
394    /// Pushes an element to the back of the list.
395    ///
396    /// # Panics
397    ///
398    /// Panics if the object is already in a container.
399    pub fn push_back(&mut self, ptr: P)
400    where
401        P: ManagedPtr,
402    {
403        // SAFETY: `P` is a `ManagedPtr`, which guarantees that the pointer is valid and that the
404        // object will outlive its reference from this list.
405        unsafe { self.push_back_raw(ptr) }
406    }
407
408    /// Pushes an element to the back of the list.
409    ///
410    /// # Panics
411    ///
412    /// Panics if the object is already in a container.
413    ///
414    /// # Safety
415    ///
416    /// The caller must ensure that `ptr` is a valid pointer to an object that is not
417    /// currently in any list.
418    pub unsafe fn push_back_raw(&mut self, ptr: P) {
419        let sentinel = self.get_sentinel();
420        let mut cursor = CursorMut { list: self, current: sentinel };
421        // SAFETY: `ptr` is valid and not in container.
422        unsafe {
423            cursor.insert_before_raw(ptr);
424        }
425    }
426
427    /// Removes and returns the first element of the list, or `None` if it is empty.
428    pub fn pop_front(&mut self) -> Option<P> {
429        if self.is_empty() {
430            return None;
431        }
432        let head = self.head;
433        let mut cursor = CursorMut { list: self, current: head };
434        cursor.erase()
435    }
436
437    /// Removes and returns the last element of the list, or `None` if it is empty.
438    pub fn pop_back(&mut self) -> Option<P> {
439        if self.is_empty() {
440            return None;
441        }
442        let tail = self.get_tail();
443        let mut cursor = CursorMut { list: self, current: tail };
444        cursor.erase()
445    }
446
447    /// Removes all elements from the list.
448    pub fn clear(&mut self) {
449        while let Some(_) = self.pop_front() {}
450    }
451
452    /// Erases the given element from the list. Returns the erased element.
453    ///
454    /// # Safety
455    ///
456    /// The caller must ensure that `obj` is a valid reference to an object that is
457    /// currently in this list instance.
458    pub unsafe fn erase(&mut self, obj: &P::Target) -> Option<P> {
459        let ptr = obj as *const P::Target as *mut P::Target;
460        let node = obj.get_node();
461
462        if !node.in_container() {
463            return None;
464        }
465
466        let mut cursor = self.cursor_mut();
467        cursor.current = ptr;
468        cursor.erase()
469    }
470
471    /// Replaces the given element with `replacement`. Returns the replaced element.
472    ///
473    /// # Safety
474    ///
475    /// The caller must ensure that `obj` is a valid reference to an object that is
476    /// currently in this list instance, and `replacement` is not in any list.
477    pub unsafe fn replace_raw(&mut self, obj: &P::Target, replacement: P) -> Option<P> {
478        let ptr = obj as *const P::Target as *mut P::Target;
479        let node = obj.get_node();
480
481        if !node.in_container() {
482            return None;
483        }
484
485        let mut cursor = self.cursor_mut();
486        cursor.current = ptr;
487        // SAFETY: `replacement` is not in any list, and cursor is positioned at a valid element.
488        unsafe { cursor.replace_raw(replacement) }
489    }
490
491    /// Finds the first element matching the predicate, removes it from the list,
492    /// and returns it. Returns `None` if no element matches.
493    pub fn erase_if<F>(&mut self, mut f: F) -> Option<P>
494    where
495        F: FnMut(&P::Target) -> bool,
496    {
497        let mut cursor = self.cursor_mut();
498        while let Some(item) = cursor.get() {
499            if f(item) {
500                return cursor.erase();
501            } else {
502                cursor.move_next();
503            }
504        }
505        None
506    }
507
508    /// Finds the first element that satisfies the predicate.
509    pub fn find_if<F>(&self, mut f: F) -> Option<&P::Target>
510    where
511        F: FnMut(&P::Target) -> bool,
512    {
513        self.iter().find(|&x| f(x))
514    }
515
516    /// Returns a cursor positioned at the front of the list.
517    pub fn cursor_mut(&mut self) -> CursorMut<'_, P, Tag, S> {
518        let head = self.head;
519        CursorMut { list: self, current: head }
520    }
521
522    /// Returns a cursor positioned at the given element.
523    ///
524    /// # Safety
525    ///
526    /// The caller must ensure that `obj` is a member of this list.
527    /// It is undefined behavior to use the returned cursor if `obj` is not in the list,
528    /// or if it is in a different list.
529    pub unsafe fn cursor_at(&mut self, obj: &P::Target) -> CursorMut<'_, P, Tag, S> {
530        assert!(obj.get_node().in_container(), "Object must be in a container");
531        CursorMut { list: self, current: obj as *const P::Target as *mut P::Target }
532    }
533
534    pub fn iter(&self) -> Iterator<'_, P, Tag> {
535        Iterator::new(self)
536    }
537
538    /// Returns a unidirectional forward iterator over the elements of the list.
539    pub fn forward_iter(&self) -> ForwardIterator<'_, P, Tag> {
540        ForwardIterator::new(self.head)
541    }
542
543    /// Returns a unidirectional reverse iterator over the elements of the list.
544    pub fn reverse_iter(&self) -> ReverseIterator<'_, P, Tag> {
545        ReverseIterator::new(self.get_tail())
546    }
547}
548
549impl<P, Tag> DoublyLinkedList<P, Tag, TrackingSize>
550where
551    P: PtrTraits,
552    P::Target: DoublyLinkedListContainable<P::Target, Tag>,
553{
554    /// Returns the number of elements in the list.
555    pub fn len(&self) -> usize {
556        self.size.get()
557    }
558}
559
560#[pinned_drop]
561impl<P, Tag, S> PinnedDrop for DoublyLinkedList<P, Tag, S>
562where
563    P: PtrTraits,
564    P::Target: DoublyLinkedListContainable<P::Target, Tag>,
565    S: SizeTracker,
566{
567    fn drop(self: Pin<&mut Self>) {
568        if P::IS_MANAGED {
569            // SAFETY: We are in drop, so the object won't move anymore.
570            let me = unsafe { self.get_unchecked_mut() };
571            me.clear();
572        } else {
573            debug_assert!(self.is_empty(), "List must be empty on destruction");
574            if S::IS_TRACKING {
575                debug_assert_eq!(self.size.get(), 0, "Size must be zero on destruction");
576            }
577        }
578    }
579}
580
581/// A cursor that can be used to iterate and modify a `DoublyLinkedList`.
582pub struct CursorMut<'a, P, Tag = DefaultObjectTag, S = NonTrackingSize>
583where
584    P: PtrTraits,
585    P::Target: DoublyLinkedListContainable<P::Target, Tag>,
586    S: SizeTracker,
587{
588    list: &'a mut DoublyLinkedList<P, Tag, S>,
589    current: *mut P::Target,
590}
591
592impl<'a, P, Tag, S> CursorMut<'a, P, Tag, S>
593where
594    P: PtrTraits,
595    P::Target: DoublyLinkedListContainable<P::Target, Tag>,
596    S: SizeTracker,
597{
598    pub fn get(&self) -> Option<&P::Target> {
599        if is_sentinel_ptr(self.current) { None } else { unsafe { Some(&*self.current) } }
600    }
601
602    pub fn get_mut(&mut self) -> Option<&mut P::Target> {
603        if is_sentinel_ptr(self.current) { None } else { unsafe { Some(&mut *self.current) } }
604    }
605
606    pub fn move_next(&mut self) {
607        if !is_sentinel_ptr(self.current) {
608            // SAFETY: `self.current` is valid current node (not sentinel).
609            let node = unsafe { self.list.get_node_ref(self.current) };
610            self.current = node.get_next();
611        }
612    }
613
614    pub fn move_prev(&mut self) {
615        if !is_sentinel_ptr(self.current) {
616            // SAFETY: `self.current` is valid current node (not sentinel).
617            let node = unsafe { self.list.get_node_ref(self.current) };
618            let prev = node.get_prev();
619            if self.current == self.list.head {
620                self.current = self.list.get_sentinel(); // Move to end.
621            } else {
622                self.current = prev;
623            }
624        } else {
625            // If we are at end (sentinel), moving prev should take us to tail.
626            self.current = self.list.get_tail();
627        }
628    }
629
630    /// Inserts a new element after the current position.
631    ///
632    /// # Panics
633    ///
634    /// Panics if the object is already in a container, or if the cursor is positioned
635    /// at the end sentinel.
636    pub fn insert_after(&mut self, ptr: P)
637    where
638        P: ManagedPtr,
639    {
640        // SAFETY: `P` is a `ManagedPtr`, which guarantees that the pointer is valid and that the
641        // object will outlive its reference from this list. `self.current` is checked to not be
642        // a sentinel.
643        unsafe { self.insert_after_raw(ptr) }
644    }
645
646    /// Inserts a new element after the current position.
647    ///
648    /// # Panics
649    ///
650    /// Panics if the object is already in a container.
651    ///
652    /// # Safety
653    ///
654    /// The caller must ensure that `ptr` is a valid pointer to a `T` and that the object outlives
655    /// the reference from the list.
656    pub unsafe fn insert_after_raw(&mut self, ptr: P) {
657        assert!(!is_sentinel_ptr(self.current), "Cannot insert after end sentinel");
658        let raw = P::into_raw(ptr);
659        // SAFETY: `raw` is valid.
660        let node = unsafe { self.list.get_node_ref(raw) };
661        assert!(!node.in_container());
662
663        // SAFETY: `self.current` is valid current node (not sentinel).
664        let current_node = unsafe { self.list.get_node_ref(self.current) };
665        let next = current_node.get_next();
666
667        let current_save = self.current;
668        self.current = next;
669        // SAFETY: `raw` is a single node, and we are inserting it before `next`
670        // (which is equivalent to inserting after `current_save`).
671        unsafe {
672            self.insert_chain_before(raw, raw, 1);
673        }
674        self.current = current_save;
675    }
676
677    /// Replaces the element at the current position with `replacement`. Returns the replaced
678    /// element.
679    ///
680    /// # Panics
681    ///
682    /// Panics if the object is already in a container.
683    pub fn replace(&mut self, replacement: P) -> Option<P>
684    where
685        P: ManagedPtr,
686    {
687        // SAFETY: `P` is a `ManagedPtr`, which guarantees that the pointer is valid and that the
688        // object will outlive its reference from this list.
689        unsafe { self.replace_raw(replacement) }
690    }
691
692    /// Replaces the element at the current position with `replacement`. Returns the replaced
693    /// element.
694    ///
695    /// # Panics
696    ///
697    /// Panics if the object is already in a container.
698    ///
699    /// # Safety
700    ///
701    /// The caller must ensure that `replacement` is a valid pointer to a `T` and that the object
702    /// outlives the reference from the list.
703    pub unsafe fn replace_raw(&mut self, replacement: P) -> Option<P> {
704        if is_sentinel_ptr(self.current) {
705            return None;
706        }
707        // SAFETY: `replacement` is not in any list, and we are inserting it before a valid cursor
708        // position.
709        unsafe {
710            self.insert_before_raw(replacement);
711        }
712        self.erase()
713    }
714
715    /// Inserts a new element before the current position.
716    ///
717    /// # Panics
718    ///
719    /// Panics if the object is already in a container.
720    pub fn insert_before(&mut self, ptr: P)
721    where
722        P: ManagedPtr,
723    {
724        // SAFETY: `P` is a `ManagedPtr`, which guarantees that the pointer is valid and that the
725        // object will outlive its reference from this list.
726        unsafe { self.insert_before_raw(ptr) }
727    }
728
729    /// Inserts a new element before the current position.
730    ///
731    /// # Panics
732    ///
733    /// Panics if the object is already in a container.
734    ///
735    /// # Safety
736    ///
737    /// The caller must ensure that `ptr` is a valid pointer to a `T` and that the object outlives
738    /// the reference from the list.
739    pub unsafe fn insert_before_raw(&mut self, ptr: P) {
740        let raw = P::into_raw(ptr);
741        // SAFETY: `raw` is valid.
742        let node = unsafe { self.list.get_node_ref(raw) };
743        assert!(!node.in_container());
744
745        // SAFETY: `raw` is a single node, so it is a valid chain of 1 element.
746        unsafe {
747            self.insert_chain_before(raw, raw, 1);
748        }
749    }
750
751    /// Private helper to insert a chain of nodes before the current position.
752    ///
753    /// # Safety
754    ///
755    /// The caller must ensure:
756    /// - `chain_head` and `chain_tail` are valid pointers to elements.
757    /// - They form a valid doubly linked chain.
758    /// - The chain is not empty.
759    /// - The elements in the chain are NOT currently in any list.
760    /// - `count` is the exact number of elements in the chain.
761    unsafe fn insert_chain_before(
762        &mut self,
763        chain_head: *mut P::Target,
764        chain_tail: *mut P::Target,
765        count: usize,
766    ) {
767        // SAFETY: `chain_tail` is valid from caller.
768        let chain_tail_node = unsafe { self.list.get_node_ref(chain_tail) };
769        chain_tail_node.set_next(self.current);
770
771        if self.list.is_empty() {
772            // SAFETY: `chain_head` is valid from caller.
773            let chain_head_node = unsafe { self.list.get_node_ref(chain_head) };
774            chain_head_node.set_prev(chain_tail);
775            self.list.head = chain_head;
776        } else {
777            let prev = if self.current == self.list.head || is_sentinel_ptr(self.current) {
778                self.list.get_tail()
779            } else {
780                // SAFETY: `self.current` is valid.
781                let current_node = unsafe { self.list.get_node_ref(self.current) };
782                current_node.get_prev()
783            };
784
785            // SAFETY: `chain_head` is valid from caller.
786            let chain_head_node = unsafe { self.list.get_node_ref(chain_head) };
787            chain_head_node.set_prev(prev);
788
789            // 1. Update predecessor's next if we are not inserting at head
790            if self.current != self.list.head {
791                // SAFETY: `prev` is valid predecessor.
792                let prev_node = unsafe { self.list.get_node_ref(prev) };
793                prev_node.set_next(chain_head);
794            }
795
796            // 2. Update successor's prev if we are not inserting at sentinel
797            if !is_sentinel_ptr(self.current) {
798                // SAFETY: `self.current` is valid.
799                let current_node = unsafe { self.list.get_node_ref(self.current) };
800                current_node.set_prev(chain_tail);
801            }
802
803            // 3. Update head if we are inserting at head
804            if self.current == self.list.head {
805                self.list.head = chain_head;
806            }
807
808            // 4. Update tail if we are inserting at sentinel
809            if is_sentinel_ptr(self.current) {
810                // SAFETY: `chain_tail` becomes the new tail.
811                unsafe {
812                    self.list.set_tail(chain_tail);
813                }
814            }
815        }
816
817        if S::IS_TRACKING {
818            self.list.size.set(self.list.size.get() + count);
819        }
820    }
821
822    /// Splices the elements of `other` into the list at the current cursor position.
823    ///
824    /// All elements from `other` are moved into `self.list` and inserted immediately
825    /// *before* the element currently pointed to by the cursor.
826    ///
827    /// - If the cursor is positioned at a valid element, `other` is inserted before it.
828    /// - If the cursor is positioned at the end sentinel (i.e., `cursor.get()` returns `None`),
829    ///   `other` is appended to the end of the list (after the current tail).
830    /// - If the list is empty, `other` becomes the new content of the list.
831    ///
832    /// Upon completion, `other` is left empty.
833    ///
834    /// This operation is O(1).
835    pub fn splice(&mut self, other: &mut DoublyLinkedList<P, Tag, S>) {
836        if other.is_empty() {
837            return;
838        }
839
840        let other_head = other.head;
841        let other_tail = other.get_tail();
842        let count = if S::IS_TRACKING { other.size.get() } else { 0 };
843
844        // SAFETY: We are moving elements from `other` which is a valid list,
845        // so they are valid and not in any other list.
846        unsafe {
847            self.insert_chain_before(other_head, other_tail, count);
848        }
849
850        other.head = other.get_sentinel();
851        if S::IS_TRACKING {
852            other.size.set(0);
853        }
854    }
855
856    pub fn erase(&mut self) -> Option<P> {
857        if is_sentinel_ptr(self.current) {
858            return None;
859        }
860        let ptr = self.current;
861        // SAFETY: `ptr` is valid current node.
862        let node = unsafe { self.list.get_node_ref(ptr) };
863        let next = node.get_next();
864        let prev = node.get_prev();
865
866        self.list.size.decrement();
867
868        if self.list.head == ptr && is_sentinel_ptr(next) {
869            self.list.head = self.list.get_sentinel();
870        } else {
871            // 1. Update predecessor's next if we are not erasing head
872            if self.current != self.list.head {
873                // SAFETY: `prev` is valid predecessor.
874                let prev_node = unsafe { self.list.get_node_ref(prev) };
875                prev_node.set_next(next);
876            }
877
878            // 2. Update successor's prev if we are not erasing tail
879            if !is_sentinel_ptr(next) {
880                // SAFETY: `next` is valid successor.
881                let next_node = unsafe { self.list.get_node_ref(next) };
882                next_node.set_prev(prev);
883            }
884
885            // 3. Update head if we are erasing head
886            if self.current == self.list.head {
887                self.list.head = next;
888            }
889
890            // 4. Update tail if we are erasing tail
891            if is_sentinel_ptr(next) {
892                // SAFETY: `prev` becomes the new tail.
893                unsafe {
894                    self.list.set_tail(prev);
895                }
896            }
897        }
898
899        node.set_next(core::ptr::null_mut());
900        node.set_prev(core::ptr::null_mut());
901
902        self.current = next;
903        // SAFETY: `ptr` was popped, safe to reconstruct.
904        Some(unsafe { P::from_raw(ptr) })
905    }
906}
907
908/// An iterator over the elements of a `DoublyLinkedList`.
909pub struct Iterator<'a, P, Tag = DefaultObjectTag>
910where
911    P: PtrTraits,
912    P::Target: DoublyLinkedListContainable<P::Target, Tag>,
913{
914    front: ForwardIterator<'a, P, Tag>,
915    back: ReverseIterator<'a, P, Tag>,
916}
917
918impl<'a, P, Tag> Iterator<'a, P, Tag>
919where
920    P: PtrTraits,
921    P::Target: DoublyLinkedListContainable<P::Target, Tag>,
922{
923    fn new<S: SizeTracker>(list: &'a DoublyLinkedList<P, Tag, S>) -> Self {
924        if list.is_empty() {
925            Self {
926                front: ForwardIterator::new(crate::make_sentinel_null()),
927                back: ReverseIterator::new(crate::make_sentinel_null()),
928            }
929        } else {
930            Self {
931                front: ForwardIterator::new(list.head),
932                back: ReverseIterator::new(list.get_tail()),
933            }
934        }
935    }
936}
937
938impl<'a, P, Tag> core::iter::Iterator for Iterator<'a, P, Tag>
939where
940    P: PtrTraits,
941    P::Target: DoublyLinkedListContainable<P::Target, Tag>,
942{
943    type Item = &'a P::Target;
944
945    fn next(&mut self) -> Option<Self::Item> {
946        let met = self.front.current == self.back.current;
947        let item = self.front.next();
948        if item.is_some() {
949            if met {
950                self.front.current = crate::make_sentinel_null();
951                self.back.current = crate::make_sentinel_null();
952            }
953        }
954        item
955    }
956}
957
958impl<'a, P, Tag> core::iter::DoubleEndedIterator for Iterator<'a, P, Tag>
959where
960    P: PtrTraits,
961    P::Target: DoublyLinkedListContainable<P::Target, Tag>,
962{
963    fn next_back(&mut self) -> Option<Self::Item> {
964        let met = self.front.current == self.back.current;
965        let item = self.back.next();
966        if item.is_some() {
967            if met {
968                self.front.current = crate::make_sentinel_null();
969                self.back.current = crate::make_sentinel_null();
970            }
971        }
972        item
973    }
974}
975
976/// A unidirectional forward iterator over the elements of a `DoublyLinkedList`.
977pub struct ForwardIterator<'a, P, Tag = DefaultObjectTag>
978where
979    P: PtrTraits,
980    P::Target: DoublyLinkedListContainable<P::Target, Tag>,
981{
982    current: *mut P::Target,
983    _phantom: core::marker::PhantomData<&'a (P, Tag)>,
984}
985
986impl<'a, P, Tag> ForwardIterator<'a, P, Tag>
987where
988    P: PtrTraits,
989    P::Target: DoublyLinkedListContainable<P::Target, Tag>,
990{
991    fn new(current: *mut P::Target) -> Self {
992        Self { current, _phantom: core::marker::PhantomData }
993    }
994
995    /// Creates an iterator starting from a specific element.
996    ///
997    /// # Panics
998    ///
999    /// Panics if the object is not in a container.
1000    pub fn from_element(obj: &'a P::Target) -> Self {
1001        assert!(obj.get_node().in_container(), "Object must be in a container");
1002        Self { current: obj as *const _ as *mut _, _phantom: core::marker::PhantomData }
1003    }
1004}
1005
1006impl<'a, P, Tag> core::iter::Iterator for ForwardIterator<'a, P, Tag>
1007where
1008    P: PtrTraits,
1009    P::Target: DoublyLinkedListContainable<P::Target, Tag>,
1010{
1011    type Item = &'a P::Target;
1012
1013    fn next(&mut self) -> Option<Self::Item> {
1014        if is_sentinel_ptr(self.current) {
1015            None
1016        } else {
1017            // SAFETY: `self.current` is not a sentinel, so it is a valid, aligned pointer to an
1018            // element.  The list is guaranteed to be immutable for the lifetime `'a` of the
1019            // iterator.
1020            let current = unsafe { &*self.current };
1021            self.current = current.get_node().get_next();
1022            Some(current)
1023        }
1024    }
1025}
1026
1027/// A unidirectional reverse iterator over the elements of a `DoublyLinkedList`.
1028pub struct ReverseIterator<'a, P, Tag = DefaultObjectTag>
1029where
1030    P: PtrTraits,
1031    P::Target: DoublyLinkedListContainable<P::Target, Tag>,
1032{
1033    current: *mut P::Target,
1034    _phantom: core::marker::PhantomData<&'a (P, Tag)>,
1035}
1036
1037impl<'a, P, Tag> ReverseIterator<'a, P, Tag>
1038where
1039    P: PtrTraits,
1040    P::Target: DoublyLinkedListContainable<P::Target, Tag>,
1041{
1042    fn new(current: *mut P::Target) -> Self {
1043        Self { current, _phantom: core::marker::PhantomData }
1044    }
1045
1046    /// Creates a reverse iterator starting from a specific element.
1047    ///
1048    /// # Panics
1049    ///
1050    /// Panics if the object is not in a container.
1051    pub fn from_element(obj: &'a P::Target) -> Self {
1052        assert!(obj.get_node().in_container(), "Object must be in a container");
1053        Self { current: obj as *const _ as *mut _, _phantom: core::marker::PhantomData }
1054    }
1055}
1056
1057impl<'a, P, Tag> core::iter::Iterator for ReverseIterator<'a, P, Tag>
1058where
1059    P: PtrTraits,
1060    P::Target: DoublyLinkedListContainable<P::Target, Tag>,
1061{
1062    type Item = &'a P::Target;
1063
1064    fn next(&mut self) -> Option<Self::Item> {
1065        if is_sentinel_ptr(self.current) {
1066            None
1067        } else {
1068            // SAFETY: `self.current` is not a sentinel, so it is a valid, aligned pointer to an
1069            // element.  The list is guaranteed to be immutable for the lifetime `'a` of the
1070            // iterator.
1071            let current = unsafe { &*self.current };
1072            let prev = current.get_node().get_prev();
1073
1074            // SAFETY: `prev` must be a valid pointer because `current` is in the list.  In a
1075            // circular doubly linked list, prev is never null.
1076            let prev_node = unsafe { &*prev }.get_node();
1077            if is_sentinel_ptr(prev_node.get_next()) {
1078                // We have looped around the head and landed on the tail.
1079                // Set current to the sentinel to terminate iteration.
1080                self.current = prev_node.get_next();
1081            } else {
1082                self.current = prev;
1083            }
1084            Some(current)
1085        }
1086    }
1087}
1088
1089/// Removes an object from its container without a reference to the container.
1090///
1091/// # Safety
1092///
1093/// The caller must ensure that `obj` is currently in a valid list instance that does NOT
1094/// track its size (uses `NonTrackingSize`), and that no other mutable references to that
1095/// list are active.
1096pub unsafe fn remove_from_container<T, Tag, P>(obj: &T) -> Option<P>
1097where
1098    P: PtrTraits<Target = T>,
1099    T: DoublyLinkedListContainable<T, Tag>,
1100{
1101    let node = obj.get_node();
1102    if !node.in_container() {
1103        return None;
1104    }
1105
1106    let mut current = obj as *const T as *mut T;
1107    unsafe {
1108        while !is_sentinel_ptr(current) {
1109            current = (*current).get_node().get_next();
1110        }
1111
1112        let list_ptr = crate::sentinel::unmake_sentinel::<
1113            DoublyLinkedList<P, Tag, NonTrackingSize>,
1114            T,
1115        >(current);
1116        let list_ref = &mut *list_ptr;
1117
1118        list_ref.erase(obj)
1119    }
1120}
1121
1122impl<P, Tag, S> core::fmt::Debug for DoublyLinkedList<P, Tag, S>
1123where
1124    P: PtrTraits,
1125    P::Target: DoublyLinkedListContainable<P::Target, Tag> + core::fmt::Debug,
1126    S: SizeTracker,
1127{
1128    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
1129        f.debug_list().entries(self.iter()).finish()
1130    }
1131}
1132
1133#[cfg(test)]
1134mod tests {
1135    extern crate alloc;
1136    use super::*;
1137    use crate::intrusive_container_test_support::*;
1138    use crate::ref_ptr::RefPtr;
1139    use crate::unique_ptr::UniquePtr;
1140    use core::ffi::c_void;
1141    use pin_init::stack_pin_init;
1142
1143    #[derive(crate::DoublyLinkedListContainable, crate::Recyclable)]
1144    struct TestObject {
1145        value: i32,
1146        #[dll_node]
1147        node: DoublyLinkedListNode<TestObject>,
1148    }
1149
1150    impl TestObject {
1151        fn new(value: i32) -> Self {
1152            Self { value, node: DoublyLinkedListNode::new() }
1153        }
1154    }
1155
1156    impl TestValue for TestObject {
1157        fn new(value: i32) -> Self {
1158            Self::new(value)
1159        }
1160    }
1161
1162    ::zr::static_assert!(
1163        core::mem::size_of::<DoublyLinkedList<*mut TestObject>>()
1164            == core::mem::size_of::<*mut TestObject>()
1165    );
1166    ::zr::static_assert!(
1167        core::mem::align_of::<DoublyLinkedList<*mut TestObject>>()
1168            == core::mem::align_of::<*mut TestObject>()
1169    );
1170
1171    ::zr::static_assert!(
1172        core::mem::size_of::<DoublyLinkedList<*mut TestObject, DefaultObjectTag, TrackingSize>>()
1173            == 2 * core::mem::size_of::<*mut TestObject>()
1174    );
1175    ::zr::static_assert!(
1176        core::mem::align_of::<DoublyLinkedList<*mut TestObject, DefaultObjectTag, TrackingSize>>()
1177            == core::mem::align_of::<*mut TestObject>()
1178    );
1179
1180    ::zr::static_assert!(
1181        core::mem::size_of::<ForwardIterator<'_, *mut TestObject>>()
1182            == core::mem::size_of::<*mut TestObject>()
1183    );
1184    ::zr::static_assert!(
1185        core::mem::align_of::<ForwardIterator<'_, *mut TestObject>>()
1186            == core::mem::align_of::<*mut TestObject>()
1187    );
1188
1189    ::zr::static_assert!(
1190        core::mem::size_of::<ReverseIterator<'_, *mut TestObject>>()
1191            == core::mem::size_of::<*mut TestObject>()
1192    );
1193    ::zr::static_assert!(
1194        core::mem::align_of::<ReverseIterator<'_, *mut TestObject>>()
1195            == core::mem::align_of::<*mut TestObject>()
1196    );
1197
1198    #[derive(crate::DoublyLinkedListContainable, crate::Recyclable)]
1199    struct UniqueTestObject {
1200        value: i32,
1201        #[dll_node]
1202        node: DoublyLinkedListNode<UniqueTestObject>,
1203    }
1204
1205    impl UniqueTestObject {
1206        fn new(value: i32) -> Self {
1207            Self { value, node: DoublyLinkedListNode::new() }
1208        }
1209    }
1210
1211    impl TestValue for UniqueTestObject {
1212        fn new(value: i32) -> Self {
1213            Self::new(value)
1214        }
1215    }
1216
1217    #[fbl::ref_counted]
1218    #[derive(crate::DoublyLinkedListContainable, crate::Recyclable)]
1219    #[repr(C)]
1220    pub struct RefTestObject {
1221        value: i32,
1222        #[dll_node]
1223        node: DoublyLinkedListNode<RefTestObject>,
1224    }
1225
1226    impl TestValue for RefTestObject {
1227        fn new_ref_counted(value: i32) -> RefPtr<Self> {
1228            crate::make_ref_counted!(RefTestObject {
1229                value: value,
1230                node: DoublyLinkedListNode::new()
1231            })
1232            .unwrap()
1233        }
1234    }
1235
1236    macro_rules! generate_list_tests {
1237        ($mod_name:ident, $ptr_type:ty, $factory_type:ty, $get_val:expr, $push:expr) => {
1238            mod $mod_name {
1239                use super::*;
1240
1241                #[test]
1242                fn test_basic() {
1243                    let mut factory = <$factory_type>::new();
1244                    stack_pin_init!(let list = DoublyLinkedList::<$ptr_type>::new());
1245                    let list = unsafe { list.get_unchecked_mut() };
1246                    assert!(list.is_empty());
1247
1248                    let obj1 = factory.create(1);
1249                    let obj2 = factory.create(2);
1250
1251                    $push(list, obj1);
1252                    $push(list, obj2);
1253
1254                    assert!(!list.is_empty());
1255
1256                    let mut iter = list.iter();
1257                    assert_eq!(iter.next().unwrap().value, 2);
1258                    assert_eq!(iter.next().unwrap().value, 1);
1259                    assert!(iter.next().is_none());
1260
1261                    list.clear();
1262                    assert!(list.is_empty());
1263                }
1264
1265                #[test]
1266                fn test_double_ended_iterator() {
1267                    let mut factory = <$factory_type>::new();
1268                    stack_pin_init!(let list = DoublyLinkedList::<$ptr_type>::new());
1269                    let list = unsafe { list.get_unchecked_mut() };
1270                    let obj1 = factory.create(1);
1271                    let obj2 = factory.create(2);
1272                    let obj3 = factory.create(3);
1273
1274                    $push(list, obj1);
1275                    $push(list, obj2);
1276                    $push(list, obj3);
1277
1278                    let mut iter = list.iter();
1279                    assert_eq!(iter.next().unwrap().value, 3);
1280                    assert_eq!(iter.next_back().unwrap().value, 1);
1281                    assert_eq!(iter.next().unwrap().value, 2);
1282                    assert!(iter.next().is_none());
1283                    assert!(iter.next_back().is_none());
1284
1285                    list.clear();
1286                }
1287
1288                #[test]
1289                fn test_explicit_pops() {
1290                    let mut factory = <$factory_type>::new();
1291                    stack_pin_init!(let list = DoublyLinkedList::<$ptr_type>::new());
1292                    let list = unsafe { list.get_unchecked_mut() };
1293                    let obj1 = factory.create(1);
1294                    let obj2 = factory.create(2);
1295
1296                    $push(list, obj1);
1297                    $push(list, obj2);
1298
1299                    let p1 = list.pop_front();
1300                    assert!(p1.is_some());
1301                    let p2 = list.pop_front();
1302                    assert!(p2.is_some());
1303                    assert!(list.pop_front().is_none());
1304                }
1305
1306                #[test]
1307                fn test_cursor_move_prev() {
1308                    let mut factory = <$factory_type>::new();
1309                    stack_pin_init!(let list = DoublyLinkedList::<$ptr_type>::new());
1310                    let list = unsafe { list.get_unchecked_mut() };
1311                    let obj1 = factory.create(1);
1312                    let obj2 = factory.create(2);
1313                    let obj3 = factory.create(3);
1314
1315                    $push(list, obj1);
1316                    $push(list, obj2);
1317                    $push(list, obj3);
1318
1319                    let (a, b, c) = {
1320                        let mut iter = list.iter();
1321                        (
1322                            $get_val(iter.next().unwrap()),
1323                            $get_val(iter.next().unwrap()),
1324                            $get_val(iter.next().unwrap()),
1325                        )
1326                    };
1327
1328                    let mut cursor = list.cursor_mut();
1329                    assert_eq!($get_val(cursor.get().unwrap()), a);
1330
1331                    cursor.move_prev();
1332                    assert!(cursor.get().is_none()); // Sentinel
1333
1334                    cursor.move_prev();
1335                    assert_eq!($get_val(cursor.get().unwrap()), c);
1336
1337                    cursor.move_prev();
1338                    assert_eq!($get_val(cursor.get().unwrap()), b);
1339
1340                    cursor.move_prev();
1341                    assert_eq!($get_val(cursor.get().unwrap()), a);
1342
1343                    list.clear();
1344                }
1345
1346                #[test]
1347                fn test_cursor_insert_after() {
1348                    let mut factory = <$factory_type>::new();
1349                    stack_pin_init!(let list = DoublyLinkedList::<$ptr_type>::new());
1350                    let list = unsafe { list.get_unchecked_mut() };
1351                    let obj1 = factory.create(1);
1352                    let obj2 = factory.create(2);
1353                    let obj3 = factory.create(3);
1354
1355                    $push(list, obj1);
1356
1357                    let mut cursor = list.cursor_mut();
1358                    unsafe {
1359                        cursor.insert_after_raw(obj3);
1360                        cursor.insert_after_raw(obj2);
1361                    }
1362
1363                    let mut iter = list.iter();
1364                    assert_eq!($get_val(iter.next().unwrap()), 1);
1365                    assert_eq!($get_val(iter.next().unwrap()), 2);
1366                    assert_eq!($get_val(iter.next().unwrap()), 3);
1367                    assert!(iter.next().is_none());
1368
1369                    list.clear();
1370                }
1371
1372                #[test]
1373                fn test_pop_back() {
1374                    let mut factory = <$factory_type>::new();
1375                    stack_pin_init!(let list = DoublyLinkedList::<$ptr_type>::new());
1376                    let list = unsafe { list.get_unchecked_mut() };
1377                    let obj1 = factory.create(1);
1378                    let obj2 = factory.create(2);
1379
1380                    $push(list, obj1);
1381                    $push(list, obj2);
1382
1383                    let p1 = list.pop_back();
1384                    assert!(p1.is_some());
1385                    let p2 = list.pop_back();
1386                    assert!(p2.is_some());
1387                    assert!(list.pop_back().is_none());
1388                }
1389
1390                #[test]
1391                fn test_erase() {
1392                    let mut factory = <$factory_type>::new();
1393                    stack_pin_init!(let list = DoublyLinkedList::<$ptr_type>::new());
1394                    let list = unsafe { list.get_unchecked_mut() };
1395                    let obj1 = factory.create(1);
1396                    let obj2 = factory.create(2);
1397                    let obj3 = factory.create(3);
1398
1399                    $push(list, obj1);
1400                    $push(list, obj2);
1401                    $push(list, obj3);
1402
1403                    let mut cursor = list.cursor_mut();
1404                    cursor.move_next();
1405                    let erased = cursor.erase();
1406                    assert!(erased.is_some());
1407                    factory.cleanup(erased.unwrap());
1408
1409                    let mut iter = list.iter();
1410                    assert!(iter.next().is_some());
1411                    assert!(iter.next().is_some());
1412                    assert!(iter.next().is_none());
1413
1414                    list.clear();
1415                }
1416
1417                #[test]
1418                fn test_erase_if() {
1419                    let mut factory = <$factory_type>::new();
1420                    stack_pin_init!(let list = DoublyLinkedList::<$ptr_type>::new());
1421                    let list = unsafe { list.get_unchecked_mut() };
1422                    let obj1 = factory.create(1);
1423                    let obj2 = factory.create(2);
1424                    let obj3 = factory.create(3);
1425
1426                    $push(list, obj1);
1427                    $push(list, obj2);
1428                    $push(list, obj3);
1429
1430                    let erased = list.erase_if(|o| o.value == 2);
1431                    assert!(erased.is_some());
1432                    assert_eq!($get_val(erased.unwrap().get_ref()), 2);
1433
1434                    let mut iter = list.iter();
1435                    assert_eq!($get_val(iter.next().unwrap()), 3);
1436                    assert_eq!($get_val(iter.next().unwrap()), 1);
1437                    assert!(iter.next().is_none());
1438
1439                    list.clear();
1440                }
1441
1442                #[test]
1443                fn test_find_if() {
1444                    let mut factory = <$factory_type>::new();
1445                    stack_pin_init!(let list = DoublyLinkedList::<$ptr_type>::new());
1446                    let list = unsafe { list.get_unchecked_mut() };
1447                    let obj1 = factory.create(1);
1448                    let obj2 = factory.create(2);
1449
1450                    $push(list, obj1);
1451                    $push(list, obj2);
1452
1453                    let found = list.find_if(|o| o.value == 1);
1454                    assert!(found.is_some());
1455                    assert_eq!(found.unwrap().value, 1);
1456
1457                    let found = list.find_if(|o| o.value == 3);
1458                    assert!(found.is_none());
1459
1460                    list.clear();
1461                }
1462
1463                #[test]
1464                fn test_complete_reverse_iteration() {
1465                    let mut factory = <$factory_type>::new();
1466                    stack_pin_init!(let list = DoublyLinkedList::<$ptr_type>::new());
1467                    let list = unsafe { list.get_unchecked_mut() };
1468                    let obj1 = factory.create(1);
1469                    let obj2 = factory.create(2);
1470                    let obj3 = factory.create(3);
1471
1472                    $push(list, obj1);
1473                    $push(list, obj2);
1474                    $push(list, obj3);
1475
1476                    let (a, b, c) = {
1477                        let mut iter = list.iter();
1478                        (
1479                            $get_val(iter.next().unwrap()),
1480                            $get_val(iter.next().unwrap()),
1481                            $get_val(iter.next().unwrap()),
1482                        )
1483                    };
1484
1485                    let mut iter = list.iter();
1486                    assert_eq!($get_val(iter.next_back().unwrap()), c);
1487                    assert_eq!($get_val(iter.next_back().unwrap()), b);
1488                    assert_eq!($get_val(iter.next_back().unwrap()), a);
1489                    assert!(iter.next_back().is_none());
1490
1491                    list.clear();
1492                }
1493            }
1494        };
1495    }
1496
1497    generate_list_tests!(
1498        raw_ptr_tests,
1499        *mut TestObject,
1500        RawFactory<TestObject>,
1501        |p: &TestObject| p.value,
1502        |list: &mut DoublyLinkedList<*mut TestObject>, obj| unsafe {
1503            list.push_front_raw(obj);
1504        }
1505    );
1506
1507    generate_list_tests!(
1508        unique_ptr_tests,
1509        UniquePtr<UniqueTestObject>,
1510        UniqueFactory<UniqueTestObject>,
1511        |p: &UniqueTestObject| p.value,
1512        |list: &mut DoublyLinkedList<UniquePtr<UniqueTestObject>>, obj| list.push_front(obj)
1513    );
1514
1515    generate_list_tests!(
1516        ref_ptr_tests,
1517        RefPtr<RefTestObject>,
1518        RefFactory<RefTestObject>,
1519        |p: &RefTestObject| p.value,
1520        |list: &mut DoublyLinkedList<RefPtr<RefTestObject>>, obj| list.push_front(obj)
1521    );
1522
1523    #[test]
1524    fn test_tracking_size() {
1525        stack_pin_init!(let list =
1526            DoublyLinkedList::<UniquePtr<UniqueTestObject>, DefaultObjectTag, TrackingSize>::new());
1527        let list = unsafe { list.get_unchecked_mut() };
1528
1529        assert_eq!(list.len(), 0);
1530        list.push_front(UniquePtr::try_new(UniqueTestObject::new(1)).unwrap());
1531        assert_eq!(list.len(), 1);
1532        list.push_front(UniquePtr::try_new(UniqueTestObject::new(2)).unwrap());
1533        assert_eq!(list.len(), 2);
1534        list.pop_front();
1535        assert_eq!(list.len(), 1);
1536        list.clear();
1537        assert_eq!(list.len(), 0);
1538    }
1539
1540    #[test]
1541    fn test_insert_before() {
1542        stack_pin_init!(let list =
1543            DoublyLinkedList::<UniquePtr<UniqueTestObject>, DefaultObjectTag, TrackingSize>::new());
1544        let list = unsafe { list.get_unchecked_mut() };
1545
1546        let mut cursor = list.cursor_mut();
1547        cursor.insert_before(UniquePtr::try_new(UniqueTestObject::new(1)).unwrap());
1548        assert_eq!(list.len(), 1);
1549        assert_eq!(list.front().unwrap().value, 1);
1550
1551        let mut cursor = list.cursor_mut();
1552        cursor.insert_before(UniquePtr::try_new(UniqueTestObject::new(2)).unwrap());
1553        assert_eq!(list.len(), 2);
1554        assert_eq!(list.front().unwrap().value, 2);
1555
1556        let mut cursor = list.cursor_mut();
1557        cursor.move_next(); // point to obj1
1558        cursor.insert_before(UniquePtr::try_new(UniqueTestObject::new(3)).unwrap());
1559        assert_eq!(list.len(), 3);
1560
1561        let mut cursor = list.cursor_mut();
1562        while cursor.get().unwrap().value != 1 {
1563            cursor.move_next();
1564        }
1565        cursor.move_next(); // point to sentinel
1566        cursor.insert_before(UniquePtr::try_new(UniqueTestObject::new(4)).unwrap());
1567        assert_eq!(list.len(), 4);
1568
1569        let mut iter = list.iter();
1570        assert_eq!(iter.next().unwrap().value, 2);
1571        assert_eq!(iter.next().unwrap().value, 3);
1572        assert_eq!(iter.next().unwrap().value, 1);
1573        assert_eq!(iter.next().unwrap().value, 4);
1574        assert!(iter.next().is_none());
1575
1576        list.clear();
1577    }
1578
1579    #[test]
1580    fn test_splice_middle() {
1581        stack_pin_init!(let list1 =
1582            DoublyLinkedList::<UniquePtr<UniqueTestObject>, DefaultObjectTag, TrackingSize>::new());
1583        let list1 = unsafe { list1.get_unchecked_mut() };
1584        stack_pin_init!(let list2 =
1585            DoublyLinkedList::<UniquePtr<UniqueTestObject>, DefaultObjectTag, TrackingSize>::new());
1586        let list2 = unsafe { list2.get_unchecked_mut() };
1587
1588        list1.push_back(UniquePtr::try_new(UniqueTestObject::new(1)).unwrap());
1589        list1.push_back(UniquePtr::try_new(UniqueTestObject::new(2)).unwrap());
1590        list2.push_back(UniquePtr::try_new(UniqueTestObject::new(3)).unwrap());
1591        list2.push_back(UniquePtr::try_new(UniqueTestObject::new(4)).unwrap());
1592
1593        let mut cursor = list1.cursor_mut();
1594        cursor.move_next(); // point to obj2
1595
1596        cursor.splice(list2);
1597
1598        assert!(list2.is_empty());
1599        assert_eq!(list1.len(), 4);
1600
1601        let mut iter = list1.iter();
1602        assert_eq!(iter.next().unwrap().value, 1);
1603        assert_eq!(iter.next().unwrap().value, 3);
1604        assert_eq!(iter.next().unwrap().value, 4);
1605        assert_eq!(iter.next().unwrap().value, 2);
1606        assert!(iter.next().is_none());
1607
1608        list1.clear();
1609    }
1610
1611    #[test]
1612    fn test_splice_head() {
1613        stack_pin_init!(let list1 =
1614            DoublyLinkedList::<UniquePtr<UniqueTestObject>, DefaultObjectTag, TrackingSize>::new());
1615        let list1 = unsafe { list1.get_unchecked_mut() };
1616        stack_pin_init!(let list2 =
1617            DoublyLinkedList::<UniquePtr<UniqueTestObject>, DefaultObjectTag, TrackingSize>::new());
1618        let list2 = unsafe { list2.get_unchecked_mut() };
1619
1620        list1.push_back(UniquePtr::try_new(UniqueTestObject::new(1)).unwrap());
1621        list1.push_back(UniquePtr::try_new(UniqueTestObject::new(2)).unwrap());
1622        list2.push_back(UniquePtr::try_new(UniqueTestObject::new(3)).unwrap());
1623        list2.push_back(UniquePtr::try_new(UniqueTestObject::new(4)).unwrap());
1624
1625        let mut cursor = list1.cursor_mut();
1626
1627        cursor.splice(list2);
1628
1629        assert!(list2.is_empty());
1630        assert_eq!(list1.len(), 4);
1631
1632        let mut iter = list1.iter();
1633        assert_eq!(iter.next().unwrap().value, 3);
1634        assert_eq!(iter.next().unwrap().value, 4);
1635        assert_eq!(iter.next().unwrap().value, 1);
1636        assert_eq!(iter.next().unwrap().value, 2);
1637        assert!(iter.next().is_none());
1638
1639        list1.clear();
1640    }
1641
1642    #[test]
1643    fn test_splice_tail() {
1644        stack_pin_init!(let list1 =
1645            DoublyLinkedList::<UniquePtr<UniqueTestObject>, DefaultObjectTag, TrackingSize>::new());
1646        let list1 = unsafe { list1.get_unchecked_mut() };
1647        stack_pin_init!(let list2 =
1648            DoublyLinkedList::<UniquePtr<UniqueTestObject>, DefaultObjectTag, TrackingSize>::new());
1649        let list2 = unsafe { list2.get_unchecked_mut() };
1650
1651        list1.push_back(UniquePtr::try_new(UniqueTestObject::new(1)).unwrap());
1652        list1.push_back(UniquePtr::try_new(UniqueTestObject::new(2)).unwrap());
1653        list2.push_back(UniquePtr::try_new(UniqueTestObject::new(3)).unwrap());
1654        list2.push_back(UniquePtr::try_new(UniqueTestObject::new(4)).unwrap());
1655
1656        let mut cursor = list1.cursor_mut();
1657        cursor.move_next();
1658        cursor.move_next(); // point to sentinel
1659
1660        cursor.splice(list2);
1661
1662        assert!(list2.is_empty());
1663        assert_eq!(list1.len(), 4);
1664
1665        let mut iter = list1.iter();
1666        assert_eq!(iter.next().unwrap().value, 1);
1667        assert_eq!(iter.next().unwrap().value, 2);
1668        assert_eq!(iter.next().unwrap().value, 3);
1669        assert_eq!(iter.next().unwrap().value, 4);
1670        assert!(iter.next().is_none());
1671
1672        list1.clear();
1673    }
1674
1675    #[test]
1676    fn test_splice_empty() {
1677        stack_pin_init!(let list1 =
1678            DoublyLinkedList::<UniquePtr<UniqueTestObject>, DefaultObjectTag, TrackingSize>::new());
1679        let list1 = unsafe { list1.get_unchecked_mut() };
1680        stack_pin_init!(let list2 =
1681            DoublyLinkedList::<UniquePtr<UniqueTestObject>, DefaultObjectTag, TrackingSize>::new());
1682        let list2 = unsafe { list2.get_unchecked_mut() };
1683
1684        list2.push_back(UniquePtr::try_new(UniqueTestObject::new(1)).unwrap());
1685        list2.push_back(UniquePtr::try_new(UniqueTestObject::new(2)).unwrap());
1686
1687        let mut cursor = list1.cursor_mut();
1688        cursor.splice(list2);
1689
1690        assert!(list2.is_empty());
1691        assert_eq!(list1.len(), 2);
1692
1693        let mut iter = list1.iter();
1694        assert_eq!(iter.next().unwrap().value, 1);
1695        assert_eq!(iter.next().unwrap().value, 2);
1696        assert!(iter.next().is_none());
1697
1698        list1.clear();
1699    }
1700
1701    #[test]
1702    fn test_splice_non_tracking() {
1703        stack_pin_init!(let list1 =
1704            DoublyLinkedList::<UniquePtr<UniqueTestObject>, DefaultObjectTag, NonTrackingSize>::new());
1705        let list1 = unsafe { list1.get_unchecked_mut() };
1706        stack_pin_init!(let list2 =
1707            DoublyLinkedList::<UniquePtr<UniqueTestObject>, DefaultObjectTag, NonTrackingSize>::new());
1708        let list2 = unsafe { list2.get_unchecked_mut() };
1709
1710        list1.push_back(UniquePtr::try_new(UniqueTestObject::new(1)).unwrap());
1711        list1.push_back(UniquePtr::try_new(UniqueTestObject::new(2)).unwrap());
1712        list2.push_back(UniquePtr::try_new(UniqueTestObject::new(3)).unwrap());
1713        list2.push_back(UniquePtr::try_new(UniqueTestObject::new(4)).unwrap());
1714
1715        let mut cursor = list1.cursor_mut();
1716        cursor.move_next(); // point to obj2
1717
1718        cursor.splice(list2);
1719
1720        assert!(list2.is_empty());
1721
1722        let mut iter = list1.iter();
1723        assert_eq!(iter.next().unwrap().value, 1);
1724        assert_eq!(iter.next().unwrap().value, 3);
1725        assert_eq!(iter.next().unwrap().value, 4);
1726        assert_eq!(iter.next().unwrap().value, 2);
1727        assert!(iter.next().is_none());
1728
1729        list1.clear();
1730    }
1731
1732    #[test]
1733    fn test_pop_back() {
1734        stack_pin_init!(let list =
1735            DoublyLinkedList::<UniquePtr<UniqueTestObject>, DefaultObjectTag, TrackingSize>::new());
1736        let list = unsafe { list.get_unchecked_mut() };
1737
1738        list.push_back(UniquePtr::try_new(UniqueTestObject::new(1)).unwrap());
1739        list.push_back(UniquePtr::try_new(UniqueTestObject::new(2)).unwrap());
1740
1741        assert_eq!(list.len(), 2);
1742        let popped = list.pop_back();
1743        assert!(popped.is_some());
1744        assert_eq!(popped.unwrap().value, 2);
1745        assert_eq!(list.len(), 1);
1746
1747        let popped = list.pop_back();
1748        assert!(popped.is_some());
1749        assert_eq!(popped.unwrap().value, 1);
1750        assert_eq!(list.len(), 0);
1751
1752        assert!(list.pop_back().is_none());
1753    }
1754
1755    #[test]
1756    fn test_erase() {
1757        stack_pin_init!(let list =
1758            DoublyLinkedList::<UniquePtr<UniqueTestObject>, DefaultObjectTag, TrackingSize>::new());
1759        let list = unsafe { list.get_unchecked_mut() };
1760
1761        list.push_back(UniquePtr::try_new(UniqueTestObject::new(1)).unwrap());
1762        list.push_back(UniquePtr::try_new(UniqueTestObject::new(2)).unwrap());
1763        list.push_back(UniquePtr::try_new(UniqueTestObject::new(3)).unwrap());
1764
1765        assert_eq!(list.len(), 3);
1766
1767        // 1. Erase middle (obj2)
1768        let mut cursor = list.cursor_mut();
1769        cursor.move_next(); // point to obj2
1770        let erased = cursor.erase();
1771        assert!(erased.is_some());
1772        assert_eq!(erased.unwrap().value, 2);
1773        assert_eq!(list.len(), 2);
1774
1775        let mut iter = list.iter();
1776        assert_eq!(iter.next().unwrap().value, 1);
1777        assert_eq!(iter.next().unwrap().value, 3);
1778        assert!(iter.next().is_none());
1779
1780        // 2. Erase head (obj1)
1781        let mut cursor = list.cursor_mut();
1782        let erased = cursor.erase(); // current is head (obj1)
1783        assert!(erased.is_some());
1784        assert_eq!(erased.unwrap().value, 1);
1785        assert_eq!(list.len(), 1);
1786        assert_eq!(list.front().unwrap().value, 3); // obj3 is now head!
1787
1788        // 3. Erase last element (obj3)
1789        let mut cursor = list.cursor_mut();
1790        let erased = cursor.erase(); // current is head/tail (obj3)
1791        assert!(erased.is_some());
1792        assert_eq!(erased.unwrap().value, 3);
1793        assert_eq!(list.len(), 0);
1794        assert!(list.is_empty());
1795
1796        list.clear();
1797    }
1798
1799    #[test]
1800    fn test_erase_if() {
1801        stack_pin_init!(let list =
1802            DoublyLinkedList::<UniquePtr<UniqueTestObject>, DefaultObjectTag, TrackingSize>::new());
1803        let list = unsafe { list.get_unchecked_mut() };
1804
1805        list.push_back(UniquePtr::try_new(UniqueTestObject::new(1)).unwrap());
1806        list.push_back(UniquePtr::try_new(UniqueTestObject::new(2)).unwrap());
1807        list.push_back(UniquePtr::try_new(UniqueTestObject::new(3)).unwrap());
1808
1809        let erased = list.erase_if(|obj| obj.value % 2 == 0);
1810        assert!(erased.is_some());
1811        assert_eq!(erased.unwrap().value, 2);
1812
1813        assert_eq!(list.len(), 2);
1814        let mut iter = list.iter();
1815        assert_eq!(iter.next().unwrap().value, 1);
1816        assert_eq!(iter.next().unwrap().value, 3);
1817        assert!(iter.next().is_none());
1818
1819        list.clear();
1820    }
1821
1822    #[test]
1823    fn test_erase_by_reference() {
1824        stack_pin_init!(let list =
1825            DoublyLinkedList::<*mut TestObject, DefaultObjectTag, TrackingSize>::new());
1826        let list = unsafe { list.get_unchecked_mut() };
1827        let mut obj1 = TestObject::new(1);
1828        let mut obj2 = TestObject::new(2);
1829        let mut obj3 = TestObject::new(3);
1830
1831        unsafe {
1832            list.push_back_raw(&mut obj1);
1833            list.push_back_raw(&mut obj2);
1834            list.push_back_raw(&mut obj3);
1835        }
1836
1837        assert_eq!(list.len(), 3);
1838
1839        // Erase obj2 directly (safe because it's unmanaged raw pointer to stack)
1840        let erased = unsafe { list.erase(&obj2) };
1841        assert!(erased.is_some());
1842        assert_eq!(unsafe { &*erased.unwrap() }.value, 2);
1843        assert_eq!(list.len(), 2);
1844
1845        let mut iter = list.iter();
1846        assert_eq!(iter.next().unwrap().value, 1);
1847        assert_eq!(iter.next().unwrap().value, 3);
1848        assert!(iter.next().is_none());
1849
1850        list.clear();
1851    }
1852
1853    #[test]
1854    fn test_remove_from_container() {
1855        stack_pin_init!(let list = DoublyLinkedList::<*mut TestObject>::new());
1856        let list = unsafe { list.get_unchecked_mut() };
1857        let mut obj1 = TestObject::new(1);
1858        let mut obj2 = TestObject::new(2);
1859        let mut obj3 = TestObject::new(3);
1860
1861        // Case 1: Attempt to remove an element not in any container
1862        let removed = unsafe {
1863            remove_from_container::<TestObject, DefaultObjectTag, *mut TestObject>(&obj1)
1864        };
1865        assert!(removed.is_none());
1866
1867        unsafe {
1868            list.push_back_raw(&mut obj1);
1869            list.push_back_raw(&mut obj2);
1870            list.push_back_raw(&mut obj3);
1871        }
1872
1873        // Case 2: Remove middle (obj2)
1874        let removed = unsafe {
1875            remove_from_container::<TestObject, DefaultObjectTag, *mut TestObject>(&obj2)
1876        };
1877        assert!(removed.is_some());
1878        assert_eq!(unsafe { &*removed.unwrap() }.value, 2);
1879
1880        let mut iter = list.iter();
1881        assert_eq!(iter.next().unwrap().value, 1);
1882        assert_eq!(iter.next().unwrap().value, 3);
1883        assert!(iter.next().is_none());
1884
1885        // Case 3: Remove head (obj1)
1886        let removed = unsafe {
1887            remove_from_container::<TestObject, DefaultObjectTag, *mut TestObject>(&obj1)
1888        };
1889        assert!(removed.is_some());
1890        assert_eq!(unsafe { &*removed.unwrap() }.value, 1);
1891
1892        let mut iter = list.iter();
1893        assert_eq!(iter.next().unwrap().value, 3);
1894        assert!(iter.next().is_none());
1895
1896        // Case 4: Remove last remaining element (obj3 -> leaves empty!)
1897        let removed = unsafe {
1898            remove_from_container::<TestObject, DefaultObjectTag, *mut TestObject>(&obj3)
1899        };
1900        assert!(removed.is_some());
1901        assert_eq!(unsafe { &*removed.unwrap() }.value, 3);
1902        assert!(list.is_empty());
1903
1904        list.clear();
1905    }
1906
1907    #[test]
1908    fn test_replace() {
1909        stack_pin_init!(let list =
1910            DoublyLinkedList::<*mut TestObject, DefaultObjectTag, TrackingSize>::new());
1911        let list = unsafe { list.get_unchecked_mut() };
1912        let mut obj1 = TestObject::new(1);
1913        let mut obj2 = TestObject::new(2);
1914        let mut obj3 = TestObject::new(3);
1915
1916        unsafe {
1917            list.push_back_raw(&mut obj1);
1918            list.push_back_raw(&mut obj2);
1919        }
1920
1921        assert_eq!(list.len(), 2);
1922
1923        let old = unsafe { list.replace_raw(&obj2, &mut obj3) };
1924        assert!(old.is_some());
1925        assert_eq!(unsafe { &*old.unwrap() }.value, 2);
1926        assert_eq!(list.len(), 2);
1927
1928        let mut iter = list.iter();
1929        assert_eq!(iter.next().unwrap().value, 1);
1930        assert_eq!(iter.next().unwrap().value, 3);
1931        assert!(iter.next().is_none());
1932
1933        list.clear();
1934    }
1935
1936    #[test]
1937    fn test_cursor_replace() {
1938        stack_pin_init!(let list = DoublyLinkedList::<UniquePtr<UniqueTestObject>>::new());
1939        let list = unsafe { list.get_unchecked_mut() };
1940
1941        let obj1 = UniquePtr::try_new(UniqueTestObject::new(1)).unwrap();
1942        let obj2 = UniquePtr::try_new(UniqueTestObject::new(2)).unwrap();
1943        let obj3 = UniquePtr::try_new(UniqueTestObject::new(3)).unwrap();
1944
1945        list.push_back(obj1);
1946        list.push_back(obj2);
1947
1948        let mut cursor = list.cursor_mut();
1949        cursor.move_next(); // point to obj2
1950
1951        let old = cursor.replace(obj3);
1952        assert!(old.is_some());
1953        assert_eq!(old.unwrap().value, 2);
1954
1955        let mut iter = list.iter();
1956        assert_eq!(iter.next().unwrap().value, 1);
1957        assert_eq!(iter.next().unwrap().value, 3);
1958        assert!(iter.next().is_none());
1959
1960        list.clear();
1961    }
1962
1963    struct Tag2;
1964
1965    #[fbl::ref_counted]
1966    #[derive(crate::DoublyLinkedListContainable, crate::Recyclable)]
1967    #[repr(C)]
1968    struct MultiListObject {
1969        value: i32,
1970        #[dll_node]
1971        node1: DoublyLinkedListNode<MultiListObject>,
1972        #[dll_node(tag = Tag2)]
1973        node2: DoublyLinkedListNode<MultiListObject>,
1974    }
1975
1976    #[test]
1977    fn test_multiple_containers() {
1978        stack_pin_init!(let list1 =
1979            DoublyLinkedList::<RefPtr<MultiListObject>, DefaultObjectTag>::new());
1980        let list1 = unsafe { list1.get_unchecked_mut() };
1981        stack_pin_init!(let list2 = DoublyLinkedList::<RefPtr<MultiListObject>, Tag2>::new());
1982        let list2 = unsafe { list2.get_unchecked_mut() };
1983
1984        let obj1 = fbl::make_ref_counted!(MultiListObject {
1985            value: 1,
1986            node1: DoublyLinkedListNode::new(),
1987            node2: DoublyLinkedListNode::new(),
1988        })
1989        .unwrap();
1990
1991        let obj2 = fbl::make_ref_counted!(MultiListObject {
1992            value: 2,
1993            node1: DoublyLinkedListNode::new(),
1994            node2: DoublyLinkedListNode::new(),
1995        })
1996        .unwrap();
1997
1998        list1.push_back(obj1.clone());
1999        list1.push_back(obj2.clone());
2000
2001        list2.push_back(obj2); // obj2 is now in both lists!
2002
2003        let mut iter1 = list1.iter();
2004        assert_eq!(iter1.next().unwrap().value, 1);
2005        assert_eq!(iter1.next().unwrap().value, 2);
2006        assert!(iter1.next().is_none());
2007
2008        let mut iter2 = list2.iter();
2009        assert_eq!(iter2.next().unwrap().value, 2);
2010        assert!(iter2.next().is_none());
2011
2012        list1.clear();
2013        list2.clear();
2014    }
2015
2016    use alloc::sync::Arc;
2017    use core::sync::atomic::{AtomicBool, Ordering};
2018
2019    #[derive(crate::DoublyLinkedListContainable, crate::Recyclable)]
2020    struct LifecycleObject {
2021        destroyed: Arc<AtomicBool>,
2022        #[dll_node]
2023        node: DoublyLinkedListNode<LifecycleObject>,
2024    }
2025
2026    impl LifecycleObject {
2027        fn new(destroyed: Arc<AtomicBool>) -> Self {
2028            Self { destroyed, node: DoublyLinkedListNode::new() }
2029        }
2030    }
2031
2032    impl Drop for LifecycleObject {
2033        fn drop(&mut self) {
2034            self.destroyed.store(true, Ordering::Relaxed);
2035        }
2036    }
2037
2038    #[test]
2039    fn test_lifecycle_on_drop() {
2040        let destroyed1 = Arc::new(AtomicBool::new(false));
2041        let destroyed2 = Arc::new(AtomicBool::new(false));
2042
2043        {
2044            stack_pin_init!(let list = DoublyLinkedList::<UniquePtr<LifecycleObject>>::new());
2045            let list = unsafe { list.get_unchecked_mut() };
2046
2047            let obj1 = UniquePtr::try_new(LifecycleObject::new(destroyed1.clone())).unwrap();
2048            let obj2 = UniquePtr::try_new(LifecycleObject::new(destroyed2.clone())).unwrap();
2049
2050            list.push_back(obj1);
2051            list.push_back(obj2);
2052
2053            assert!(!destroyed1.load(Ordering::Relaxed));
2054            assert!(!destroyed2.load(Ordering::Relaxed));
2055        } // list drops here
2056
2057        assert!(destroyed1.load(Ordering::Relaxed));
2058        assert!(destroyed2.load(Ordering::Relaxed));
2059    }
2060
2061    #[test]
2062    fn test_sized_managed_list() {
2063        stack_pin_init!(let list =
2064            DoublyLinkedList::<UniquePtr<UniqueTestObject>, DefaultObjectTag, TrackingSize>::new());
2065        let list = unsafe { list.get_unchecked_mut() };
2066
2067        assert_eq!(list.len(), 0);
2068
2069        let obj1 = UniquePtr::try_new(UniqueTestObject::new(1)).unwrap();
2070        let obj2 = UniquePtr::try_new(UniqueTestObject::new(2)).unwrap();
2071
2072        list.push_back(obj1);
2073        assert_eq!(list.len(), 1);
2074
2075        list.push_back(obj2);
2076        assert_eq!(list.len(), 2);
2077
2078        let popped = list.pop_front();
2079        assert!(popped.is_some());
2080        assert_eq!(list.len(), 1);
2081
2082        list.clear();
2083        assert_eq!(list.len(), 0);
2084    }
2085
2086    #[test]
2087    fn test_unidirectional_iterators() {
2088        stack_pin_init!(let list = DoublyLinkedList::<UniquePtr<UniqueTestObject>>::new());
2089        let list = unsafe { list.get_unchecked_mut() };
2090
2091        list.push_back(UniquePtr::try_new(UniqueTestObject::new(1)).unwrap());
2092        list.push_back(UniquePtr::try_new(UniqueTestObject::new(2)).unwrap());
2093        list.push_back(UniquePtr::try_new(UniqueTestObject::new(3)).unwrap());
2094
2095        // 1. Test ForwardIterator from beginning
2096        let mut f_iter = list.forward_iter();
2097        assert_eq!(f_iter.next().unwrap().value, 1);
2098        let obj2_ref = f_iter.next().unwrap();
2099        assert_eq!(obj2_ref.value, 2);
2100        assert_eq!(f_iter.next().unwrap().value, 3);
2101        assert!(f_iter.next().is_none());
2102
2103        // 2. Test ForwardIterator from element in the middle (obj2_ref)
2104        let mut f_element_iter =
2105            ForwardIterator::<UniquePtr<UniqueTestObject>>::from_element(obj2_ref);
2106        assert_eq!(f_element_iter.next().unwrap().value, 2);
2107        assert_eq!(f_element_iter.next().unwrap().value, 3);
2108        assert!(f_element_iter.next().is_none());
2109
2110        // 3. Test ReverseIterator from end
2111        let mut r_iter = list.reverse_iter();
2112        assert_eq!(r_iter.next().unwrap().value, 3);
2113        let obj2_ref_r = r_iter.next().unwrap();
2114        assert_eq!(obj2_ref_r.value, 2);
2115        assert_eq!(r_iter.next().unwrap().value, 1);
2116        assert!(r_iter.next().is_none());
2117
2118        // 4. Test ReverseIterator from element in the middle (obj2_ref_r)
2119        let mut r_element_iter =
2120            ReverseIterator::<UniquePtr<UniqueTestObject>>::from_element(obj2_ref_r);
2121        assert_eq!(r_element_iter.next().unwrap().value, 2);
2122        assert_eq!(r_element_iter.next().unwrap().value, 1);
2123        assert!(r_element_iter.next().is_none());
2124
2125        list.clear();
2126    }
2127
2128    #[test]
2129    fn test_cursor_at() {
2130        stack_pin_init!(let list =
2131            DoublyLinkedList::<*mut TestObject, DefaultObjectTag, TrackingSize>::new());
2132        let list = unsafe { list.get_unchecked_mut() };
2133        let mut obj1 = TestObject::new(1);
2134        let mut obj2 = TestObject::new(2);
2135        let mut obj3 = TestObject::new(3);
2136
2137        unsafe {
2138            list.push_back_raw(&mut obj1);
2139            list.push_back_raw(&mut obj2);
2140            list.push_back_raw(&mut obj3);
2141        }
2142
2143        // Create a cursor at the second element (obj2).
2144        // SAFETY: `obj2` is a member of `list`.
2145        let mut cursor = unsafe { list.cursor_at(&obj2) };
2146        assert_eq!(cursor.get().unwrap().value, 2);
2147
2148        // Verify we can move next.
2149        cursor.move_next();
2150        assert_eq!(cursor.get().unwrap().value, 3);
2151
2152        // Verify we can move prev from the original position.
2153        // SAFETY: `obj2` is a member of `list`.
2154        let mut cursor = unsafe { list.cursor_at(&obj2) };
2155        cursor.move_prev();
2156        assert_eq!(cursor.get().unwrap().value, 1);
2157
2158        // Verify we can erase via the cursor created at the element.
2159        // SAFETY: `obj2` is a member of `list`.
2160        let mut cursor = unsafe { list.cursor_at(&obj2) };
2161        let erased = cursor.erase().unwrap();
2162        assert_eq!(unsafe { &*erased }.value, 2);
2163
2164        // Verify list contents after erase.
2165        let mut iter = list.iter();
2166        assert_eq!(iter.next().unwrap().value, 1);
2167        assert_eq!(iter.next().unwrap().value, 3);
2168        assert!(iter.next().is_none());
2169
2170        list.clear();
2171    }
2172
2173    // FFI Declarations
2174    unsafe extern "C" {
2175        // UniqueList Helpers
2176        fn cpp_create_unique_list() -> *mut c_void;
2177        fn cpp_destroy_unique_list(list: *mut c_void);
2178        fn cpp_unique_list_push_back(list: *mut c_void, item: *mut c_void);
2179        fn cpp_unique_list_pop_front(list: *mut c_void) -> *mut c_void;
2180        fn cpp_unique_list_is_empty(list: *mut c_void) -> bool;
2181
2182        // RefList Helpers
2183        fn cpp_create_ref_list() -> *mut c_void;
2184        fn cpp_destroy_ref_list(list: *mut c_void);
2185        fn cpp_ref_list_push_back(list: *mut c_void, item: *mut c_void);
2186        fn cpp_ref_list_pop_front(list: *mut c_void) -> *mut c_void;
2187        fn cpp_ref_list_is_empty(list: *mut c_void) -> bool;
2188
2189        // SharedUniqueObject Helpers
2190        fn cpp_create_unique_object(value: i32, destruction_flag: *mut bool) -> *mut c_void;
2191        fn cpp_get_unique_object_value(obj: *mut c_void) -> i32;
2192
2193        // SharedRefObject Helpers
2194        fn cpp_create_ref_object(value: i32, destruction_flag: *mut bool) -> *mut c_void;
2195        fn cpp_get_ref_object_value(obj: *mut c_void) -> i32;
2196    }
2197
2198    #[test]
2199    fn test_interop_rust_list_cpp_unique_objects() {
2200        let destroyed1 = AtomicBool::new(false);
2201        let destroyed2 = AtomicBool::new(false);
2202
2203        unsafe {
2204            stack_pin_init!(let list = DoublyLinkedList::<UniquePtr<SharedUniqueObject>>::new());
2205            let list = list.get_unchecked_mut();
2206
2207            let cpp_raw1 = cpp_create_unique_object(1, destroyed1.as_ptr() as *mut bool);
2208            let cpp_raw2 = cpp_create_unique_object(2, destroyed2.as_ptr() as *mut bool);
2209
2210            let obj1 = UniquePtr::from_raw(cpp_raw1 as *mut SharedUniqueObject);
2211            let obj2 = UniquePtr::from_raw(cpp_raw2 as *mut SharedUniqueObject);
2212
2213            list.push_back(obj1);
2214            list.push_back(obj2);
2215
2216            assert!(!destroyed1.load(Ordering::Relaxed));
2217            assert!(!destroyed2.load(Ordering::Relaxed));
2218
2219            // Pop one
2220            let popped = list.pop_front();
2221            assert!(popped.is_some());
2222            assert_eq!(popped.as_ref().unwrap().value, 1);
2223
2224            // Drop popped -> should destroy in C++!
2225            drop(popped);
2226            assert!(destroyed1.load(Ordering::Relaxed));
2227            assert!(!destroyed2.load(Ordering::Relaxed));
2228
2229            // Drop list -> should destroy remaining in C++!
2230        }
2231        assert!(destroyed2.load(Ordering::Relaxed));
2232    }
2233
2234    #[test]
2235    fn test_interop_cpp_list_rust_unique_objects() {
2236        let destroyed1 = Arc::new(AtomicBool::new(false));
2237        let destroyed2 = Arc::new(AtomicBool::new(false));
2238
2239        unsafe {
2240            let cpp_list = cpp_create_unique_list();
2241            assert!(cpp_unique_list_is_empty(cpp_list));
2242
2243            let obj1 = UniquePtr::try_new(SharedUniqueObject::new(1)).unwrap();
2244            let obj2 = UniquePtr::try_new(SharedUniqueObject::new(2)).unwrap();
2245
2246            // Set destruction flags
2247            let raw1 = UniquePtr::as_ptr(&obj1) as *mut SharedUniqueObject;
2248            (*raw1).destruction_flag = destroyed1.as_ptr() as *mut bool;
2249            let raw2 = UniquePtr::as_ptr(&obj2) as *mut SharedUniqueObject;
2250            (*raw2).destruction_flag = destroyed2.as_ptr() as *mut bool;
2251
2252            // Push to C++ list (transfers ownership)
2253            cpp_unique_list_push_back(cpp_list, UniquePtr::into_raw(obj1) as *mut c_void);
2254            cpp_unique_list_push_back(cpp_list, UniquePtr::into_raw(obj2) as *mut c_void);
2255
2256            assert!(!destroyed1.load(Ordering::Relaxed));
2257            assert!(!destroyed2.load(Ordering::Relaxed));
2258
2259            // Pop one from C++
2260            let popped = cpp_unique_list_pop_front(cpp_list);
2261            assert!(!popped.is_null());
2262            assert_eq!(cpp_get_unique_object_value(popped), 1);
2263
2264            // Convert back to Rust UniquePtr and drop -> should free in Rust!
2265            let popped_rust = UniquePtr::from_raw(popped as *mut SharedUniqueObject);
2266            drop(popped_rust);
2267            assert!(destroyed1.load(Ordering::Relaxed));
2268            assert!(!destroyed2.load(Ordering::Relaxed));
2269
2270            // Destroy C++ list -> should destroy remaining in Rust!
2271            cpp_destroy_unique_list(cpp_list);
2272        }
2273        assert!(destroyed2.load(Ordering::Relaxed));
2274    }
2275
2276    #[test]
2277    fn test_interop_rust_list_cpp_ref_objects() {
2278        let destroyed1 = AtomicBool::new(false);
2279        let destroyed2 = AtomicBool::new(false);
2280
2281        unsafe {
2282            stack_pin_init!(let list = DoublyLinkedList::<RefPtr<SharedRefObject>>::new());
2283            let list = list.get_unchecked_mut();
2284
2285            let cpp_raw1 = cpp_create_ref_object(1, destroyed1.as_ptr() as *mut bool);
2286            let cpp_raw2 = cpp_create_ref_object(2, destroyed2.as_ptr() as *mut bool);
2287
2288            let obj1 = RefPtr::from_raw(cpp_raw1 as *mut SharedRefObject);
2289            let obj2 = RefPtr::from_raw(cpp_raw2 as *mut SharedRefObject);
2290
2291            list.push_back(obj1);
2292            list.push_back(obj2);
2293
2294            assert!(!destroyed1.load(Ordering::Relaxed));
2295            assert!(!destroyed2.load(Ordering::Relaxed));
2296
2297            // Pop one
2298            let popped = list.pop_front();
2299            assert!(popped.is_some());
2300            assert_eq!(popped.as_ref().unwrap().value, 1);
2301
2302            // Drop popped -> should destroy in C++!
2303            drop(popped);
2304            assert!(destroyed1.load(Ordering::Relaxed));
2305            assert!(!destroyed2.load(Ordering::Relaxed));
2306
2307            // Drop list -> should destroy remaining in C++!
2308        }
2309        assert!(destroyed2.load(Ordering::Relaxed));
2310    }
2311
2312    #[test]
2313    fn test_interop_cpp_list_rust_ref_objects() {
2314        let destroyed1 = Arc::new(AtomicBool::new(false));
2315        let destroyed2 = Arc::new(AtomicBool::new(false));
2316
2317        unsafe {
2318            let cpp_list = cpp_create_ref_list();
2319            assert!(cpp_ref_list_is_empty(cpp_list));
2320
2321            let obj1 = SharedRefObject::new_ref_counted(1);
2322            let obj2 = SharedRefObject::new_ref_counted(2);
2323
2324            // Set destruction flags
2325            let raw1 = RefPtr::as_ptr(&obj1) as *mut SharedRefObject;
2326            (*raw1).destruction_flag = destroyed1.as_ptr() as *mut bool;
2327            let raw2 = RefPtr::as_ptr(&obj2) as *mut SharedRefObject;
2328            (*raw2).destruction_flag = destroyed2.as_ptr() as *mut bool;
2329
2330            // Push to C++ list (transfers ownership)
2331            cpp_ref_list_push_back(
2332                cpp_list,
2333                RefPtr::into_raw(obj1) as *mut SharedRefObject as *mut c_void,
2334            );
2335            cpp_ref_list_push_back(
2336                cpp_list,
2337                RefPtr::into_raw(obj2) as *mut SharedRefObject as *mut c_void,
2338            );
2339
2340            assert!(!destroyed1.load(Ordering::Relaxed));
2341            assert!(!destroyed2.load(Ordering::Relaxed));
2342
2343            // Pop one from C++
2344            let popped = cpp_ref_list_pop_front(cpp_list);
2345            assert!(!popped.is_null());
2346            assert_eq!(cpp_get_ref_object_value(popped), 1);
2347
2348            // Convert back to Rust RefPtr and drop -> should free in Rust!
2349            let popped_rust = RefPtr::from_raw(popped as *mut SharedRefObject);
2350            drop(popped_rust);
2351            assert!(destroyed1.load(Ordering::Relaxed));
2352            assert!(!destroyed2.load(Ordering::Relaxed));
2353
2354            // Destroy C++ list -> should destroy remaining in Rust!
2355            cpp_destroy_ref_list(cpp_list);
2356        }
2357        assert!(destroyed2.load(Ordering::Relaxed));
2358    }
2359}