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