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, MutPtr, 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///
15/// Nodes are `!Unpin`: while an element is linked into a list, its neighbors hold raw pointers to
16/// it, so it must not be moved (or have its node swapped/overwritten). Containing types should mark
17/// their node field(s) with `#[pin]` when using `#[pin_data]` so that the `!Unpin`-ness propagates.
18#[repr(C)]
19pub struct DoublyLinkedListNode<T> {
20    /// The next element in the list.
21    pub next: UnsafeCell<*mut T>,
22    /// The previous element in the list.
23    pub prev: UnsafeCell<*mut T>,
24    /// Marker making the node (and any type embedding it) `!Unpin`.
25    ///
26    /// Wrapped in `PhantomData` so the node remains FFI-safe (`improper_ctypes` rejects a bare
27    /// `PhantomPinned` in `extern` signatures, but ignores `PhantomData` fields).
28    _pin: core::marker::PhantomData<core::marker::PhantomPinned>,
29}
30
31impl<T> DoublyLinkedListNode<T> {
32    /// Creates a new, unlinked node.
33    #[inline]
34    pub const fn new() -> Self {
35        Self {
36            next: UnsafeCell::new(core::ptr::null_mut()),
37            prev: UnsafeCell::new(core::ptr::null_mut()),
38            _pin: core::marker::PhantomData,
39        }
40    }
41
42    /// Returns true if the node is currently in a list.
43    #[inline]
44    pub fn in_container(&self) -> bool {
45        // SAFETY: `self.next.get()` returns a valid pointer to the inner field of `self.next`
46        // which is a validly allocated UnsafeCell inside `self`.
47        !unsafe { *self.next.get() }.is_null()
48    }
49
50    #[inline]
51    fn get_next(&self) -> *mut T {
52        // SAFETY: `self.next.get()` is a valid pointer to `self.next` which is owned by `self`.
53        unsafe { *self.next.get() }
54    }
55
56    #[inline]
57    fn set_next(&self, next: *mut T) {
58        // SAFETY: `self.next.get()` is a valid, writable pointer to `self.next` owned by `self`.
59        // UnsafeCell allows interior mutability through a shared reference.
60        unsafe {
61            *self.next.get() = next;
62        }
63    }
64
65    #[inline]
66    fn get_prev(&self) -> *mut T {
67        // SAFETY: `self.prev.get()` is a valid pointer to `self.prev` which is owned by `self`.
68        unsafe { *self.prev.get() }
69    }
70
71    #[inline]
72    fn set_prev(&self, prev: *mut T) {
73        // SAFETY: `self.prev.get()` is a valid, writable pointer to `self.prev` owned by `self`.
74        // UnsafeCell allows interior mutability through a shared reference.
75        unsafe {
76            *self.prev.get() = prev;
77        }
78    }
79}
80
81impl<T> core::fmt::Debug for DoublyLinkedListNode<T> {
82    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
83        f.debug_struct("DoublyLinkedListNode").field("in_container", &self.in_container()).finish()
84    }
85}
86
87impl<T> Default for DoublyLinkedListNode<T> {
88    #[inline]
89    fn default() -> Self {
90        Self::new()
91    }
92}
93
94impl<T> Drop for DoublyLinkedListNode<T> {
95    #[inline]
96    fn drop(&mut self) {
97        debug_assert!(!self.in_container(), "Object destroyed while still in container");
98    }
99}
100
101/// Trait that types must implement to be contained in a `DoublyLinkedList`.
102pub trait DoublyLinkedListContainable<T, Tag = DefaultObjectTag> {
103    /// Returns a reference to the list node.
104    fn get_node(&self) -> &DoublyLinkedListNode<T>;
105}
106
107/// An intrusive doubly linked list container supporting custom ownership semantics, constant-time
108/// operations, and circular-like node layout.
109///
110/// ### Bookkeeping & Memory Storage
111///
112/// The bookkeeping storage (`DoublyLinkedListNode`) required to link elements exists directly
113/// on the objects themselves. This intrusive pattern eliminates the need for runtime bookkeeping
114/// allocations/deallocations when adding or removing members to/from the container.
115///
116/// The list stores pointers to the objects, not the objects themselves, and is parameterized
117/// based on the specific pointer wrapper to be stored (`P`). Supported pointer wrappers are:
118///
119/// * `*mut T`       : Raw unmanaged pointers.
120/// * `UniquePtr<T>` : Unique managed pointers.
121/// * `RefPtr<T>`    : Shared managed pointers to reference-counted objects.
122///
123/// ### Lifecycle Management
124///
125/// * **Managed Pointers (`UniquePtr`/`RefPtr`)**: The list holds ownership references of elements
126///   and follows the rules of the respective smart pointer. Clearing the list or dropping it out of
127///   scope automatically releases references, which may destruct the elements if it was their last
128///   reference.
129///
130/// * **Unmanaged Pointers (`*mut T`)**: The list performs no lifecycle management. It is up to the
131///   caller to ensure elements outlive the list and are freed correctly. As a safety check, a list
132///   of unmanaged pointers will panic/debug-assert if it is dropped with elements still inside.
133///
134/// ### Ring Layout & Sentinel
135///
136/// Nodes are arranged in a circular-like ring structure:
137///
138/// * `head` stores a sentinel value (a pointer to the container itself) when the list is empty.
139/// * For non-empty lists, the `next` pointer of the tail node points to the sentinel, and the
140///   `prev` pointer of the head node points to the tail node. This allows constant-time O(1) tail
141///   lookup and bidirectionality.
142/// * Because the sentinel points back to the container's own memory address, the `DoublyLinkedList`
143///   container **must be pinned in memory** (typically via `pin_init::stack_pin_init!`) and cannot
144///   be safely moved after initialization.
145///
146/// ### Additional Functionality over SinglyLinkedList
147///
148/// * O(1) `push_back`, `pop_back`, and `back` operations.
149/// * The ability to `insert` (before an element) in addition to `insert_after`.
150/// * The ability to `erase` (by reference or iterator) in addition to `erase_next`.
151/// * Bidirectional iteration support.
152///
153/// ### Multiple List Participation
154///
155/// Objects may exist on multiple lists simultaneously through the use of custom `Tag` classes
156/// implementing `DoublyLinkedListContainable` multiple times.
157///
158/// ---
159///
160/// ### Example: Simple list of unmanaged raw pointers
161///
162/// ```rust
163/// # use fbl::{DoublyLinkedList, DoublyLinkedListNode, stack_pin_init, pin_init::PinInit};
164/// #[derive(fbl::DoublyLinkedListContainable)]
165/// struct Foo {
166///     value: i32,
167///     #[dll_node]
168///     node: DoublyLinkedListNode<Foo>,
169/// }
170///
171/// impl Foo {
172///     fn new(value: i32) -> Self {
173///         Self { value, node: DoublyLinkedListNode::new() }
174///     }
175/// }
176///
177/// stack_pin_init!(let list = DoublyLinkedList::<*mut Foo>::new());
178///
179/// // SAFETY: The objects are freshly allocated and are freed only after being removed.
180/// unsafe {
181///     list.as_mut().push_front_raw(Box::into_raw(Box::new(Foo::new(1))));
182///     list.as_mut().push_back_raw(Box::into_raw(Box::new(Foo::new(2))));
183/// }
184///
185/// for foo in list.iter() {
186///     println!("Value: {}", foo.value);
187/// }
188///
189/// while let Some(foo_ptr) = list.as_mut().pop_front() {
190///     // SAFETY: `foo_ptr` was created by `Box::into_raw` and is no longer in the list.
191///     let _ = unsafe { Box::from_raw(foo_ptr) };
192/// }
193/// ```
194///
195/// ### Example: Simple list of unique managed pointers
196///
197/// ```rust
198/// use fbl::{DoublyLinkedList, DoublyLinkedListNode, UniquePtr, stack_pin_init};
199///
200/// #[derive(fbl::DoublyLinkedListContainable, fbl::Recyclable)]
201/// struct Foo {
202///     value: i32,
203///     #[dll_node]
204///     node: DoublyLinkedListNode<Foo>,
205/// }
206///
207/// impl Foo {
208///     fn new(value: i32) -> Self {
209///         Self { value, node: DoublyLinkedListNode::new() }
210///     }
211/// }
212///
213/// stack_pin_init!(let list = DoublyLinkedList::<UniquePtr<Foo>>::new());
214///
215/// list.as_mut().push_front(UniquePtr::try_new(Foo::new(1)).unwrap());
216/// list.as_mut().push_back(UniquePtr::try_new(Foo::new(2)).unwrap());
217///
218/// for foo in list.iter() {
219///     println!("Value: {}", foo.value);
220/// }
221///
222/// // Clearing the list automatically drops unique pointers and reclaims their memory!
223/// list.as_mut().clear();
224/// ```
225///
226/// ### Example: Shared objects in multiple lists simultaneously using Tags
227///
228/// ```rust
229/// use fbl::{DoublyLinkedList, DoublyLinkedListNode, RefPtr, stack_pin_init};
230///
231/// struct TagA;
232/// struct TagB;
233///
234/// #[fbl::ref_counted]
235/// #[derive(fbl::DoublyLinkedListContainable)]
236/// struct Foo {
237///     value: i32,
238///     #[dll_node(TagA)]
239///     node_a: DoublyLinkedListNode<Foo>,
240///     #[dll_node(TagB)]
241///     node_b: DoublyLinkedListNode<Foo>,
242/// }
243///
244/// stack_pin_init!(let list_a = DoublyLinkedList::<RefPtr<Foo>, TagA>::new());
245/// stack_pin_init!(let list_b = DoublyLinkedList::<RefPtr<Foo>, TagB>::new());
246///
247/// let foo = fbl::make_ref_counted!(Foo {
248///     value: 42,
249///     node_a: DoublyLinkedListNode::new(),
250///     node_b: DoublyLinkedListNode::new(),
251/// }).unwrap();
252///
253/// list_a.as_mut().push_back(foo.clone());
254/// list_b.as_mut().push_back(foo);
255/// ```
256#[repr(C)]
257#[pin_data(PinnedDrop)]
258pub struct DoublyLinkedList<P, Tag = DefaultObjectTag, S = NonTrackingSize>
259where
260    P: PtrTraits,
261    P::Target: DoublyLinkedListContainable<P::Target, Tag>,
262    S: SizeTracker,
263{
264    /// Pointer to the first element of the list.
265    ///
266    /// # Link Structure
267    ///
268    /// Nodes in the list are arranged in a circular-like ring structure using a sentinel:
269    /// * For a non-empty list, the `next` pointer of each node points to the next element,
270    ///   and the `next` pointer of the **tail** node points to the **sentinel** (which is
271    ///   a pointer back to this `DoublyLinkedList` container itself).
272    /// * The `prev` pointer of each node points to the previous element.
273    ///
274    /// # Empty List Value
275    ///
276    /// When the list is empty, this `head` pointer holds the **sentinel** value (a pointer
277    /// to the container itself).
278    ///
279    /// # Tail Pointer Location
280    ///
281    /// The tail pointer of the list is located in the `prev` field of the **head** node's
282    /// list node (`head->prev`), which can be accessed or updated via `self.get_tail()` and
283    /// `self.set_tail()`.
284    head: *mut P::Target,
285
286    /// The size tracker for the list, supporting either O(N) or O(1) size operations
287    /// depending on the `S` parameter (e.g., `NonTrackingSize` or `TrackingSize`).
288    size: S,
289
290    /// Marker to ensure the list container is pinned in memory. Pinning is required
291    /// because the sentinel pointer points back to the container's own memory address,
292    /// meaning the list cannot be safely moved once initialized.
293    ///
294    /// Wrapped in `PhantomData` so the list remains FFI-safe when embedded in `#[repr(C)]`
295    /// structs named in `extern` signatures (`improper_ctypes` rejects a bare `PhantomPinned`,
296    /// but ignores `PhantomData` fields).
297    #[pin]
298    _pin: core::marker::PhantomData<core::marker::PhantomPinned>,
299
300    _phantom: core::marker::PhantomData<(P, Tag)>,
301}
302
303impl<P, Tag, S> DoublyLinkedList<P, Tag, S>
304where
305    P: PtrTraits,
306    P::Target: DoublyLinkedListContainable<P::Target, Tag>,
307    S: SizeTracker,
308{
309    /// Creates a new, empty list.
310    #[inline]
311    pub fn new() -> impl PinInit<Self, core::convert::Infallible> {
312        pin_init!(&this in Self {
313            head: make_sentinel(this.as_ptr()),
314            size: S::INIT,
315            _pin: core::marker::PhantomData,
316            _phantom: core::marker::PhantomData,
317        })
318    }
319
320    #[inline]
321    fn get_sentinel(&self) -> *mut P::Target {
322        make_sentinel(self as *const Self as *mut Self)
323    }
324
325    #[inline]
326    fn get_tail(&self) -> *mut P::Target {
327        if self.is_empty() {
328            self.get_sentinel()
329        } else {
330            // SAFETY: `self.head` is a valid, aligned pointer to an element in the list.
331            // Reading `prev` from its node returns a valid pointer (either another node or
332            // sentinel).
333            unsafe { *(*self.head).get_node().prev.get() }
334        }
335    }
336
337    /// # Safety
338    ///
339    /// The caller must ensure that the list is not empty.
340    #[inline]
341    unsafe fn set_tail(&self, tail: *mut P::Target) {
342        debug_assert!(!self.is_empty());
343        // SAFETY: `self.head` is a valid, aligned pointer to an element in the list.
344        // Writing to its `prev` node UnsafeCell is safe because we have exclusive or shared access
345        // and interior mutability is allowed.
346        unsafe {
347            *(*self.head).get_node().prev.get() = tail;
348        }
349    }
350
351    /// # Safety
352    ///
353    /// The caller must ensure that `ptr` is a valid, aligned, and dereferenceable pointer
354    /// to an initialized `P::Target` object that is alive for `'a`.
355    #[inline]
356    unsafe fn get_node_ref<'a>(&self, ptr: *mut P::Target) -> &'a DoublyLinkedListNode<P::Target> {
357        let _ = self;
358        // SAFETY: The caller guarantees `ptr` is valid, aligned, and dereferenceable.
359        unsafe { &(*ptr) }.get_node()
360    }
361
362    /// Returns true if the list is empty.
363    #[inline]
364    pub fn is_empty(&self) -> bool {
365        is_sentinel_ptr(self.head)
366    }
367
368    /// Returns a reference to the first element of the list, or `None` if it is empty.
369    #[inline]
370    pub fn front(&self) -> Option<&P::Target> {
371        if self.is_empty() { None } else { unsafe { Some(&*self.head) } }
372    }
373
374    /// Returns a pinned mutable reference to the first element of the list, or `None` if it is
375    /// empty.
376    #[inline]
377    pub fn front_mut(self: Pin<&mut Self>) -> Option<Pin<&mut P::Target>>
378    where
379        P: MutPtr,
380    {
381        if self.is_empty() {
382            None
383        } else {
384            // SAFETY: `self.head` is a valid element of this list. `P: MutPtr` guarantees that
385            // exclusive access to the list implies exclusive access to its elements, and the list
386            // never moves its elements while they are linked.
387            Some(unsafe { Pin::new_unchecked(&mut *self.head) })
388        }
389    }
390
391    /// Returns a reference to the last element of the list, or `None` if it is empty.
392    #[inline]
393    pub fn back(&self) -> Option<&P::Target> {
394        let tail = self.get_tail();
395        if is_sentinel_ptr(tail) { None } else { unsafe { Some(&*tail) } }
396    }
397
398    /// Returns a pinned mutable reference to the last element of the list, or `None` if it is
399    /// empty.
400    #[inline]
401    pub fn back_mut(self: Pin<&mut Self>) -> Option<Pin<&mut P::Target>>
402    where
403        P: MutPtr,
404    {
405        let tail = self.get_tail();
406        if is_sentinel_ptr(tail) {
407            None
408        } else {
409            // SAFETY: `tail` is a valid element of this list. `P: MutPtr` guarantees that
410            // exclusive access to the list implies exclusive access to its elements, and the list
411            // never moves its elements while they are linked.
412            Some(unsafe { Pin::new_unchecked(&mut *tail) })
413        }
414    }
415
416    /// Returns a cursor positioned at `current`, which must be either a member of this list or
417    /// this list's sentinel.
418    #[inline]
419    fn cursor_at_ptr(self: Pin<&mut Self>, current: *mut P::Target) -> CursorMut<'_, P, Tag, S> {
420        CursorMut { list: self, current }
421    }
422
423    /// Pushes an element to the front of the list.
424    ///
425    /// # Panics
426    ///
427    /// Panics if the object is already in a container.
428    #[inline]
429    pub fn push_front(self: Pin<&mut Self>, ptr: P)
430    where
431        P: ManagedPtr,
432    {
433        // SAFETY: `P` is a `ManagedPtr`, which guarantees that the pointer is valid and that the
434        // object will outlive its reference from this list.
435        unsafe { self.push_front_raw(ptr) }
436    }
437
438    /// Pushes an element to the front of the list.
439    ///
440    /// # Panics
441    ///
442    /// Panics in debug builds if the object is already in a container.
443    ///
444    /// # Safety
445    ///
446    /// The caller must ensure that `ptr` is a valid pointer to a `T` that is not currently in any
447    /// list, and that the object outlives the reference from the list. If mutable element
448    /// accessors (`front_mut`, `back_mut`, `iter_mut`, `CursorMut::get_mut`, etc.) are used on a
449    /// raw-pointer list, the caller must also ensure that no other references to the element are
450    /// accessed while it is mutably borrowed through the list, and that the element satisfies
451    /// `Pin`'s drop guarantee (it is not moved out of its memory location before being dropped,
452    /// unless `P::Target: Unpin`).
453    #[inline]
454    pub unsafe fn push_front_raw(self: Pin<&mut Self>, ptr: P) {
455        let mut cursor = self.cursor_front_mut();
456        // SAFETY: `ptr` is valid and not in container (debug-asserted inside insert_before_raw).
457        unsafe {
458            cursor.insert_before_raw(ptr);
459        }
460    }
461
462    /// Pushes an element to the back of the list.
463    ///
464    /// # Panics
465    ///
466    /// Panics if the object is already in a container.
467    #[inline]
468    pub fn push_back(self: Pin<&mut Self>, ptr: P)
469    where
470        P: ManagedPtr,
471    {
472        // SAFETY: `P` is a `ManagedPtr`, which guarantees that the pointer is valid and that the
473        // object will outlive its reference from this list.
474        unsafe { self.push_back_raw(ptr) }
475    }
476
477    /// Pushes an element to the back of the list.
478    ///
479    /// # Panics
480    ///
481    /// Panics in debug builds if the object is already in a container.
482    ///
483    /// # Safety
484    ///
485    /// The caller must ensure that `ptr` is a valid pointer to an object that is not
486    /// currently in any list. If mutable element accessors (`front_mut`, `back_mut`, `iter_mut`,
487    /// `CursorMut::get_mut`, etc.) are used on a raw-pointer list, the caller must also ensure
488    /// that no other references to the element are accessed while it is mutably borrowed through
489    /// the list, and that the element satisfies `Pin`'s drop guarantee (it is not moved out of its
490    /// memory location before being dropped, unless `P::Target: Unpin`).
491    #[inline]
492    pub unsafe fn push_back_raw(self: Pin<&mut Self>, ptr: P) {
493        let mut cursor = self.cursor_back_mut();
494        // SAFETY: `ptr` is valid and not in container.
495        unsafe {
496            cursor.insert_before_raw(ptr);
497        }
498    }
499
500    /// Removes and returns the first element of the list, or `None` if it is empty.
501    #[inline]
502    pub fn pop_front(self: Pin<&mut Self>) -> Option<P> {
503        self.cursor_front_mut().erase()
504    }
505
506    /// Removes and returns the last element of the list, or `None` if it is empty.
507    #[inline]
508    pub fn pop_back(self: Pin<&mut Self>) -> Option<P> {
509        let tail = self.get_tail();
510        self.cursor_at_ptr(tail).erase()
511    }
512
513    /// Removes all elements from the list.
514    pub fn clear(mut self: Pin<&mut Self>) {
515        while self.as_mut().pop_front().is_some() {}
516    }
517
518    /// A special clear operation that resets the internal container structure in O(1) time,
519    /// leaving the node state of the current elements unmodified.
520    ///
521    /// Only usable with containers of unmanaged pointers (`!P::IS_MANAGED`); attempting to call
522    /// this on a container of managed pointers (`UniquePtr` or `RefPtr`) fails to compile.
523    ///
524    /// While this can be useful in special cases (such as resetting a free list for a pool or slab
525    /// allocator during destruction), you normally do not want this behavior. Think carefully
526    /// before calling this!
527    ///
528    /// # Safety
529    ///
530    /// Unlike C++, `DoublyLinkedListNode` does not have an `AllowClearUnsafe` node option; this
531    /// safety contract replaces the C++ node-option `static_assert`:
532    /// - After this call, every former element retains stale `next` and `prev` links and still
533    ///   reports `in_container() == true`.
534    /// - The caller must ensure that no former element's node is used again by any list or cursor
535    ///   operation (such as insertion, `erase`, `cursor_at`, `replace_raw`, or
536    ///   `remove_from_container`) until its memory is freed or the node is reinitialized.
537    /// - The caller must ensure that no former element's node is dropped while its `Drop`
538    ///   implementation's `!in_container()` debug assertion would fire (for example, by keeping
539    ///   the node in `ManuallyDrop`, freeing the backing memory without running `Drop`, or
540    ///   manually resetting the node state first).
541    #[inline]
542    pub unsafe fn clear_unsafe(self: Pin<&mut Self>) {
543        const {
544            assert!(
545                !P::IS_MANAGED,
546                "clear_unsafe is not allowed for containers of managed pointers",
547            );
548        }
549
550        let sentinel = self.get_sentinel();
551        let this = self.project();
552        *this.head = sentinel;
553
554        // Update our count bookkeeping.
555        if S::IS_TRACKING {
556            this.size.set(0);
557        }
558    }
559
560    /// Erases the given element from the list. Returns the erased element.
561    ///
562    /// # Safety
563    ///
564    /// The caller must ensure that `obj` is a valid reference to an object that is
565    /// currently in this list instance.
566    #[inline]
567    pub unsafe fn erase(self: Pin<&mut Self>, obj: &P::Target) -> Option<P> {
568        let ptr = obj as *const P::Target as *mut P::Target;
569        let node = obj.get_node();
570
571        if !node.in_container() {
572            return None;
573        }
574
575        self.cursor_at_ptr(ptr).erase()
576    }
577
578    /// Replaces the given element with `replacement`. Returns the replaced element.
579    ///
580    /// # Safety
581    ///
582    /// The caller must ensure that `obj` is a valid reference to an object that is
583    /// currently in this list instance, and `replacement` is not in any list. If mutable element
584    /// accessors (`front_mut`, `back_mut`, `iter_mut`, `CursorMut::get_mut`, etc.) are used on a
585    /// raw-pointer list, the caller must also ensure that no other references to `replacement` are
586    /// accessed while it is mutably borrowed through the list, and that `replacement` satisfies
587    /// `Pin`'s drop guarantee (it is not moved out of its memory location before being dropped,
588    /// unless `P::Target: Unpin`).
589    #[inline]
590    pub unsafe fn replace_raw(self: Pin<&mut Self>, obj: &P::Target, replacement: P) -> Option<P> {
591        let ptr = obj as *const P::Target as *mut P::Target;
592        let node = obj.get_node();
593
594        if !node.in_container() {
595            return None;
596        }
597
598        let mut cursor = self.cursor_at_ptr(ptr);
599        // SAFETY: `replacement` is not in any list, and cursor is positioned at a valid element.
600        unsafe { cursor.replace_raw(replacement) }
601    }
602
603    /// Finds the first element matching the predicate, removes it from the list,
604    /// and returns it. Returns `None` if no element matches.
605    #[inline]
606    pub fn erase_if<F>(self: Pin<&mut Self>, mut f: F) -> Option<P>
607    where
608        F: FnMut(&P::Target) -> bool,
609    {
610        let mut cursor = self.cursor_front_mut();
611        while let Some(item) = cursor.get() {
612            if f(item) {
613                return cursor.erase();
614            } else {
615                cursor.move_next();
616            }
617        }
618        None
619    }
620
621    /// Finds the first element that satisfies the predicate.
622    #[inline]
623    pub fn find_if<F>(&self, mut f: F) -> Option<&P::Target>
624    where
625        F: FnMut(&P::Target) -> bool,
626    {
627        self.iter().find(|&x| f(x))
628    }
629
630    /// Returns a cursor positioned at the front of the list.
631    #[inline]
632    pub fn cursor_front_mut(self: Pin<&mut Self>) -> CursorMut<'_, P, Tag, S> {
633        let head = self.head;
634        self.cursor_at_ptr(head)
635    }
636
637    /// Returns a cursor positioned at the back (end sentinel) of the list.
638    #[inline]
639    pub fn cursor_back_mut(self: Pin<&mut Self>) -> CursorMut<'_, P, Tag, S> {
640        let sentinel = self.get_sentinel();
641        self.cursor_at_ptr(sentinel)
642    }
643
644    /// Returns a cursor positioned at the given element.
645    ///
646    /// # Safety
647    ///
648    /// The caller must ensure that `obj` is a member of this list.
649    /// It is undefined behavior to use the returned cursor if `obj` is not in the list,
650    /// or if it is in a different list.
651    #[inline]
652    pub unsafe fn cursor_at(self: Pin<&mut Self>, obj: &P::Target) -> CursorMut<'_, P, Tag, S> {
653        debug_assert!(obj.get_node().in_container(), "Object must be in a container");
654        self.cursor_at_ptr(obj as *const P::Target as *mut P::Target)
655    }
656
657    /// Splices all elements from `other` onto the end of `self`.
658    ///
659    /// Upon completion, `other` is left empty.
660    ///
661    /// This operation is O(1).
662    #[inline]
663    pub fn splice(self: Pin<&mut Self>, other: Pin<&mut DoublyLinkedList<P, Tag, S>>) {
664        self.cursor_back_mut().splice(other);
665    }
666
667    #[inline]
668    pub fn iter(&self) -> Iterator<'_, P, Tag> {
669        Iterator::new(self)
670    }
671
672    /// Returns a mutable bidirectional iterator over the elements of the list.
673    ///
674    /// Elements are yielded as `Pin<&mut P::Target>` since they must not be moved while linked.
675    #[inline]
676    pub fn iter_mut(self: Pin<&mut Self>) -> IteratorMut<'_, P, Tag>
677    where
678        P: MutPtr,
679    {
680        IteratorMut::new(self)
681    }
682
683    /// Returns a unidirectional forward iterator over the elements of the list.
684    #[inline]
685    pub fn forward_iter(&self) -> ForwardIterator<'_, P, Tag> {
686        ForwardIterator::new(self.head)
687    }
688
689    /// Returns a unidirectional forward mutable iterator over the elements of the list.
690    ///
691    /// Elements are yielded as `Pin<&mut P::Target>` since they must not be moved while linked.
692    #[inline]
693    pub fn forward_iter_mut(self: Pin<&mut Self>) -> ForwardIteratorMut<'_, P, Tag>
694    where
695        P: MutPtr,
696    {
697        ForwardIteratorMut::new(self.head)
698    }
699
700    /// Returns a unidirectional reverse iterator over the elements of the list.
701    #[inline]
702    pub fn reverse_iter(&self) -> ReverseIterator<'_, P, Tag> {
703        ReverseIterator::new(self.get_tail())
704    }
705
706    /// Returns a unidirectional reverse mutable iterator over the elements of the list.
707    ///
708    /// Elements are yielded as `Pin<&mut P::Target>` since they must not be moved while linked.
709    #[inline]
710    pub fn reverse_iter_mut(self: Pin<&mut Self>) -> ReverseIteratorMut<'_, P, Tag>
711    where
712        P: MutPtr,
713    {
714        ReverseIteratorMut::new(self.get_tail(), self.head)
715    }
716}
717
718impl<P, Tag> DoublyLinkedList<P, Tag, TrackingSize>
719where
720    P: PtrTraits,
721    P::Target: DoublyLinkedListContainable<P::Target, Tag>,
722{
723    /// Returns the number of elements in the list.
724    #[inline]
725    pub fn len(&self) -> usize {
726        self.size.get()
727    }
728}
729
730#[pinned_drop]
731impl<P, Tag, S> PinnedDrop for DoublyLinkedList<P, Tag, S>
732where
733    P: PtrTraits,
734    P::Target: DoublyLinkedListContainable<P::Target, Tag>,
735    S: SizeTracker,
736{
737    fn drop(self: Pin<&mut Self>) {
738        if P::IS_MANAGED {
739            self.clear();
740        } else {
741            debug_assert!(self.is_empty(), "List must be empty on destruction");
742            if S::IS_TRACKING {
743                debug_assert_eq!(self.size.get(), 0, "Size must be zero on destruction");
744            }
745        }
746    }
747}
748
749/// A cursor that can be used to iterate and modify a `DoublyLinkedList`.
750///
751/// The cursor holds the list as `Pin<&mut DoublyLinkedList>` and mutates the list's `head` and
752/// `size` fields through pin projection, so an unpinned `&mut DoublyLinkedList` is never
753/// materialized.
754pub struct CursorMut<'a, P, Tag = DefaultObjectTag, S = NonTrackingSize>
755where
756    P: PtrTraits,
757    P::Target: DoublyLinkedListContainable<P::Target, Tag>,
758    S: SizeTracker,
759{
760    list: Pin<&'a mut DoublyLinkedList<P, Tag, S>>,
761    current: *mut P::Target,
762}
763
764impl<'a, P, Tag, S> CursorMut<'a, P, Tag, S>
765where
766    P: PtrTraits,
767    P::Target: DoublyLinkedListContainable<P::Target, Tag>,
768    S: SizeTracker,
769{
770    #[inline]
771    pub fn get(&self) -> Option<&P::Target> {
772        if is_sentinel_ptr(self.current) { None } else { unsafe { Some(&*self.current) } }
773    }
774
775    /// Returns a pinned mutable reference to the element at the current position, or `None` if
776    /// the cursor is positioned at the end sentinel.
777    #[inline]
778    pub fn get_mut(&mut self) -> Option<Pin<&mut P::Target>>
779    where
780        P: MutPtr,
781    {
782        if is_sentinel_ptr(self.current) {
783            None
784        } else {
785            // SAFETY: `self.current` is a valid element of the list (not the sentinel). `P: MutPtr`
786            // guarantees that exclusive access to the list (held by this cursor) implies exclusive
787            // access to its elements, and the list never moves its elements while they are linked.
788            Some(unsafe { Pin::new_unchecked(&mut *self.current) })
789        }
790    }
791
792    #[inline]
793    pub fn move_next(&mut self) {
794        if !is_sentinel_ptr(self.current) {
795            // SAFETY: `self.current` is valid current node (not sentinel).
796            let node = unsafe { self.list.get_node_ref(self.current) };
797            self.current = node.get_next();
798        }
799    }
800
801    #[inline]
802    pub fn move_prev(&mut self) {
803        if !is_sentinel_ptr(self.current) {
804            // SAFETY: `self.current` is valid current node (not sentinel).
805            let node = unsafe { self.list.get_node_ref(self.current) };
806            let prev = node.get_prev();
807            if self.current == self.list.head {
808                self.current = self.list.get_sentinel(); // Move to end.
809            } else {
810                self.current = prev;
811            }
812        } else {
813            // If we are at end (sentinel), moving prev should take us to tail.
814            self.current = self.list.get_tail();
815        }
816    }
817
818    /// Inserts a new element after the current position.
819    ///
820    /// # Panics
821    ///
822    /// Panics if the object is already in a container, or if the cursor is positioned
823    /// at the end sentinel.
824    #[inline]
825    pub fn insert_after(&mut self, ptr: P)
826    where
827        P: ManagedPtr,
828    {
829        debug_assert!(!ptr.get_ref().get_node().in_container());
830        // SAFETY: `P` is a `ManagedPtr`, which guarantees that the pointer is valid and that the
831        // object will outlive its reference from this list. `self.current` is checked to not be
832        // a sentinel.
833        unsafe { self.insert_after_raw(ptr) }
834    }
835
836    /// Inserts a new element after the current position.
837    ///
838    /// # Panics
839    ///
840    /// Panics if the cursor is positioned at the end sentinel, or in debug builds if the object is
841    /// already in a container.
842    ///
843    /// # Safety
844    ///
845    /// The caller must ensure that `ptr` is a valid pointer to a `T` that is not currently in any
846    /// list, and that the object outlives the reference from the list. If mutable element
847    /// accessors (`front_mut`, `back_mut`, `iter_mut`, `CursorMut::get_mut`, etc.) are used on a
848    /// raw-pointer list, the caller must also ensure that no other references to the element are
849    /// accessed while it is mutably borrowed through the list, and that the element satisfies
850    /// `Pin`'s drop guarantee (it is not moved out of its memory location before being dropped,
851    /// unless `P::Target: Unpin`).
852    #[inline]
853    pub unsafe fn insert_after_raw(&mut self, ptr: P) {
854        debug_assert!(!is_sentinel_ptr(self.current), "Cannot insert after end sentinel");
855        let raw = P::into_raw(ptr);
856        // SAFETY: `raw` is valid.
857        let node = unsafe { self.list.get_node_ref(raw) };
858        debug_assert!(!node.in_container());
859
860        // SAFETY: `self.current` is valid current node (not sentinel).
861        let current_node = unsafe { self.list.get_node_ref(self.current) };
862        let next = current_node.get_next();
863
864        let current_save = self.current;
865        self.current = next;
866        // SAFETY: `raw` is a single node, and we are inserting it before `next`
867        // (which is equivalent to inserting after `current_save`).
868        unsafe {
869            self.insert_chain_before(raw, raw, 1);
870        }
871        self.current = current_save;
872    }
873
874    /// Replaces the element at the current position with `replacement`. Returns the replaced
875    /// element.
876    ///
877    /// # Panics
878    ///
879    /// Panics if the object is already in a container.
880    #[inline]
881    pub fn replace(&mut self, replacement: P) -> Option<P>
882    where
883        P: ManagedPtr,
884    {
885        // SAFETY: `P` is a `ManagedPtr`, which guarantees that the pointer is valid and that the
886        // object will outlive its reference from this list.
887        unsafe { self.replace_raw(replacement) }
888    }
889
890    /// Replaces the element at the current position with `replacement`. Returns the replaced
891    /// element.
892    ///
893    /// # Panics
894    ///
895    /// Panics in debug builds if the object is already in a container.
896    ///
897    /// # Safety
898    ///
899    /// The caller must ensure that `replacement` is a valid pointer to a `T` that is not currently
900    /// in any list, and that the object outlives the reference from the list. If mutable element
901    /// accessors (`front_mut`, `back_mut`, `iter_mut`, `CursorMut::get_mut`, etc.) are used on a
902    /// raw-pointer list, the caller must also ensure that no other references to `replacement` are
903    /// accessed while it is mutably borrowed through the list, and that `replacement` satisfies
904    /// `Pin`'s drop guarantee (it is not moved out of its memory location before being dropped,
905    /// unless `P::Target: Unpin`).
906    #[inline]
907    pub unsafe fn replace_raw(&mut self, replacement: P) -> Option<P> {
908        if is_sentinel_ptr(self.current) {
909            return None;
910        }
911        // SAFETY: `replacement` is not in any list, and we are inserting it before a valid cursor
912        // position.
913        unsafe {
914            self.insert_before_raw(replacement);
915        }
916        self.erase()
917    }
918
919    /// Inserts a new element before the current position.
920    ///
921    /// # Panics
922    ///
923    /// Panics if the object is already in a container.
924    #[inline]
925    pub fn insert_before(&mut self, ptr: P)
926    where
927        P: ManagedPtr,
928    {
929        debug_assert!(!ptr.get_ref().get_node().in_container());
930        // SAFETY: `P` is a `ManagedPtr`, which guarantees that the pointer is valid and that the
931        // object will outlive its reference from this list.
932        unsafe { self.insert_before_raw(ptr) }
933    }
934
935    /// Inserts a new element before the current position.
936    ///
937    /// # Panics
938    ///
939    /// Panics in debug builds if the object is already in a container.
940    ///
941    /// # Safety
942    ///
943    /// The caller must ensure that `ptr` is a valid pointer to a `T` that is not currently in any
944    /// list, and that the object outlives the reference from the list. If mutable element
945    /// accessors (`front_mut`, `back_mut`, `iter_mut`, `CursorMut::get_mut`, etc.) are used on a
946    /// raw-pointer list, the caller must also ensure that no other references to the element are
947    /// accessed while it is mutably borrowed through the list, and that the element satisfies
948    /// `Pin`'s drop guarantee (it is not moved out of its memory location before being dropped,
949    /// unless `P::Target: Unpin`).
950    #[inline]
951    pub unsafe fn insert_before_raw(&mut self, ptr: P) {
952        let raw = P::into_raw(ptr);
953        // SAFETY: `raw` is valid.
954        let node = unsafe { self.list.get_node_ref(raw) };
955        debug_assert!(!node.in_container());
956
957        // SAFETY: `raw` is a single node, so it is a valid chain of 1 element.
958        unsafe {
959            self.insert_chain_before(raw, raw, 1);
960        }
961    }
962
963    /// Private helper to insert a chain of nodes before the current position.
964    ///
965    /// # Safety
966    ///
967    /// The caller must ensure:
968    /// - `chain_head` and `chain_tail` are valid pointers to elements.
969    /// - They form a valid doubly linked chain.
970    /// - The chain is not empty.
971    /// - The elements in the chain are NOT currently in any list.
972    /// - `count` is the exact number of elements in the chain.
973    #[inline]
974    unsafe fn insert_chain_before(
975        &mut self,
976        chain_head: *mut P::Target,
977        chain_tail: *mut P::Target,
978        count: usize,
979    ) {
980        let head = self.list.head;
981        let before = self.current;
982        // SAFETY: `chain_tail` is valid from caller.
983        let chain_tail_node = unsafe { self.list.get_node_ref(chain_tail) };
984        // SAFETY: `chain_head` is valid from caller.
985        let chain_head_node = unsafe { self.list.get_node_ref(chain_head) };
986
987        if is_sentinel_ptr(head) {
988            chain_tail_node.set_next(before);
989            chain_head_node.set_prev(chain_tail);
990            *self.list.as_mut().project().head = chain_head;
991        } else if before == head {
992            // SAFETY: `head` is not a sentinel, so it is a valid node.
993            let head_node = unsafe { self.list.get_node_ref(head) };
994            let tail = head_node.get_prev();
995            chain_tail_node.set_next(before);
996            chain_head_node.set_prev(tail);
997            head_node.set_prev(chain_tail);
998            *self.list.as_mut().project().head = chain_head;
999        } else if is_sentinel_ptr(before) {
1000            // SAFETY: `head` is not a sentinel, so it is a valid node.
1001            let head_node = unsafe { self.list.get_node_ref(head) };
1002            let tail = head_node.get_prev();
1003            // SAFETY: `tail` is a valid node in a non-empty list.
1004            let tail_node = unsafe { self.list.get_node_ref(tail) };
1005            chain_tail_node.set_next(before);
1006            chain_head_node.set_prev(tail);
1007            tail_node.set_next(chain_head);
1008            head_node.set_prev(chain_tail);
1009        } else {
1010            // SAFETY: `before` is not a sentinel, so it is a valid node.
1011            let current_node = unsafe { self.list.get_node_ref(before) };
1012            let prev = current_node.get_prev();
1013            // SAFETY: `prev` is a valid predecessor node.
1014            let prev_node = unsafe { self.list.get_node_ref(prev) };
1015            chain_tail_node.set_next(before);
1016            chain_head_node.set_prev(prev);
1017            prev_node.set_next(chain_head);
1018            current_node.set_prev(chain_tail);
1019        }
1020
1021        if S::IS_TRACKING {
1022            let new_size = self.list.size.get() + count;
1023            self.list.as_mut().project().size.set(new_size);
1024        }
1025    }
1026
1027    /// Splices the elements of `other` into the list at the current cursor position.
1028    ///
1029    /// All elements from `other` are moved into `self.list` and inserted immediately
1030    /// *before* the element currently pointed to by the cursor.
1031    ///
1032    /// - If the cursor is positioned at a valid element, `other` is inserted before it.
1033    /// - If the cursor is positioned at the end sentinel (i.e., `cursor.get()` returns `None`),
1034    ///   `other` is appended to the end of the list (after the current tail).
1035    /// - If the list is empty, `other` becomes the new content of the list.
1036    ///
1037    /// Upon completion, `other` is left empty.
1038    ///
1039    /// This operation is O(1).
1040    pub fn splice(&mut self, other: Pin<&mut DoublyLinkedList<P, Tag, S>>) {
1041        if other.is_empty() {
1042            return;
1043        }
1044
1045        let other_head = other.head;
1046        let other_tail = other.get_tail();
1047        let other_sentinel = other.get_sentinel();
1048        let count = if S::IS_TRACKING { other.size.get() } else { 0 };
1049
1050        // SAFETY: We are moving elements from `other` which is a valid list,
1051        // so they are valid and not in any other list.
1052        unsafe {
1053            self.insert_chain_before(other_head, other_tail, count);
1054        }
1055
1056        let other = other.project();
1057        *other.head = other_sentinel;
1058        if S::IS_TRACKING {
1059            other.size.set(0);
1060        }
1061    }
1062
1063    /// Splits the list immediately after the current cursor position, moving all elements
1064    /// after the cursor into `dest`, inserted before `dest`'s current position.
1065    ///
1066    /// The current list retains all elements up to and including the current element.
1067    ///
1068    /// If the cursor is positioned at the tail of the list, no elements are moved.
1069    ///
1070    /// # Panics
1071    ///
1072    /// Panics if the cursor is positioned at the end sentinel.
1073    ///
1074    /// This operation is O(1) for lists with non-tracking size.
1075    pub fn split_after(&mut self, dest: &mut CursorMut<'_, P, Tag, S>) {
1076        debug_assert!(!is_sentinel_ptr(self.current), "Cannot split after end sentinel");
1077
1078        // SAFETY: `self.current` is not sentinel.
1079        let curr_node = unsafe { self.list.get_node_ref(self.current) };
1080        let next_ptr = curr_node.get_next();
1081
1082        // If cursor is at the tail, there are no elements after it.
1083        if is_sentinel_ptr(next_ptr) {
1084            return;
1085        }
1086
1087        let chain_head = next_ptr;
1088        let chain_tail = self.list.get_tail();
1089
1090        let mut count = 0;
1091        if S::IS_TRACKING {
1092            let mut p = chain_head;
1093            let sentinel = self.list.get_sentinel();
1094            while p != sentinel {
1095                count += 1;
1096                // SAFETY: `p` is in the chain.
1097                p = unsafe { self.list.get_node_ref(p) }.get_next();
1098            }
1099            let new_size = self.list.size.get() - count;
1100            self.list.as_mut().project().size.set(new_size);
1101        }
1102
1103        // Update self.list: `self.current` becomes the new tail.
1104        curr_node.set_next(self.list.get_sentinel());
1105        unsafe {
1106            self.list.set_tail(self.current);
1107        }
1108
1109        // Insert the extracted chain before dest's current position.
1110        // SAFETY: The chain [chain_head .. chain_tail] is valid, detached from self.list,
1111        // and count is exact.
1112        unsafe {
1113            dest.insert_chain_before(chain_head, chain_tail, count);
1114        }
1115    }
1116
1117    /// Splits the list immediately before the current cursor position, moving all elements
1118    /// before the cursor into `dest`, inserted before `dest`'s current position.
1119    ///
1120    /// The current list retains all elements from the current position to the end of the list.
1121    ///
1122    /// - If the cursor is positioned at the head of the list, no elements are moved.
1123    /// - If the cursor is positioned at the end sentinel, all elements of the list are moved
1124    ///   into `dest`, leaving this list empty.
1125    /// - If the cursor is positioned at an element between head and sentinel, all elements from
1126    ///   head up to (and excluding) the current element are moved into `dest`.
1127    ///
1128    /// Upon completion, the cursor remains positioned at the same element (which is now the new
1129    /// head of this list, or the sentinel).
1130    ///
1131    /// This operation is O(1) for lists with non-tracking size.
1132    pub fn split_before(&mut self, dest: &mut CursorMut<'_, P, Tag, S>) {
1133        // Case 1: Cursor is at head. No elements before head.
1134        if self.current == self.list.head {
1135            return;
1136        }
1137
1138        // Case 2: Cursor is at sentinel. All elements in list are before sentinel.
1139        if is_sentinel_ptr(self.current) {
1140            if self.list.is_empty() {
1141                return;
1142            }
1143            let chain_head = self.list.head;
1144            let chain_tail = self.list.get_tail();
1145            let sentinel = self.list.get_sentinel();
1146            let list = self.list.as_mut().project();
1147            let count = if S::IS_TRACKING {
1148                let c = list.size.get();
1149                list.size.set(0);
1150                c
1151            } else {
1152                0
1153            };
1154
1155            *list.head = sentinel;
1156
1157            // SAFETY: The chain [chain_head .. chain_tail] is valid, detached from self.list,
1158            // and count is exact.
1159            unsafe {
1160                dest.insert_chain_before(chain_head, chain_tail, count);
1161            }
1162            return;
1163        }
1164
1165        // Case 3: Cursor is at an interior element B.
1166        // Elements before B are [head .. B.prev].
1167        let b = self.current;
1168        let b_node = unsafe { self.list.get_node_ref(b) };
1169        let chain_head = self.list.head;
1170        let chain_tail = b_node.get_prev();
1171        let old_tail = self.list.get_tail();
1172
1173        let mut count = 0;
1174        if S::IS_TRACKING {
1175            let mut p = chain_head;
1176            while p != b {
1177                count += 1;
1178                // SAFETY: `p` is in the chain.
1179                p = unsafe { self.list.get_node_ref(p) }.get_next();
1180            }
1181            let new_size = self.list.size.get() - count;
1182            self.list.as_mut().project().size.set(new_size);
1183        }
1184
1185        // Update self.list: B becomes the new head, and its prev points to old_tail.
1186        *self.list.as_mut().project().head = b;
1187        b_node.set_prev(old_tail);
1188
1189        // Insert the extracted chain before dest's current position.
1190        // SAFETY: The chain [chain_head .. chain_tail] is valid, detached from self.list,
1191        // and count is exact.
1192        unsafe {
1193            dest.insert_chain_before(chain_head, chain_tail, count);
1194        }
1195    }
1196
1197    #[inline]
1198    pub fn erase(&mut self) -> Option<P> {
1199        let ptr = self.current;
1200        if is_sentinel_ptr(ptr) {
1201            return None;
1202        }
1203        let head = self.list.head;
1204        // SAFETY: `ptr` is valid current node.
1205        let node = unsafe { self.list.get_node_ref(ptr) };
1206        let next = node.get_next();
1207        let prev = node.get_prev();
1208
1209        self.list.as_mut().project().size.decrement();
1210
1211        let tgt_prev_node = if is_sentinel_ptr(next) { head } else { next };
1212        // SAFETY: Both `head` and `next` (when not sentinel) are valid nodes in a non-empty list.
1213        unsafe { self.list.get_node_ref(tgt_prev_node) }.set_prev(prev);
1214
1215        if ptr == head {
1216            *self.list.as_mut().project().head = next;
1217        } else {
1218            // SAFETY: `prev` is a valid predecessor node.
1219            unsafe { self.list.get_node_ref(prev) }.set_next(next);
1220        }
1221
1222        node.set_prev(core::ptr::null_mut());
1223        node.set_next(core::ptr::null_mut());
1224
1225        self.current = next;
1226        // SAFETY: `ptr` was popped, safe to reconstruct.
1227        Some(unsafe { P::from_raw(ptr) })
1228    }
1229}
1230
1231/// An iterator over the elements of a `DoublyLinkedList`.
1232pub struct Iterator<'a, P, Tag = DefaultObjectTag>
1233where
1234    P: PtrTraits,
1235    P::Target: DoublyLinkedListContainable<P::Target, Tag>,
1236{
1237    front: ForwardIterator<'a, P, Tag>,
1238    back: ReverseIterator<'a, P, Tag>,
1239}
1240
1241impl<'a, P, Tag> Iterator<'a, P, Tag>
1242where
1243    P: PtrTraits,
1244    P::Target: DoublyLinkedListContainable<P::Target, Tag>,
1245{
1246    fn new<S: SizeTracker>(list: &'a DoublyLinkedList<P, Tag, S>) -> Self {
1247        if list.is_empty() {
1248            Self {
1249                front: ForwardIterator::new(crate::make_sentinel_null()),
1250                back: ReverseIterator::new(crate::make_sentinel_null()),
1251            }
1252        } else {
1253            Self {
1254                front: ForwardIterator::new(list.head),
1255                back: ReverseIterator::new(list.get_tail()),
1256            }
1257        }
1258    }
1259}
1260
1261impl<'a, P, Tag> core::iter::Iterator for Iterator<'a, P, Tag>
1262where
1263    P: PtrTraits,
1264    P::Target: DoublyLinkedListContainable<P::Target, Tag>,
1265{
1266    type Item = &'a P::Target;
1267
1268    fn next(&mut self) -> Option<Self::Item> {
1269        let met = self.front.current == self.back.current;
1270        let item = self.front.next();
1271        if item.is_some() && met {
1272            self.front.current = crate::make_sentinel_null();
1273            self.back.current = crate::make_sentinel_null();
1274        }
1275        item
1276    }
1277}
1278
1279impl<'a, P, Tag> core::iter::DoubleEndedIterator for Iterator<'a, P, Tag>
1280where
1281    P: PtrTraits,
1282    P::Target: DoublyLinkedListContainable<P::Target, Tag>,
1283{
1284    fn next_back(&mut self) -> Option<Self::Item> {
1285        let met = self.front.current == self.back.current;
1286        let item = self.back.next();
1287        if item.is_some() && met {
1288            self.front.current = crate::make_sentinel_null();
1289            self.back.current = crate::make_sentinel_null();
1290        }
1291        item
1292    }
1293}
1294
1295/// A unidirectional forward iterator over the elements of a `DoublyLinkedList`.
1296pub struct ForwardIterator<'a, P, Tag = DefaultObjectTag>
1297where
1298    P: PtrTraits,
1299    P::Target: DoublyLinkedListContainable<P::Target, Tag>,
1300{
1301    current: *mut P::Target,
1302    _phantom: core::marker::PhantomData<&'a (P, Tag)>,
1303}
1304
1305impl<'a, P, Tag> ForwardIterator<'a, P, Tag>
1306where
1307    P: PtrTraits,
1308    P::Target: DoublyLinkedListContainable<P::Target, Tag>,
1309{
1310    fn new(current: *mut P::Target) -> Self {
1311        Self { current, _phantom: core::marker::PhantomData }
1312    }
1313}
1314
1315impl<'a, P, Tag> core::iter::Iterator for ForwardIterator<'a, P, Tag>
1316where
1317    P: PtrTraits,
1318    P::Target: DoublyLinkedListContainable<P::Target, Tag>,
1319{
1320    type Item = &'a P::Target;
1321
1322    fn next(&mut self) -> Option<Self::Item> {
1323        if is_sentinel_ptr(self.current) {
1324            None
1325        } else {
1326            // SAFETY: `self.current` is not a sentinel, so it is a valid, aligned pointer to an
1327            // element.  The list is guaranteed to be immutable for the lifetime `'a` of the
1328            // iterator.
1329            let current = unsafe { &*self.current };
1330            self.current = current.get_node().get_next();
1331            Some(current)
1332        }
1333    }
1334}
1335
1336/// A unidirectional reverse iterator over the elements of a `DoublyLinkedList`.
1337pub struct ReverseIterator<'a, P, Tag = DefaultObjectTag>
1338where
1339    P: PtrTraits,
1340    P::Target: DoublyLinkedListContainable<P::Target, Tag>,
1341{
1342    current: *mut P::Target,
1343    _phantom: core::marker::PhantomData<&'a (P, Tag)>,
1344}
1345
1346impl<'a, P, Tag> ReverseIterator<'a, P, Tag>
1347where
1348    P: PtrTraits,
1349    P::Target: DoublyLinkedListContainable<P::Target, Tag>,
1350{
1351    fn new(current: *mut P::Target) -> Self {
1352        Self { current, _phantom: core::marker::PhantomData }
1353    }
1354}
1355
1356impl<'a, P, Tag> core::iter::Iterator for ReverseIterator<'a, P, Tag>
1357where
1358    P: PtrTraits,
1359    P::Target: DoublyLinkedListContainable<P::Target, Tag>,
1360{
1361    type Item = &'a P::Target;
1362
1363    fn next(&mut self) -> Option<Self::Item> {
1364        if is_sentinel_ptr(self.current) {
1365            None
1366        } else {
1367            // SAFETY: `self.current` is not a sentinel, so it is a valid, aligned pointer to an
1368            // element.  The list is guaranteed to be immutable for the lifetime `'a` of the
1369            // iterator.
1370            let current = unsafe { &*self.current };
1371            let prev = current.get_node().get_prev();
1372
1373            // SAFETY: `prev` must be a valid pointer because `current` is in the list.  In a
1374            // circular doubly linked list, prev is never null.
1375            let prev_node = unsafe { &*prev }.get_node();
1376            if is_sentinel_ptr(prev_node.get_next()) {
1377                // We have looped around the head and landed on the tail.
1378                // Set current to the sentinel to terminate iteration.
1379                self.current = prev_node.get_next();
1380            } else {
1381                self.current = prev;
1382            }
1383            Some(current)
1384        }
1385    }
1386}
1387
1388/// A mutable bidirectional iterator over the elements of a `DoublyLinkedList`.
1389///
1390/// Elements are yielded as `Pin<&mut P::Target>` since they must not be moved while linked.
1391pub struct IteratorMut<'a, P, Tag = DefaultObjectTag>
1392where
1393    P: MutPtr,
1394    P::Target: DoublyLinkedListContainable<P::Target, Tag>,
1395{
1396    front: ForwardIteratorMut<'a, P, Tag>,
1397    back: ReverseIteratorMut<'a, P, Tag>,
1398}
1399
1400impl<'a, P, Tag> IteratorMut<'a, P, Tag>
1401where
1402    P: MutPtr,
1403    P::Target: DoublyLinkedListContainable<P::Target, Tag>,
1404{
1405    fn new<S: SizeTracker>(list: Pin<&'a mut DoublyLinkedList<P, Tag, S>>) -> Self {
1406        if list.is_empty() {
1407            Self {
1408                front: ForwardIteratorMut::new(crate::make_sentinel_null()),
1409                back: ReverseIteratorMut::new(
1410                    crate::make_sentinel_null(),
1411                    crate::make_sentinel_null(),
1412                ),
1413            }
1414        } else {
1415            let tail = list.get_tail();
1416            Self {
1417                front: ForwardIteratorMut::new(list.head),
1418                back: ReverseIteratorMut::new(tail, list.head),
1419            }
1420        }
1421    }
1422}
1423
1424impl<'a, P, Tag> core::iter::Iterator for IteratorMut<'a, P, Tag>
1425where
1426    P: MutPtr,
1427    P::Target: DoublyLinkedListContainable<P::Target, Tag>,
1428{
1429    type Item = Pin<&'a mut P::Target>;
1430
1431    fn next(&mut self) -> Option<Self::Item> {
1432        let met = self.front.current == self.back.current;
1433        let item = self.front.next();
1434        if item.is_some() && met {
1435            self.front.current = crate::make_sentinel_null();
1436            self.back.current = crate::make_sentinel_null();
1437        }
1438        item
1439    }
1440}
1441
1442impl<'a, P, Tag> core::iter::DoubleEndedIterator for IteratorMut<'a, P, Tag>
1443where
1444    P: MutPtr,
1445    P::Target: DoublyLinkedListContainable<P::Target, Tag>,
1446{
1447    fn next_back(&mut self) -> Option<Self::Item> {
1448        let met = self.front.current == self.back.current;
1449        let item = self.back.next();
1450        if item.is_some() && met {
1451            self.front.current = crate::make_sentinel_null();
1452            self.back.current = crate::make_sentinel_null();
1453        }
1454        item
1455    }
1456}
1457
1458/// A unidirectional forward mutable iterator over the elements of a `DoublyLinkedList`.
1459///
1460/// Elements are yielded as `Pin<&mut P::Target>` since they must not be moved while linked.
1461pub struct ForwardIteratorMut<'a, P, Tag = DefaultObjectTag>
1462where
1463    P: MutPtr,
1464    P::Target: DoublyLinkedListContainable<P::Target, Tag>,
1465{
1466    current: *mut P::Target,
1467    _phantom: core::marker::PhantomData<&'a mut (P, Tag)>,
1468}
1469
1470impl<'a, P, Tag> ForwardIteratorMut<'a, P, Tag>
1471where
1472    P: MutPtr,
1473    P::Target: DoublyLinkedListContainable<P::Target, Tag>,
1474{
1475    fn new(current: *mut P::Target) -> Self {
1476        Self { current, _phantom: core::marker::PhantomData }
1477    }
1478}
1479
1480impl<'a, P, Tag> core::iter::Iterator for ForwardIteratorMut<'a, P, Tag>
1481where
1482    P: MutPtr,
1483    P::Target: DoublyLinkedListContainable<P::Target, Tag>,
1484{
1485    type Item = Pin<&'a mut P::Target>;
1486
1487    fn next(&mut self) -> Option<Self::Item> {
1488        if is_sentinel_ptr(self.current) {
1489            None
1490        } else {
1491            let current_ptr = self.current;
1492            // SAFETY: `current_ptr` is not a sentinel, so it is a valid, aligned pointer to an
1493            // element. No mutable reference to it is live yet.
1494            self.current = unsafe { &*current_ptr }.get_node().get_next();
1495            // SAFETY: `current_ptr` is a valid element. The list is exclusively borrowed for
1496            // lifetime `'a`, `P: MutPtr` guarantees that this implies exclusive access to its
1497            // elements, and each element in the intrusive list is distinct, so yielding
1498            // `&'a mut P::Target` one-by-one is sound. The list never moves its elements while
1499            // they are linked.
1500            Some(unsafe { Pin::new_unchecked(&mut *current_ptr) })
1501        }
1502    }
1503}
1504
1505/// A unidirectional reverse mutable iterator over the elements of a `DoublyLinkedList`.
1506///
1507/// Elements are yielded as `Pin<&mut P::Target>` since they must not be moved while linked.
1508pub struct ReverseIteratorMut<'a, P, Tag = DefaultObjectTag>
1509where
1510    P: MutPtr,
1511    P::Target: DoublyLinkedListContainable<P::Target, Tag>,
1512{
1513    current: *mut P::Target,
1514    head: *mut P::Target,
1515    _phantom: core::marker::PhantomData<&'a mut (P, Tag)>,
1516}
1517
1518impl<'a, P, Tag> ReverseIteratorMut<'a, P, Tag>
1519where
1520    P: MutPtr,
1521    P::Target: DoublyLinkedListContainable<P::Target, Tag>,
1522{
1523    fn new(current: *mut P::Target, head: *mut P::Target) -> Self {
1524        Self { current, head, _phantom: core::marker::PhantomData }
1525    }
1526}
1527
1528impl<'a, P, Tag> core::iter::Iterator for ReverseIteratorMut<'a, P, Tag>
1529where
1530    P: MutPtr,
1531    P::Target: DoublyLinkedListContainable<P::Target, Tag>,
1532{
1533    type Item = Pin<&'a mut P::Target>;
1534
1535    fn next(&mut self) -> Option<Self::Item> {
1536        if is_sentinel_ptr(self.current) {
1537            None
1538        } else {
1539            let current_ptr = self.current;
1540            if current_ptr == self.head {
1541                self.current = crate::make_sentinel_null();
1542            } else {
1543                // SAFETY: `current_ptr` is not a sentinel, so it is a valid, aligned pointer to an
1544                // element. No mutable reference to it is live yet.
1545                self.current = unsafe { &*current_ptr }.get_node().get_prev();
1546            }
1547            // SAFETY: `current_ptr` is a valid element. The list is exclusively borrowed for
1548            // lifetime `'a`, `P: MutPtr` guarantees that this implies exclusive access to its
1549            // elements, and each element in the intrusive list is distinct, so yielding
1550            // `&'a mut P::Target` one-by-one is sound. The list never moves its elements while
1551            // they are linked.
1552            Some(unsafe { Pin::new_unchecked(&mut *current_ptr) })
1553        }
1554    }
1555}
1556
1557/// Removes an object from its container without a reference to the container.
1558///
1559/// # Safety
1560///
1561/// The caller must ensure that `obj` is currently in a valid list instance that does NOT
1562/// track its size (uses `NonTrackingSize`), and that no other mutable references to that
1563/// list are active.
1564#[inline]
1565pub unsafe fn remove_from_container<T, Tag, P>(obj: &T) -> Option<P>
1566where
1567    P: PtrTraits<Target = T>,
1568    T: DoublyLinkedListContainable<T, Tag>,
1569{
1570    let node = obj.get_node();
1571    let next = node.get_next();
1572    if next.is_null() {
1573        return None;
1574    }
1575    let prev = node.get_prev();
1576    debug_assert!(!prev.is_null());
1577
1578    // SAFETY: Caller guarantees `obj` is in a valid untracked list and no other references to the
1579    // list are active.
1580    unsafe {
1581        let tgt_prev = if is_sentinel_ptr(next) {
1582            let list_ptr = crate::sentinel::unmake_sentinel::<
1583                DoublyLinkedList<P, Tag, NonTrackingSize>,
1584                T,
1585            >(next);
1586            (*(*list_ptr).head).get_node().prev.get()
1587        } else {
1588            (*next).get_node().prev.get()
1589        };
1590
1591        let prev_node = (*prev).get_node();
1592        let prev_next = prev_node.get_next();
1593        let tgt_next = if is_sentinel_ptr(prev_next) {
1594            let list_ptr = crate::sentinel::unmake_sentinel::<
1595                DoublyLinkedList<P, Tag, NonTrackingSize>,
1596                T,
1597            >(prev_next);
1598            &raw mut (*list_ptr).head
1599        } else {
1600            prev_node.next.get()
1601        };
1602
1603        *tgt_prev = prev;
1604        *tgt_next = next;
1605
1606        node.set_next(core::ptr::null_mut());
1607        node.set_prev(core::ptr::null_mut());
1608
1609        Some(P::from_raw(obj as *const T as *mut T))
1610    }
1611}
1612
1613impl<P, Tag, S> core::fmt::Debug for DoublyLinkedList<P, Tag, S>
1614where
1615    P: PtrTraits,
1616    P::Target: DoublyLinkedListContainable<P::Target, Tag> + core::fmt::Debug,
1617    S: SizeTracker,
1618{
1619    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
1620        f.debug_list().entries(self.iter()).finish()
1621    }
1622}
1623
1624#[cfg(test)]
1625mod tests {
1626    extern crate alloc;
1627    use super::*;
1628    use crate::intrusive_container_test_support::*;
1629    use crate::ref_ptr::RefPtr;
1630    use crate::unique_ptr::UniquePtr;
1631    use core::ffi::c_void;
1632    use pin_init::stack_pin_init;
1633
1634    #[derive(crate::DoublyLinkedListContainable, crate::Recyclable)]
1635    #[pin_data]
1636    struct TestObject {
1637        value: i32,
1638        #[pin]
1639        #[dll_node]
1640        node: DoublyLinkedListNode<TestObject>,
1641    }
1642
1643    impl TestObject {
1644        fn new(value: i32) -> Self {
1645            Self { value, node: DoublyLinkedListNode::new() }
1646        }
1647    }
1648
1649    impl TestValue for TestObject {
1650        fn new(value: i32) -> Self {
1651            Self::new(value)
1652        }
1653    }
1654
1655    ::zr::static_assert!(
1656        core::mem::size_of::<DoublyLinkedListNode<TestObject>>()
1657            == 2 * core::mem::size_of::<*mut TestObject>()
1658    );
1659    ::zr::static_assert!(
1660        core::mem::align_of::<DoublyLinkedListNode<TestObject>>()
1661            == core::mem::align_of::<*mut TestObject>()
1662    );
1663
1664    ::zr::static_assert!(
1665        core::mem::size_of::<DoublyLinkedList<*mut TestObject>>()
1666            == core::mem::size_of::<*mut TestObject>()
1667    );
1668    ::zr::static_assert!(
1669        core::mem::align_of::<DoublyLinkedList<*mut TestObject>>()
1670            == core::mem::align_of::<*mut TestObject>()
1671    );
1672
1673    ::zr::static_assert!(
1674        core::mem::size_of::<DoublyLinkedList<*mut TestObject, DefaultObjectTag, TrackingSize>>()
1675            == 2 * core::mem::size_of::<*mut TestObject>()
1676    );
1677    ::zr::static_assert!(
1678        core::mem::align_of::<DoublyLinkedList<*mut TestObject, DefaultObjectTag, TrackingSize>>()
1679            == core::mem::align_of::<*mut TestObject>()
1680    );
1681
1682    ::zr::static_assert!(
1683        core::mem::size_of::<ForwardIterator<'_, *mut TestObject>>()
1684            == core::mem::size_of::<*mut TestObject>()
1685    );
1686    ::zr::static_assert!(
1687        core::mem::align_of::<ForwardIterator<'_, *mut TestObject>>()
1688            == core::mem::align_of::<*mut TestObject>()
1689    );
1690
1691    ::zr::static_assert!(
1692        core::mem::size_of::<ReverseIterator<'_, *mut TestObject>>()
1693            == core::mem::size_of::<*mut TestObject>()
1694    );
1695    ::zr::static_assert!(
1696        core::mem::align_of::<ReverseIterator<'_, *mut TestObject>>()
1697            == core::mem::align_of::<*mut TestObject>()
1698    );
1699
1700    #[derive(crate::DoublyLinkedListContainable, crate::Recyclable)]
1701    #[pin_data]
1702    struct UniqueTestObject {
1703        value: i32,
1704        #[pin]
1705        #[dll_node]
1706        node: DoublyLinkedListNode<UniqueTestObject>,
1707    }
1708
1709    impl UniqueTestObject {
1710        fn new(value: i32) -> Self {
1711            Self { value, node: DoublyLinkedListNode::new() }
1712        }
1713    }
1714
1715    impl TestValue for UniqueTestObject {
1716        fn new(value: i32) -> Self {
1717            Self::new(value)
1718        }
1719    }
1720
1721    #[fbl::ref_counted]
1722    #[derive(crate::DoublyLinkedListContainable, crate::Recyclable)]
1723    #[repr(C)]
1724    pub struct RefTestObject {
1725        value: i32,
1726        #[dll_node]
1727        node: DoublyLinkedListNode<RefTestObject>,
1728    }
1729
1730    impl TestValue for RefTestObject {
1731        fn new_ref_counted(value: i32) -> RefPtr<Self> {
1732            crate::make_ref_counted!(RefTestObject {
1733                value: value,
1734                node: DoublyLinkedListNode::new()
1735            })
1736            .unwrap()
1737        }
1738    }
1739
1740    macro_rules! generate_list_tests {
1741        ($mod_name:ident, $ptr_type:ty, $factory_type:ty, $get_val:expr, $push:expr) => {
1742            mod $mod_name {
1743                use super::*;
1744
1745                #[test]
1746                fn test_basic() {
1747                    let mut factory = <$factory_type>::new();
1748                    stack_pin_init!(let list = DoublyLinkedList::<$ptr_type>::new());
1749                    assert!(list.is_empty());
1750
1751                    let obj1 = factory.create(1);
1752                    let obj2 = factory.create(2);
1753
1754                    $push(list.as_mut(), obj1);
1755                    $push(list.as_mut(), obj2);
1756
1757                    assert!(!list.is_empty());
1758
1759                    let mut iter = list.iter();
1760                    assert_eq!(iter.next().unwrap().value, 2);
1761                    assert_eq!(iter.next().unwrap().value, 1);
1762                    assert!(iter.next().is_none());
1763
1764                    list.as_mut().clear();
1765                    assert!(list.is_empty());
1766                }
1767
1768                #[test]
1769                fn test_double_ended_iterator() {
1770                    let mut factory = <$factory_type>::new();
1771                    stack_pin_init!(let list = DoublyLinkedList::<$ptr_type>::new());
1772                    let obj1 = factory.create(1);
1773                    let obj2 = factory.create(2);
1774                    let obj3 = factory.create(3);
1775
1776                    $push(list.as_mut(), obj1);
1777                    $push(list.as_mut(), obj2);
1778                    $push(list.as_mut(), obj3);
1779
1780                    let mut iter = list.iter();
1781                    assert_eq!(iter.next().unwrap().value, 3);
1782                    assert_eq!(iter.next_back().unwrap().value, 1);
1783                    assert_eq!(iter.next().unwrap().value, 2);
1784                    assert!(iter.next().is_none());
1785                    assert!(iter.next_back().is_none());
1786
1787                    list.as_mut().clear();
1788                }
1789
1790                #[test]
1791                fn test_explicit_pops() {
1792                    let mut factory = <$factory_type>::new();
1793                    stack_pin_init!(let list = DoublyLinkedList::<$ptr_type>::new());
1794                    let obj1 = factory.create(1);
1795                    let obj2 = factory.create(2);
1796
1797                    $push(list.as_mut(), obj1);
1798                    $push(list.as_mut(), obj2);
1799
1800                    let p1 = list.as_mut().pop_front();
1801                    assert!(p1.is_some());
1802                    let p2 = list.as_mut().pop_front();
1803                    assert!(p2.is_some());
1804                    assert!(list.as_mut().pop_front().is_none());
1805                }
1806
1807                #[test]
1808                fn test_cursor_move_prev() {
1809                    let mut factory = <$factory_type>::new();
1810                    stack_pin_init!(let list = DoublyLinkedList::<$ptr_type>::new());
1811                    let obj1 = factory.create(1);
1812                    let obj2 = factory.create(2);
1813                    let obj3 = factory.create(3);
1814
1815                    $push(list.as_mut(), obj1);
1816                    $push(list.as_mut(), obj2);
1817                    $push(list.as_mut(), obj3);
1818
1819                    let (a, b, c) = {
1820                        let mut iter = list.iter();
1821                        (
1822                            $get_val(iter.next().unwrap()),
1823                            $get_val(iter.next().unwrap()),
1824                            $get_val(iter.next().unwrap()),
1825                        )
1826                    };
1827
1828                    let mut cursor = list.as_mut().cursor_front_mut();
1829                    assert_eq!($get_val(cursor.get().unwrap()), a);
1830
1831                    cursor.move_prev();
1832                    assert!(cursor.get().is_none()); // Sentinel
1833
1834                    cursor.move_prev();
1835                    assert_eq!($get_val(cursor.get().unwrap()), c);
1836
1837                    cursor.move_prev();
1838                    assert_eq!($get_val(cursor.get().unwrap()), b);
1839
1840                    cursor.move_prev();
1841                    assert_eq!($get_val(cursor.get().unwrap()), a);
1842
1843                    list.as_mut().clear();
1844                }
1845
1846                #[test]
1847                fn test_cursor_insert_after() {
1848                    let mut factory = <$factory_type>::new();
1849                    stack_pin_init!(let list = DoublyLinkedList::<$ptr_type>::new());
1850                    let obj1 = factory.create(1);
1851                    let obj2 = factory.create(2);
1852                    let obj3 = factory.create(3);
1853
1854                    $push(list.as_mut(), obj1);
1855
1856                    let mut cursor = list.as_mut().cursor_front_mut();
1857                    unsafe {
1858                        cursor.insert_after_raw(obj3);
1859                        cursor.insert_after_raw(obj2);
1860                    }
1861
1862                    let mut iter = list.iter();
1863                    assert_eq!($get_val(iter.next().unwrap()), 1);
1864                    assert_eq!($get_val(iter.next().unwrap()), 2);
1865                    assert_eq!($get_val(iter.next().unwrap()), 3);
1866                    assert!(iter.next().is_none());
1867
1868                    list.as_mut().clear();
1869                }
1870
1871                #[test]
1872                fn test_pop_back() {
1873                    let mut factory = <$factory_type>::new();
1874                    stack_pin_init!(let list = DoublyLinkedList::<$ptr_type>::new());
1875                    let obj1 = factory.create(1);
1876                    let obj2 = factory.create(2);
1877
1878                    $push(list.as_mut(), obj1);
1879                    $push(list.as_mut(), obj2);
1880
1881                    let p1 = list.as_mut().pop_back();
1882                    assert!(p1.is_some());
1883                    let p2 = list.as_mut().pop_back();
1884                    assert!(p2.is_some());
1885                    assert!(list.as_mut().pop_back().is_none());
1886                }
1887
1888                #[test]
1889                fn test_erase() {
1890                    let mut factory = <$factory_type>::new();
1891                    stack_pin_init!(let list = DoublyLinkedList::<$ptr_type>::new());
1892                    let obj1 = factory.create(1);
1893                    let obj2 = factory.create(2);
1894                    let obj3 = factory.create(3);
1895
1896                    $push(list.as_mut(), obj1);
1897                    $push(list.as_mut(), obj2);
1898                    $push(list.as_mut(), obj3);
1899
1900                    let mut cursor = list.as_mut().cursor_front_mut();
1901                    cursor.move_next();
1902                    let erased = cursor.erase();
1903                    assert!(erased.is_some());
1904                    factory.cleanup(erased.unwrap());
1905
1906                    let mut iter = list.iter();
1907                    assert!(iter.next().is_some());
1908                    assert!(iter.next().is_some());
1909                    assert!(iter.next().is_none());
1910
1911                    list.as_mut().clear();
1912                }
1913
1914                #[test]
1915                fn test_erase_if() {
1916                    let mut factory = <$factory_type>::new();
1917                    stack_pin_init!(let list = DoublyLinkedList::<$ptr_type>::new());
1918                    let obj1 = factory.create(1);
1919                    let obj2 = factory.create(2);
1920                    let obj3 = factory.create(3);
1921
1922                    $push(list.as_mut(), obj1);
1923                    $push(list.as_mut(), obj2);
1924                    $push(list.as_mut(), obj3);
1925
1926                    let erased = list.as_mut().erase_if(|o| o.value == 2);
1927                    assert!(erased.is_some());
1928                    assert_eq!($get_val(erased.unwrap().get_ref()), 2);
1929
1930                    let mut iter = list.iter();
1931                    assert_eq!($get_val(iter.next().unwrap()), 3);
1932                    assert_eq!($get_val(iter.next().unwrap()), 1);
1933                    assert!(iter.next().is_none());
1934
1935                    list.as_mut().clear();
1936                }
1937
1938                #[test]
1939                fn test_find_if() {
1940                    let mut factory = <$factory_type>::new();
1941                    stack_pin_init!(let list = DoublyLinkedList::<$ptr_type>::new());
1942                    let obj1 = factory.create(1);
1943                    let obj2 = factory.create(2);
1944
1945                    $push(list.as_mut(), obj1);
1946                    $push(list.as_mut(), obj2);
1947
1948                    let found = list.find_if(|o| o.value == 1);
1949                    assert!(found.is_some());
1950                    assert_eq!(found.unwrap().value, 1);
1951
1952                    let found = list.find_if(|o| o.value == 3);
1953                    assert!(found.is_none());
1954
1955                    list.as_mut().clear();
1956                }
1957
1958                #[test]
1959                fn test_complete_reverse_iteration() {
1960                    let mut factory = <$factory_type>::new();
1961                    stack_pin_init!(let list = DoublyLinkedList::<$ptr_type>::new());
1962                    let obj1 = factory.create(1);
1963                    let obj2 = factory.create(2);
1964                    let obj3 = factory.create(3);
1965
1966                    $push(list.as_mut(), obj1);
1967                    $push(list.as_mut(), obj2);
1968                    $push(list.as_mut(), obj3);
1969
1970                    let (a, b, c) = {
1971                        let mut iter = list.iter();
1972                        (
1973                            $get_val(iter.next().unwrap()),
1974                            $get_val(iter.next().unwrap()),
1975                            $get_val(iter.next().unwrap()),
1976                        )
1977                    };
1978
1979                    let mut iter = list.iter();
1980                    assert_eq!($get_val(iter.next_back().unwrap()), c);
1981                    assert_eq!($get_val(iter.next_back().unwrap()), b);
1982                    assert_eq!($get_val(iter.next_back().unwrap()), a);
1983                    assert!(iter.next_back().is_none());
1984
1985                    list.as_mut().clear();
1986                }
1987
1988                #[test]
1989                fn test_split_after() {
1990                    let mut factory = <$factory_type>::new();
1991                    stack_pin_init!(let list1 = DoublyLinkedList::<$ptr_type>::new());
1992                    stack_pin_init!(let list2 = DoublyLinkedList::<$ptr_type>::new());
1993
1994                    let obj1 = factory.create(1);
1995                    let obj2 = factory.create(2);
1996                    let obj3 = factory.create(3);
1997                    let obj4 = factory.create(4);
1998
1999                    $push(list1.as_mut(), obj4);
2000                    $push(list1.as_mut(), obj3);
2001                    $push(list1.as_mut(), obj2);
2002                    $push(list1.as_mut(), obj1);
2003
2004                    let mut cursor = list1.as_mut().cursor_front_mut();
2005                    cursor.move_next(); // points to 2
2006
2007                    let mut dest_cursor = list2.as_mut().cursor_back_mut();
2008                    cursor.split_after(&mut dest_cursor);
2009
2010                    let mut iter1 = list1.iter();
2011                    assert_eq!($get_val(iter1.next().unwrap()), 1);
2012                    assert_eq!($get_val(iter1.next().unwrap()), 2);
2013                    assert!(iter1.next().is_none());
2014
2015                    let mut iter2 = list2.iter();
2016                    assert_eq!($get_val(iter2.next().unwrap()), 3);
2017                    assert_eq!($get_val(iter2.next().unwrap()), 4);
2018                    assert!(iter2.next().is_none());
2019
2020                    list1.as_mut().clear();
2021                    list2.as_mut().clear();
2022                }
2023
2024                #[test]
2025                fn test_split_before() {
2026                    let mut factory = <$factory_type>::new();
2027                    stack_pin_init!(let list1 = DoublyLinkedList::<$ptr_type>::new());
2028                    stack_pin_init!(let list2 = DoublyLinkedList::<$ptr_type>::new());
2029
2030                    let obj1 = factory.create(1);
2031                    let obj2 = factory.create(2);
2032                    let obj3 = factory.create(3);
2033                    let obj4 = factory.create(4);
2034
2035                    $push(list1.as_mut(), obj4);
2036                    $push(list1.as_mut(), obj3);
2037                    $push(list1.as_mut(), obj2);
2038                    $push(list1.as_mut(), obj1);
2039
2040                    let mut cursor = list1.as_mut().cursor_front_mut();
2041                    cursor.move_next();
2042                    cursor.move_next(); // points to 3
2043
2044                    let mut dest_cursor = list2.as_mut().cursor_back_mut();
2045                    cursor.split_before(&mut dest_cursor);
2046
2047                    // list2 should have elements before cursor (1, 2)
2048                    let mut iter2 = list2.iter();
2049                    assert_eq!($get_val(iter2.next().unwrap()), 1);
2050                    assert_eq!($get_val(iter2.next().unwrap()), 2);
2051                    assert!(iter2.next().is_none());
2052
2053                    // list1 should have elements from cursor onwards (3, 4)
2054                    let mut iter1 = list1.iter();
2055                    assert_eq!($get_val(iter1.next().unwrap()), 3);
2056                    assert_eq!($get_val(iter1.next().unwrap()), 4);
2057                    assert!(iter1.next().is_none());
2058
2059                    list1.as_mut().clear();
2060                    list2.as_mut().clear();
2061                }
2062            }
2063        };
2064    }
2065
2066    generate_list_tests!(
2067        raw_ptr_tests,
2068        *mut TestObject,
2069        RawFactory<TestObject>,
2070        |p: &TestObject| p.value,
2071        |list: Pin<&mut DoublyLinkedList<*mut TestObject>>, obj| {
2072            // SAFETY: `obj` is a freshly allocated, unlinked object that outlives the list.
2073            unsafe { list.push_front_raw(obj) };
2074        }
2075    );
2076
2077    generate_list_tests!(
2078        unique_ptr_tests,
2079        UniquePtr<UniqueTestObject>,
2080        UniqueFactory<UniqueTestObject>,
2081        |p: &UniqueTestObject| p.value,
2082        |list: Pin<&mut DoublyLinkedList<UniquePtr<UniqueTestObject>>>, obj| list.push_front(obj)
2083    );
2084
2085    generate_list_tests!(
2086        ref_ptr_tests,
2087        RefPtr<RefTestObject>,
2088        RefFactory<RefTestObject>,
2089        |p: &RefTestObject| p.value,
2090        |list: Pin<&mut DoublyLinkedList<RefPtr<RefTestObject>>>, obj| list.push_front(obj)
2091    );
2092
2093    #[test]
2094    fn test_tracking_size() {
2095        stack_pin_init!(let list =
2096            DoublyLinkedList::<UniquePtr<UniqueTestObject>, DefaultObjectTag, TrackingSize>::new());
2097
2098        assert_eq!(list.len(), 0);
2099        list.as_mut().push_front(UniquePtr::try_new(UniqueTestObject::new(1)).unwrap());
2100        assert_eq!(list.len(), 1);
2101        list.as_mut().push_front(UniquePtr::try_new(UniqueTestObject::new(2)).unwrap());
2102        assert_eq!(list.len(), 2);
2103        list.as_mut().pop_front();
2104        assert_eq!(list.len(), 1);
2105        list.as_mut().clear();
2106        assert_eq!(list.len(), 0);
2107    }
2108
2109    #[test]
2110    fn test_insert_before() {
2111        stack_pin_init!(let list =
2112            DoublyLinkedList::<UniquePtr<UniqueTestObject>, DefaultObjectTag, TrackingSize>::new());
2113
2114        let mut cursor = list.as_mut().cursor_front_mut();
2115        cursor.insert_before(UniquePtr::try_new(UniqueTestObject::new(1)).unwrap());
2116        assert_eq!(list.len(), 1);
2117        assert_eq!(list.front().unwrap().value, 1);
2118
2119        let mut cursor = list.as_mut().cursor_front_mut();
2120        cursor.insert_before(UniquePtr::try_new(UniqueTestObject::new(2)).unwrap());
2121        assert_eq!(list.len(), 2);
2122        assert_eq!(list.front().unwrap().value, 2);
2123
2124        let mut cursor = list.as_mut().cursor_front_mut();
2125        cursor.move_next(); // point to obj1
2126        cursor.insert_before(UniquePtr::try_new(UniqueTestObject::new(3)).unwrap());
2127        assert_eq!(list.len(), 3);
2128
2129        let mut cursor = list.as_mut().cursor_front_mut();
2130        while cursor.get().unwrap().value != 1 {
2131            cursor.move_next();
2132        }
2133        cursor.move_next(); // point to sentinel
2134        cursor.insert_before(UniquePtr::try_new(UniqueTestObject::new(4)).unwrap());
2135        assert_eq!(list.len(), 4);
2136
2137        let mut iter = list.iter();
2138        assert_eq!(iter.next().unwrap().value, 2);
2139        assert_eq!(iter.next().unwrap().value, 3);
2140        assert_eq!(iter.next().unwrap().value, 1);
2141        assert_eq!(iter.next().unwrap().value, 4);
2142        assert!(iter.next().is_none());
2143
2144        list.as_mut().clear();
2145    }
2146
2147    #[test]
2148    fn test_front_mut_and_back_mut() {
2149        stack_pin_init!(let list =
2150            DoublyLinkedList::<UniquePtr<UniqueTestObject>, DefaultObjectTag, TrackingSize>::new());
2151
2152        assert!(list.as_mut().front_mut().is_none());
2153        assert!(list.as_mut().back_mut().is_none());
2154
2155        // 1-element list: head == tail.
2156        list.as_mut().push_back(UniquePtr::try_new(UniqueTestObject::new(1)).unwrap());
2157        *list.as_mut().front_mut().unwrap().project().value = 2;
2158        assert_eq!(list.as_mut().back_mut().unwrap().value, 2);
2159        *list.as_mut().back_mut().unwrap().project().value = 3;
2160        assert_eq!(list.as_mut().front_mut().unwrap().value, 3);
2161        assert_eq!(list.front().unwrap().value, 3);
2162        assert_eq!(list.back().unwrap().value, 3);
2163        assert_eq!(list.as_mut().pop_front().unwrap().value, 3);
2164        assert!(list.is_empty());
2165
2166        list.as_mut().push_back(UniquePtr::try_new(UniqueTestObject::new(10)).unwrap());
2167        list.as_mut().push_back(UniquePtr::try_new(UniqueTestObject::new(20)).unwrap());
2168
2169        assert_eq!(list.as_mut().front_mut().unwrap().value, 10);
2170        assert_eq!(list.as_mut().back_mut().unwrap().value, 20);
2171
2172        *list.as_mut().front_mut().unwrap().project().value = 100;
2173        *list.as_mut().back_mut().unwrap().project().value = 200;
2174
2175        assert_eq!(list.front().unwrap().value, 100);
2176        assert_eq!(list.back().unwrap().value, 200);
2177
2178        list.as_mut().clear();
2179    }
2180
2181    // Compile-time check that `T` does NOT implement `Trait`. If `T` implemented `Trait`, the
2182    // `<T as AmbiguousIfImpl<_>>` path below would be ambiguous between the two impls and fail to
2183    // compile.
2184    macro_rules! assert_not_impl {
2185        ($t:ty: $($trait:tt)+) => {
2186            const _: fn() = || {
2187                trait AmbiguousIfImpl<A> {
2188                    fn some_item() {}
2189                }
2190                impl<T: ?Sized> AmbiguousIfImpl<()> for T {}
2191                enum Invalid {}
2192                impl<T: ?Sized + $($trait)+> AmbiguousIfImpl<Invalid> for T {}
2193                let _ = <$t as AmbiguousIfImpl<_>>::some_item;
2194            };
2195        };
2196    }
2197
2198    // Linked elements must not be movable through safe `Pin` APIs.
2199    assert_not_impl!(DoublyLinkedListNode<TestObject>: Unpin);
2200    assert_not_impl!(TestObject: Unpin);
2201    assert_not_impl!(UniqueTestObject: Unpin);
2202    assert_not_impl!(RefTestObject: Unpin);
2203    // Lists must not be movable through safe `Pin` APIs, since elements point back at them.
2204    assert_not_impl!(DoublyLinkedList<*mut TestObject>: Unpin);
2205    // Shared ownership must not grant mutable element access.
2206    assert_not_impl!(RefPtr<RefTestObject>: MutPtr);
2207
2208    #[test]
2209    fn test_iter_mut() {
2210        stack_pin_init!(let list =
2211            DoublyLinkedList::<UniquePtr<UniqueTestObject>, DefaultObjectTag, TrackingSize>::new());
2212
2213        assert!(list.as_mut().iter_mut().next().is_none());
2214        assert!(list.as_mut().iter_mut().next_back().is_none());
2215
2216        // 1-element list: head == tail and head.prev == head.
2217        list.as_mut().push_back(UniquePtr::try_new(UniqueTestObject::new(7)).unwrap());
2218        {
2219            let mut iter = list.as_mut().iter_mut();
2220            let only = iter.next_back().unwrap();
2221            assert_eq!(only.value, 7);
2222            *only.project().value = 8;
2223            assert!(iter.next_back().is_none());
2224            assert!(iter.next().is_none());
2225        }
2226        {
2227            let mut iter = list.as_mut().iter_mut();
2228            assert_eq!(iter.next().unwrap().value, 8);
2229            assert!(iter.next().is_none());
2230            assert!(iter.next_back().is_none());
2231        }
2232        assert_eq!(list.as_mut().pop_front().unwrap().value, 8);
2233        assert!(list.is_empty());
2234
2235        list.as_mut().push_back(UniquePtr::try_new(UniqueTestObject::new(1)).unwrap());
2236        list.as_mut().push_back(UniquePtr::try_new(UniqueTestObject::new(2)).unwrap());
2237        list.as_mut().push_back(UniquePtr::try_new(UniqueTestObject::new(3)).unwrap());
2238
2239        for obj in list.as_mut().iter_mut() {
2240            *obj.project().value *= 10;
2241        }
2242
2243        let mut iter = list.as_mut().iter_mut();
2244        assert_eq!(iter.next().unwrap().value, 10);
2245        let mut last = iter.next_back().unwrap();
2246        assert_eq!(last.value, 30);
2247        *last.as_mut().project().value += 1;
2248        let mut middle = iter.next().unwrap();
2249        *middle.as_mut().project().value += 2;
2250        assert!(iter.next().is_none());
2251        assert!(iter.next_back().is_none());
2252
2253        let values: alloc::vec::Vec<i32> = list.iter().map(|o| o.value).collect();
2254        assert_eq!(values, [10, 22, 31]);
2255        assert_eq!(list.len(), 3);
2256
2257        // Hold every yielded reference simultaneously.
2258        {
2259            let mut items: alloc::vec::Vec<_> = list.as_mut().iter_mut().collect();
2260            assert_eq!(items.len(), 3);
2261            for item in items.iter_mut() {
2262                *item.as_mut().project().value += 1;
2263            }
2264            *items[0].as_mut().project().value += 100;
2265            *items[2].as_mut().project().value += 200;
2266        }
2267        let values: alloc::vec::Vec<i32> = list.iter().map(|o| o.value).collect();
2268        assert_eq!(values, [111, 23, 232]);
2269
2270        list.as_mut().clear();
2271        assert!(list.is_empty());
2272
2273        // 2-element list: hold `first` (the head) across the `next_back()` call where the front
2274        // and back iterators meet, and write to it afterward.
2275        list.as_mut().push_back(UniquePtr::try_new(UniqueTestObject::new(1)).unwrap());
2276        list.as_mut().push_back(UniquePtr::try_new(UniqueTestObject::new(2)).unwrap());
2277        {
2278            let mut iter = list.as_mut().iter_mut();
2279            let mut first = iter.next().unwrap();
2280            *first.as_mut().project().value = 10;
2281            let mut second = iter.next_back().unwrap();
2282            *first.as_mut().project().value = 11;
2283            *second.as_mut().project().value = 20;
2284            assert!(iter.next().is_none());
2285            assert!(iter.next_back().is_none());
2286            assert_eq!(first.value, 11);
2287            assert_eq!(second.value, 20);
2288        }
2289        let values: alloc::vec::Vec<i32> = list.iter().map(|o| o.value).collect();
2290        assert_eq!(values, [11, 20]);
2291
2292        // Same as above, but starting from the back.
2293        {
2294            let mut iter = list.as_mut().iter_mut();
2295            let mut last = iter.next_back().unwrap();
2296            *last.as_mut().project().value = 21;
2297            let mut first = iter.next().unwrap();
2298            *last.as_mut().project().value = 22;
2299            *first.as_mut().project().value = 12;
2300            assert!(iter.next().is_none());
2301            assert!(iter.next_back().is_none());
2302        }
2303        let values: alloc::vec::Vec<i32> = list.iter().map(|o| o.value).collect();
2304        assert_eq!(values, [12, 22]);
2305
2306        list.as_mut().clear();
2307    }
2308
2309    #[test]
2310    fn test_forward_and_reverse_iter_mut() {
2311        stack_pin_init!(let list = DoublyLinkedList::<UniquePtr<UniqueTestObject>>::new());
2312
2313        assert!(list.as_mut().forward_iter_mut().next().is_none());
2314        assert!(list.as_mut().reverse_iter_mut().next().is_none());
2315
2316        // 1-element list: head == tail and head.prev == head.
2317        list.as_mut().push_back(UniquePtr::try_new(UniqueTestObject::new(5)).unwrap());
2318        {
2319            let mut r_iter = list.as_mut().reverse_iter_mut();
2320            let only = r_iter.next().unwrap();
2321            assert_eq!(only.value, 5);
2322            *only.project().value = 6;
2323            assert!(r_iter.next().is_none());
2324        }
2325        {
2326            let mut f_iter = list.as_mut().forward_iter_mut();
2327            assert_eq!(f_iter.next().unwrap().value, 6);
2328            assert!(f_iter.next().is_none());
2329        }
2330        assert_eq!(list.as_mut().pop_front().unwrap().value, 6);
2331        assert!(list.is_empty());
2332
2333        list.as_mut().push_back(UniquePtr::try_new(UniqueTestObject::new(1)).unwrap());
2334        list.as_mut().push_back(UniquePtr::try_new(UniqueTestObject::new(2)).unwrap());
2335        list.as_mut().push_back(UniquePtr::try_new(UniqueTestObject::new(3)).unwrap());
2336
2337        // Forward: add 10 to every element.
2338        for obj in list.as_mut().forward_iter_mut() {
2339            *obj.project().value += 10;
2340        }
2341        let values: alloc::vec::Vec<i32> = list.iter().map(|o| o.value).collect();
2342        assert_eq!(values, [11, 12, 13]);
2343
2344        // Reverse: visit in reverse order and record it.
2345        let mut visited = alloc::vec::Vec::new();
2346        for obj in list.as_mut().reverse_iter_mut() {
2347            visited.push(obj.value);
2348            *obj.project().value *= 2;
2349        }
2350        assert_eq!(visited, [13, 12, 11]);
2351        let values: alloc::vec::Vec<i32> = list.iter().map(|o| o.value).collect();
2352        assert_eq!(values, [22, 24, 26]);
2353
2354        // Hold every yielded reference from the reverse iterator simultaneously.
2355        {
2356            let mut items: alloc::vec::Vec<_> = list.as_mut().reverse_iter_mut().collect();
2357            assert_eq!(items.len(), 3);
2358            for item in items.iter_mut() {
2359                *item.as_mut().project().value += 1;
2360            }
2361            // `items[0]` is the tail and `items[2]` is the head; write to both after all
2362            // references were yielded.
2363            *items[0].as_mut().project().value += 100;
2364            *items[2].as_mut().project().value += 200;
2365            assert_eq!(items[0].value, 127);
2366            assert_eq!(items[1].value, 25);
2367            assert_eq!(items[2].value, 223);
2368        }
2369        let values: alloc::vec::Vec<i32> = list.iter().map(|o| o.value).collect();
2370        assert_eq!(values, [223, 25, 127]);
2371
2372        // Hold every yielded reference from the forward iterator simultaneously.
2373        {
2374            let mut items: alloc::vec::Vec<_> = list.as_mut().forward_iter_mut().collect();
2375            assert_eq!(items.len(), 3);
2376            for item in items.iter_mut() {
2377                *item.as_mut().project().value -= 1;
2378            }
2379            *items[2].as_mut().project().value -= 100;
2380            *items[0].as_mut().project().value -= 200;
2381        }
2382        let values: alloc::vec::Vec<i32> = list.iter().map(|o| o.value).collect();
2383        assert_eq!(values, [22, 24, 26]);
2384
2385        list.as_mut().clear();
2386    }
2387
2388    #[test]
2389    fn test_iter_mut_raw_ptr() {
2390        stack_pin_init!(let list = DoublyLinkedList::<*mut TestObject>::new());
2391        let mut obj1 = TestObject::new(1);
2392        let mut obj2 = TestObject::new(2);
2393
2394        // SAFETY: The objects outlive the list and are removed before the list is dropped.
2395        unsafe {
2396            list.as_mut().push_back_raw(&mut obj1);
2397            list.as_mut().push_back_raw(&mut obj2);
2398        }
2399
2400        for obj in list.as_mut().iter_mut() {
2401            *obj.project().value += 100;
2402        }
2403        *list.as_mut().front_mut().unwrap().project().value += 1;
2404        *list.as_mut().back_mut().unwrap().project().value += 2;
2405
2406        let values: alloc::vec::Vec<i32> = list.iter().map(|o| o.value).collect();
2407        assert_eq!(values, [102, 104]);
2408
2409        list.as_mut().clear();
2410    }
2411
2412    #[test]
2413    fn test_cursor_get_mut() {
2414        stack_pin_init!(let list =
2415            DoublyLinkedList::<UniquePtr<UniqueTestObject>, DefaultObjectTag, TrackingSize>::new());
2416
2417        assert!(list.as_mut().cursor_front_mut().get_mut().is_none());
2418
2419        list.as_mut().push_back(UniquePtr::try_new(UniqueTestObject::new(1)).unwrap());
2420        list.as_mut().push_back(UniquePtr::try_new(UniqueTestObject::new(2)).unwrap());
2421
2422        let mut cursor = list.as_mut().cursor_front_mut();
2423        *cursor.get_mut().unwrap().project().value = 10;
2424        cursor.move_next();
2425        assert_eq!(cursor.get_mut().unwrap().value, 2);
2426        *cursor.get_mut().unwrap().project().value = 20;
2427        cursor.move_next();
2428        assert!(cursor.get_mut().is_none()); // Sentinel.
2429
2430        let mut iter = list.iter();
2431        assert_eq!(iter.next().unwrap().value, 10);
2432        assert_eq!(iter.next().unwrap().value, 20);
2433        assert!(iter.next().is_none());
2434        assert_eq!(list.len(), 2);
2435
2436        list.as_mut().clear();
2437    }
2438
2439    #[test]
2440    fn test_cursor_front_and_back_mut() {
2441        stack_pin_init!(let list =
2442            DoublyLinkedList::<UniquePtr<UniqueTestObject>, DefaultObjectTag, TrackingSize>::new());
2443
2444        assert!(list.as_mut().cursor_front_mut().get().is_none());
2445        assert!(list.as_mut().cursor_back_mut().get().is_none());
2446
2447        list.as_mut().push_back(UniquePtr::try_new(UniqueTestObject::new(10)).unwrap());
2448        list.as_mut().push_back(UniquePtr::try_new(UniqueTestObject::new(20)).unwrap());
2449
2450        let mut front_cursor = list.as_mut().cursor_front_mut();
2451        assert_eq!(front_cursor.get().unwrap().value, 10);
2452        front_cursor.move_next();
2453        assert_eq!(front_cursor.get().unwrap().value, 20);
2454
2455        let mut back_cursor = list.as_mut().cursor_back_mut();
2456        assert!(back_cursor.get().is_none());
2457        back_cursor.move_prev();
2458        assert_eq!(back_cursor.get().unwrap().value, 20);
2459
2460        let mut back_cursor = list.as_mut().cursor_back_mut();
2461        back_cursor.insert_before(UniquePtr::try_new(UniqueTestObject::new(30)).unwrap());
2462        assert_eq!(list.len(), 3);
2463        assert_eq!(list.back().unwrap().value, 30);
2464
2465        list.as_mut().clear();
2466    }
2467
2468    #[test]
2469    fn test_splice_middle() {
2470        stack_pin_init!(let list1 =
2471            DoublyLinkedList::<UniquePtr<UniqueTestObject>, DefaultObjectTag, TrackingSize>::new());
2472        stack_pin_init!(let list2 =
2473            DoublyLinkedList::<UniquePtr<UniqueTestObject>, DefaultObjectTag, TrackingSize>::new());
2474
2475        list1.as_mut().push_back(UniquePtr::try_new(UniqueTestObject::new(1)).unwrap());
2476        list1.as_mut().push_back(UniquePtr::try_new(UniqueTestObject::new(2)).unwrap());
2477        list2.as_mut().push_back(UniquePtr::try_new(UniqueTestObject::new(3)).unwrap());
2478        list2.as_mut().push_back(UniquePtr::try_new(UniqueTestObject::new(4)).unwrap());
2479
2480        let mut cursor = list1.as_mut().cursor_front_mut();
2481        cursor.move_next(); // point to obj2
2482
2483        cursor.splice(list2.as_mut());
2484
2485        assert!(list2.is_empty());
2486        assert_eq!(list1.len(), 4);
2487
2488        let mut iter = list1.iter();
2489        assert_eq!(iter.next().unwrap().value, 1);
2490        assert_eq!(iter.next().unwrap().value, 3);
2491        assert_eq!(iter.next().unwrap().value, 4);
2492        assert_eq!(iter.next().unwrap().value, 2);
2493        assert!(iter.next().is_none());
2494
2495        list1.as_mut().clear();
2496    }
2497
2498    #[test]
2499    fn test_splice_head() {
2500        stack_pin_init!(let list1 =
2501            DoublyLinkedList::<UniquePtr<UniqueTestObject>, DefaultObjectTag, TrackingSize>::new());
2502        stack_pin_init!(let list2 =
2503            DoublyLinkedList::<UniquePtr<UniqueTestObject>, DefaultObjectTag, TrackingSize>::new());
2504
2505        list1.as_mut().push_back(UniquePtr::try_new(UniqueTestObject::new(1)).unwrap());
2506        list1.as_mut().push_back(UniquePtr::try_new(UniqueTestObject::new(2)).unwrap());
2507        list2.as_mut().push_back(UniquePtr::try_new(UniqueTestObject::new(3)).unwrap());
2508        list2.as_mut().push_back(UniquePtr::try_new(UniqueTestObject::new(4)).unwrap());
2509
2510        let mut cursor = list1.as_mut().cursor_front_mut();
2511
2512        cursor.splice(list2.as_mut());
2513
2514        assert!(list2.is_empty());
2515        assert_eq!(list1.len(), 4);
2516
2517        let mut iter = list1.iter();
2518        assert_eq!(iter.next().unwrap().value, 3);
2519        assert_eq!(iter.next().unwrap().value, 4);
2520        assert_eq!(iter.next().unwrap().value, 1);
2521        assert_eq!(iter.next().unwrap().value, 2);
2522        assert!(iter.next().is_none());
2523
2524        list1.as_mut().clear();
2525    }
2526
2527    #[test]
2528    fn test_splice_tail() {
2529        stack_pin_init!(let list1 =
2530            DoublyLinkedList::<UniquePtr<UniqueTestObject>, DefaultObjectTag, TrackingSize>::new());
2531        stack_pin_init!(let list2 =
2532            DoublyLinkedList::<UniquePtr<UniqueTestObject>, DefaultObjectTag, TrackingSize>::new());
2533
2534        list1.as_mut().push_back(UniquePtr::try_new(UniqueTestObject::new(1)).unwrap());
2535        list1.as_mut().push_back(UniquePtr::try_new(UniqueTestObject::new(2)).unwrap());
2536        list2.as_mut().push_back(UniquePtr::try_new(UniqueTestObject::new(3)).unwrap());
2537        list2.as_mut().push_back(UniquePtr::try_new(UniqueTestObject::new(4)).unwrap());
2538
2539        let mut cursor = list1.as_mut().cursor_front_mut();
2540        cursor.move_next();
2541        cursor.move_next(); // point to sentinel
2542
2543        cursor.splice(list2.as_mut());
2544
2545        assert!(list2.is_empty());
2546        assert_eq!(list1.len(), 4);
2547
2548        let mut iter = list1.iter();
2549        assert_eq!(iter.next().unwrap().value, 1);
2550        assert_eq!(iter.next().unwrap().value, 2);
2551        assert_eq!(iter.next().unwrap().value, 3);
2552        assert_eq!(iter.next().unwrap().value, 4);
2553        assert!(iter.next().is_none());
2554
2555        list1.as_mut().clear();
2556    }
2557
2558    #[test]
2559    fn test_splice_empty() {
2560        stack_pin_init!(let list1 =
2561            DoublyLinkedList::<UniquePtr<UniqueTestObject>, DefaultObjectTag, TrackingSize>::new());
2562        stack_pin_init!(let list2 =
2563            DoublyLinkedList::<UniquePtr<UniqueTestObject>, DefaultObjectTag, TrackingSize>::new());
2564
2565        list2.as_mut().push_back(UniquePtr::try_new(UniqueTestObject::new(1)).unwrap());
2566        list2.as_mut().push_back(UniquePtr::try_new(UniqueTestObject::new(2)).unwrap());
2567
2568        let mut cursor = list1.as_mut().cursor_front_mut();
2569        cursor.splice(list2.as_mut());
2570
2571        assert!(list2.is_empty());
2572        assert_eq!(list1.len(), 2);
2573
2574        let mut iter = list1.iter();
2575        assert_eq!(iter.next().unwrap().value, 1);
2576        assert_eq!(iter.next().unwrap().value, 2);
2577        assert!(iter.next().is_none());
2578
2579        list1.as_mut().clear();
2580    }
2581
2582    #[test]
2583    fn test_splice_non_tracking() {
2584        stack_pin_init!(let list1 =
2585            DoublyLinkedList::<UniquePtr<UniqueTestObject>, DefaultObjectTag, NonTrackingSize>::new());
2586        stack_pin_init!(let list2 =
2587            DoublyLinkedList::<UniquePtr<UniqueTestObject>, DefaultObjectTag, NonTrackingSize>::new());
2588
2589        list1.as_mut().push_back(UniquePtr::try_new(UniqueTestObject::new(1)).unwrap());
2590        list1.as_mut().push_back(UniquePtr::try_new(UniqueTestObject::new(2)).unwrap());
2591        list2.as_mut().push_back(UniquePtr::try_new(UniqueTestObject::new(3)).unwrap());
2592        list2.as_mut().push_back(UniquePtr::try_new(UniqueTestObject::new(4)).unwrap());
2593
2594        let mut cursor = list1.as_mut().cursor_front_mut();
2595        cursor.move_next(); // point to obj2
2596
2597        cursor.splice(list2.as_mut());
2598
2599        assert!(list2.is_empty());
2600
2601        let mut iter = list1.iter();
2602        assert_eq!(iter.next().unwrap().value, 1);
2603        assert_eq!(iter.next().unwrap().value, 3);
2604        assert_eq!(iter.next().unwrap().value, 4);
2605        assert_eq!(iter.next().unwrap().value, 2);
2606        assert!(iter.next().is_none());
2607
2608        list1.as_mut().clear();
2609    }
2610
2611    #[test]
2612    fn test_list_splice() {
2613        // Test splicing non-empty other into non-empty self.
2614        stack_pin_init!(let list1 =
2615            DoublyLinkedList::<UniquePtr<UniqueTestObject>, DefaultObjectTag, TrackingSize>::new());
2616        stack_pin_init!(let list2 =
2617            DoublyLinkedList::<UniquePtr<UniqueTestObject>, DefaultObjectTag, TrackingSize>::new());
2618
2619        list1.as_mut().push_back(UniquePtr::try_new(UniqueTestObject::new(1)).unwrap());
2620        list1.as_mut().push_back(UniquePtr::try_new(UniqueTestObject::new(2)).unwrap());
2621        list2.as_mut().push_back(UniquePtr::try_new(UniqueTestObject::new(3)).unwrap());
2622        list2.as_mut().push_back(UniquePtr::try_new(UniqueTestObject::new(4)).unwrap());
2623
2624        list1.as_mut().splice(list2.as_mut());
2625
2626        assert!(list2.is_empty());
2627        assert_eq!(list2.len(), 0);
2628        assert_eq!(list1.len(), 4);
2629
2630        let mut iter = list1.iter();
2631        assert_eq!(iter.next().unwrap().value, 1);
2632        assert_eq!(iter.next().unwrap().value, 2);
2633        assert_eq!(iter.next().unwrap().value, 3);
2634        assert_eq!(iter.next().unwrap().value, 4);
2635        assert!(iter.next().is_none());
2636
2637        // Test splicing into empty self.
2638        stack_pin_init!(let list3 =
2639            DoublyLinkedList::<UniquePtr<UniqueTestObject>, DefaultObjectTag, TrackingSize>::new());
2640
2641        list3.as_mut().splice(list1.as_mut());
2642
2643        assert!(list1.is_empty());
2644        assert_eq!(list1.len(), 0);
2645        assert_eq!(list3.len(), 4);
2646
2647        let mut iter = list3.iter();
2648        assert_eq!(iter.next().unwrap().value, 1);
2649        assert_eq!(iter.next().unwrap().value, 2);
2650        assert_eq!(iter.next().unwrap().value, 3);
2651        assert_eq!(iter.next().unwrap().value, 4);
2652        assert!(iter.next().is_none());
2653
2654        // Test splicing empty list into non-empty self (no-op).
2655        list3.as_mut().splice(list1.as_mut());
2656        assert_eq!(list3.len(), 4);
2657        assert!(list1.is_empty());
2658
2659        list3.as_mut().clear();
2660    }
2661
2662    #[test]
2663    fn test_split_after_at_tail() {
2664        stack_pin_init!(let list1 =
2665            DoublyLinkedList::<UniquePtr<UniqueTestObject>, DefaultObjectTag, TrackingSize>::new());
2666        stack_pin_init!(let list2 =
2667            DoublyLinkedList::<UniquePtr<UniqueTestObject>, DefaultObjectTag, TrackingSize>::new());
2668
2669        list1.as_mut().push_back(UniquePtr::try_new(UniqueTestObject::new(1)).unwrap());
2670        list1.as_mut().push_back(UniquePtr::try_new(UniqueTestObject::new(2)).unwrap());
2671
2672        let mut cursor = list1.as_mut().cursor_front_mut();
2673        cursor.move_next(); // points to 2 (tail)
2674
2675        let mut dest_cursor = list2.as_mut().cursor_back_mut();
2676        cursor.split_after(&mut dest_cursor);
2677
2678        assert!(list2.is_empty());
2679        assert_eq!(list2.len(), 0);
2680        assert_eq!(list1.len(), 2);
2681
2682        list1.as_mut().clear();
2683    }
2684
2685    #[test]
2686    fn test_split_after_at_head() {
2687        stack_pin_init!(let list1 =
2688            DoublyLinkedList::<UniquePtr<UniqueTestObject>, DefaultObjectTag, TrackingSize>::new());
2689        stack_pin_init!(let list2 =
2690            DoublyLinkedList::<UniquePtr<UniqueTestObject>, DefaultObjectTag, TrackingSize>::new());
2691
2692        list1.as_mut().push_back(UniquePtr::try_new(UniqueTestObject::new(1)).unwrap());
2693        list1.as_mut().push_back(UniquePtr::try_new(UniqueTestObject::new(2)).unwrap());
2694        list1.as_mut().push_back(UniquePtr::try_new(UniqueTestObject::new(3)).unwrap());
2695
2696        let mut cursor = list1.as_mut().cursor_front_mut(); // points to 1 (head)
2697
2698        let mut dest_cursor = list2.as_mut().cursor_back_mut();
2699        cursor.split_after(&mut dest_cursor);
2700
2701        assert_eq!(list1.len(), 1);
2702        assert_eq!(list2.len(), 2);
2703
2704        let mut iter1 = list1.iter();
2705        assert_eq!(iter1.next().unwrap().value, 1);
2706        assert!(iter1.next().is_none());
2707
2708        let mut iter2 = list2.iter();
2709        assert_eq!(iter2.next().unwrap().value, 2);
2710        assert_eq!(iter2.next().unwrap().value, 3);
2711        assert!(iter2.next().is_none());
2712
2713        list1.as_mut().clear();
2714        list2.as_mut().clear();
2715    }
2716
2717    #[test]
2718    fn test_split_before_at_head() {
2719        stack_pin_init!(let list1 =
2720            DoublyLinkedList::<UniquePtr<UniqueTestObject>, DefaultObjectTag, TrackingSize>::new());
2721        stack_pin_init!(let list2 =
2722            DoublyLinkedList::<UniquePtr<UniqueTestObject>, DefaultObjectTag, TrackingSize>::new());
2723
2724        list1.as_mut().push_back(UniquePtr::try_new(UniqueTestObject::new(1)).unwrap());
2725        list1.as_mut().push_back(UniquePtr::try_new(UniqueTestObject::new(2)).unwrap());
2726
2727        let mut cursor = list1.as_mut().cursor_front_mut(); // points to 1 (head)
2728
2729        let mut dest_cursor = list2.as_mut().cursor_back_mut();
2730        cursor.split_before(&mut dest_cursor);
2731
2732        assert!(list2.is_empty());
2733        assert_eq!(list2.len(), 0);
2734        assert_eq!(list1.len(), 2);
2735
2736        list1.as_mut().clear();
2737    }
2738
2739    #[test]
2740    fn test_split_before_at_tail() {
2741        stack_pin_init!(let list1 =
2742            DoublyLinkedList::<UniquePtr<UniqueTestObject>, DefaultObjectTag, TrackingSize>::new());
2743        stack_pin_init!(let list2 =
2744            DoublyLinkedList::<UniquePtr<UniqueTestObject>, DefaultObjectTag, TrackingSize>::new());
2745
2746        list1.as_mut().push_back(UniquePtr::try_new(UniqueTestObject::new(1)).unwrap());
2747        list1.as_mut().push_back(UniquePtr::try_new(UniqueTestObject::new(2)).unwrap());
2748        list1.as_mut().push_back(UniquePtr::try_new(UniqueTestObject::new(3)).unwrap());
2749
2750        let mut cursor = list1.as_mut().cursor_front_mut();
2751        cursor.move_next();
2752        cursor.move_next(); // points to 3 (tail)
2753
2754        let mut dest_cursor = list2.as_mut().cursor_back_mut();
2755        cursor.split_before(&mut dest_cursor);
2756
2757        assert_eq!(list2.len(), 2);
2758        assert_eq!(list1.len(), 1);
2759
2760        let mut iter2 = list2.iter();
2761        assert_eq!(iter2.next().unwrap().value, 1);
2762        assert_eq!(iter2.next().unwrap().value, 2);
2763        assert!(iter2.next().is_none());
2764
2765        let mut iter1 = list1.iter();
2766        assert_eq!(iter1.next().unwrap().value, 3);
2767        assert!(iter1.next().is_none());
2768
2769        list1.as_mut().clear();
2770        list2.as_mut().clear();
2771    }
2772
2773    #[test]
2774    fn test_split_before_at_sentinel() {
2775        stack_pin_init!(let list1 =
2776            DoublyLinkedList::<UniquePtr<UniqueTestObject>, DefaultObjectTag, TrackingSize>::new());
2777        stack_pin_init!(let list2 =
2778            DoublyLinkedList::<UniquePtr<UniqueTestObject>, DefaultObjectTag, TrackingSize>::new());
2779
2780        list1.as_mut().push_back(UniquePtr::try_new(UniqueTestObject::new(1)).unwrap());
2781        list1.as_mut().push_back(UniquePtr::try_new(UniqueTestObject::new(2)).unwrap());
2782
2783        let mut cursor = list1.as_mut().cursor_back_mut(); // points to sentinel
2784
2785        let mut dest_cursor = list2.as_mut().cursor_back_mut();
2786        cursor.split_before(&mut dest_cursor);
2787
2788        assert!(list1.is_empty());
2789        assert_eq!(list1.len(), 0);
2790        assert_eq!(list2.len(), 2);
2791
2792        let mut iter2 = list2.iter();
2793        assert_eq!(iter2.next().unwrap().value, 1);
2794        assert_eq!(iter2.next().unwrap().value, 2);
2795        assert!(iter2.next().is_none());
2796
2797        list2.as_mut().clear();
2798    }
2799
2800    #[test]
2801    fn test_split_into_middle_of_dest_list() {
2802        stack_pin_init!(let list1 =
2803            DoublyLinkedList::<UniquePtr<UniqueTestObject>, DefaultObjectTag, TrackingSize>::new());
2804        stack_pin_init!(let list2 =
2805            DoublyLinkedList::<UniquePtr<UniqueTestObject>, DefaultObjectTag, TrackingSize>::new());
2806
2807        list1.as_mut().push_back(UniquePtr::try_new(UniqueTestObject::new(1)).unwrap());
2808        list1.as_mut().push_back(UniquePtr::try_new(UniqueTestObject::new(2)).unwrap());
2809        list1.as_mut().push_back(UniquePtr::try_new(UniqueTestObject::new(3)).unwrap());
2810        list1.as_mut().push_back(UniquePtr::try_new(UniqueTestObject::new(4)).unwrap());
2811
2812        list2.as_mut().push_back(UniquePtr::try_new(UniqueTestObject::new(10)).unwrap());
2813        list2.as_mut().push_back(UniquePtr::try_new(UniqueTestObject::new(20)).unwrap());
2814
2815        // Split after 2 from list1, and insert before 20 in list2
2816        let mut cursor1 = list1.as_mut().cursor_front_mut();
2817        cursor1.move_next(); // points to 2
2818
2819        let mut cursor2 = list2.as_mut().cursor_front_mut();
2820        cursor2.move_next(); // points to 20
2821
2822        cursor1.split_after(&mut cursor2);
2823
2824        // list1 should retain [1, 2]
2825        assert_eq!(list1.len(), 2);
2826        let mut iter1 = list1.iter();
2827        assert_eq!(iter1.next().unwrap().value, 1);
2828        assert_eq!(iter1.next().unwrap().value, 2);
2829        assert!(iter1.next().is_none());
2830
2831        // list2 should now be [10, 3, 4, 20]
2832        assert_eq!(list2.len(), 4);
2833        let mut iter2 = list2.iter();
2834        assert_eq!(iter2.next().unwrap().value, 10);
2835        assert_eq!(iter2.next().unwrap().value, 3);
2836        assert_eq!(iter2.next().unwrap().value, 4);
2837        assert_eq!(iter2.next().unwrap().value, 20);
2838        assert!(iter2.next().is_none());
2839
2840        list1.as_mut().clear();
2841        list2.as_mut().clear();
2842    }
2843
2844    #[test]
2845    fn test_list_split_methods() {
2846        let mut obj1 = TestObject::new(1);
2847        let mut obj2 = TestObject::new(2);
2848        let mut obj3 = TestObject::new(3);
2849
2850        stack_pin_init!(let list1 = DoublyLinkedList::<*mut TestObject>::new());
2851        stack_pin_init!(let list2 = DoublyLinkedList::<*mut TestObject>::new());
2852
2853        unsafe {
2854            list1.as_mut().push_back_raw(&mut obj1);
2855            list1.as_mut().push_back_raw(&mut obj2);
2856            list1.as_mut().push_back_raw(&mut obj3);
2857
2858            // Split after obj1
2859            let mut cursor1 = list1.as_mut().cursor_at(&obj1);
2860            let mut cursor2 = list2.as_mut().cursor_back_mut();
2861            cursor1.split_after(&mut cursor2);
2862
2863            assert_eq!(list1.iter().count(), 1);
2864            assert_eq!(list2.iter().count(), 2);
2865
2866            let mut iter1 = list1.iter();
2867            assert_eq!(iter1.next().unwrap().value, 1);
2868            assert!(iter1.next().is_none());
2869
2870            let mut iter2 = list2.iter();
2871            assert_eq!(iter2.next().unwrap().value, 2);
2872            assert_eq!(iter2.next().unwrap().value, 3);
2873            assert!(iter2.next().is_none());
2874
2875            // Splice back
2876            list1.as_mut().splice(list2.as_mut());
2877            assert_eq!(list1.iter().count(), 3);
2878
2879            // Split before obj3
2880            let mut cursor1 = list1.as_mut().cursor_at(&obj3);
2881            let mut cursor2 = list2.as_mut().cursor_back_mut();
2882            cursor1.split_before(&mut cursor2);
2883
2884            assert_eq!(list2.iter().count(), 2);
2885            assert_eq!(list1.iter().count(), 1);
2886
2887            let mut iter2 = list2.iter();
2888            assert_eq!(iter2.next().unwrap().value, 1);
2889            assert_eq!(iter2.next().unwrap().value, 2);
2890            assert!(iter2.next().is_none());
2891
2892            let mut iter1 = list1.iter();
2893            assert_eq!(iter1.next().unwrap().value, 3);
2894            assert!(iter1.next().is_none());
2895
2896            list1.as_mut().clear();
2897            list2.as_mut().clear();
2898        }
2899    }
2900
2901    #[test]
2902    fn test_cursor_get() {
2903        stack_pin_init!(let list = DoublyLinkedList::<UniquePtr<UniqueTestObject>>::new());
2904
2905        let cursor = list.as_mut().cursor_front_mut();
2906        assert!(cursor.get().is_none());
2907
2908        list.as_mut().push_back(UniquePtr::try_new(UniqueTestObject::new(42)).unwrap());
2909
2910        let mut cursor = list.as_mut().cursor_front_mut();
2911        assert!(cursor.get().is_some());
2912        assert_eq!(cursor.get().unwrap().value, 42);
2913
2914        cursor.move_next();
2915        assert!(cursor.get().is_none());
2916
2917        list.as_mut().clear();
2918    }
2919
2920    #[test]
2921    fn test_pop_back() {
2922        stack_pin_init!(let list =
2923            DoublyLinkedList::<UniquePtr<UniqueTestObject>, DefaultObjectTag, TrackingSize>::new());
2924
2925        list.as_mut().push_back(UniquePtr::try_new(UniqueTestObject::new(1)).unwrap());
2926        list.as_mut().push_back(UniquePtr::try_new(UniqueTestObject::new(2)).unwrap());
2927
2928        assert_eq!(list.len(), 2);
2929        let popped = list.as_mut().pop_back();
2930        assert!(popped.is_some());
2931        assert_eq!(popped.unwrap().value, 2);
2932        assert_eq!(list.len(), 1);
2933
2934        let popped = list.as_mut().pop_back();
2935        assert!(popped.is_some());
2936        assert_eq!(popped.unwrap().value, 1);
2937        assert_eq!(list.len(), 0);
2938
2939        assert!(list.as_mut().pop_back().is_none());
2940    }
2941
2942    #[test]
2943    fn test_erase() {
2944        stack_pin_init!(let list =
2945            DoublyLinkedList::<UniquePtr<UniqueTestObject>, DefaultObjectTag, TrackingSize>::new());
2946
2947        list.as_mut().push_back(UniquePtr::try_new(UniqueTestObject::new(1)).unwrap());
2948        list.as_mut().push_back(UniquePtr::try_new(UniqueTestObject::new(2)).unwrap());
2949        list.as_mut().push_back(UniquePtr::try_new(UniqueTestObject::new(3)).unwrap());
2950
2951        assert_eq!(list.len(), 3);
2952
2953        // 1. Erase middle (obj2)
2954        let mut cursor = list.as_mut().cursor_front_mut();
2955        cursor.move_next(); // point to obj2
2956        let erased = cursor.erase();
2957        assert!(erased.is_some());
2958        assert_eq!(erased.unwrap().value, 2);
2959        assert_eq!(list.len(), 2);
2960
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        // 2. Erase head (obj1)
2967        let mut cursor = list.as_mut().cursor_front_mut();
2968        let erased = cursor.erase(); // current is head (obj1)
2969        assert!(erased.is_some());
2970        assert_eq!(erased.unwrap().value, 1);
2971        assert_eq!(list.len(), 1);
2972        assert_eq!(list.front().unwrap().value, 3); // obj3 is now head!
2973
2974        // 3. Erase last element (obj3)
2975        let mut cursor = list.as_mut().cursor_front_mut();
2976        let erased = cursor.erase(); // current is head/tail (obj3)
2977        assert!(erased.is_some());
2978        assert_eq!(erased.unwrap().value, 3);
2979        assert_eq!(list.len(), 0);
2980        assert!(list.is_empty());
2981
2982        list.as_mut().clear();
2983    }
2984
2985    #[test]
2986    fn test_erase_if() {
2987        stack_pin_init!(let list =
2988            DoublyLinkedList::<UniquePtr<UniqueTestObject>, DefaultObjectTag, TrackingSize>::new());
2989
2990        list.as_mut().push_back(UniquePtr::try_new(UniqueTestObject::new(1)).unwrap());
2991        list.as_mut().push_back(UniquePtr::try_new(UniqueTestObject::new(2)).unwrap());
2992        list.as_mut().push_back(UniquePtr::try_new(UniqueTestObject::new(3)).unwrap());
2993
2994        let erased = list.as_mut().erase_if(|obj| obj.value % 2 == 0);
2995        assert!(erased.is_some());
2996        assert_eq!(erased.unwrap().value, 2);
2997
2998        assert_eq!(list.len(), 2);
2999        let mut iter = list.iter();
3000        assert_eq!(iter.next().unwrap().value, 1);
3001        assert_eq!(iter.next().unwrap().value, 3);
3002        assert!(iter.next().is_none());
3003
3004        list.as_mut().clear();
3005    }
3006
3007    #[test]
3008    fn test_erase_by_reference() {
3009        stack_pin_init!(let list =
3010            DoublyLinkedList::<*mut TestObject, DefaultObjectTag, TrackingSize>::new());
3011        let mut obj1 = TestObject::new(1);
3012        let mut obj2 = TestObject::new(2);
3013        let mut obj3 = TestObject::new(3);
3014
3015        unsafe {
3016            list.as_mut().push_back_raw(&mut obj1);
3017            list.as_mut().push_back_raw(&mut obj2);
3018            list.as_mut().push_back_raw(&mut obj3);
3019        }
3020
3021        assert_eq!(list.len(), 3);
3022
3023        // Erase obj2 directly (safe because it's unmanaged raw pointer to stack)
3024        let erased = unsafe { list.as_mut().erase(&obj2) };
3025        assert!(erased.is_some());
3026        assert_eq!(unsafe { &*erased.unwrap() }.value, 2);
3027        assert_eq!(list.len(), 2);
3028
3029        let mut iter = list.iter();
3030        assert_eq!(iter.next().unwrap().value, 1);
3031        assert_eq!(iter.next().unwrap().value, 3);
3032        assert!(iter.next().is_none());
3033
3034        list.as_mut().clear();
3035    }
3036
3037    #[test]
3038    fn test_remove_from_container() {
3039        stack_pin_init!(let list = DoublyLinkedList::<*mut TestObject>::new());
3040        let mut obj1 = TestObject::new(1);
3041        let mut obj2 = TestObject::new(2);
3042        let mut obj3 = TestObject::new(3);
3043
3044        // Case 1: Attempt to remove an element not in any container
3045        let removed = unsafe {
3046            remove_from_container::<TestObject, DefaultObjectTag, *mut TestObject>(&obj1)
3047        };
3048        assert!(removed.is_none());
3049
3050        unsafe {
3051            list.as_mut().push_back_raw(&mut obj1);
3052            list.as_mut().push_back_raw(&mut obj2);
3053            list.as_mut().push_back_raw(&mut obj3);
3054        }
3055
3056        // Case 2: Remove middle (obj2)
3057        let removed = unsafe {
3058            remove_from_container::<TestObject, DefaultObjectTag, *mut TestObject>(&obj2)
3059        };
3060        assert!(removed.is_some());
3061        assert_eq!(unsafe { &*removed.unwrap() }.value, 2);
3062
3063        let mut iter = list.iter();
3064        assert_eq!(iter.next().unwrap().value, 1);
3065        assert_eq!(iter.next().unwrap().value, 3);
3066        assert!(iter.next().is_none());
3067
3068        // Case 3: Remove head (obj1)
3069        let removed = unsafe {
3070            remove_from_container::<TestObject, DefaultObjectTag, *mut TestObject>(&obj1)
3071        };
3072        assert!(removed.is_some());
3073        assert_eq!(unsafe { &*removed.unwrap() }.value, 1);
3074
3075        let mut iter = list.iter();
3076        assert_eq!(iter.next().unwrap().value, 3);
3077        assert!(iter.next().is_none());
3078
3079        // Case 4: Remove last remaining element (obj3 -> leaves empty!)
3080        let removed = unsafe {
3081            remove_from_container::<TestObject, DefaultObjectTag, *mut TestObject>(&obj3)
3082        };
3083        assert!(removed.is_some());
3084        assert_eq!(unsafe { &*removed.unwrap() }.value, 3);
3085        assert!(list.is_empty());
3086
3087        list.as_mut().clear();
3088    }
3089
3090    #[test]
3091    fn test_replace() {
3092        stack_pin_init!(let list =
3093            DoublyLinkedList::<*mut TestObject, DefaultObjectTag, TrackingSize>::new());
3094        let mut obj1 = TestObject::new(1);
3095        let mut obj2 = TestObject::new(2);
3096        let mut obj3 = TestObject::new(3);
3097
3098        unsafe {
3099            list.as_mut().push_back_raw(&mut obj1);
3100            list.as_mut().push_back_raw(&mut obj2);
3101        }
3102
3103        assert_eq!(list.len(), 2);
3104
3105        let old = unsafe { list.as_mut().replace_raw(&obj2, &mut obj3) };
3106        assert!(old.is_some());
3107        assert_eq!(unsafe { &*old.unwrap() }.value, 2);
3108        assert_eq!(list.len(), 2);
3109
3110        let mut iter = list.iter();
3111        assert_eq!(iter.next().unwrap().value, 1);
3112        assert_eq!(iter.next().unwrap().value, 3);
3113        assert!(iter.next().is_none());
3114
3115        list.as_mut().clear();
3116    }
3117
3118    #[test]
3119    fn test_cursor_replace() {
3120        stack_pin_init!(let list = DoublyLinkedList::<UniquePtr<UniqueTestObject>>::new());
3121
3122        let obj1 = UniquePtr::try_new(UniqueTestObject::new(1)).unwrap();
3123        let obj2 = UniquePtr::try_new(UniqueTestObject::new(2)).unwrap();
3124        let obj3 = UniquePtr::try_new(UniqueTestObject::new(3)).unwrap();
3125
3126        list.as_mut().push_back(obj1);
3127        list.as_mut().push_back(obj2);
3128
3129        let mut cursor = list.as_mut().cursor_front_mut();
3130        cursor.move_next(); // point to obj2
3131
3132        let old = cursor.replace(obj3);
3133        assert!(old.is_some());
3134        assert_eq!(old.unwrap().value, 2);
3135
3136        let mut iter = list.iter();
3137        assert_eq!(iter.next().unwrap().value, 1);
3138        assert_eq!(iter.next().unwrap().value, 3);
3139        assert!(iter.next().is_none());
3140
3141        list.as_mut().clear();
3142    }
3143
3144    struct Tag2;
3145
3146    #[fbl::ref_counted]
3147    #[derive(crate::DoublyLinkedListContainable, crate::Recyclable)]
3148    #[repr(C)]
3149    struct MultiListObject {
3150        value: i32,
3151        #[dll_node]
3152        node1: DoublyLinkedListNode<MultiListObject>,
3153        #[dll_node(tag = Tag2)]
3154        node2: DoublyLinkedListNode<MultiListObject>,
3155    }
3156
3157    #[test]
3158    fn test_multiple_containers() {
3159        stack_pin_init!(let list1 =
3160            DoublyLinkedList::<RefPtr<MultiListObject>, DefaultObjectTag>::new());
3161        stack_pin_init!(let list2 = DoublyLinkedList::<RefPtr<MultiListObject>, Tag2>::new());
3162
3163        let obj1 = fbl::make_ref_counted!(MultiListObject {
3164            value: 1,
3165            node1: DoublyLinkedListNode::new(),
3166            node2: DoublyLinkedListNode::new(),
3167        })
3168        .unwrap();
3169
3170        let obj2 = fbl::make_ref_counted!(MultiListObject {
3171            value: 2,
3172            node1: DoublyLinkedListNode::new(),
3173            node2: DoublyLinkedListNode::new(),
3174        })
3175        .unwrap();
3176
3177        list1.as_mut().push_back(obj1.clone());
3178        list1.as_mut().push_back(obj2.clone());
3179
3180        list2.as_mut().push_back(obj2); // obj2 is now in both lists!
3181
3182        let mut iter1 = list1.iter();
3183        assert_eq!(iter1.next().unwrap().value, 1);
3184        assert_eq!(iter1.next().unwrap().value, 2);
3185        assert!(iter1.next().is_none());
3186
3187        let mut iter2 = list2.iter();
3188        assert_eq!(iter2.next().unwrap().value, 2);
3189        assert!(iter2.next().is_none());
3190
3191        list1.as_mut().clear();
3192        list2.as_mut().clear();
3193    }
3194
3195    use alloc::sync::Arc;
3196    use core::sync::atomic::{AtomicBool, Ordering};
3197
3198    #[derive(crate::DoublyLinkedListContainable, crate::Recyclable)]
3199    struct LifecycleObject {
3200        destroyed: Arc<AtomicBool>,
3201        #[dll_node]
3202        node: DoublyLinkedListNode<LifecycleObject>,
3203    }
3204
3205    impl LifecycleObject {
3206        fn new(destroyed: Arc<AtomicBool>) -> Self {
3207            Self { destroyed, node: DoublyLinkedListNode::new() }
3208        }
3209    }
3210
3211    impl Drop for LifecycleObject {
3212        fn drop(&mut self) {
3213            self.destroyed.store(true, Ordering::Relaxed);
3214        }
3215    }
3216
3217    #[test]
3218    fn test_lifecycle_on_drop() {
3219        let destroyed1 = Arc::new(AtomicBool::new(false));
3220        let destroyed2 = Arc::new(AtomicBool::new(false));
3221
3222        {
3223            stack_pin_init!(let list = DoublyLinkedList::<UniquePtr<LifecycleObject>>::new());
3224
3225            let obj1 = UniquePtr::try_new(LifecycleObject::new(destroyed1.clone())).unwrap();
3226            let obj2 = UniquePtr::try_new(LifecycleObject::new(destroyed2.clone())).unwrap();
3227
3228            list.as_mut().push_back(obj1);
3229            list.as_mut().push_back(obj2);
3230
3231            assert!(!destroyed1.load(Ordering::Relaxed));
3232            assert!(!destroyed2.load(Ordering::Relaxed));
3233        } // list drops here
3234
3235        assert!(destroyed1.load(Ordering::Relaxed));
3236        assert!(destroyed2.load(Ordering::Relaxed));
3237    }
3238
3239    #[test]
3240    fn test_sized_managed_list() {
3241        stack_pin_init!(let list =
3242            DoublyLinkedList::<UniquePtr<UniqueTestObject>, DefaultObjectTag, TrackingSize>::new());
3243
3244        assert_eq!(list.len(), 0);
3245
3246        let obj1 = UniquePtr::try_new(UniqueTestObject::new(1)).unwrap();
3247        let obj2 = UniquePtr::try_new(UniqueTestObject::new(2)).unwrap();
3248
3249        list.as_mut().push_back(obj1);
3250        assert_eq!(list.len(), 1);
3251
3252        list.as_mut().push_back(obj2);
3253        assert_eq!(list.len(), 2);
3254
3255        let popped = list.as_mut().pop_front();
3256        assert!(popped.is_some());
3257        assert_eq!(list.len(), 1);
3258
3259        list.as_mut().clear();
3260        assert_eq!(list.len(), 0);
3261    }
3262
3263    #[test]
3264    fn test_unidirectional_iterators() {
3265        stack_pin_init!(let list = DoublyLinkedList::<UniquePtr<UniqueTestObject>>::new());
3266
3267        list.as_mut().push_back(UniquePtr::try_new(UniqueTestObject::new(1)).unwrap());
3268        list.as_mut().push_back(UniquePtr::try_new(UniqueTestObject::new(2)).unwrap());
3269        list.as_mut().push_back(UniquePtr::try_new(UniqueTestObject::new(3)).unwrap());
3270
3271        // 1. Test ForwardIterator from beginning
3272        let mut f_iter = list.forward_iter();
3273        assert_eq!(f_iter.next().unwrap().value, 1);
3274        assert_eq!(f_iter.next().unwrap().value, 2);
3275        assert_eq!(f_iter.next().unwrap().value, 3);
3276        assert!(f_iter.next().is_none());
3277
3278        // 2. Test ReverseIterator from end
3279        let mut r_iter = list.reverse_iter();
3280        assert_eq!(r_iter.next().unwrap().value, 3);
3281        assert_eq!(r_iter.next().unwrap().value, 2);
3282        assert_eq!(r_iter.next().unwrap().value, 1);
3283        assert!(r_iter.next().is_none());
3284
3285        list.as_mut().clear();
3286    }
3287
3288    #[test]
3289    fn test_cursor_at() {
3290        stack_pin_init!(let list =
3291            DoublyLinkedList::<*mut TestObject, DefaultObjectTag, TrackingSize>::new());
3292        let mut obj1 = TestObject::new(1);
3293        let mut obj2 = TestObject::new(2);
3294        let mut obj3 = TestObject::new(3);
3295
3296        unsafe {
3297            list.as_mut().push_back_raw(&mut obj1);
3298            list.as_mut().push_back_raw(&mut obj2);
3299            list.as_mut().push_back_raw(&mut obj3);
3300        }
3301
3302        // Create a cursor at the second element (obj2).
3303        // SAFETY: `obj2` is a member of `list`.
3304        let mut cursor = unsafe { list.as_mut().cursor_at(&obj2) };
3305        assert_eq!(cursor.get().unwrap().value, 2);
3306
3307        // Verify we can move next.
3308        cursor.move_next();
3309        assert_eq!(cursor.get().unwrap().value, 3);
3310
3311        // Verify we can move prev from the original position.
3312        // SAFETY: `obj2` is a member of `list`.
3313        let mut cursor = unsafe { list.as_mut().cursor_at(&obj2) };
3314        cursor.move_prev();
3315        assert_eq!(cursor.get().unwrap().value, 1);
3316
3317        // Verify we can erase via the cursor created at the element.
3318        // SAFETY: `obj2` is a member of `list`.
3319        let mut cursor = unsafe { list.as_mut().cursor_at(&obj2) };
3320        let erased = cursor.erase().unwrap();
3321        assert_eq!(unsafe { &*erased }.value, 2);
3322
3323        // Verify list contents after erase.
3324        let mut iter = list.iter();
3325        assert_eq!(iter.next().unwrap().value, 1);
3326        assert_eq!(iter.next().unwrap().value, 3);
3327        assert!(iter.next().is_none());
3328
3329        list.as_mut().clear();
3330    }
3331
3332    #[test]
3333    fn test_clear_unsafe() {
3334        use core::mem::ManuallyDrop;
3335        use core::ptr::NonNull;
3336
3337        stack_pin_init!(
3338            let list =
3339                DoublyLinkedList::<*mut TestObject, DefaultObjectTag, TrackingSize>::new()
3340        );
3341
3342        // `clear_unsafe` on an empty list is a no-op and leaves the list empty and reusable.
3343        // SAFETY: The list is empty, so no former elements exist.
3344        unsafe {
3345            list.as_mut().clear_unsafe();
3346        }
3347        assert!(list.is_empty());
3348        assert_eq!(list.len(), 0);
3349
3350        // Keep `obj1..=obj3` in `ManuallyDrop` so their `DoublyLinkedListNode::drop` debug
3351        // assertion (`!in_container()`) is not triggered after `clear_unsafe`.
3352        let mut obj1 = ManuallyDrop::new(TestObject::new(10));
3353        let mut obj2 = ManuallyDrop::new(TestObject::new(20));
3354        let mut obj3 = ManuallyDrop::new(TestObject::new(30));
3355
3356        // SAFETY: `obj1`, `obj2`, and `obj3` are valid, unlinked objects that outlive their
3357        // presence in `list`.
3358        unsafe {
3359            list.as_mut().push_back_raw(&mut *obj1);
3360            list.as_mut().push_back_raw(&mut *obj2);
3361            list.as_mut().push_back_raw(&mut *obj3);
3362        }
3363
3364        assert!(!list.is_empty());
3365        assert_eq!(list.len(), 3);
3366
3367        // SAFETY: `obj1`, `obj2`, and `obj3` are wrapped in `ManuallyDrop` and are never used in
3368        // any list or cursor operation again after `clear_unsafe`.
3369        unsafe {
3370            list.as_mut().clear_unsafe();
3371        }
3372
3373        assert!(list.is_empty());
3374        assert_eq!(list.len(), 0);
3375        assert!(list.front().is_none());
3376        assert!(list.back().is_none());
3377        assert!(list.iter().next().is_none());
3378
3379        // Verify that the former nodes were not modified and still report `in_container()`.
3380        assert!(obj1.get_node().in_container());
3381        assert!(obj2.get_node().in_container());
3382        assert!(obj3.get_node().in_container());
3383
3384        // Verify that the list can be reused with fresh nodes after `clear_unsafe`.
3385        let mut fresh1 = TestObject::new(40);
3386        let mut fresh2 = TestObject::new(50);
3387        // SAFETY: `fresh1` and `fresh2` are valid, unlinked stack objects cleared before drop.
3388        unsafe {
3389            list.as_mut().push_back_raw(&mut fresh1);
3390            list.as_mut().push_back_raw(&mut fresh2);
3391        }
3392        assert!(!list.is_empty());
3393        assert_eq!(list.len(), 2);
3394        let mut iter = list.iter();
3395        assert_eq!(iter.next().unwrap().value, 40);
3396        assert_eq!(iter.next().unwrap().value, 50);
3397        assert!(iter.next().is_none());
3398        list.as_mut().clear();
3399        assert!(list.is_empty());
3400        assert_eq!(list.len(), 0);
3401
3402        // Also test a `NonNull<TestObject>` list with `NonTrackingSize`.
3403        stack_pin_init!(let nn_list = DoublyLinkedList::<NonNull<TestObject>>::new());
3404        // SAFETY: The list is empty.
3405        unsafe {
3406            nn_list.as_mut().clear_unsafe();
3407        }
3408        assert!(nn_list.is_empty());
3409
3410        let mut nn_obj1 = ManuallyDrop::new(TestObject::new(1));
3411        let mut nn_obj2 = ManuallyDrop::new(TestObject::new(2));
3412        // SAFETY: `nn_obj1` and `nn_obj2` are valid, unlinked objects wrapped in `ManuallyDrop`
3413        // and never used again after `clear_unsafe`.
3414        unsafe {
3415            nn_list.as_mut().push_front_raw(NonNull::from(&mut *nn_obj1));
3416            nn_list.as_mut().push_front_raw(NonNull::from(&mut *nn_obj2));
3417            assert!(!nn_list.is_empty());
3418            nn_list.as_mut().clear_unsafe();
3419        }
3420        assert!(nn_list.is_empty());
3421        assert!(nn_obj1.get_node().in_container());
3422        assert!(nn_obj2.get_node().in_container());
3423    }
3424
3425    // FFI Declarations
3426    unsafe extern "C" {
3427        // UniqueList Helpers
3428        fn cpp_create_unique_list() -> *mut c_void;
3429        fn cpp_destroy_unique_list(list: *mut c_void);
3430        fn cpp_unique_list_push_back(list: *mut c_void, item: *mut c_void);
3431        fn cpp_unique_list_pop_front(list: *mut c_void) -> *mut c_void;
3432        fn cpp_unique_list_is_empty(list: *mut c_void) -> bool;
3433
3434        // RefList Helpers
3435        fn cpp_create_ref_list() -> *mut c_void;
3436        fn cpp_destroy_ref_list(list: *mut c_void);
3437        fn cpp_ref_list_push_back(list: *mut c_void, item: *mut c_void);
3438        fn cpp_ref_list_pop_front(list: *mut c_void) -> *mut c_void;
3439        fn cpp_ref_list_is_empty(list: *mut c_void) -> bool;
3440
3441        // SharedUniqueObject Helpers
3442        fn cpp_create_unique_object(value: i32, destruction_flag: *mut bool) -> *mut c_void;
3443        fn cpp_get_unique_object_value(obj: *mut c_void) -> i32;
3444
3445        // SharedRefObject Helpers
3446        fn cpp_create_ref_object(value: i32, destruction_flag: *mut bool) -> *mut c_void;
3447        fn cpp_get_ref_object_value(obj: *mut c_void) -> i32;
3448    }
3449
3450    #[test]
3451    fn test_interop_rust_list_cpp_unique_objects() {
3452        let destroyed1 = AtomicBool::new(false);
3453        let destroyed2 = AtomicBool::new(false);
3454
3455        unsafe {
3456            stack_pin_init!(let list = DoublyLinkedList::<UniquePtr<SharedUniqueObject>>::new());
3457
3458            let cpp_raw1 = cpp_create_unique_object(1, destroyed1.as_ptr() as *mut bool);
3459            let cpp_raw2 = cpp_create_unique_object(2, destroyed2.as_ptr() as *mut bool);
3460
3461            let obj1 = UniquePtr::from_raw(cpp_raw1 as *mut SharedUniqueObject);
3462            let obj2 = UniquePtr::from_raw(cpp_raw2 as *mut SharedUniqueObject);
3463
3464            list.as_mut().push_back(obj1);
3465            list.as_mut().push_back(obj2);
3466
3467            assert!(!destroyed1.load(Ordering::Relaxed));
3468            assert!(!destroyed2.load(Ordering::Relaxed));
3469
3470            // Pop one
3471            let popped = list.as_mut().pop_front();
3472            assert!(popped.is_some());
3473            assert_eq!(popped.as_ref().unwrap().value, 1);
3474
3475            // Drop popped -> should destroy in C++!
3476            drop(popped);
3477            assert!(destroyed1.load(Ordering::Relaxed));
3478            assert!(!destroyed2.load(Ordering::Relaxed));
3479
3480            // Drop list -> should destroy remaining in C++!
3481        }
3482        assert!(destroyed2.load(Ordering::Relaxed));
3483    }
3484
3485    #[test]
3486    fn test_interop_cpp_list_rust_unique_objects() {
3487        let destroyed1 = Arc::new(AtomicBool::new(false));
3488        let destroyed2 = Arc::new(AtomicBool::new(false));
3489
3490        unsafe {
3491            let cpp_list = cpp_create_unique_list();
3492            assert!(cpp_unique_list_is_empty(cpp_list));
3493
3494            let obj1 = UniquePtr::try_new(SharedUniqueObject::new(1)).unwrap();
3495            let obj2 = UniquePtr::try_new(SharedUniqueObject::new(2)).unwrap();
3496
3497            // Set destruction flags
3498            let raw1 = UniquePtr::as_ptr(&obj1) as *mut SharedUniqueObject;
3499            (*raw1).destruction_flag = destroyed1.as_ptr() as *mut bool;
3500            let raw2 = UniquePtr::as_ptr(&obj2) as *mut SharedUniqueObject;
3501            (*raw2).destruction_flag = destroyed2.as_ptr() as *mut bool;
3502
3503            // Push to C++ list (transfers ownership)
3504            cpp_unique_list_push_back(cpp_list, UniquePtr::into_raw(obj1) as *mut c_void);
3505            cpp_unique_list_push_back(cpp_list, UniquePtr::into_raw(obj2) as *mut c_void);
3506
3507            assert!(!destroyed1.load(Ordering::Relaxed));
3508            assert!(!destroyed2.load(Ordering::Relaxed));
3509
3510            // Pop one from C++
3511            let popped = cpp_unique_list_pop_front(cpp_list);
3512            assert!(!popped.is_null());
3513            assert_eq!(cpp_get_unique_object_value(popped), 1);
3514
3515            // Convert back to Rust UniquePtr and drop -> should free in Rust!
3516            let popped_rust = UniquePtr::from_raw(popped as *mut SharedUniqueObject);
3517            drop(popped_rust);
3518            assert!(destroyed1.load(Ordering::Relaxed));
3519            assert!(!destroyed2.load(Ordering::Relaxed));
3520
3521            // Destroy C++ list -> should destroy remaining in Rust!
3522            cpp_destroy_unique_list(cpp_list);
3523        }
3524        assert!(destroyed2.load(Ordering::Relaxed));
3525    }
3526
3527    #[test]
3528    fn test_interop_rust_list_cpp_ref_objects() {
3529        let destroyed1 = AtomicBool::new(false);
3530        let destroyed2 = AtomicBool::new(false);
3531
3532        unsafe {
3533            stack_pin_init!(let list = DoublyLinkedList::<RefPtr<SharedRefObject>>::new());
3534
3535            let cpp_raw1 = cpp_create_ref_object(1, destroyed1.as_ptr() as *mut bool);
3536            let cpp_raw2 = cpp_create_ref_object(2, destroyed2.as_ptr() as *mut bool);
3537
3538            let obj1 = RefPtr::from_raw(cpp_raw1 as *mut SharedRefObject);
3539            let obj2 = RefPtr::from_raw(cpp_raw2 as *mut SharedRefObject);
3540
3541            list.as_mut().push_back(obj1);
3542            list.as_mut().push_back(obj2);
3543
3544            assert!(!destroyed1.load(Ordering::Relaxed));
3545            assert!(!destroyed2.load(Ordering::Relaxed));
3546
3547            // Pop one
3548            let popped = list.as_mut().pop_front();
3549            assert!(popped.is_some());
3550            assert_eq!(popped.as_ref().unwrap().value, 1);
3551
3552            // Drop popped -> should destroy in C++!
3553            drop(popped);
3554            assert!(destroyed1.load(Ordering::Relaxed));
3555            assert!(!destroyed2.load(Ordering::Relaxed));
3556
3557            // Drop list -> should destroy remaining in C++!
3558        }
3559        assert!(destroyed2.load(Ordering::Relaxed));
3560    }
3561
3562    #[test]
3563    fn test_interop_cpp_list_rust_ref_objects() {
3564        let destroyed1 = Arc::new(AtomicBool::new(false));
3565        let destroyed2 = Arc::new(AtomicBool::new(false));
3566
3567        unsafe {
3568            let cpp_list = cpp_create_ref_list();
3569            assert!(cpp_ref_list_is_empty(cpp_list));
3570
3571            let obj1 = SharedRefObject::new_ref_counted(1);
3572            let obj2 = SharedRefObject::new_ref_counted(2);
3573
3574            // Set destruction flags
3575            let raw1 = RefPtr::as_ptr(&obj1) as *mut SharedRefObject;
3576            (*raw1).destruction_flag = destroyed1.as_ptr() as *mut bool;
3577            let raw2 = RefPtr::as_ptr(&obj2) as *mut SharedRefObject;
3578            (*raw2).destruction_flag = destroyed2.as_ptr() as *mut bool;
3579
3580            // Push to C++ list (transfers ownership)
3581            cpp_ref_list_push_back(
3582                cpp_list,
3583                RefPtr::into_raw(obj1) as *mut SharedRefObject as *mut c_void,
3584            );
3585            cpp_ref_list_push_back(
3586                cpp_list,
3587                RefPtr::into_raw(obj2) as *mut SharedRefObject as *mut c_void,
3588            );
3589
3590            assert!(!destroyed1.load(Ordering::Relaxed));
3591            assert!(!destroyed2.load(Ordering::Relaxed));
3592
3593            // Pop one from C++
3594            let popped = cpp_ref_list_pop_front(cpp_list);
3595            assert!(!popped.is_null());
3596            assert_eq!(cpp_get_ref_object_value(popped), 1);
3597
3598            // Convert back to Rust RefPtr and drop -> should free in Rust!
3599            let popped_rust = RefPtr::from_raw(popped as *mut SharedRefObject);
3600            drop(popped_rust);
3601            assert!(destroyed1.load(Ordering::Relaxed));
3602            assert!(!destroyed2.load(Ordering::Relaxed));
3603
3604            // Destroy C++ list -> should destroy remaining in Rust!
3605            cpp_destroy_ref_list(cpp_list);
3606        }
3607        assert!(destroyed2.load(Ordering::Relaxed));
3608    }
3609}