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 mutable reference to the first element of the list, or `None` if it is empty.
348    pub fn front_mut(&mut self) -> Option<&mut P::Target> {
349        if self.is_empty() { None } else { unsafe { Some(&mut *self.head) } }
350    }
351
352    /// Returns a reference to the last element of the list, or `None` if it is empty.
353    pub fn back(&self) -> Option<&P::Target> {
354        let tail = self.get_tail();
355        if is_sentinel_ptr(tail) { None } else { unsafe { Some(&*tail) } }
356    }
357
358    /// Returns a mutable reference to the last element of the list, or `None` if it is empty.
359    pub fn back_mut(&mut self) -> Option<&mut P::Target> {
360        let tail = self.get_tail();
361        if is_sentinel_ptr(tail) { None } else { unsafe { Some(&mut *tail) } }
362    }
363
364    /// Pushes an element to the front of the list.
365    ///
366    /// # Panics
367    ///
368    /// Panics if the object is already in a container.
369    pub fn push_front(&mut self, ptr: P)
370    where
371        P: ManagedPtr,
372    {
373        // SAFETY: `P` is a `ManagedPtr`, which guarantees that the pointer is valid and that the
374        // object will outlive its reference from this list.
375        unsafe { self.push_front_raw(ptr) }
376    }
377
378    /// Pushes an element to the front of the list.
379    ///
380    /// # Panics
381    ///
382    /// Panics if the object is already in a container.
383    ///
384    /// # Safety
385    ///
386    /// The caller must ensure that `ptr` is a valid pointer to a `T` and that the object outlives
387    /// the reference from the list.
388    pub unsafe fn push_front_raw(&mut self, ptr: P) {
389        let head = self.head;
390        let mut cursor = CursorMut { list: self, current: head };
391        // SAFETY: `ptr` is valid and not in container (asserted inside insert_before_raw).
392        unsafe {
393            cursor.insert_before_raw(ptr);
394        }
395    }
396
397    /// Pushes an element to the back of the list.
398    ///
399    /// # Panics
400    ///
401    /// Panics if the object is already in a container.
402    pub fn push_back(&mut self, ptr: P)
403    where
404        P: ManagedPtr,
405    {
406        // SAFETY: `P` is a `ManagedPtr`, which guarantees that the pointer is valid and that the
407        // object will outlive its reference from this list.
408        unsafe { self.push_back_raw(ptr) }
409    }
410
411    /// Pushes an element to the back of the list.
412    ///
413    /// # Panics
414    ///
415    /// Panics if the object is already in a container.
416    ///
417    /// # Safety
418    ///
419    /// The caller must ensure that `ptr` is a valid pointer to an object that is not
420    /// currently in any list.
421    pub unsafe fn push_back_raw(&mut self, ptr: P) {
422        let sentinel = self.get_sentinel();
423        let mut cursor = CursorMut { list: self, current: sentinel };
424        // SAFETY: `ptr` is valid and not in container.
425        unsafe {
426            cursor.insert_before_raw(ptr);
427        }
428    }
429
430    /// Removes and returns the first element of the list, or `None` if it is empty.
431    pub fn pop_front(&mut self) -> Option<P> {
432        if self.is_empty() {
433            return None;
434        }
435        let head = self.head;
436        let mut cursor = CursorMut { list: self, current: head };
437        cursor.erase()
438    }
439
440    /// Removes and returns the last element of the list, or `None` if it is empty.
441    pub fn pop_back(&mut self) -> Option<P> {
442        if self.is_empty() {
443            return None;
444        }
445        let tail = self.get_tail();
446        let mut cursor = CursorMut { list: self, current: tail };
447        cursor.erase()
448    }
449
450    /// Removes all elements from the list.
451    pub fn clear(&mut self) {
452        while let Some(_) = self.pop_front() {}
453    }
454
455    /// Erases the given element from the list. Returns the erased element.
456    ///
457    /// # Safety
458    ///
459    /// The caller must ensure that `obj` is a valid reference to an object that is
460    /// currently in this list instance.
461    pub unsafe fn erase(&mut self, obj: &P::Target) -> Option<P> {
462        let ptr = obj as *const P::Target as *mut P::Target;
463        let node = obj.get_node();
464
465        if !node.in_container() {
466            return None;
467        }
468
469        let mut cursor = self.cursor_front_mut();
470        cursor.current = ptr;
471        cursor.erase()
472    }
473
474    /// Replaces the given element with `replacement`. Returns the replaced element.
475    ///
476    /// # Safety
477    ///
478    /// The caller must ensure that `obj` is a valid reference to an object that is
479    /// currently in this list instance, and `replacement` is not in any list.
480    pub unsafe fn replace_raw(&mut self, obj: &P::Target, replacement: P) -> Option<P> {
481        let ptr = obj as *const P::Target as *mut P::Target;
482        let node = obj.get_node();
483
484        if !node.in_container() {
485            return None;
486        }
487
488        let mut cursor = self.cursor_front_mut();
489        cursor.current = ptr;
490        // SAFETY: `replacement` is not in any list, and cursor is positioned at a valid element.
491        unsafe { cursor.replace_raw(replacement) }
492    }
493
494    /// Finds the first element matching the predicate, removes it from the list,
495    /// and returns it. Returns `None` if no element matches.
496    pub fn erase_if<F>(&mut self, mut f: F) -> Option<P>
497    where
498        F: FnMut(&P::Target) -> bool,
499    {
500        let mut cursor = self.cursor_front_mut();
501        while let Some(item) = cursor.get() {
502            if f(item) {
503                return cursor.erase();
504            } else {
505                cursor.move_next();
506            }
507        }
508        None
509    }
510
511    /// Finds the first element that satisfies the predicate.
512    pub fn find_if<F>(&self, mut f: F) -> Option<&P::Target>
513    where
514        F: FnMut(&P::Target) -> bool,
515    {
516        self.iter().find(|&x| f(x))
517    }
518
519    /// Returns a cursor positioned at the front of the list.
520    pub fn cursor_front_mut(&mut self) -> CursorMut<'_, P, Tag, S> {
521        let head = self.head;
522        CursorMut { list: self, current: head }
523    }
524
525    /// Returns a cursor positioned at the back (end sentinel) of the list.
526    pub fn cursor_back_mut(&mut self) -> CursorMut<'_, P, Tag, S> {
527        let sentinel = self.get_sentinel();
528        CursorMut { list: self, current: sentinel }
529    }
530
531    /// Returns a cursor positioned at the given element.
532    ///
533    /// # Safety
534    ///
535    /// The caller must ensure that `obj` is a member of this list.
536    /// It is undefined behavior to use the returned cursor if `obj` is not in the list,
537    /// or if it is in a different list.
538    pub unsafe fn cursor_at(&mut self, obj: &P::Target) -> CursorMut<'_, P, Tag, S> {
539        assert!(obj.get_node().in_container(), "Object must be in a container");
540        CursorMut { list: self, current: obj as *const P::Target as *mut P::Target }
541    }
542
543    /// Splices all elements from `other` onto the end of `self`.
544    ///
545    /// Upon completion, `other` is left empty.
546    ///
547    /// This operation is O(1).
548    pub fn splice(&mut self, other: &mut DoublyLinkedList<P, Tag, S>) {
549        self.cursor_back_mut().splice(other);
550    }
551
552    pub fn iter(&self) -> Iterator<'_, P, Tag> {
553        Iterator::new(self)
554    }
555
556    /// Returns a mutable bidirectional iterator over the elements of the list.
557    pub fn iter_mut(&mut self) -> IteratorMut<'_, P, Tag> {
558        IteratorMut::new(self)
559    }
560
561    /// Returns a unidirectional forward iterator over the elements of the list.
562    pub fn forward_iter(&self) -> ForwardIterator<'_, P, Tag> {
563        ForwardIterator::new(self.head)
564    }
565
566    /// Returns a unidirectional forward mutable iterator over the elements of the list.
567    pub fn forward_iter_mut(&mut self) -> ForwardIteratorMut<'_, P, Tag> {
568        ForwardIteratorMut::new(self.head)
569    }
570
571    /// Returns a unidirectional reverse iterator over the elements of the list.
572    pub fn reverse_iter(&self) -> ReverseIterator<'_, P, Tag> {
573        ReverseIterator::new(self.get_tail())
574    }
575
576    /// Returns a unidirectional reverse mutable iterator over the elements of the list.
577    pub fn reverse_iter_mut(&mut self) -> ReverseIteratorMut<'_, P, Tag> {
578        ReverseIteratorMut::new(self.get_tail())
579    }
580}
581
582impl<P, Tag> DoublyLinkedList<P, Tag, TrackingSize>
583where
584    P: PtrTraits,
585    P::Target: DoublyLinkedListContainable<P::Target, Tag>,
586{
587    /// Returns the number of elements in the list.
588    pub fn len(&self) -> usize {
589        self.size.get()
590    }
591}
592
593#[pinned_drop]
594impl<P, Tag, S> PinnedDrop for DoublyLinkedList<P, Tag, S>
595where
596    P: PtrTraits,
597    P::Target: DoublyLinkedListContainable<P::Target, Tag>,
598    S: SizeTracker,
599{
600    fn drop(self: Pin<&mut Self>) {
601        if P::IS_MANAGED {
602            // SAFETY: We are in drop, so the object won't move anymore.
603            let me = unsafe { self.get_unchecked_mut() };
604            me.clear();
605        } else {
606            debug_assert!(self.is_empty(), "List must be empty on destruction");
607            if S::IS_TRACKING {
608                debug_assert_eq!(self.size.get(), 0, "Size must be zero on destruction");
609            }
610        }
611    }
612}
613
614/// A cursor that can be used to iterate and modify a `DoublyLinkedList`.
615pub struct CursorMut<'a, P, Tag = DefaultObjectTag, S = NonTrackingSize>
616where
617    P: PtrTraits,
618    P::Target: DoublyLinkedListContainable<P::Target, Tag>,
619    S: SizeTracker,
620{
621    list: &'a mut DoublyLinkedList<P, Tag, S>,
622    current: *mut P::Target,
623}
624
625impl<'a, P, Tag, S> CursorMut<'a, P, Tag, S>
626where
627    P: PtrTraits,
628    P::Target: DoublyLinkedListContainable<P::Target, Tag>,
629    S: SizeTracker,
630{
631    pub fn get(&self) -> Option<&P::Target> {
632        if is_sentinel_ptr(self.current) { None } else { unsafe { Some(&*self.current) } }
633    }
634
635    pub fn get_mut(&mut self) -> Option<&mut P::Target> {
636        if is_sentinel_ptr(self.current) { None } else { unsafe { Some(&mut *self.current) } }
637    }
638
639    pub fn move_next(&mut self) {
640        if !is_sentinel_ptr(self.current) {
641            // SAFETY: `self.current` is valid current node (not sentinel).
642            let node = unsafe { self.list.get_node_ref(self.current) };
643            self.current = node.get_next();
644        }
645    }
646
647    pub fn move_prev(&mut self) {
648        if !is_sentinel_ptr(self.current) {
649            // SAFETY: `self.current` is valid current node (not sentinel).
650            let node = unsafe { self.list.get_node_ref(self.current) };
651            let prev = node.get_prev();
652            if self.current == self.list.head {
653                self.current = self.list.get_sentinel(); // Move to end.
654            } else {
655                self.current = prev;
656            }
657        } else {
658            // If we are at end (sentinel), moving prev should take us to tail.
659            self.current = self.list.get_tail();
660        }
661    }
662
663    /// Inserts a new element after the current position.
664    ///
665    /// # Panics
666    ///
667    /// Panics if the object is already in a container, or if the cursor is positioned
668    /// at the end sentinel.
669    pub fn insert_after(&mut self, ptr: P)
670    where
671        P: ManagedPtr,
672    {
673        // SAFETY: `P` is a `ManagedPtr`, which guarantees that the pointer is valid and that the
674        // object will outlive its reference from this list. `self.current` is checked to not be
675        // a sentinel.
676        unsafe { self.insert_after_raw(ptr) }
677    }
678
679    /// Inserts a new element after the current position.
680    ///
681    /// # Panics
682    ///
683    /// Panics if the object is already in a container.
684    ///
685    /// # Safety
686    ///
687    /// The caller must ensure that `ptr` is a valid pointer to a `T` and that the object outlives
688    /// the reference from the list.
689    pub unsafe fn insert_after_raw(&mut self, ptr: P) {
690        assert!(!is_sentinel_ptr(self.current), "Cannot insert after end sentinel");
691        let raw = P::into_raw(ptr);
692        // SAFETY: `raw` is valid.
693        let node = unsafe { self.list.get_node_ref(raw) };
694        assert!(!node.in_container());
695
696        // SAFETY: `self.current` is valid current node (not sentinel).
697        let current_node = unsafe { self.list.get_node_ref(self.current) };
698        let next = current_node.get_next();
699
700        let current_save = self.current;
701        self.current = next;
702        // SAFETY: `raw` is a single node, and we are inserting it before `next`
703        // (which is equivalent to inserting after `current_save`).
704        unsafe {
705            self.insert_chain_before(raw, raw, 1);
706        }
707        self.current = current_save;
708    }
709
710    /// Replaces the element at the current position with `replacement`. Returns the replaced
711    /// element.
712    ///
713    /// # Panics
714    ///
715    /// Panics if the object is already in a container.
716    pub fn replace(&mut self, replacement: P) -> Option<P>
717    where
718        P: ManagedPtr,
719    {
720        // SAFETY: `P` is a `ManagedPtr`, which guarantees that the pointer is valid and that the
721        // object will outlive its reference from this list.
722        unsafe { self.replace_raw(replacement) }
723    }
724
725    /// Replaces the element at the current position with `replacement`. Returns the replaced
726    /// element.
727    ///
728    /// # Panics
729    ///
730    /// Panics if the object is already in a container.
731    ///
732    /// # Safety
733    ///
734    /// The caller must ensure that `replacement` is a valid pointer to a `T` and that the object
735    /// outlives the reference from the list.
736    pub unsafe fn replace_raw(&mut self, replacement: P) -> Option<P> {
737        if is_sentinel_ptr(self.current) {
738            return None;
739        }
740        // SAFETY: `replacement` is not in any list, and we are inserting it before a valid cursor
741        // position.
742        unsafe {
743            self.insert_before_raw(replacement);
744        }
745        self.erase()
746    }
747
748    /// Inserts a new element before the current position.
749    ///
750    /// # Panics
751    ///
752    /// Panics if the object is already in a container.
753    pub fn insert_before(&mut self, ptr: P)
754    where
755        P: ManagedPtr,
756    {
757        // SAFETY: `P` is a `ManagedPtr`, which guarantees that the pointer is valid and that the
758        // object will outlive its reference from this list.
759        unsafe { self.insert_before_raw(ptr) }
760    }
761
762    /// Inserts a new element before the current position.
763    ///
764    /// # Panics
765    ///
766    /// Panics if the object is already in a container.
767    ///
768    /// # Safety
769    ///
770    /// The caller must ensure that `ptr` is a valid pointer to a `T` and that the object outlives
771    /// the reference from the list.
772    pub unsafe fn insert_before_raw(&mut self, ptr: P) {
773        let raw = P::into_raw(ptr);
774        // SAFETY: `raw` is valid.
775        let node = unsafe { self.list.get_node_ref(raw) };
776        assert!(!node.in_container());
777
778        // SAFETY: `raw` is a single node, so it is a valid chain of 1 element.
779        unsafe {
780            self.insert_chain_before(raw, raw, 1);
781        }
782    }
783
784    /// Private helper to insert a chain of nodes before the current position.
785    ///
786    /// # Safety
787    ///
788    /// The caller must ensure:
789    /// - `chain_head` and `chain_tail` are valid pointers to elements.
790    /// - They form a valid doubly linked chain.
791    /// - The chain is not empty.
792    /// - The elements in the chain are NOT currently in any list.
793    /// - `count` is the exact number of elements in the chain.
794    unsafe fn insert_chain_before(
795        &mut self,
796        chain_head: *mut P::Target,
797        chain_tail: *mut P::Target,
798        count: usize,
799    ) {
800        // SAFETY: `chain_tail` is valid from caller.
801        let chain_tail_node = unsafe { self.list.get_node_ref(chain_tail) };
802        chain_tail_node.set_next(self.current);
803
804        if self.list.is_empty() {
805            // SAFETY: `chain_head` is valid from caller.
806            let chain_head_node = unsafe { self.list.get_node_ref(chain_head) };
807            chain_head_node.set_prev(chain_tail);
808            self.list.head = chain_head;
809        } else {
810            let prev = if self.current == self.list.head || is_sentinel_ptr(self.current) {
811                self.list.get_tail()
812            } else {
813                // SAFETY: `self.current` is valid.
814                let current_node = unsafe { self.list.get_node_ref(self.current) };
815                current_node.get_prev()
816            };
817
818            // SAFETY: `chain_head` is valid from caller.
819            let chain_head_node = unsafe { self.list.get_node_ref(chain_head) };
820            chain_head_node.set_prev(prev);
821
822            // 1. Update predecessor's next if we are not inserting at head
823            if self.current != self.list.head {
824                // SAFETY: `prev` is valid predecessor.
825                let prev_node = unsafe { self.list.get_node_ref(prev) };
826                prev_node.set_next(chain_head);
827            }
828
829            // 2. Update successor's prev if we are not inserting at sentinel
830            if !is_sentinel_ptr(self.current) {
831                // SAFETY: `self.current` is valid.
832                let current_node = unsafe { self.list.get_node_ref(self.current) };
833                current_node.set_prev(chain_tail);
834            }
835
836            // 3. Update head if we are inserting at head
837            if self.current == self.list.head {
838                self.list.head = chain_head;
839            }
840
841            // 4. Update tail if we are inserting at sentinel
842            if is_sentinel_ptr(self.current) {
843                // SAFETY: `chain_tail` becomes the new tail.
844                unsafe {
845                    self.list.set_tail(chain_tail);
846                }
847            }
848        }
849
850        if S::IS_TRACKING {
851            self.list.size.set(self.list.size.get() + count);
852        }
853    }
854
855    /// Splices the elements of `other` into the list at the current cursor position.
856    ///
857    /// All elements from `other` are moved into `self.list` and inserted immediately
858    /// *before* the element currently pointed to by the cursor.
859    ///
860    /// - If the cursor is positioned at a valid element, `other` is inserted before it.
861    /// - If the cursor is positioned at the end sentinel (i.e., `cursor.get()` returns `None`),
862    ///   `other` is appended to the end of the list (after the current tail).
863    /// - If the list is empty, `other` becomes the new content of the list.
864    ///
865    /// Upon completion, `other` is left empty.
866    ///
867    /// This operation is O(1).
868    pub fn splice(&mut self, other: &mut DoublyLinkedList<P, Tag, S>) {
869        if other.is_empty() {
870            return;
871        }
872
873        let other_head = other.head;
874        let other_tail = other.get_tail();
875        let count = if S::IS_TRACKING { other.size.get() } else { 0 };
876
877        // SAFETY: We are moving elements from `other` which is a valid list,
878        // so they are valid and not in any other list.
879        unsafe {
880            self.insert_chain_before(other_head, other_tail, count);
881        }
882
883        other.head = other.get_sentinel();
884        if S::IS_TRACKING {
885            other.size.set(0);
886        }
887    }
888
889    /// Splits the list immediately after the current cursor position, moving all elements
890    /// after the cursor into `dest`, inserted before `dest`'s current position.
891    ///
892    /// The current list retains all elements up to and including the current element.
893    ///
894    /// If the cursor is positioned at the tail of the list, no elements are moved.
895    ///
896    /// # Panics
897    ///
898    /// Panics if the cursor is positioned at the end sentinel.
899    ///
900    /// This operation is O(1) for lists with non-tracking size.
901    pub fn split_after(&mut self, dest: &mut CursorMut<'_, P, Tag, S>) {
902        assert!(!is_sentinel_ptr(self.current), "Cannot split after end sentinel");
903
904        // SAFETY: `self.current` is not sentinel.
905        let curr_node = unsafe { self.list.get_node_ref(self.current) };
906        let next_ptr = curr_node.get_next();
907
908        // If cursor is at the tail, there are no elements after it.
909        if is_sentinel_ptr(next_ptr) {
910            return;
911        }
912
913        let chain_head = next_ptr;
914        let chain_tail = self.list.get_tail();
915
916        let mut count = 0;
917        if S::IS_TRACKING {
918            let mut p = chain_head;
919            let sentinel = self.list.get_sentinel();
920            while p != sentinel {
921                count += 1;
922                // SAFETY: `p` is in the chain.
923                p = unsafe { self.list.get_node_ref(p) }.get_next();
924            }
925            self.list.size.set(self.list.size.get() - count);
926        }
927
928        // Update self.list: `self.current` becomes the new tail.
929        curr_node.set_next(self.list.get_sentinel());
930        unsafe {
931            self.list.set_tail(self.current);
932        }
933
934        // Insert the extracted chain before dest's current position.
935        // SAFETY: The chain [chain_head .. chain_tail] is valid, detached from self.list,
936        // and count is exact.
937        unsafe {
938            dest.insert_chain_before(chain_head, chain_tail, count);
939        }
940    }
941
942    /// Splits the list immediately before the current cursor position, moving all elements
943    /// before the cursor into `dest`, inserted before `dest`'s current position.
944    ///
945    /// The current list retains all elements from the current position to the end of the list.
946    ///
947    /// - If the cursor is positioned at the head of the list, no elements are moved.
948    /// - If the cursor is positioned at the end sentinel, all elements of the list are moved
949    ///   into `dest`, leaving this list empty.
950    /// - If the cursor is positioned at an element between head and sentinel, all elements from
951    ///   head up to (and excluding) the current element are moved into `dest`.
952    ///
953    /// Upon completion, the cursor remains positioned at the same element (which is now the new
954    /// head of this list, or the sentinel).
955    ///
956    /// This operation is O(1) for lists with non-tracking size.
957    pub fn split_before(&mut self, dest: &mut CursorMut<'_, P, Tag, S>) {
958        // Case 1: Cursor is at head. No elements before head.
959        if self.current == self.list.head {
960            return;
961        }
962
963        // Case 2: Cursor is at sentinel. All elements in list are before sentinel.
964        if is_sentinel_ptr(self.current) {
965            if self.list.is_empty() {
966                return;
967            }
968            let chain_head = self.list.head;
969            let chain_tail = self.list.get_tail();
970            let count = if S::IS_TRACKING {
971                let c = self.list.size.get();
972                self.list.size.set(0);
973                c
974            } else {
975                0
976            };
977
978            self.list.head = self.list.get_sentinel();
979
980            // SAFETY: The chain [chain_head .. chain_tail] is valid, detached from self.list,
981            // and count is exact.
982            unsafe {
983                dest.insert_chain_before(chain_head, chain_tail, count);
984            }
985            return;
986        }
987
988        // Case 3: Cursor is at an interior element B.
989        // Elements before B are [head .. B.prev].
990        let b = self.current;
991        let b_node = unsafe { self.list.get_node_ref(b) };
992        let chain_head = self.list.head;
993        let chain_tail = b_node.get_prev();
994        let old_tail = self.list.get_tail();
995
996        let mut count = 0;
997        if S::IS_TRACKING {
998            let mut p = chain_head;
999            while p != b {
1000                count += 1;
1001                // SAFETY: `p` is in the chain.
1002                p = unsafe { self.list.get_node_ref(p) }.get_next();
1003            }
1004            self.list.size.set(self.list.size.get() - count);
1005        }
1006
1007        // Update self.list: B becomes the new head, and its prev points to old_tail.
1008        self.list.head = b;
1009        b_node.set_prev(old_tail);
1010
1011        // Insert the extracted chain before dest's current position.
1012        // SAFETY: The chain [chain_head .. chain_tail] is valid, detached from self.list,
1013        // and count is exact.
1014        unsafe {
1015            dest.insert_chain_before(chain_head, chain_tail, count);
1016        }
1017    }
1018
1019    pub fn erase(&mut self) -> Option<P> {
1020        if is_sentinel_ptr(self.current) {
1021            return None;
1022        }
1023        let ptr = self.current;
1024        // SAFETY: `ptr` is valid current node.
1025        let node = unsafe { self.list.get_node_ref(ptr) };
1026        let next = node.get_next();
1027        let prev = node.get_prev();
1028
1029        self.list.size.decrement();
1030
1031        if self.list.head == ptr && is_sentinel_ptr(next) {
1032            self.list.head = self.list.get_sentinel();
1033        } else {
1034            // 1. Update predecessor's next if we are not erasing head
1035            if self.current != self.list.head {
1036                // SAFETY: `prev` is valid predecessor.
1037                let prev_node = unsafe { self.list.get_node_ref(prev) };
1038                prev_node.set_next(next);
1039            }
1040
1041            // 2. Update successor's prev if we are not erasing tail
1042            if !is_sentinel_ptr(next) {
1043                // SAFETY: `next` is valid successor.
1044                let next_node = unsafe { self.list.get_node_ref(next) };
1045                next_node.set_prev(prev);
1046            }
1047
1048            // 3. Update head if we are erasing head
1049            if self.current == self.list.head {
1050                self.list.head = next;
1051            }
1052
1053            // 4. Update tail if we are erasing tail
1054            if is_sentinel_ptr(next) {
1055                // SAFETY: `prev` becomes the new tail.
1056                unsafe {
1057                    self.list.set_tail(prev);
1058                }
1059            }
1060        }
1061
1062        node.set_next(core::ptr::null_mut());
1063        node.set_prev(core::ptr::null_mut());
1064
1065        self.current = next;
1066        // SAFETY: `ptr` was popped, safe to reconstruct.
1067        Some(unsafe { P::from_raw(ptr) })
1068    }
1069}
1070
1071/// An iterator over the elements of a `DoublyLinkedList`.
1072pub struct Iterator<'a, P, Tag = DefaultObjectTag>
1073where
1074    P: PtrTraits,
1075    P::Target: DoublyLinkedListContainable<P::Target, Tag>,
1076{
1077    front: ForwardIterator<'a, P, Tag>,
1078    back: ReverseIterator<'a, P, Tag>,
1079}
1080
1081impl<'a, P, Tag> Iterator<'a, P, Tag>
1082where
1083    P: PtrTraits,
1084    P::Target: DoublyLinkedListContainable<P::Target, Tag>,
1085{
1086    fn new<S: SizeTracker>(list: &'a DoublyLinkedList<P, Tag, S>) -> Self {
1087        if list.is_empty() {
1088            Self {
1089                front: ForwardIterator::new(crate::make_sentinel_null()),
1090                back: ReverseIterator::new(crate::make_sentinel_null()),
1091            }
1092        } else {
1093            Self {
1094                front: ForwardIterator::new(list.head),
1095                back: ReverseIterator::new(list.get_tail()),
1096            }
1097        }
1098    }
1099}
1100
1101impl<'a, P, Tag> core::iter::Iterator for Iterator<'a, P, Tag>
1102where
1103    P: PtrTraits,
1104    P::Target: DoublyLinkedListContainable<P::Target, Tag>,
1105{
1106    type Item = &'a P::Target;
1107
1108    fn next(&mut self) -> Option<Self::Item> {
1109        let met = self.front.current == self.back.current;
1110        let item = self.front.next();
1111        if item.is_some() {
1112            if met {
1113                self.front.current = crate::make_sentinel_null();
1114                self.back.current = crate::make_sentinel_null();
1115            }
1116        }
1117        item
1118    }
1119}
1120
1121impl<'a, P, Tag> core::iter::DoubleEndedIterator for Iterator<'a, P, Tag>
1122where
1123    P: PtrTraits,
1124    P::Target: DoublyLinkedListContainable<P::Target, Tag>,
1125{
1126    fn next_back(&mut self) -> Option<Self::Item> {
1127        let met = self.front.current == self.back.current;
1128        let item = self.back.next();
1129        if item.is_some() {
1130            if met {
1131                self.front.current = crate::make_sentinel_null();
1132                self.back.current = crate::make_sentinel_null();
1133            }
1134        }
1135        item
1136    }
1137}
1138
1139/// A unidirectional forward iterator over the elements of a `DoublyLinkedList`.
1140pub struct ForwardIterator<'a, P, Tag = DefaultObjectTag>
1141where
1142    P: PtrTraits,
1143    P::Target: DoublyLinkedListContainable<P::Target, Tag>,
1144{
1145    current: *mut P::Target,
1146    _phantom: core::marker::PhantomData<&'a (P, Tag)>,
1147}
1148
1149impl<'a, P, Tag> ForwardIterator<'a, P, Tag>
1150where
1151    P: PtrTraits,
1152    P::Target: DoublyLinkedListContainable<P::Target, Tag>,
1153{
1154    fn new(current: *mut P::Target) -> Self {
1155        Self { current, _phantom: core::marker::PhantomData }
1156    }
1157
1158    /// Creates an iterator starting from a specific element.
1159    ///
1160    /// # Panics
1161    ///
1162    /// Panics if the object is not in a container.
1163    pub fn from_element(obj: &'a P::Target) -> Self {
1164        assert!(obj.get_node().in_container(), "Object must be in a container");
1165        Self { current: obj as *const _ as *mut _, _phantom: core::marker::PhantomData }
1166    }
1167}
1168
1169impl<'a, P, Tag> core::iter::Iterator for ForwardIterator<'a, P, Tag>
1170where
1171    P: PtrTraits,
1172    P::Target: DoublyLinkedListContainable<P::Target, Tag>,
1173{
1174    type Item = &'a P::Target;
1175
1176    fn next(&mut self) -> Option<Self::Item> {
1177        if is_sentinel_ptr(self.current) {
1178            None
1179        } else {
1180            // SAFETY: `self.current` is not a sentinel, so it is a valid, aligned pointer to an
1181            // element.  The list is guaranteed to be immutable for the lifetime `'a` of the
1182            // iterator.
1183            let current = unsafe { &*self.current };
1184            self.current = current.get_node().get_next();
1185            Some(current)
1186        }
1187    }
1188}
1189
1190/// A unidirectional reverse iterator over the elements of a `DoublyLinkedList`.
1191pub struct ReverseIterator<'a, P, Tag = DefaultObjectTag>
1192where
1193    P: PtrTraits,
1194    P::Target: DoublyLinkedListContainable<P::Target, Tag>,
1195{
1196    current: *mut P::Target,
1197    _phantom: core::marker::PhantomData<&'a (P, Tag)>,
1198}
1199
1200impl<'a, P, Tag> ReverseIterator<'a, P, Tag>
1201where
1202    P: PtrTraits,
1203    P::Target: DoublyLinkedListContainable<P::Target, Tag>,
1204{
1205    fn new(current: *mut P::Target) -> Self {
1206        Self { current, _phantom: core::marker::PhantomData }
1207    }
1208
1209    /// Creates a reverse iterator starting from a specific element.
1210    ///
1211    /// # Panics
1212    ///
1213    /// Panics if the object is not in a container.
1214    pub fn from_element(obj: &'a P::Target) -> Self {
1215        assert!(obj.get_node().in_container(), "Object must be in a container");
1216        Self { current: obj as *const _ as *mut _, _phantom: core::marker::PhantomData }
1217    }
1218}
1219
1220impl<'a, P, Tag> core::iter::Iterator for ReverseIterator<'a, P, Tag>
1221where
1222    P: PtrTraits,
1223    P::Target: DoublyLinkedListContainable<P::Target, Tag>,
1224{
1225    type Item = &'a P::Target;
1226
1227    fn next(&mut self) -> Option<Self::Item> {
1228        if is_sentinel_ptr(self.current) {
1229            None
1230        } else {
1231            // SAFETY: `self.current` is not a sentinel, so it is a valid, aligned pointer to an
1232            // element.  The list is guaranteed to be immutable for the lifetime `'a` of the
1233            // iterator.
1234            let current = unsafe { &*self.current };
1235            let prev = current.get_node().get_prev();
1236
1237            // SAFETY: `prev` must be a valid pointer because `current` is in the list.  In a
1238            // circular doubly linked list, prev is never null.
1239            let prev_node = unsafe { &*prev }.get_node();
1240            if is_sentinel_ptr(prev_node.get_next()) {
1241                // We have looped around the head and landed on the tail.
1242                // Set current to the sentinel to terminate iteration.
1243                self.current = prev_node.get_next();
1244            } else {
1245                self.current = prev;
1246            }
1247            Some(current)
1248        }
1249    }
1250}
1251
1252/// A mutable bidirectional iterator over the elements of a `DoublyLinkedList`.
1253pub struct IteratorMut<'a, P, Tag = DefaultObjectTag>
1254where
1255    P: PtrTraits,
1256    P::Target: DoublyLinkedListContainable<P::Target, Tag>,
1257{
1258    front: ForwardIteratorMut<'a, P, Tag>,
1259    back: ReverseIteratorMut<'a, P, Tag>,
1260}
1261
1262impl<'a, P, Tag> IteratorMut<'a, P, Tag>
1263where
1264    P: PtrTraits,
1265    P::Target: DoublyLinkedListContainable<P::Target, Tag>,
1266{
1267    fn new<S: SizeTracker>(list: &'a mut DoublyLinkedList<P, Tag, S>) -> Self {
1268        if list.is_empty() {
1269            Self {
1270                front: ForwardIteratorMut::new(crate::make_sentinel_null()),
1271                back: ReverseIteratorMut::new(crate::make_sentinel_null()),
1272            }
1273        } else {
1274            let tail = list.get_tail();
1275            Self { front: ForwardIteratorMut::new(list.head), back: ReverseIteratorMut::new(tail) }
1276        }
1277    }
1278}
1279
1280impl<'a, P, Tag> core::iter::Iterator for IteratorMut<'a, P, Tag>
1281where
1282    P: PtrTraits,
1283    P::Target: DoublyLinkedListContainable<P::Target, Tag>,
1284{
1285    type Item = &'a mut P::Target;
1286
1287    fn next(&mut self) -> Option<Self::Item> {
1288        let met = self.front.current == self.back.current;
1289        let item = self.front.next();
1290        if item.is_some() && met {
1291            self.front.current = crate::make_sentinel_null();
1292            self.back.current = crate::make_sentinel_null();
1293        }
1294        item
1295    }
1296}
1297
1298impl<'a, P, Tag> core::iter::DoubleEndedIterator for IteratorMut<'a, P, Tag>
1299where
1300    P: PtrTraits,
1301    P::Target: DoublyLinkedListContainable<P::Target, Tag>,
1302{
1303    fn next_back(&mut self) -> Option<Self::Item> {
1304        let met = self.front.current == self.back.current;
1305        let item = self.back.next();
1306        if item.is_some() && met {
1307            self.front.current = crate::make_sentinel_null();
1308            self.back.current = crate::make_sentinel_null();
1309        }
1310        item
1311    }
1312}
1313
1314/// A unidirectional forward mutable iterator over the elements of a `DoublyLinkedList`.
1315pub struct ForwardIteratorMut<'a, P, Tag = DefaultObjectTag>
1316where
1317    P: PtrTraits,
1318    P::Target: DoublyLinkedListContainable<P::Target, Tag>,
1319{
1320    current: *mut P::Target,
1321    _phantom: core::marker::PhantomData<&'a mut (P, Tag)>,
1322}
1323
1324impl<'a, P, Tag> ForwardIteratorMut<'a, P, Tag>
1325where
1326    P: PtrTraits,
1327    P::Target: DoublyLinkedListContainable<P::Target, Tag>,
1328{
1329    fn new(current: *mut P::Target) -> Self {
1330        Self { current, _phantom: core::marker::PhantomData }
1331    }
1332
1333    /// Creates an iterator starting from a specific element.
1334    ///
1335    /// # Panics
1336    ///
1337    /// Panics if the object is not in a container.
1338    pub fn from_element(obj: &'a mut P::Target) -> Self {
1339        assert!(obj.get_node().in_container(), "Object must be in a container");
1340        Self { current: obj as *mut _, _phantom: core::marker::PhantomData }
1341    }
1342}
1343
1344impl<'a, P, Tag> core::iter::Iterator for ForwardIteratorMut<'a, P, Tag>
1345where
1346    P: PtrTraits,
1347    P::Target: DoublyLinkedListContainable<P::Target, Tag>,
1348{
1349    type Item = &'a mut P::Target;
1350
1351    fn next(&mut self) -> Option<Self::Item> {
1352        if is_sentinel_ptr(self.current) {
1353            None
1354        } else {
1355            // SAFETY: `self.current` is not a sentinel, so it is a valid, aligned pointer to an
1356            // element. The list is exclusively borrowed for lifetime `'a`, and each element in the
1357            // intrusive list is distinct, so yielding `&'a mut P::Target` one-by-one is sound.
1358            let current = unsafe { &mut *self.current };
1359            self.current = current.get_node().get_next();
1360            Some(current)
1361        }
1362    }
1363}
1364
1365/// A unidirectional reverse mutable iterator over the elements of a `DoublyLinkedList`.
1366pub struct ReverseIteratorMut<'a, P, Tag = DefaultObjectTag>
1367where
1368    P: PtrTraits,
1369    P::Target: DoublyLinkedListContainable<P::Target, Tag>,
1370{
1371    current: *mut P::Target,
1372    _phantom: core::marker::PhantomData<&'a mut (P, Tag)>,
1373}
1374
1375impl<'a, P, Tag> ReverseIteratorMut<'a, P, Tag>
1376where
1377    P: PtrTraits,
1378    P::Target: DoublyLinkedListContainable<P::Target, Tag>,
1379{
1380    fn new(current: *mut P::Target) -> Self {
1381        Self { current, _phantom: core::marker::PhantomData }
1382    }
1383
1384    /// Creates a reverse iterator starting from a specific element.
1385    ///
1386    /// # Panics
1387    ///
1388    /// Panics if the object is not in a container.
1389    pub fn from_element(obj: &'a mut P::Target) -> Self {
1390        assert!(obj.get_node().in_container(), "Object must be in a container");
1391        Self { current: obj as *mut _, _phantom: core::marker::PhantomData }
1392    }
1393}
1394
1395impl<'a, P, Tag> core::iter::Iterator for ReverseIteratorMut<'a, P, Tag>
1396where
1397    P: PtrTraits,
1398    P::Target: DoublyLinkedListContainable<P::Target, Tag>,
1399{
1400    type Item = &'a mut P::Target;
1401
1402    fn next(&mut self) -> Option<Self::Item> {
1403        if is_sentinel_ptr(self.current) {
1404            None
1405        } else {
1406            // SAFETY: `self.current` is not a sentinel, so it is a valid, aligned pointer to an
1407            // element. The list is exclusively borrowed for lifetime `'a`, and each element in the
1408            // intrusive list is distinct, so yielding `&'a mut P::Target` one-by-one is sound.
1409            let current = unsafe { &mut *self.current };
1410            let prev = current.get_node().get_prev();
1411
1412            // SAFETY: `prev` must be a valid pointer because `current` is in the list. In a
1413            // circular doubly linked list, prev is never null.
1414            let prev_node = unsafe { &*prev }.get_node();
1415            if is_sentinel_ptr(prev_node.get_next()) {
1416                self.current = prev_node.get_next();
1417            } else {
1418                self.current = prev;
1419            }
1420            Some(current)
1421        }
1422    }
1423}
1424
1425/// Removes an object from its container without a reference to the container.
1426///
1427/// # Safety
1428///
1429/// The caller must ensure that `obj` is currently in a valid list instance that does NOT
1430/// track its size (uses `NonTrackingSize`), and that no other mutable references to that
1431/// list are active.
1432pub unsafe fn remove_from_container<T, Tag, P>(obj: &T) -> Option<P>
1433where
1434    P: PtrTraits<Target = T>,
1435    T: DoublyLinkedListContainable<T, Tag>,
1436{
1437    let node = obj.get_node();
1438    if !node.in_container() {
1439        return None;
1440    }
1441
1442    let mut current = obj as *const T as *mut T;
1443    unsafe {
1444        while !is_sentinel_ptr(current) {
1445            current = (*current).get_node().get_next();
1446        }
1447
1448        let list_ptr = crate::sentinel::unmake_sentinel::<
1449            DoublyLinkedList<P, Tag, NonTrackingSize>,
1450            T,
1451        >(current);
1452        let list_ref = &mut *list_ptr;
1453
1454        list_ref.erase(obj)
1455    }
1456}
1457
1458impl<P, Tag, S> core::fmt::Debug for DoublyLinkedList<P, Tag, S>
1459where
1460    P: PtrTraits,
1461    P::Target: DoublyLinkedListContainable<P::Target, Tag> + core::fmt::Debug,
1462    S: SizeTracker,
1463{
1464    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
1465        f.debug_list().entries(self.iter()).finish()
1466    }
1467}
1468
1469#[cfg(test)]
1470mod tests {
1471    extern crate alloc;
1472    use super::*;
1473    use crate::intrusive_container_test_support::*;
1474    use crate::ref_ptr::RefPtr;
1475    use crate::unique_ptr::UniquePtr;
1476    use core::ffi::c_void;
1477    use pin_init::stack_pin_init;
1478
1479    #[derive(crate::DoublyLinkedListContainable, crate::Recyclable)]
1480    struct TestObject {
1481        value: i32,
1482        #[dll_node]
1483        node: DoublyLinkedListNode<TestObject>,
1484    }
1485
1486    impl TestObject {
1487        fn new(value: i32) -> Self {
1488            Self { value, node: DoublyLinkedListNode::new() }
1489        }
1490    }
1491
1492    impl TestValue for TestObject {
1493        fn new(value: i32) -> Self {
1494            Self::new(value)
1495        }
1496    }
1497
1498    ::zr::static_assert!(
1499        core::mem::size_of::<DoublyLinkedList<*mut TestObject>>()
1500            == core::mem::size_of::<*mut TestObject>()
1501    );
1502    ::zr::static_assert!(
1503        core::mem::align_of::<DoublyLinkedList<*mut TestObject>>()
1504            == core::mem::align_of::<*mut TestObject>()
1505    );
1506
1507    ::zr::static_assert!(
1508        core::mem::size_of::<DoublyLinkedList<*mut TestObject, DefaultObjectTag, TrackingSize>>()
1509            == 2 * core::mem::size_of::<*mut TestObject>()
1510    );
1511    ::zr::static_assert!(
1512        core::mem::align_of::<DoublyLinkedList<*mut TestObject, DefaultObjectTag, TrackingSize>>()
1513            == core::mem::align_of::<*mut TestObject>()
1514    );
1515
1516    ::zr::static_assert!(
1517        core::mem::size_of::<ForwardIterator<'_, *mut TestObject>>()
1518            == core::mem::size_of::<*mut TestObject>()
1519    );
1520    ::zr::static_assert!(
1521        core::mem::align_of::<ForwardIterator<'_, *mut TestObject>>()
1522            == core::mem::align_of::<*mut TestObject>()
1523    );
1524
1525    ::zr::static_assert!(
1526        core::mem::size_of::<ReverseIterator<'_, *mut TestObject>>()
1527            == core::mem::size_of::<*mut TestObject>()
1528    );
1529    ::zr::static_assert!(
1530        core::mem::align_of::<ReverseIterator<'_, *mut TestObject>>()
1531            == core::mem::align_of::<*mut TestObject>()
1532    );
1533
1534    #[derive(crate::DoublyLinkedListContainable, crate::Recyclable)]
1535    struct UniqueTestObject {
1536        value: i32,
1537        #[dll_node]
1538        node: DoublyLinkedListNode<UniqueTestObject>,
1539    }
1540
1541    impl UniqueTestObject {
1542        fn new(value: i32) -> Self {
1543            Self { value, node: DoublyLinkedListNode::new() }
1544        }
1545    }
1546
1547    impl TestValue for UniqueTestObject {
1548        fn new(value: i32) -> Self {
1549            Self::new(value)
1550        }
1551    }
1552
1553    #[fbl::ref_counted]
1554    #[derive(crate::DoublyLinkedListContainable, crate::Recyclable)]
1555    #[repr(C)]
1556    pub struct RefTestObject {
1557        value: i32,
1558        #[dll_node]
1559        node: DoublyLinkedListNode<RefTestObject>,
1560    }
1561
1562    impl TestValue for RefTestObject {
1563        fn new_ref_counted(value: i32) -> RefPtr<Self> {
1564            crate::make_ref_counted!(RefTestObject {
1565                value: value,
1566                node: DoublyLinkedListNode::new()
1567            })
1568            .unwrap()
1569        }
1570    }
1571
1572    macro_rules! generate_list_tests {
1573        ($mod_name:ident, $ptr_type:ty, $factory_type:ty, $get_val:expr, $push:expr) => {
1574            mod $mod_name {
1575                use super::*;
1576
1577                #[test]
1578                fn test_basic() {
1579                    let mut factory = <$factory_type>::new();
1580                    stack_pin_init!(let list = DoublyLinkedList::<$ptr_type>::new());
1581                    let list = unsafe { list.get_unchecked_mut() };
1582                    assert!(list.is_empty());
1583
1584                    let obj1 = factory.create(1);
1585                    let obj2 = factory.create(2);
1586
1587                    $push(list, obj1);
1588                    $push(list, obj2);
1589
1590                    assert!(!list.is_empty());
1591
1592                    let mut iter = list.iter();
1593                    assert_eq!(iter.next().unwrap().value, 2);
1594                    assert_eq!(iter.next().unwrap().value, 1);
1595                    assert!(iter.next().is_none());
1596
1597                    list.clear();
1598                    assert!(list.is_empty());
1599                }
1600
1601                #[test]
1602                fn test_double_ended_iterator() {
1603                    let mut factory = <$factory_type>::new();
1604                    stack_pin_init!(let list = DoublyLinkedList::<$ptr_type>::new());
1605                    let list = unsafe { list.get_unchecked_mut() };
1606                    let obj1 = factory.create(1);
1607                    let obj2 = factory.create(2);
1608                    let obj3 = factory.create(3);
1609
1610                    $push(list, obj1);
1611                    $push(list, obj2);
1612                    $push(list, obj3);
1613
1614                    let mut iter = list.iter();
1615                    assert_eq!(iter.next().unwrap().value, 3);
1616                    assert_eq!(iter.next_back().unwrap().value, 1);
1617                    assert_eq!(iter.next().unwrap().value, 2);
1618                    assert!(iter.next().is_none());
1619                    assert!(iter.next_back().is_none());
1620
1621                    list.clear();
1622                }
1623
1624                #[test]
1625                fn test_explicit_pops() {
1626                    let mut factory = <$factory_type>::new();
1627                    stack_pin_init!(let list = DoublyLinkedList::<$ptr_type>::new());
1628                    let list = unsafe { list.get_unchecked_mut() };
1629                    let obj1 = factory.create(1);
1630                    let obj2 = factory.create(2);
1631
1632                    $push(list, obj1);
1633                    $push(list, obj2);
1634
1635                    let p1 = list.pop_front();
1636                    assert!(p1.is_some());
1637                    let p2 = list.pop_front();
1638                    assert!(p2.is_some());
1639                    assert!(list.pop_front().is_none());
1640                }
1641
1642                #[test]
1643                fn test_cursor_move_prev() {
1644                    let mut factory = <$factory_type>::new();
1645                    stack_pin_init!(let list = DoublyLinkedList::<$ptr_type>::new());
1646                    let list = unsafe { list.get_unchecked_mut() };
1647                    let obj1 = factory.create(1);
1648                    let obj2 = factory.create(2);
1649                    let obj3 = factory.create(3);
1650
1651                    $push(list, obj1);
1652                    $push(list, obj2);
1653                    $push(list, obj3);
1654
1655                    let (a, b, c) = {
1656                        let mut iter = list.iter();
1657                        (
1658                            $get_val(iter.next().unwrap()),
1659                            $get_val(iter.next().unwrap()),
1660                            $get_val(iter.next().unwrap()),
1661                        )
1662                    };
1663
1664                    let mut cursor = list.cursor_front_mut();
1665                    assert_eq!($get_val(cursor.get().unwrap()), a);
1666
1667                    cursor.move_prev();
1668                    assert!(cursor.get().is_none()); // Sentinel
1669
1670                    cursor.move_prev();
1671                    assert_eq!($get_val(cursor.get().unwrap()), c);
1672
1673                    cursor.move_prev();
1674                    assert_eq!($get_val(cursor.get().unwrap()), b);
1675
1676                    cursor.move_prev();
1677                    assert_eq!($get_val(cursor.get().unwrap()), a);
1678
1679                    list.clear();
1680                }
1681
1682                #[test]
1683                fn test_cursor_insert_after() {
1684                    let mut factory = <$factory_type>::new();
1685                    stack_pin_init!(let list = DoublyLinkedList::<$ptr_type>::new());
1686                    let list = unsafe { list.get_unchecked_mut() };
1687                    let obj1 = factory.create(1);
1688                    let obj2 = factory.create(2);
1689                    let obj3 = factory.create(3);
1690
1691                    $push(list, obj1);
1692
1693                    let mut cursor = list.cursor_front_mut();
1694                    unsafe {
1695                        cursor.insert_after_raw(obj3);
1696                        cursor.insert_after_raw(obj2);
1697                    }
1698
1699                    let mut iter = list.iter();
1700                    assert_eq!($get_val(iter.next().unwrap()), 1);
1701                    assert_eq!($get_val(iter.next().unwrap()), 2);
1702                    assert_eq!($get_val(iter.next().unwrap()), 3);
1703                    assert!(iter.next().is_none());
1704
1705                    list.clear();
1706                }
1707
1708                #[test]
1709                fn test_pop_back() {
1710                    let mut factory = <$factory_type>::new();
1711                    stack_pin_init!(let list = DoublyLinkedList::<$ptr_type>::new());
1712                    let list = unsafe { list.get_unchecked_mut() };
1713                    let obj1 = factory.create(1);
1714                    let obj2 = factory.create(2);
1715
1716                    $push(list, obj1);
1717                    $push(list, obj2);
1718
1719                    let p1 = list.pop_back();
1720                    assert!(p1.is_some());
1721                    let p2 = list.pop_back();
1722                    assert!(p2.is_some());
1723                    assert!(list.pop_back().is_none());
1724                }
1725
1726                #[test]
1727                fn test_erase() {
1728                    let mut factory = <$factory_type>::new();
1729                    stack_pin_init!(let list = DoublyLinkedList::<$ptr_type>::new());
1730                    let list = unsafe { list.get_unchecked_mut() };
1731                    let obj1 = factory.create(1);
1732                    let obj2 = factory.create(2);
1733                    let obj3 = factory.create(3);
1734
1735                    $push(list, obj1);
1736                    $push(list, obj2);
1737                    $push(list, obj3);
1738
1739                    let mut cursor = list.cursor_front_mut();
1740                    cursor.move_next();
1741                    let erased = cursor.erase();
1742                    assert!(erased.is_some());
1743                    factory.cleanup(erased.unwrap());
1744
1745                    let mut iter = list.iter();
1746                    assert!(iter.next().is_some());
1747                    assert!(iter.next().is_some());
1748                    assert!(iter.next().is_none());
1749
1750                    list.clear();
1751                }
1752
1753                #[test]
1754                fn test_erase_if() {
1755                    let mut factory = <$factory_type>::new();
1756                    stack_pin_init!(let list = DoublyLinkedList::<$ptr_type>::new());
1757                    let list = unsafe { list.get_unchecked_mut() };
1758                    let obj1 = factory.create(1);
1759                    let obj2 = factory.create(2);
1760                    let obj3 = factory.create(3);
1761
1762                    $push(list, obj1);
1763                    $push(list, obj2);
1764                    $push(list, obj3);
1765
1766                    let erased = list.erase_if(|o| o.value == 2);
1767                    assert!(erased.is_some());
1768                    assert_eq!($get_val(erased.unwrap().get_ref()), 2);
1769
1770                    let mut iter = list.iter();
1771                    assert_eq!($get_val(iter.next().unwrap()), 3);
1772                    assert_eq!($get_val(iter.next().unwrap()), 1);
1773                    assert!(iter.next().is_none());
1774
1775                    list.clear();
1776                }
1777
1778                #[test]
1779                fn test_find_if() {
1780                    let mut factory = <$factory_type>::new();
1781                    stack_pin_init!(let list = DoublyLinkedList::<$ptr_type>::new());
1782                    let list = unsafe { list.get_unchecked_mut() };
1783                    let obj1 = factory.create(1);
1784                    let obj2 = factory.create(2);
1785
1786                    $push(list, obj1);
1787                    $push(list, obj2);
1788
1789                    let found = list.find_if(|o| o.value == 1);
1790                    assert!(found.is_some());
1791                    assert_eq!(found.unwrap().value, 1);
1792
1793                    let found = list.find_if(|o| o.value == 3);
1794                    assert!(found.is_none());
1795
1796                    list.clear();
1797                }
1798
1799                #[test]
1800                fn test_complete_reverse_iteration() {
1801                    let mut factory = <$factory_type>::new();
1802                    stack_pin_init!(let list = DoublyLinkedList::<$ptr_type>::new());
1803                    let list = unsafe { list.get_unchecked_mut() };
1804                    let obj1 = factory.create(1);
1805                    let obj2 = factory.create(2);
1806                    let obj3 = factory.create(3);
1807
1808                    $push(list, obj1);
1809                    $push(list, obj2);
1810                    $push(list, obj3);
1811
1812                    let (a, b, c) = {
1813                        let mut iter = list.iter();
1814                        (
1815                            $get_val(iter.next().unwrap()),
1816                            $get_val(iter.next().unwrap()),
1817                            $get_val(iter.next().unwrap()),
1818                        )
1819                    };
1820
1821                    let mut iter = list.iter();
1822                    assert_eq!($get_val(iter.next_back().unwrap()), c);
1823                    assert_eq!($get_val(iter.next_back().unwrap()), b);
1824                    assert_eq!($get_val(iter.next_back().unwrap()), a);
1825                    assert!(iter.next_back().is_none());
1826
1827                    list.clear();
1828                }
1829
1830                #[test]
1831                fn test_split_after() {
1832                    let mut factory = <$factory_type>::new();
1833                    stack_pin_init!(let list1 = DoublyLinkedList::<$ptr_type>::new());
1834                    let list1 = unsafe { list1.get_unchecked_mut() };
1835                    stack_pin_init!(let list2 = DoublyLinkedList::<$ptr_type>::new());
1836                    let list2 = unsafe { list2.get_unchecked_mut() };
1837
1838                    let obj1 = factory.create(1);
1839                    let obj2 = factory.create(2);
1840                    let obj3 = factory.create(3);
1841                    let obj4 = factory.create(4);
1842
1843                    $push(list1, obj4);
1844                    $push(list1, obj3);
1845                    $push(list1, obj2);
1846                    $push(list1, obj1);
1847
1848                    let mut cursor = list1.cursor_front_mut();
1849                    cursor.move_next(); // points to 2
1850
1851                    let mut dest_cursor = list2.cursor_back_mut();
1852                    cursor.split_after(&mut dest_cursor);
1853
1854                    let mut iter1 = list1.iter();
1855                    assert_eq!($get_val(iter1.next().unwrap()), 1);
1856                    assert_eq!($get_val(iter1.next().unwrap()), 2);
1857                    assert!(iter1.next().is_none());
1858
1859                    let mut iter2 = list2.iter();
1860                    assert_eq!($get_val(iter2.next().unwrap()), 3);
1861                    assert_eq!($get_val(iter2.next().unwrap()), 4);
1862                    assert!(iter2.next().is_none());
1863
1864                    list1.clear();
1865                    list2.clear();
1866                }
1867
1868                #[test]
1869                fn test_split_before() {
1870                    let mut factory = <$factory_type>::new();
1871                    stack_pin_init!(let list1 = DoublyLinkedList::<$ptr_type>::new());
1872                    let list1 = unsafe { list1.get_unchecked_mut() };
1873                    stack_pin_init!(let list2 = DoublyLinkedList::<$ptr_type>::new());
1874                    let list2 = unsafe { list2.get_unchecked_mut() };
1875
1876                    let obj1 = factory.create(1);
1877                    let obj2 = factory.create(2);
1878                    let obj3 = factory.create(3);
1879                    let obj4 = factory.create(4);
1880
1881                    $push(list1, obj4);
1882                    $push(list1, obj3);
1883                    $push(list1, obj2);
1884                    $push(list1, obj1);
1885
1886                    let mut cursor = list1.cursor_front_mut();
1887                    cursor.move_next();
1888                    cursor.move_next(); // points to 3
1889
1890                    let mut dest_cursor = list2.cursor_back_mut();
1891                    cursor.split_before(&mut dest_cursor);
1892
1893                    // list2 should have elements before cursor (1, 2)
1894                    let mut iter2 = list2.iter();
1895                    assert_eq!($get_val(iter2.next().unwrap()), 1);
1896                    assert_eq!($get_val(iter2.next().unwrap()), 2);
1897                    assert!(iter2.next().is_none());
1898
1899                    // list1 should have elements from cursor onwards (3, 4)
1900                    let mut iter1 = list1.iter();
1901                    assert_eq!($get_val(iter1.next().unwrap()), 3);
1902                    assert_eq!($get_val(iter1.next().unwrap()), 4);
1903                    assert!(iter1.next().is_none());
1904
1905                    list1.clear();
1906                    list2.clear();
1907                }
1908            }
1909        };
1910    }
1911
1912    generate_list_tests!(
1913        raw_ptr_tests,
1914        *mut TestObject,
1915        RawFactory<TestObject>,
1916        |p: &TestObject| p.value,
1917        |list: &mut DoublyLinkedList<*mut TestObject>, obj| unsafe {
1918            list.push_front_raw(obj);
1919        }
1920    );
1921
1922    generate_list_tests!(
1923        unique_ptr_tests,
1924        UniquePtr<UniqueTestObject>,
1925        UniqueFactory<UniqueTestObject>,
1926        |p: &UniqueTestObject| p.value,
1927        |list: &mut DoublyLinkedList<UniquePtr<UniqueTestObject>>, obj| list.push_front(obj)
1928    );
1929
1930    generate_list_tests!(
1931        ref_ptr_tests,
1932        RefPtr<RefTestObject>,
1933        RefFactory<RefTestObject>,
1934        |p: &RefTestObject| p.value,
1935        |list: &mut DoublyLinkedList<RefPtr<RefTestObject>>, obj| list.push_front(obj)
1936    );
1937
1938    #[test]
1939    fn test_tracking_size() {
1940        stack_pin_init!(let list =
1941            DoublyLinkedList::<UniquePtr<UniqueTestObject>, DefaultObjectTag, TrackingSize>::new());
1942        let list = unsafe { list.get_unchecked_mut() };
1943
1944        assert_eq!(list.len(), 0);
1945        list.push_front(UniquePtr::try_new(UniqueTestObject::new(1)).unwrap());
1946        assert_eq!(list.len(), 1);
1947        list.push_front(UniquePtr::try_new(UniqueTestObject::new(2)).unwrap());
1948        assert_eq!(list.len(), 2);
1949        list.pop_front();
1950        assert_eq!(list.len(), 1);
1951        list.clear();
1952        assert_eq!(list.len(), 0);
1953    }
1954
1955    #[test]
1956    fn test_insert_before() {
1957        stack_pin_init!(let list =
1958            DoublyLinkedList::<UniquePtr<UniqueTestObject>, DefaultObjectTag, TrackingSize>::new());
1959        let list = unsafe { list.get_unchecked_mut() };
1960
1961        let mut cursor = list.cursor_front_mut();
1962        cursor.insert_before(UniquePtr::try_new(UniqueTestObject::new(1)).unwrap());
1963        assert_eq!(list.len(), 1);
1964        assert_eq!(list.front().unwrap().value, 1);
1965
1966        let mut cursor = list.cursor_front_mut();
1967        cursor.insert_before(UniquePtr::try_new(UniqueTestObject::new(2)).unwrap());
1968        assert_eq!(list.len(), 2);
1969        assert_eq!(list.front().unwrap().value, 2);
1970
1971        let mut cursor = list.cursor_front_mut();
1972        cursor.move_next(); // point to obj1
1973        cursor.insert_before(UniquePtr::try_new(UniqueTestObject::new(3)).unwrap());
1974        assert_eq!(list.len(), 3);
1975
1976        let mut cursor = list.cursor_front_mut();
1977        while cursor.get().unwrap().value != 1 {
1978            cursor.move_next();
1979        }
1980        cursor.move_next(); // point to sentinel
1981        cursor.insert_before(UniquePtr::try_new(UniqueTestObject::new(4)).unwrap());
1982        assert_eq!(list.len(), 4);
1983
1984        let mut iter = list.iter();
1985        assert_eq!(iter.next().unwrap().value, 2);
1986        assert_eq!(iter.next().unwrap().value, 3);
1987        assert_eq!(iter.next().unwrap().value, 1);
1988        assert_eq!(iter.next().unwrap().value, 4);
1989        assert!(iter.next().is_none());
1990
1991        list.clear();
1992    }
1993
1994    #[test]
1995    fn test_front_mut_and_back_mut() {
1996        stack_pin_init!(let list =
1997            DoublyLinkedList::<UniquePtr<UniqueTestObject>, DefaultObjectTag, TrackingSize>::new());
1998        let list = unsafe { list.get_unchecked_mut() };
1999
2000        assert!(list.front_mut().is_none());
2001        assert!(list.back_mut().is_none());
2002
2003        list.push_back(UniquePtr::try_new(UniqueTestObject::new(10)).unwrap());
2004        list.push_back(UniquePtr::try_new(UniqueTestObject::new(20)).unwrap());
2005
2006        assert_eq!(list.front_mut().unwrap().value, 10);
2007        assert_eq!(list.back_mut().unwrap().value, 20);
2008
2009        list.front_mut().unwrap().value = 100;
2010        list.back_mut().unwrap().value = 200;
2011
2012        assert_eq!(list.front().unwrap().value, 100);
2013        assert_eq!(list.back().unwrap().value, 200);
2014
2015        list.clear();
2016    }
2017
2018    #[test]
2019    fn test_cursor_front_and_back_mut() {
2020        stack_pin_init!(let list =
2021            DoublyLinkedList::<UniquePtr<UniqueTestObject>, DefaultObjectTag, TrackingSize>::new());
2022        let list = unsafe { list.get_unchecked_mut() };
2023
2024        assert!(list.cursor_front_mut().get().is_none());
2025        assert!(list.cursor_back_mut().get().is_none());
2026
2027        list.push_back(UniquePtr::try_new(UniqueTestObject::new(10)).unwrap());
2028        list.push_back(UniquePtr::try_new(UniqueTestObject::new(20)).unwrap());
2029
2030        let mut front_cursor = list.cursor_front_mut();
2031        assert_eq!(front_cursor.get().unwrap().value, 10);
2032        front_cursor.move_next();
2033        assert_eq!(front_cursor.get().unwrap().value, 20);
2034
2035        let mut back_cursor = list.cursor_back_mut();
2036        assert!(back_cursor.get().is_none());
2037        back_cursor.move_prev();
2038        assert_eq!(back_cursor.get().unwrap().value, 20);
2039
2040        let mut back_cursor = list.cursor_back_mut();
2041        back_cursor.insert_before(UniquePtr::try_new(UniqueTestObject::new(30)).unwrap());
2042        assert_eq!(list.len(), 3);
2043        assert_eq!(list.back().unwrap().value, 30);
2044
2045        list.clear();
2046    }
2047
2048    #[test]
2049    fn test_splice_middle() {
2050        stack_pin_init!(let list1 =
2051            DoublyLinkedList::<UniquePtr<UniqueTestObject>, DefaultObjectTag, TrackingSize>::new());
2052        let list1 = unsafe { list1.get_unchecked_mut() };
2053        stack_pin_init!(let list2 =
2054            DoublyLinkedList::<UniquePtr<UniqueTestObject>, DefaultObjectTag, TrackingSize>::new());
2055        let list2 = unsafe { list2.get_unchecked_mut() };
2056
2057        list1.push_back(UniquePtr::try_new(UniqueTestObject::new(1)).unwrap());
2058        list1.push_back(UniquePtr::try_new(UniqueTestObject::new(2)).unwrap());
2059        list2.push_back(UniquePtr::try_new(UniqueTestObject::new(3)).unwrap());
2060        list2.push_back(UniquePtr::try_new(UniqueTestObject::new(4)).unwrap());
2061
2062        let mut cursor = list1.cursor_front_mut();
2063        cursor.move_next(); // point to obj2
2064
2065        cursor.splice(list2);
2066
2067        assert!(list2.is_empty());
2068        assert_eq!(list1.len(), 4);
2069
2070        let mut iter = list1.iter();
2071        assert_eq!(iter.next().unwrap().value, 1);
2072        assert_eq!(iter.next().unwrap().value, 3);
2073        assert_eq!(iter.next().unwrap().value, 4);
2074        assert_eq!(iter.next().unwrap().value, 2);
2075        assert!(iter.next().is_none());
2076
2077        list1.clear();
2078    }
2079
2080    #[test]
2081    fn test_splice_head() {
2082        stack_pin_init!(let list1 =
2083            DoublyLinkedList::<UniquePtr<UniqueTestObject>, DefaultObjectTag, TrackingSize>::new());
2084        let list1 = unsafe { list1.get_unchecked_mut() };
2085        stack_pin_init!(let list2 =
2086            DoublyLinkedList::<UniquePtr<UniqueTestObject>, DefaultObjectTag, TrackingSize>::new());
2087        let list2 = unsafe { list2.get_unchecked_mut() };
2088
2089        list1.push_back(UniquePtr::try_new(UniqueTestObject::new(1)).unwrap());
2090        list1.push_back(UniquePtr::try_new(UniqueTestObject::new(2)).unwrap());
2091        list2.push_back(UniquePtr::try_new(UniqueTestObject::new(3)).unwrap());
2092        list2.push_back(UniquePtr::try_new(UniqueTestObject::new(4)).unwrap());
2093
2094        let mut cursor = list1.cursor_front_mut();
2095
2096        cursor.splice(list2);
2097
2098        assert!(list2.is_empty());
2099        assert_eq!(list1.len(), 4);
2100
2101        let mut iter = list1.iter();
2102        assert_eq!(iter.next().unwrap().value, 3);
2103        assert_eq!(iter.next().unwrap().value, 4);
2104        assert_eq!(iter.next().unwrap().value, 1);
2105        assert_eq!(iter.next().unwrap().value, 2);
2106        assert!(iter.next().is_none());
2107
2108        list1.clear();
2109    }
2110
2111    #[test]
2112    fn test_splice_tail() {
2113        stack_pin_init!(let list1 =
2114            DoublyLinkedList::<UniquePtr<UniqueTestObject>, DefaultObjectTag, TrackingSize>::new());
2115        let list1 = unsafe { list1.get_unchecked_mut() };
2116        stack_pin_init!(let list2 =
2117            DoublyLinkedList::<UniquePtr<UniqueTestObject>, DefaultObjectTag, TrackingSize>::new());
2118        let list2 = unsafe { list2.get_unchecked_mut() };
2119
2120        list1.push_back(UniquePtr::try_new(UniqueTestObject::new(1)).unwrap());
2121        list1.push_back(UniquePtr::try_new(UniqueTestObject::new(2)).unwrap());
2122        list2.push_back(UniquePtr::try_new(UniqueTestObject::new(3)).unwrap());
2123        list2.push_back(UniquePtr::try_new(UniqueTestObject::new(4)).unwrap());
2124
2125        let mut cursor = list1.cursor_front_mut();
2126        cursor.move_next();
2127        cursor.move_next(); // point to sentinel
2128
2129        cursor.splice(list2);
2130
2131        assert!(list2.is_empty());
2132        assert_eq!(list1.len(), 4);
2133
2134        let mut iter = list1.iter();
2135        assert_eq!(iter.next().unwrap().value, 1);
2136        assert_eq!(iter.next().unwrap().value, 2);
2137        assert_eq!(iter.next().unwrap().value, 3);
2138        assert_eq!(iter.next().unwrap().value, 4);
2139        assert!(iter.next().is_none());
2140
2141        list1.clear();
2142    }
2143
2144    #[test]
2145    fn test_splice_empty() {
2146        stack_pin_init!(let list1 =
2147            DoublyLinkedList::<UniquePtr<UniqueTestObject>, DefaultObjectTag, TrackingSize>::new());
2148        let list1 = unsafe { list1.get_unchecked_mut() };
2149        stack_pin_init!(let list2 =
2150            DoublyLinkedList::<UniquePtr<UniqueTestObject>, DefaultObjectTag, TrackingSize>::new());
2151        let list2 = unsafe { list2.get_unchecked_mut() };
2152
2153        list2.push_back(UniquePtr::try_new(UniqueTestObject::new(1)).unwrap());
2154        list2.push_back(UniquePtr::try_new(UniqueTestObject::new(2)).unwrap());
2155
2156        let mut cursor = list1.cursor_front_mut();
2157        cursor.splice(list2);
2158
2159        assert!(list2.is_empty());
2160        assert_eq!(list1.len(), 2);
2161
2162        let mut iter = list1.iter();
2163        assert_eq!(iter.next().unwrap().value, 1);
2164        assert_eq!(iter.next().unwrap().value, 2);
2165        assert!(iter.next().is_none());
2166
2167        list1.clear();
2168    }
2169
2170    #[test]
2171    fn test_splice_non_tracking() {
2172        stack_pin_init!(let list1 =
2173            DoublyLinkedList::<UniquePtr<UniqueTestObject>, DefaultObjectTag, NonTrackingSize>::new());
2174        let list1 = unsafe { list1.get_unchecked_mut() };
2175        stack_pin_init!(let list2 =
2176            DoublyLinkedList::<UniquePtr<UniqueTestObject>, DefaultObjectTag, NonTrackingSize>::new());
2177        let list2 = unsafe { list2.get_unchecked_mut() };
2178
2179        list1.push_back(UniquePtr::try_new(UniqueTestObject::new(1)).unwrap());
2180        list1.push_back(UniquePtr::try_new(UniqueTestObject::new(2)).unwrap());
2181        list2.push_back(UniquePtr::try_new(UniqueTestObject::new(3)).unwrap());
2182        list2.push_back(UniquePtr::try_new(UniqueTestObject::new(4)).unwrap());
2183
2184        let mut cursor = list1.cursor_front_mut();
2185        cursor.move_next(); // point to obj2
2186
2187        cursor.splice(list2);
2188
2189        assert!(list2.is_empty());
2190
2191        let mut iter = list1.iter();
2192        assert_eq!(iter.next().unwrap().value, 1);
2193        assert_eq!(iter.next().unwrap().value, 3);
2194        assert_eq!(iter.next().unwrap().value, 4);
2195        assert_eq!(iter.next().unwrap().value, 2);
2196        assert!(iter.next().is_none());
2197
2198        list1.clear();
2199    }
2200
2201    #[test]
2202    fn test_list_splice() {
2203        // Test splicing non-empty other into non-empty self.
2204        stack_pin_init!(let list1 =
2205            DoublyLinkedList::<UniquePtr<UniqueTestObject>, DefaultObjectTag, TrackingSize>::new());
2206        let list1 = unsafe { list1.get_unchecked_mut() };
2207        stack_pin_init!(let list2 =
2208            DoublyLinkedList::<UniquePtr<UniqueTestObject>, DefaultObjectTag, TrackingSize>::new());
2209        let list2 = unsafe { list2.get_unchecked_mut() };
2210
2211        list1.push_back(UniquePtr::try_new(UniqueTestObject::new(1)).unwrap());
2212        list1.push_back(UniquePtr::try_new(UniqueTestObject::new(2)).unwrap());
2213        list2.push_back(UniquePtr::try_new(UniqueTestObject::new(3)).unwrap());
2214        list2.push_back(UniquePtr::try_new(UniqueTestObject::new(4)).unwrap());
2215
2216        list1.splice(list2);
2217
2218        assert!(list2.is_empty());
2219        assert_eq!(list2.len(), 0);
2220        assert_eq!(list1.len(), 4);
2221
2222        let mut iter = list1.iter();
2223        assert_eq!(iter.next().unwrap().value, 1);
2224        assert_eq!(iter.next().unwrap().value, 2);
2225        assert_eq!(iter.next().unwrap().value, 3);
2226        assert_eq!(iter.next().unwrap().value, 4);
2227        assert!(iter.next().is_none());
2228
2229        // Test splicing into empty self.
2230        stack_pin_init!(let list3 =
2231            DoublyLinkedList::<UniquePtr<UniqueTestObject>, DefaultObjectTag, TrackingSize>::new());
2232        let list3 = unsafe { list3.get_unchecked_mut() };
2233
2234        list3.splice(list1);
2235
2236        assert!(list1.is_empty());
2237        assert_eq!(list1.len(), 0);
2238        assert_eq!(list3.len(), 4);
2239
2240        let mut iter = list3.iter();
2241        assert_eq!(iter.next().unwrap().value, 1);
2242        assert_eq!(iter.next().unwrap().value, 2);
2243        assert_eq!(iter.next().unwrap().value, 3);
2244        assert_eq!(iter.next().unwrap().value, 4);
2245        assert!(iter.next().is_none());
2246
2247        // Test splicing empty list into non-empty self (no-op).
2248        list3.splice(list1);
2249        assert_eq!(list3.len(), 4);
2250        assert!(list1.is_empty());
2251
2252        list3.clear();
2253    }
2254
2255    #[test]
2256    fn test_split_after_at_tail() {
2257        stack_pin_init!(let list1 =
2258            DoublyLinkedList::<UniquePtr<UniqueTestObject>, DefaultObjectTag, TrackingSize>::new());
2259        let list1 = unsafe { list1.get_unchecked_mut() };
2260        stack_pin_init!(let list2 =
2261            DoublyLinkedList::<UniquePtr<UniqueTestObject>, DefaultObjectTag, TrackingSize>::new());
2262        let list2 = unsafe { list2.get_unchecked_mut() };
2263
2264        list1.push_back(UniquePtr::try_new(UniqueTestObject::new(1)).unwrap());
2265        list1.push_back(UniquePtr::try_new(UniqueTestObject::new(2)).unwrap());
2266
2267        let mut cursor = list1.cursor_front_mut();
2268        cursor.move_next(); // points to 2 (tail)
2269
2270        let mut dest_cursor = list2.cursor_back_mut();
2271        cursor.split_after(&mut dest_cursor);
2272
2273        assert!(list2.is_empty());
2274        assert_eq!(list2.len(), 0);
2275        assert_eq!(list1.len(), 2);
2276
2277        list1.clear();
2278    }
2279
2280    #[test]
2281    fn test_split_after_at_head() {
2282        stack_pin_init!(let list1 =
2283            DoublyLinkedList::<UniquePtr<UniqueTestObject>, DefaultObjectTag, TrackingSize>::new());
2284        let list1 = unsafe { list1.get_unchecked_mut() };
2285        stack_pin_init!(let list2 =
2286            DoublyLinkedList::<UniquePtr<UniqueTestObject>, DefaultObjectTag, TrackingSize>::new());
2287        let list2 = unsafe { list2.get_unchecked_mut() };
2288
2289        list1.push_back(UniquePtr::try_new(UniqueTestObject::new(1)).unwrap());
2290        list1.push_back(UniquePtr::try_new(UniqueTestObject::new(2)).unwrap());
2291        list1.push_back(UniquePtr::try_new(UniqueTestObject::new(3)).unwrap());
2292
2293        let mut cursor = list1.cursor_front_mut(); // points to 1 (head)
2294
2295        let mut dest_cursor = list2.cursor_back_mut();
2296        cursor.split_after(&mut dest_cursor);
2297
2298        assert_eq!(list1.len(), 1);
2299        assert_eq!(list2.len(), 2);
2300
2301        let mut iter1 = list1.iter();
2302        assert_eq!(iter1.next().unwrap().value, 1);
2303        assert!(iter1.next().is_none());
2304
2305        let mut iter2 = list2.iter();
2306        assert_eq!(iter2.next().unwrap().value, 2);
2307        assert_eq!(iter2.next().unwrap().value, 3);
2308        assert!(iter2.next().is_none());
2309
2310        list1.clear();
2311        list2.clear();
2312    }
2313
2314    #[test]
2315    fn test_split_before_at_head() {
2316        stack_pin_init!(let list1 =
2317            DoublyLinkedList::<UniquePtr<UniqueTestObject>, DefaultObjectTag, TrackingSize>::new());
2318        let list1 = unsafe { list1.get_unchecked_mut() };
2319        stack_pin_init!(let list2 =
2320            DoublyLinkedList::<UniquePtr<UniqueTestObject>, DefaultObjectTag, TrackingSize>::new());
2321        let list2 = unsafe { list2.get_unchecked_mut() };
2322
2323        list1.push_back(UniquePtr::try_new(UniqueTestObject::new(1)).unwrap());
2324        list1.push_back(UniquePtr::try_new(UniqueTestObject::new(2)).unwrap());
2325
2326        let mut cursor = list1.cursor_front_mut(); // points to 1 (head)
2327
2328        let mut dest_cursor = list2.cursor_back_mut();
2329        cursor.split_before(&mut dest_cursor);
2330
2331        assert!(list2.is_empty());
2332        assert_eq!(list2.len(), 0);
2333        assert_eq!(list1.len(), 2);
2334
2335        list1.clear();
2336    }
2337
2338    #[test]
2339    fn test_split_before_at_tail() {
2340        stack_pin_init!(let list1 =
2341            DoublyLinkedList::<UniquePtr<UniqueTestObject>, DefaultObjectTag, TrackingSize>::new());
2342        let list1 = unsafe { list1.get_unchecked_mut() };
2343        stack_pin_init!(let list2 =
2344            DoublyLinkedList::<UniquePtr<UniqueTestObject>, DefaultObjectTag, TrackingSize>::new());
2345        let list2 = unsafe { list2.get_unchecked_mut() };
2346
2347        list1.push_back(UniquePtr::try_new(UniqueTestObject::new(1)).unwrap());
2348        list1.push_back(UniquePtr::try_new(UniqueTestObject::new(2)).unwrap());
2349        list1.push_back(UniquePtr::try_new(UniqueTestObject::new(3)).unwrap());
2350
2351        let mut cursor = list1.cursor_front_mut();
2352        cursor.move_next();
2353        cursor.move_next(); // points to 3 (tail)
2354
2355        let mut dest_cursor = list2.cursor_back_mut();
2356        cursor.split_before(&mut dest_cursor);
2357
2358        assert_eq!(list2.len(), 2);
2359        assert_eq!(list1.len(), 1);
2360
2361        let mut iter2 = list2.iter();
2362        assert_eq!(iter2.next().unwrap().value, 1);
2363        assert_eq!(iter2.next().unwrap().value, 2);
2364        assert!(iter2.next().is_none());
2365
2366        let mut iter1 = list1.iter();
2367        assert_eq!(iter1.next().unwrap().value, 3);
2368        assert!(iter1.next().is_none());
2369
2370        list1.clear();
2371        list2.clear();
2372    }
2373
2374    #[test]
2375    fn test_split_before_at_sentinel() {
2376        stack_pin_init!(let list1 =
2377            DoublyLinkedList::<UniquePtr<UniqueTestObject>, DefaultObjectTag, TrackingSize>::new());
2378        let list1 = unsafe { list1.get_unchecked_mut() };
2379        stack_pin_init!(let list2 =
2380            DoublyLinkedList::<UniquePtr<UniqueTestObject>, DefaultObjectTag, TrackingSize>::new());
2381        let list2 = unsafe { list2.get_unchecked_mut() };
2382
2383        list1.push_back(UniquePtr::try_new(UniqueTestObject::new(1)).unwrap());
2384        list1.push_back(UniquePtr::try_new(UniqueTestObject::new(2)).unwrap());
2385
2386        let mut cursor = list1.cursor_back_mut(); // points to sentinel
2387
2388        let mut dest_cursor = list2.cursor_back_mut();
2389        cursor.split_before(&mut dest_cursor);
2390
2391        assert!(list1.is_empty());
2392        assert_eq!(list1.len(), 0);
2393        assert_eq!(list2.len(), 2);
2394
2395        let mut iter2 = list2.iter();
2396        assert_eq!(iter2.next().unwrap().value, 1);
2397        assert_eq!(iter2.next().unwrap().value, 2);
2398        assert!(iter2.next().is_none());
2399
2400        list2.clear();
2401    }
2402
2403    #[test]
2404    fn test_split_into_middle_of_dest_list() {
2405        stack_pin_init!(let list1 =
2406            DoublyLinkedList::<UniquePtr<UniqueTestObject>, DefaultObjectTag, TrackingSize>::new());
2407        let list1 = unsafe { list1.get_unchecked_mut() };
2408        stack_pin_init!(let list2 =
2409            DoublyLinkedList::<UniquePtr<UniqueTestObject>, DefaultObjectTag, TrackingSize>::new());
2410        let list2 = unsafe { list2.get_unchecked_mut() };
2411
2412        list1.push_back(UniquePtr::try_new(UniqueTestObject::new(1)).unwrap());
2413        list1.push_back(UniquePtr::try_new(UniqueTestObject::new(2)).unwrap());
2414        list1.push_back(UniquePtr::try_new(UniqueTestObject::new(3)).unwrap());
2415        list1.push_back(UniquePtr::try_new(UniqueTestObject::new(4)).unwrap());
2416
2417        list2.push_back(UniquePtr::try_new(UniqueTestObject::new(10)).unwrap());
2418        list2.push_back(UniquePtr::try_new(UniqueTestObject::new(20)).unwrap());
2419
2420        // Split after 2 from list1, and insert before 20 in list2
2421        let mut cursor1 = list1.cursor_front_mut();
2422        cursor1.move_next(); // points to 2
2423
2424        let mut cursor2 = list2.cursor_front_mut();
2425        cursor2.move_next(); // points to 20
2426
2427        cursor1.split_after(&mut cursor2);
2428
2429        // list1 should retain [1, 2]
2430        assert_eq!(list1.len(), 2);
2431        let mut iter1 = list1.iter();
2432        assert_eq!(iter1.next().unwrap().value, 1);
2433        assert_eq!(iter1.next().unwrap().value, 2);
2434        assert!(iter1.next().is_none());
2435
2436        // list2 should now be [10, 3, 4, 20]
2437        assert_eq!(list2.len(), 4);
2438        let mut iter2 = list2.iter();
2439        assert_eq!(iter2.next().unwrap().value, 10);
2440        assert_eq!(iter2.next().unwrap().value, 3);
2441        assert_eq!(iter2.next().unwrap().value, 4);
2442        assert_eq!(iter2.next().unwrap().value, 20);
2443        assert!(iter2.next().is_none());
2444
2445        list1.clear();
2446        list2.clear();
2447    }
2448
2449    #[test]
2450    fn test_list_split_methods() {
2451        let mut obj1 = TestObject::new(1);
2452        let mut obj2 = TestObject::new(2);
2453        let mut obj3 = TestObject::new(3);
2454
2455        stack_pin_init!(let list1 = DoublyLinkedList::<*mut TestObject>::new());
2456        let list1 = unsafe { list1.get_unchecked_mut() };
2457        stack_pin_init!(let list2 = DoublyLinkedList::<*mut TestObject>::new());
2458        let list2 = unsafe { list2.get_unchecked_mut() };
2459
2460        unsafe {
2461            list1.push_back_raw(&mut obj1);
2462            list1.push_back_raw(&mut obj2);
2463            list1.push_back_raw(&mut obj3);
2464
2465            // Split after obj1
2466            let mut cursor1 = list1.cursor_at(&obj1);
2467            let mut cursor2 = list2.cursor_back_mut();
2468            cursor1.split_after(&mut cursor2);
2469
2470            assert_eq!(list1.iter().count(), 1);
2471            assert_eq!(list2.iter().count(), 2);
2472
2473            let mut iter1 = list1.iter();
2474            assert_eq!(iter1.next().unwrap().value, 1);
2475            assert!(iter1.next().is_none());
2476
2477            let mut iter2 = list2.iter();
2478            assert_eq!(iter2.next().unwrap().value, 2);
2479            assert_eq!(iter2.next().unwrap().value, 3);
2480            assert!(iter2.next().is_none());
2481
2482            // Splice back
2483            list1.splice(list2);
2484            assert_eq!(list1.iter().count(), 3);
2485
2486            // Split before obj3
2487            let mut cursor1 = list1.cursor_at(&obj3);
2488            let mut cursor2 = list2.cursor_back_mut();
2489            cursor1.split_before(&mut cursor2);
2490
2491            assert_eq!(list2.iter().count(), 2);
2492            assert_eq!(list1.iter().count(), 1);
2493
2494            let mut iter2 = list2.iter();
2495            assert_eq!(iter2.next().unwrap().value, 1);
2496            assert_eq!(iter2.next().unwrap().value, 2);
2497            assert!(iter2.next().is_none());
2498
2499            let mut iter1 = list1.iter();
2500            assert_eq!(iter1.next().unwrap().value, 3);
2501            assert!(iter1.next().is_none());
2502
2503            list1.clear();
2504            list2.clear();
2505        }
2506    }
2507
2508    #[test]
2509    fn test_cursor_get() {
2510        stack_pin_init!(let list = DoublyLinkedList::<UniquePtr<UniqueTestObject>>::new());
2511        let list = unsafe { list.get_unchecked_mut() };
2512
2513        let cursor = list.cursor_front_mut();
2514        assert!(cursor.get().is_none());
2515
2516        list.push_back(UniquePtr::try_new(UniqueTestObject::new(42)).unwrap());
2517
2518        let mut cursor = list.cursor_front_mut();
2519        assert!(cursor.get().is_some());
2520        assert_eq!(cursor.get().unwrap().value, 42);
2521
2522        cursor.move_next();
2523        assert!(cursor.get().is_none());
2524
2525        list.clear();
2526    }
2527
2528    #[test]
2529    fn test_pop_back() {
2530        stack_pin_init!(let list =
2531            DoublyLinkedList::<UniquePtr<UniqueTestObject>, DefaultObjectTag, TrackingSize>::new());
2532        let list = unsafe { list.get_unchecked_mut() };
2533
2534        list.push_back(UniquePtr::try_new(UniqueTestObject::new(1)).unwrap());
2535        list.push_back(UniquePtr::try_new(UniqueTestObject::new(2)).unwrap());
2536
2537        assert_eq!(list.len(), 2);
2538        let popped = list.pop_back();
2539        assert!(popped.is_some());
2540        assert_eq!(popped.unwrap().value, 2);
2541        assert_eq!(list.len(), 1);
2542
2543        let popped = list.pop_back();
2544        assert!(popped.is_some());
2545        assert_eq!(popped.unwrap().value, 1);
2546        assert_eq!(list.len(), 0);
2547
2548        assert!(list.pop_back().is_none());
2549    }
2550
2551    #[test]
2552    fn test_erase() {
2553        stack_pin_init!(let list =
2554            DoublyLinkedList::<UniquePtr<UniqueTestObject>, DefaultObjectTag, TrackingSize>::new());
2555        let list = unsafe { list.get_unchecked_mut() };
2556
2557        list.push_back(UniquePtr::try_new(UniqueTestObject::new(1)).unwrap());
2558        list.push_back(UniquePtr::try_new(UniqueTestObject::new(2)).unwrap());
2559        list.push_back(UniquePtr::try_new(UniqueTestObject::new(3)).unwrap());
2560
2561        assert_eq!(list.len(), 3);
2562
2563        // 1. Erase middle (obj2)
2564        let mut cursor = list.cursor_front_mut();
2565        cursor.move_next(); // point to obj2
2566        let erased = cursor.erase();
2567        assert!(erased.is_some());
2568        assert_eq!(erased.unwrap().value, 2);
2569        assert_eq!(list.len(), 2);
2570
2571        let mut iter = list.iter();
2572        assert_eq!(iter.next().unwrap().value, 1);
2573        assert_eq!(iter.next().unwrap().value, 3);
2574        assert!(iter.next().is_none());
2575
2576        // 2. Erase head (obj1)
2577        let mut cursor = list.cursor_front_mut();
2578        let erased = cursor.erase(); // current is head (obj1)
2579        assert!(erased.is_some());
2580        assert_eq!(erased.unwrap().value, 1);
2581        assert_eq!(list.len(), 1);
2582        assert_eq!(list.front().unwrap().value, 3); // obj3 is now head!
2583
2584        // 3. Erase last element (obj3)
2585        let mut cursor = list.cursor_front_mut();
2586        let erased = cursor.erase(); // current is head/tail (obj3)
2587        assert!(erased.is_some());
2588        assert_eq!(erased.unwrap().value, 3);
2589        assert_eq!(list.len(), 0);
2590        assert!(list.is_empty());
2591
2592        list.clear();
2593    }
2594
2595    #[test]
2596    fn test_erase_if() {
2597        stack_pin_init!(let list =
2598            DoublyLinkedList::<UniquePtr<UniqueTestObject>, DefaultObjectTag, TrackingSize>::new());
2599        let list = unsafe { list.get_unchecked_mut() };
2600
2601        list.push_back(UniquePtr::try_new(UniqueTestObject::new(1)).unwrap());
2602        list.push_back(UniquePtr::try_new(UniqueTestObject::new(2)).unwrap());
2603        list.push_back(UniquePtr::try_new(UniqueTestObject::new(3)).unwrap());
2604
2605        let erased = list.erase_if(|obj| obj.value % 2 == 0);
2606        assert!(erased.is_some());
2607        assert_eq!(erased.unwrap().value, 2);
2608
2609        assert_eq!(list.len(), 2);
2610        let mut iter = list.iter();
2611        assert_eq!(iter.next().unwrap().value, 1);
2612        assert_eq!(iter.next().unwrap().value, 3);
2613        assert!(iter.next().is_none());
2614
2615        list.clear();
2616    }
2617
2618    #[test]
2619    fn test_erase_by_reference() {
2620        stack_pin_init!(let list =
2621            DoublyLinkedList::<*mut TestObject, DefaultObjectTag, TrackingSize>::new());
2622        let list = unsafe { list.get_unchecked_mut() };
2623        let mut obj1 = TestObject::new(1);
2624        let mut obj2 = TestObject::new(2);
2625        let mut obj3 = TestObject::new(3);
2626
2627        unsafe {
2628            list.push_back_raw(&mut obj1);
2629            list.push_back_raw(&mut obj2);
2630            list.push_back_raw(&mut obj3);
2631        }
2632
2633        assert_eq!(list.len(), 3);
2634
2635        // Erase obj2 directly (safe because it's unmanaged raw pointer to stack)
2636        let erased = unsafe { list.erase(&obj2) };
2637        assert!(erased.is_some());
2638        assert_eq!(unsafe { &*erased.unwrap() }.value, 2);
2639        assert_eq!(list.len(), 2);
2640
2641        let mut iter = list.iter();
2642        assert_eq!(iter.next().unwrap().value, 1);
2643        assert_eq!(iter.next().unwrap().value, 3);
2644        assert!(iter.next().is_none());
2645
2646        list.clear();
2647    }
2648
2649    #[test]
2650    fn test_remove_from_container() {
2651        stack_pin_init!(let list = DoublyLinkedList::<*mut TestObject>::new());
2652        let list = unsafe { list.get_unchecked_mut() };
2653        let mut obj1 = TestObject::new(1);
2654        let mut obj2 = TestObject::new(2);
2655        let mut obj3 = TestObject::new(3);
2656
2657        // Case 1: Attempt to remove an element not in any container
2658        let removed = unsafe {
2659            remove_from_container::<TestObject, DefaultObjectTag, *mut TestObject>(&obj1)
2660        };
2661        assert!(removed.is_none());
2662
2663        unsafe {
2664            list.push_back_raw(&mut obj1);
2665            list.push_back_raw(&mut obj2);
2666            list.push_back_raw(&mut obj3);
2667        }
2668
2669        // Case 2: Remove middle (obj2)
2670        let removed = unsafe {
2671            remove_from_container::<TestObject, DefaultObjectTag, *mut TestObject>(&obj2)
2672        };
2673        assert!(removed.is_some());
2674        assert_eq!(unsafe { &*removed.unwrap() }.value, 2);
2675
2676        let mut iter = list.iter();
2677        assert_eq!(iter.next().unwrap().value, 1);
2678        assert_eq!(iter.next().unwrap().value, 3);
2679        assert!(iter.next().is_none());
2680
2681        // Case 3: Remove head (obj1)
2682        let removed = unsafe {
2683            remove_from_container::<TestObject, DefaultObjectTag, *mut TestObject>(&obj1)
2684        };
2685        assert!(removed.is_some());
2686        assert_eq!(unsafe { &*removed.unwrap() }.value, 1);
2687
2688        let mut iter = list.iter();
2689        assert_eq!(iter.next().unwrap().value, 3);
2690        assert!(iter.next().is_none());
2691
2692        // Case 4: Remove last remaining element (obj3 -> leaves empty!)
2693        let removed = unsafe {
2694            remove_from_container::<TestObject, DefaultObjectTag, *mut TestObject>(&obj3)
2695        };
2696        assert!(removed.is_some());
2697        assert_eq!(unsafe { &*removed.unwrap() }.value, 3);
2698        assert!(list.is_empty());
2699
2700        list.clear();
2701    }
2702
2703    #[test]
2704    fn test_replace() {
2705        stack_pin_init!(let list =
2706            DoublyLinkedList::<*mut TestObject, DefaultObjectTag, TrackingSize>::new());
2707        let list = unsafe { list.get_unchecked_mut() };
2708        let mut obj1 = TestObject::new(1);
2709        let mut obj2 = TestObject::new(2);
2710        let mut obj3 = TestObject::new(3);
2711
2712        unsafe {
2713            list.push_back_raw(&mut obj1);
2714            list.push_back_raw(&mut obj2);
2715        }
2716
2717        assert_eq!(list.len(), 2);
2718
2719        let old = unsafe { list.replace_raw(&obj2, &mut obj3) };
2720        assert!(old.is_some());
2721        assert_eq!(unsafe { &*old.unwrap() }.value, 2);
2722        assert_eq!(list.len(), 2);
2723
2724        let mut iter = list.iter();
2725        assert_eq!(iter.next().unwrap().value, 1);
2726        assert_eq!(iter.next().unwrap().value, 3);
2727        assert!(iter.next().is_none());
2728
2729        list.clear();
2730    }
2731
2732    #[test]
2733    fn test_cursor_replace() {
2734        stack_pin_init!(let list = DoublyLinkedList::<UniquePtr<UniqueTestObject>>::new());
2735        let list = unsafe { list.get_unchecked_mut() };
2736
2737        let obj1 = UniquePtr::try_new(UniqueTestObject::new(1)).unwrap();
2738        let obj2 = UniquePtr::try_new(UniqueTestObject::new(2)).unwrap();
2739        let obj3 = UniquePtr::try_new(UniqueTestObject::new(3)).unwrap();
2740
2741        list.push_back(obj1);
2742        list.push_back(obj2);
2743
2744        let mut cursor = list.cursor_front_mut();
2745        cursor.move_next(); // point to obj2
2746
2747        let old = cursor.replace(obj3);
2748        assert!(old.is_some());
2749        assert_eq!(old.unwrap().value, 2);
2750
2751        let mut iter = list.iter();
2752        assert_eq!(iter.next().unwrap().value, 1);
2753        assert_eq!(iter.next().unwrap().value, 3);
2754        assert!(iter.next().is_none());
2755
2756        list.clear();
2757    }
2758
2759    struct Tag2;
2760
2761    #[fbl::ref_counted]
2762    #[derive(crate::DoublyLinkedListContainable, crate::Recyclable)]
2763    #[repr(C)]
2764    struct MultiListObject {
2765        value: i32,
2766        #[dll_node]
2767        node1: DoublyLinkedListNode<MultiListObject>,
2768        #[dll_node(tag = Tag2)]
2769        node2: DoublyLinkedListNode<MultiListObject>,
2770    }
2771
2772    #[test]
2773    fn test_multiple_containers() {
2774        stack_pin_init!(let list1 =
2775            DoublyLinkedList::<RefPtr<MultiListObject>, DefaultObjectTag>::new());
2776        let list1 = unsafe { list1.get_unchecked_mut() };
2777        stack_pin_init!(let list2 = DoublyLinkedList::<RefPtr<MultiListObject>, Tag2>::new());
2778        let list2 = unsafe { list2.get_unchecked_mut() };
2779
2780        let obj1 = fbl::make_ref_counted!(MultiListObject {
2781            value: 1,
2782            node1: DoublyLinkedListNode::new(),
2783            node2: DoublyLinkedListNode::new(),
2784        })
2785        .unwrap();
2786
2787        let obj2 = fbl::make_ref_counted!(MultiListObject {
2788            value: 2,
2789            node1: DoublyLinkedListNode::new(),
2790            node2: DoublyLinkedListNode::new(),
2791        })
2792        .unwrap();
2793
2794        list1.push_back(obj1.clone());
2795        list1.push_back(obj2.clone());
2796
2797        list2.push_back(obj2); // obj2 is now in both lists!
2798
2799        let mut iter1 = list1.iter();
2800        assert_eq!(iter1.next().unwrap().value, 1);
2801        assert_eq!(iter1.next().unwrap().value, 2);
2802        assert!(iter1.next().is_none());
2803
2804        let mut iter2 = list2.iter();
2805        assert_eq!(iter2.next().unwrap().value, 2);
2806        assert!(iter2.next().is_none());
2807
2808        list1.clear();
2809        list2.clear();
2810    }
2811
2812    use alloc::sync::Arc;
2813    use core::sync::atomic::{AtomicBool, Ordering};
2814
2815    #[derive(crate::DoublyLinkedListContainable, crate::Recyclable)]
2816    struct LifecycleObject {
2817        destroyed: Arc<AtomicBool>,
2818        #[dll_node]
2819        node: DoublyLinkedListNode<LifecycleObject>,
2820    }
2821
2822    impl LifecycleObject {
2823        fn new(destroyed: Arc<AtomicBool>) -> Self {
2824            Self { destroyed, node: DoublyLinkedListNode::new() }
2825        }
2826    }
2827
2828    impl Drop for LifecycleObject {
2829        fn drop(&mut self) {
2830            self.destroyed.store(true, Ordering::Relaxed);
2831        }
2832    }
2833
2834    #[test]
2835    fn test_lifecycle_on_drop() {
2836        let destroyed1 = Arc::new(AtomicBool::new(false));
2837        let destroyed2 = Arc::new(AtomicBool::new(false));
2838
2839        {
2840            stack_pin_init!(let list = DoublyLinkedList::<UniquePtr<LifecycleObject>>::new());
2841            let list = unsafe { list.get_unchecked_mut() };
2842
2843            let obj1 = UniquePtr::try_new(LifecycleObject::new(destroyed1.clone())).unwrap();
2844            let obj2 = UniquePtr::try_new(LifecycleObject::new(destroyed2.clone())).unwrap();
2845
2846            list.push_back(obj1);
2847            list.push_back(obj2);
2848
2849            assert!(!destroyed1.load(Ordering::Relaxed));
2850            assert!(!destroyed2.load(Ordering::Relaxed));
2851        } // list drops here
2852
2853        assert!(destroyed1.load(Ordering::Relaxed));
2854        assert!(destroyed2.load(Ordering::Relaxed));
2855    }
2856
2857    #[test]
2858    fn test_sized_managed_list() {
2859        stack_pin_init!(let list =
2860            DoublyLinkedList::<UniquePtr<UniqueTestObject>, DefaultObjectTag, TrackingSize>::new());
2861        let list = unsafe { list.get_unchecked_mut() };
2862
2863        assert_eq!(list.len(), 0);
2864
2865        let obj1 = UniquePtr::try_new(UniqueTestObject::new(1)).unwrap();
2866        let obj2 = UniquePtr::try_new(UniqueTestObject::new(2)).unwrap();
2867
2868        list.push_back(obj1);
2869        assert_eq!(list.len(), 1);
2870
2871        list.push_back(obj2);
2872        assert_eq!(list.len(), 2);
2873
2874        let popped = list.pop_front();
2875        assert!(popped.is_some());
2876        assert_eq!(list.len(), 1);
2877
2878        list.clear();
2879        assert_eq!(list.len(), 0);
2880    }
2881
2882    #[test]
2883    fn test_unidirectional_iterators() {
2884        stack_pin_init!(let list = DoublyLinkedList::<UniquePtr<UniqueTestObject>>::new());
2885        let list = unsafe { list.get_unchecked_mut() };
2886
2887        list.push_back(UniquePtr::try_new(UniqueTestObject::new(1)).unwrap());
2888        list.push_back(UniquePtr::try_new(UniqueTestObject::new(2)).unwrap());
2889        list.push_back(UniquePtr::try_new(UniqueTestObject::new(3)).unwrap());
2890
2891        // 1. Test ForwardIterator from beginning
2892        let mut f_iter = list.forward_iter();
2893        assert_eq!(f_iter.next().unwrap().value, 1);
2894        let obj2_ref = f_iter.next().unwrap();
2895        assert_eq!(obj2_ref.value, 2);
2896        assert_eq!(f_iter.next().unwrap().value, 3);
2897        assert!(f_iter.next().is_none());
2898
2899        // 2. Test ForwardIterator from element in the middle (obj2_ref)
2900        let mut f_element_iter =
2901            ForwardIterator::<UniquePtr<UniqueTestObject>>::from_element(obj2_ref);
2902        assert_eq!(f_element_iter.next().unwrap().value, 2);
2903        assert_eq!(f_element_iter.next().unwrap().value, 3);
2904        assert!(f_element_iter.next().is_none());
2905
2906        // 3. Test ReverseIterator from end
2907        let mut r_iter = list.reverse_iter();
2908        assert_eq!(r_iter.next().unwrap().value, 3);
2909        let obj2_ref_r = r_iter.next().unwrap();
2910        assert_eq!(obj2_ref_r.value, 2);
2911        assert_eq!(r_iter.next().unwrap().value, 1);
2912        assert!(r_iter.next().is_none());
2913
2914        // 4. Test ReverseIterator from element in the middle (obj2_ref_r)
2915        let mut r_element_iter =
2916            ReverseIterator::<UniquePtr<UniqueTestObject>>::from_element(obj2_ref_r);
2917        assert_eq!(r_element_iter.next().unwrap().value, 2);
2918        assert_eq!(r_element_iter.next().unwrap().value, 1);
2919        assert!(r_element_iter.next().is_none());
2920
2921        list.clear();
2922    }
2923
2924    #[test]
2925    fn test_cursor_at() {
2926        stack_pin_init!(let list =
2927            DoublyLinkedList::<*mut TestObject, DefaultObjectTag, TrackingSize>::new());
2928        let list = unsafe { list.get_unchecked_mut() };
2929        let mut obj1 = TestObject::new(1);
2930        let mut obj2 = TestObject::new(2);
2931        let mut obj3 = TestObject::new(3);
2932
2933        unsafe {
2934            list.push_back_raw(&mut obj1);
2935            list.push_back_raw(&mut obj2);
2936            list.push_back_raw(&mut obj3);
2937        }
2938
2939        // Create a cursor at the second element (obj2).
2940        // SAFETY: `obj2` is a member of `list`.
2941        let mut cursor = unsafe { list.cursor_at(&obj2) };
2942        assert_eq!(cursor.get().unwrap().value, 2);
2943
2944        // Verify we can move next.
2945        cursor.move_next();
2946        assert_eq!(cursor.get().unwrap().value, 3);
2947
2948        // Verify we can move prev from the original position.
2949        // SAFETY: `obj2` is a member of `list`.
2950        let mut cursor = unsafe { list.cursor_at(&obj2) };
2951        cursor.move_prev();
2952        assert_eq!(cursor.get().unwrap().value, 1);
2953
2954        // Verify we can erase via the cursor created at the element.
2955        // SAFETY: `obj2` is a member of `list`.
2956        let mut cursor = unsafe { list.cursor_at(&obj2) };
2957        let erased = cursor.erase().unwrap();
2958        assert_eq!(unsafe { &*erased }.value, 2);
2959
2960        // Verify list contents after erase.
2961        let mut iter = list.iter();
2962        assert_eq!(iter.next().unwrap().value, 1);
2963        assert_eq!(iter.next().unwrap().value, 3);
2964        assert!(iter.next().is_none());
2965
2966        list.clear();
2967    }
2968
2969    // FFI Declarations
2970    unsafe extern "C" {
2971        // UniqueList Helpers
2972        fn cpp_create_unique_list() -> *mut c_void;
2973        fn cpp_destroy_unique_list(list: *mut c_void);
2974        fn cpp_unique_list_push_back(list: *mut c_void, item: *mut c_void);
2975        fn cpp_unique_list_pop_front(list: *mut c_void) -> *mut c_void;
2976        fn cpp_unique_list_is_empty(list: *mut c_void) -> bool;
2977
2978        // RefList Helpers
2979        fn cpp_create_ref_list() -> *mut c_void;
2980        fn cpp_destroy_ref_list(list: *mut c_void);
2981        fn cpp_ref_list_push_back(list: *mut c_void, item: *mut c_void);
2982        fn cpp_ref_list_pop_front(list: *mut c_void) -> *mut c_void;
2983        fn cpp_ref_list_is_empty(list: *mut c_void) -> bool;
2984
2985        // SharedUniqueObject Helpers
2986        fn cpp_create_unique_object(value: i32, destruction_flag: *mut bool) -> *mut c_void;
2987        fn cpp_get_unique_object_value(obj: *mut c_void) -> i32;
2988
2989        // SharedRefObject Helpers
2990        fn cpp_create_ref_object(value: i32, destruction_flag: *mut bool) -> *mut c_void;
2991        fn cpp_get_ref_object_value(obj: *mut c_void) -> i32;
2992    }
2993
2994    #[test]
2995    fn test_interop_rust_list_cpp_unique_objects() {
2996        let destroyed1 = AtomicBool::new(false);
2997        let destroyed2 = AtomicBool::new(false);
2998
2999        unsafe {
3000            stack_pin_init!(let list = DoublyLinkedList::<UniquePtr<SharedUniqueObject>>::new());
3001            let list = list.get_unchecked_mut();
3002
3003            let cpp_raw1 = cpp_create_unique_object(1, destroyed1.as_ptr() as *mut bool);
3004            let cpp_raw2 = cpp_create_unique_object(2, destroyed2.as_ptr() as *mut bool);
3005
3006            let obj1 = UniquePtr::from_raw(cpp_raw1 as *mut SharedUniqueObject);
3007            let obj2 = UniquePtr::from_raw(cpp_raw2 as *mut SharedUniqueObject);
3008
3009            list.push_back(obj1);
3010            list.push_back(obj2);
3011
3012            assert!(!destroyed1.load(Ordering::Relaxed));
3013            assert!(!destroyed2.load(Ordering::Relaxed));
3014
3015            // Pop one
3016            let popped = list.pop_front();
3017            assert!(popped.is_some());
3018            assert_eq!(popped.as_ref().unwrap().value, 1);
3019
3020            // Drop popped -> should destroy in C++!
3021            drop(popped);
3022            assert!(destroyed1.load(Ordering::Relaxed));
3023            assert!(!destroyed2.load(Ordering::Relaxed));
3024
3025            // Drop list -> should destroy remaining in C++!
3026        }
3027        assert!(destroyed2.load(Ordering::Relaxed));
3028    }
3029
3030    #[test]
3031    fn test_interop_cpp_list_rust_unique_objects() {
3032        let destroyed1 = Arc::new(AtomicBool::new(false));
3033        let destroyed2 = Arc::new(AtomicBool::new(false));
3034
3035        unsafe {
3036            let cpp_list = cpp_create_unique_list();
3037            assert!(cpp_unique_list_is_empty(cpp_list));
3038
3039            let obj1 = UniquePtr::try_new(SharedUniqueObject::new(1)).unwrap();
3040            let obj2 = UniquePtr::try_new(SharedUniqueObject::new(2)).unwrap();
3041
3042            // Set destruction flags
3043            let raw1 = UniquePtr::as_ptr(&obj1) as *mut SharedUniqueObject;
3044            (*raw1).destruction_flag = destroyed1.as_ptr() as *mut bool;
3045            let raw2 = UniquePtr::as_ptr(&obj2) as *mut SharedUniqueObject;
3046            (*raw2).destruction_flag = destroyed2.as_ptr() as *mut bool;
3047
3048            // Push to C++ list (transfers ownership)
3049            cpp_unique_list_push_back(cpp_list, UniquePtr::into_raw(obj1) as *mut c_void);
3050            cpp_unique_list_push_back(cpp_list, UniquePtr::into_raw(obj2) as *mut c_void);
3051
3052            assert!(!destroyed1.load(Ordering::Relaxed));
3053            assert!(!destroyed2.load(Ordering::Relaxed));
3054
3055            // Pop one from C++
3056            let popped = cpp_unique_list_pop_front(cpp_list);
3057            assert!(!popped.is_null());
3058            assert_eq!(cpp_get_unique_object_value(popped), 1);
3059
3060            // Convert back to Rust UniquePtr and drop -> should free in Rust!
3061            let popped_rust = UniquePtr::from_raw(popped as *mut SharedUniqueObject);
3062            drop(popped_rust);
3063            assert!(destroyed1.load(Ordering::Relaxed));
3064            assert!(!destroyed2.load(Ordering::Relaxed));
3065
3066            // Destroy C++ list -> should destroy remaining in Rust!
3067            cpp_destroy_unique_list(cpp_list);
3068        }
3069        assert!(destroyed2.load(Ordering::Relaxed));
3070    }
3071
3072    #[test]
3073    fn test_interop_rust_list_cpp_ref_objects() {
3074        let destroyed1 = AtomicBool::new(false);
3075        let destroyed2 = AtomicBool::new(false);
3076
3077        unsafe {
3078            stack_pin_init!(let list = DoublyLinkedList::<RefPtr<SharedRefObject>>::new());
3079            let list = list.get_unchecked_mut();
3080
3081            let cpp_raw1 = cpp_create_ref_object(1, destroyed1.as_ptr() as *mut bool);
3082            let cpp_raw2 = cpp_create_ref_object(2, destroyed2.as_ptr() as *mut bool);
3083
3084            let obj1 = RefPtr::from_raw(cpp_raw1 as *mut SharedRefObject);
3085            let obj2 = RefPtr::from_raw(cpp_raw2 as *mut SharedRefObject);
3086
3087            list.push_back(obj1);
3088            list.push_back(obj2);
3089
3090            assert!(!destroyed1.load(Ordering::Relaxed));
3091            assert!(!destroyed2.load(Ordering::Relaxed));
3092
3093            // Pop one
3094            let popped = list.pop_front();
3095            assert!(popped.is_some());
3096            assert_eq!(popped.as_ref().unwrap().value, 1);
3097
3098            // Drop popped -> should destroy in C++!
3099            drop(popped);
3100            assert!(destroyed1.load(Ordering::Relaxed));
3101            assert!(!destroyed2.load(Ordering::Relaxed));
3102
3103            // Drop list -> should destroy remaining in C++!
3104        }
3105        assert!(destroyed2.load(Ordering::Relaxed));
3106    }
3107
3108    #[test]
3109    fn test_interop_cpp_list_rust_ref_objects() {
3110        let destroyed1 = Arc::new(AtomicBool::new(false));
3111        let destroyed2 = Arc::new(AtomicBool::new(false));
3112
3113        unsafe {
3114            let cpp_list = cpp_create_ref_list();
3115            assert!(cpp_ref_list_is_empty(cpp_list));
3116
3117            let obj1 = SharedRefObject::new_ref_counted(1);
3118            let obj2 = SharedRefObject::new_ref_counted(2);
3119
3120            // Set destruction flags
3121            let raw1 = RefPtr::as_ptr(&obj1) as *mut SharedRefObject;
3122            (*raw1).destruction_flag = destroyed1.as_ptr() as *mut bool;
3123            let raw2 = RefPtr::as_ptr(&obj2) as *mut SharedRefObject;
3124            (*raw2).destruction_flag = destroyed2.as_ptr() as *mut bool;
3125
3126            // Push to C++ list (transfers ownership)
3127            cpp_ref_list_push_back(
3128                cpp_list,
3129                RefPtr::into_raw(obj1) as *mut SharedRefObject as *mut c_void,
3130            );
3131            cpp_ref_list_push_back(
3132                cpp_list,
3133                RefPtr::into_raw(obj2) as *mut SharedRefObject as *mut c_void,
3134            );
3135
3136            assert!(!destroyed1.load(Ordering::Relaxed));
3137            assert!(!destroyed2.load(Ordering::Relaxed));
3138
3139            // Pop one from C++
3140            let popped = cpp_ref_list_pop_front(cpp_list);
3141            assert!(!popped.is_null());
3142            assert_eq!(cpp_get_ref_object_value(popped), 1);
3143
3144            // Convert back to Rust RefPtr and drop -> should free in Rust!
3145            let popped_rust = RefPtr::from_raw(popped as *mut SharedRefObject);
3146            drop(popped_rust);
3147            assert!(destroyed1.load(Ordering::Relaxed));
3148            assert!(!destroyed2.load(Ordering::Relaxed));
3149
3150            // Destroy C++ list -> should destroy remaining in Rust!
3151            cpp_destroy_ref_list(cpp_list);
3152        }
3153        assert!(destroyed2.load(Ordering::Relaxed));
3154    }
3155}