tokio/util/
linked_list.rs

1#![cfg_attr(not(feature = "full"), allow(dead_code))]
2// It doesn't make sense to enforce `unsafe_op_in_unsafe_fn` for this module because
3//
4// * The intrusive linked list naturally relies on unsafe operations.
5// * Excessive `unsafe {}` blocks hurt readability significantly.
6// TODO: replace with `#[expect(unsafe_op_in_unsafe_fn)]` after bumpping
7// the MSRV to 1.81.0.
8#![allow(unsafe_op_in_unsafe_fn)]
9
10//! An intrusive double linked list of data.
11//!
12//! The data structure supports tracking pinned nodes. Most of the data
13//! structure's APIs are `unsafe` as they require the caller to ensure the
14//! specified node is actually contained by the list.
15
16use core::cell::UnsafeCell;
17use core::fmt;
18use core::marker::{PhantomData, PhantomPinned};
19use core::mem::ManuallyDrop;
20use core::ptr::{self, NonNull};
21
22/// An intrusive linked list.
23///
24/// Currently, the list is not emptied on drop. It is the caller's
25/// responsibility to ensure the list is empty before dropping it.
26pub(crate) struct LinkedList<L, T> {
27    /// Linked list head
28    head: Option<NonNull<T>>,
29
30    /// Linked list tail
31    tail: Option<NonNull<T>>,
32
33    /// Node type marker.
34    _marker: PhantomData<*const L>,
35}
36
37unsafe impl<L: Link> Send for LinkedList<L, L::Target> where L::Target: Send {}
38unsafe impl<L: Link> Sync for LinkedList<L, L::Target> where L::Target: Sync {}
39
40/// Defines how a type is tracked within a linked list.
41///
42/// In order to support storing a single type within multiple lists, accessing
43/// the list pointers is decoupled from the entry type.
44///
45/// # Safety
46///
47/// Implementations must guarantee that `Target` types are pinned in memory. In
48/// other words, when a node is inserted, the value will not be moved as long as
49/// it is stored in the list.
50pub(crate) unsafe trait Link {
51    /// Handle to the list entry.
52    ///
53    /// This is usually a pointer-ish type.
54    type Handle;
55
56    /// Node type.
57    type Target;
58
59    /// Convert the handle to a raw pointer without consuming the handle.
60    #[allow(clippy::wrong_self_convention)]
61    fn as_raw(handle: &Self::Handle) -> NonNull<Self::Target>;
62
63    /// Convert the raw pointer to a handle
64    unsafe fn from_raw(ptr: NonNull<Self::Target>) -> Self::Handle;
65
66    /// Return the pointers for a node
67    ///
68    /// # Safety
69    ///
70    /// The resulting pointer should have the same tag in the stacked-borrows
71    /// stack as the argument. In particular, the method may not create an
72    /// intermediate reference in the process of creating the resulting raw
73    /// pointer.
74    ///
75    /// The `target` pointer must be valid.
76    unsafe fn pointers(target: NonNull<Self::Target>) -> NonNull<Pointers<Self::Target>>;
77}
78
79/// Previous / next pointers.
80pub(crate) struct Pointers<T> {
81    inner: UnsafeCell<PointersInner<T>>,
82}
83/// We do not want the compiler to put the `noalias` attribute on mutable
84/// references to this type, so the type has been made `!Unpin` with a
85/// `PhantomPinned` field.
86///
87/// Additionally, we never access the `prev` or `next` fields directly, as any
88/// such access would implicitly involve the creation of a reference to the
89/// field, which we want to avoid since the fields are not `!Unpin`, and would
90/// hence be given the `noalias` attribute if we were to do such an access. As
91/// an alternative to accessing the fields directly, the `Pointers` type
92/// provides getters and setters for the two fields, and those are implemented
93/// using `ptr`-specific methods which avoids the creation of intermediate
94/// references.
95///
96/// See this link for more information:
97/// <https://github.com/rust-lang/rust/pull/82834>
98struct PointersInner<T> {
99    /// The previous node in the list. null if there is no previous node.
100    prev: Option<NonNull<T>>,
101
102    /// The next node in the list. null if there is no previous node.
103    next: Option<NonNull<T>>,
104
105    /// This type is !Unpin due to the heuristic from:
106    /// <https://github.com/rust-lang/rust/pull/82834>
107    _pin: PhantomPinned,
108}
109
110unsafe impl<T: Send> Send for Pointers<T> {}
111unsafe impl<T: Sync> Sync for Pointers<T> {}
112
113// ===== impl LinkedList =====
114
115impl<L, T> LinkedList<L, T> {
116    /// Creates an empty linked list.
117    pub(crate) const fn new() -> LinkedList<L, T> {
118        LinkedList {
119            head: None,
120            tail: None,
121            _marker: PhantomData,
122        }
123    }
124}
125
126impl<L: Link> LinkedList<L, L::Target> {
127    /// Adds an element first in the list.
128    pub(crate) fn push_front(&mut self, val: L::Handle) {
129        // The value should not be dropped, it is being inserted into the list
130        let val = ManuallyDrop::new(val);
131        let ptr = L::as_raw(&val);
132        assert_ne!(self.head, Some(ptr));
133        unsafe {
134            L::pointers(ptr).as_mut().set_next(self.head);
135            L::pointers(ptr).as_mut().set_prev(None);
136
137            if let Some(head) = self.head {
138                L::pointers(head).as_mut().set_prev(Some(ptr));
139            }
140
141            self.head = Some(ptr);
142
143            if self.tail.is_none() {
144                self.tail = Some(ptr);
145            }
146        }
147    }
148
149    /// Removes the first element from a list and returns it, or None if it is
150    /// empty.
151    pub(crate) fn pop_front(&mut self) -> Option<L::Handle> {
152        unsafe {
153            let head = self.head?;
154            self.head = L::pointers(head).as_ref().get_next();
155
156            if let Some(new_head) = L::pointers(head).as_ref().get_next() {
157                L::pointers(new_head).as_mut().set_prev(None);
158            } else {
159                self.tail = None;
160            }
161
162            L::pointers(head).as_mut().set_prev(None);
163            L::pointers(head).as_mut().set_next(None);
164
165            Some(L::from_raw(head))
166        }
167    }
168
169    /// Removes the last element from a list and returns it, or None if it is
170    /// empty.
171    pub(crate) fn pop_back(&mut self) -> Option<L::Handle> {
172        unsafe {
173            let last = self.tail?;
174            self.tail = L::pointers(last).as_ref().get_prev();
175
176            if let Some(prev) = L::pointers(last).as_ref().get_prev() {
177                L::pointers(prev).as_mut().set_next(None);
178            } else {
179                self.head = None;
180            }
181
182            L::pointers(last).as_mut().set_prev(None);
183            L::pointers(last).as_mut().set_next(None);
184
185            Some(L::from_raw(last))
186        }
187    }
188
189    /// Returns whether the linked list does not contain any node
190    pub(crate) fn is_empty(&self) -> bool {
191        if self.head.is_some() {
192            return false;
193        }
194
195        assert!(self.tail.is_none());
196        true
197    }
198
199    /// Removes the specified node from the list
200    ///
201    /// # Safety
202    ///
203    /// The caller **must** ensure that exactly one of the following is true:
204    /// - `node` is currently contained by `self`,
205    /// - `node` is not contained by any list,
206    /// - `node` is currently contained by some other `GuardedLinkedList` **and**
207    ///   the caller has an exclusive access to that list. This condition is
208    ///   used by the linked list in `sync::Notify`.
209    pub(crate) unsafe fn remove(&mut self, node: NonNull<L::Target>) -> Option<L::Handle> {
210        if let Some(prev) = L::pointers(node).as_ref().get_prev() {
211            debug_assert_eq!(L::pointers(prev).as_ref().get_next(), Some(node));
212            L::pointers(prev)
213                .as_mut()
214                .set_next(L::pointers(node).as_ref().get_next());
215        } else {
216            if self.head != Some(node) {
217                return None;
218            }
219
220            self.head = L::pointers(node).as_ref().get_next();
221        }
222
223        if let Some(next) = L::pointers(node).as_ref().get_next() {
224            debug_assert_eq!(L::pointers(next).as_ref().get_prev(), Some(node));
225            L::pointers(next)
226                .as_mut()
227                .set_prev(L::pointers(node).as_ref().get_prev());
228        } else {
229            // This might be the last item in the list
230            if self.tail != Some(node) {
231                return None;
232            }
233
234            self.tail = L::pointers(node).as_ref().get_prev();
235        }
236
237        L::pointers(node).as_mut().set_next(None);
238        L::pointers(node).as_mut().set_prev(None);
239
240        Some(L::from_raw(node))
241    }
242}
243
244impl<L: Link> fmt::Debug for LinkedList<L, L::Target> {
245    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
246        f.debug_struct("LinkedList")
247            .field("head", &self.head)
248            .field("tail", &self.tail)
249            .finish()
250    }
251}
252
253#[cfg(any(
254    feature = "fs",
255    feature = "rt",
256    all(unix, feature = "process"),
257    feature = "signal",
258    feature = "sync",
259))]
260impl<L: Link> LinkedList<L, L::Target> {
261    pub(crate) fn last(&self) -> Option<&L::Target> {
262        let tail = self.tail.as_ref()?;
263        unsafe { Some(&*tail.as_ptr()) }
264    }
265}
266
267impl<L: Link> Default for LinkedList<L, L::Target> {
268    fn default() -> Self {
269        Self::new()
270    }
271}
272
273// ===== impl DrainFilter =====
274
275cfg_io_driver_impl! {
276    pub(crate) struct DrainFilter<'a, T: Link, F> {
277        list: &'a mut LinkedList<T, T::Target>,
278        filter: F,
279        curr: Option<NonNull<T::Target>>,
280    }
281
282    impl<T: Link> LinkedList<T, T::Target> {
283        pub(crate) fn drain_filter<F>(&mut self, filter: F) -> DrainFilter<'_, T, F>
284        where
285            F: FnMut(&T::Target) -> bool,
286        {
287            let curr = self.head;
288            DrainFilter {
289                curr,
290                filter,
291                list: self,
292            }
293        }
294    }
295
296    impl<'a, T, F> Iterator for DrainFilter<'a, T, F>
297    where
298        T: Link,
299        F: FnMut(&T::Target) -> bool,
300    {
301        type Item = T::Handle;
302
303        fn next(&mut self) -> Option<Self::Item> {
304            while let Some(curr) = self.curr {
305                // safety: the pointer references data contained by the list
306                self.curr = unsafe { T::pointers(curr).as_ref() }.get_next();
307
308                // safety: the value is still owned by the linked list.
309                if (self.filter)(unsafe { &mut *curr.as_ptr() }) {
310                    return unsafe { self.list.remove(curr) };
311                }
312            }
313
314            None
315        }
316    }
317}
318
319cfg_taskdump! {
320    impl<T: Link> LinkedList<T, T::Target> {
321        pub(crate) fn for_each<F>(&mut self, mut f: F)
322        where
323            F: FnMut(&T::Handle),
324        {
325            let mut next = self.head;
326
327            while let Some(curr) = next {
328                unsafe {
329                    let handle = ManuallyDrop::new(T::from_raw(curr));
330                    f(&handle);
331                    next = T::pointers(curr).as_ref().get_next();
332                }
333            }
334        }
335    }
336}
337
338// ===== impl GuardedLinkedList =====
339
340feature! {
341    #![any(
342        feature = "process",
343        feature = "sync",
344        feature = "rt",
345        feature = "signal",
346    )]
347
348    /// An intrusive linked list, but instead of keeping pointers to the head
349    /// and tail nodes, it uses a special guard node linked with those nodes.
350    /// It means that the list is circular and every pointer of a node from
351    /// the list is not `None`, including pointers from the guard node.
352    ///
353    /// If a list is empty, then both pointers of the guard node are pointing
354    /// at the guard node itself.
355    pub(crate) struct GuardedLinkedList<L, T> {
356        /// Pointer to the guard node.
357        guard: NonNull<T>,
358
359        /// Node type marker.
360        _marker: PhantomData<*const L>,
361    }
362
363    impl<L: Link> LinkedList<L, L::Target> {
364        /// Turns a linked list into the guarded version by linking the guard node
365        /// with the head and tail nodes. Like with other nodes, you should guarantee
366        /// that the guard node is pinned in memory.
367        pub(crate) fn into_guarded(self, guard_handle: L::Handle) -> GuardedLinkedList<L, L::Target> {
368            // `guard_handle` is a NonNull pointer, we don't have to care about dropping it.
369            let guard = L::as_raw(&guard_handle);
370
371            unsafe {
372                if let Some(head) = self.head {
373                    debug_assert!(L::pointers(head).as_ref().get_prev().is_none());
374                    L::pointers(head).as_mut().set_prev(Some(guard));
375                    L::pointers(guard).as_mut().set_next(Some(head));
376
377                    // The list is not empty, so the tail cannot be `None`.
378                    let tail = self.tail.unwrap();
379                    debug_assert!(L::pointers(tail).as_ref().get_next().is_none());
380                    L::pointers(tail).as_mut().set_next(Some(guard));
381                    L::pointers(guard).as_mut().set_prev(Some(tail));
382                } else {
383                    // The list is empty.
384                    L::pointers(guard).as_mut().set_prev(Some(guard));
385                    L::pointers(guard).as_mut().set_next(Some(guard));
386                }
387            }
388
389            GuardedLinkedList { guard, _marker: PhantomData }
390        }
391    }
392
393    impl<L: Link> GuardedLinkedList<L, L::Target> {
394        fn tail(&self) -> Option<NonNull<L::Target>> {
395            let tail_ptr = unsafe {
396                L::pointers(self.guard).as_ref().get_prev().unwrap()
397            };
398
399            // Compare the tail pointer with the address of the guard node itself.
400            // If the guard points at itself, then there are no other nodes and
401            // the list is considered empty.
402            if tail_ptr != self.guard {
403                Some(tail_ptr)
404            } else {
405                None
406            }
407        }
408
409        /// Removes the last element from a list and returns it, or None if it is
410        /// empty.
411        pub(crate) fn pop_back(&mut self) -> Option<L::Handle> {
412            unsafe {
413                let last = self.tail()?;
414                let before_last = L::pointers(last).as_ref().get_prev().unwrap();
415
416                L::pointers(self.guard).as_mut().set_prev(Some(before_last));
417                L::pointers(before_last).as_mut().set_next(Some(self.guard));
418
419                L::pointers(last).as_mut().set_prev(None);
420                L::pointers(last).as_mut().set_next(None);
421
422                Some(L::from_raw(last))
423            }
424        }
425    }
426}
427
428// ===== impl Pointers =====
429
430impl<T> Pointers<T> {
431    /// Create a new set of empty pointers
432    pub(crate) fn new() -> Pointers<T> {
433        Pointers {
434            inner: UnsafeCell::new(PointersInner {
435                prev: None,
436                next: None,
437                _pin: PhantomPinned,
438            }),
439        }
440    }
441
442    pub(crate) fn get_prev(&self) -> Option<NonNull<T>> {
443        // SAFETY: Field is accessed immutably through a reference.
444        unsafe { ptr::addr_of!((*self.inner.get()).prev).read() }
445    }
446    pub(crate) fn get_next(&self) -> Option<NonNull<T>> {
447        // SAFETY: Field is accessed immutably through a reference.
448        unsafe { ptr::addr_of!((*self.inner.get()).next).read() }
449    }
450
451    fn set_prev(&mut self, value: Option<NonNull<T>>) {
452        // SAFETY: Field is accessed mutably through a mutable reference.
453        unsafe {
454            ptr::addr_of_mut!((*self.inner.get()).prev).write(value);
455        }
456    }
457    fn set_next(&mut self, value: Option<NonNull<T>>) {
458        // SAFETY: Field is accessed mutably through a mutable reference.
459        unsafe {
460            ptr::addr_of_mut!((*self.inner.get()).next).write(value);
461        }
462    }
463}
464
465impl<T> fmt::Debug for Pointers<T> {
466    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
467        let prev = self.get_prev();
468        let next = self.get_next();
469        f.debug_struct("Pointers")
470            .field("prev", &prev)
471            .field("next", &next)
472            .finish()
473    }
474}
475
476#[cfg(any(test, fuzzing))]
477#[cfg(not(loom))]
478pub(crate) mod tests {
479    use super::*;
480
481    use std::pin::Pin;
482
483    #[derive(Debug)]
484    #[repr(C)]
485    struct Entry {
486        pointers: Pointers<Entry>,
487        val: i32,
488    }
489
490    unsafe impl<'a> Link for &'a Entry {
491        type Handle = Pin<&'a Entry>;
492        type Target = Entry;
493
494        fn as_raw(handle: &Pin<&'_ Entry>) -> NonNull<Entry> {
495            NonNull::from(handle.get_ref())
496        }
497
498        unsafe fn from_raw(ptr: NonNull<Entry>) -> Pin<&'a Entry> {
499            Pin::new_unchecked(&*ptr.as_ptr())
500        }
501
502        unsafe fn pointers(target: NonNull<Entry>) -> NonNull<Pointers<Entry>> {
503            target.cast()
504        }
505    }
506
507    fn entry(val: i32) -> Pin<Box<Entry>> {
508        Box::pin(Entry {
509            pointers: Pointers::new(),
510            val,
511        })
512    }
513
514    fn ptr(r: &Pin<Box<Entry>>) -> NonNull<Entry> {
515        r.as_ref().get_ref().into()
516    }
517
518    fn collect_list(list: &mut LinkedList<&'_ Entry, <&'_ Entry as Link>::Target>) -> Vec<i32> {
519        let mut ret = vec![];
520
521        while let Some(entry) = list.pop_back() {
522            ret.push(entry.val);
523        }
524
525        ret
526    }
527
528    fn push_all<'a>(
529        list: &mut LinkedList<&'a Entry, <&'_ Entry as Link>::Target>,
530        entries: &[Pin<&'a Entry>],
531    ) {
532        for entry in entries.iter() {
533            list.push_front(*entry);
534        }
535    }
536
537    #[cfg(test)]
538    macro_rules! assert_clean {
539        ($e:ident) => {{
540            assert!($e.pointers.get_next().is_none());
541            assert!($e.pointers.get_prev().is_none());
542        }};
543    }
544
545    #[cfg(test)]
546    macro_rules! assert_ptr_eq {
547        ($a:expr, $b:expr) => {{
548            // Deal with mapping a Pin<&mut T> -> Option<NonNull<T>>
549            assert_eq!(Some($a.as_ref().get_ref().into()), $b)
550        }};
551    }
552
553    #[test]
554    fn const_new() {
555        const _: LinkedList<&Entry, <&Entry as Link>::Target> = LinkedList::new();
556    }
557
558    #[test]
559    fn push_and_drain() {
560        let a = entry(5);
561        let b = entry(7);
562        let c = entry(31);
563
564        let mut list = LinkedList::new();
565        assert!(list.is_empty());
566
567        list.push_front(a.as_ref());
568        assert!(!list.is_empty());
569        list.push_front(b.as_ref());
570        list.push_front(c.as_ref());
571
572        let items: Vec<i32> = collect_list(&mut list);
573        assert_eq!([5, 7, 31].to_vec(), items);
574
575        assert!(list.is_empty());
576    }
577
578    #[test]
579    fn push_pop_push_pop() {
580        let a = entry(5);
581        let b = entry(7);
582
583        let mut list = LinkedList::<&Entry, <&Entry as Link>::Target>::new();
584
585        list.push_front(a.as_ref());
586
587        let entry = list.pop_back().unwrap();
588        assert_eq!(5, entry.val);
589        assert!(list.is_empty());
590
591        list.push_front(b.as_ref());
592
593        let entry = list.pop_back().unwrap();
594        assert_eq!(7, entry.val);
595
596        assert!(list.is_empty());
597        assert!(list.pop_back().is_none());
598    }
599
600    #[test]
601    fn remove_by_address() {
602        let a = entry(5);
603        let b = entry(7);
604        let c = entry(31);
605
606        unsafe {
607            // Remove first
608            let mut list = LinkedList::new();
609
610            push_all(&mut list, &[c.as_ref(), b.as_ref(), a.as_ref()]);
611            assert!(list.remove(ptr(&a)).is_some());
612            assert_clean!(a);
613            // `a` should be no longer there and can't be removed twice
614            assert!(list.remove(ptr(&a)).is_none());
615            assert!(!list.is_empty());
616
617            assert!(list.remove(ptr(&b)).is_some());
618            assert_clean!(b);
619            // `b` should be no longer there and can't be removed twice
620            assert!(list.remove(ptr(&b)).is_none());
621            assert!(!list.is_empty());
622
623            assert!(list.remove(ptr(&c)).is_some());
624            assert_clean!(c);
625            // `b` should be no longer there and can't be removed twice
626            assert!(list.remove(ptr(&c)).is_none());
627            assert!(list.is_empty());
628        }
629
630        unsafe {
631            // Remove middle
632            let mut list = LinkedList::new();
633
634            push_all(&mut list, &[c.as_ref(), b.as_ref(), a.as_ref()]);
635
636            assert!(list.remove(ptr(&a)).is_some());
637            assert_clean!(a);
638
639            assert_ptr_eq!(b, list.head);
640            assert_ptr_eq!(c, b.pointers.get_next());
641            assert_ptr_eq!(b, c.pointers.get_prev());
642
643            let items = collect_list(&mut list);
644            assert_eq!([31, 7].to_vec(), items);
645        }
646
647        unsafe {
648            // Remove middle
649            let mut list = LinkedList::new();
650
651            push_all(&mut list, &[c.as_ref(), b.as_ref(), a.as_ref()]);
652
653            assert!(list.remove(ptr(&b)).is_some());
654            assert_clean!(b);
655
656            assert_ptr_eq!(c, a.pointers.get_next());
657            assert_ptr_eq!(a, c.pointers.get_prev());
658
659            let items = collect_list(&mut list);
660            assert_eq!([31, 5].to_vec(), items);
661        }
662
663        unsafe {
664            // Remove last
665            // Remove middle
666            let mut list = LinkedList::new();
667
668            push_all(&mut list, &[c.as_ref(), b.as_ref(), a.as_ref()]);
669
670            assert!(list.remove(ptr(&c)).is_some());
671            assert_clean!(c);
672
673            assert!(b.pointers.get_next().is_none());
674            assert_ptr_eq!(b, list.tail);
675
676            let items = collect_list(&mut list);
677            assert_eq!([7, 5].to_vec(), items);
678        }
679
680        unsafe {
681            // Remove first of two
682            let mut list = LinkedList::new();
683
684            push_all(&mut list, &[b.as_ref(), a.as_ref()]);
685
686            assert!(list.remove(ptr(&a)).is_some());
687
688            assert_clean!(a);
689
690            // a should be no longer there and can't be removed twice
691            assert!(list.remove(ptr(&a)).is_none());
692
693            assert_ptr_eq!(b, list.head);
694            assert_ptr_eq!(b, list.tail);
695
696            assert!(b.pointers.get_next().is_none());
697            assert!(b.pointers.get_prev().is_none());
698
699            let items = collect_list(&mut list);
700            assert_eq!([7].to_vec(), items);
701        }
702
703        unsafe {
704            // Remove last of two
705            let mut list = LinkedList::new();
706
707            push_all(&mut list, &[b.as_ref(), a.as_ref()]);
708
709            assert!(list.remove(ptr(&b)).is_some());
710
711            assert_clean!(b);
712
713            assert_ptr_eq!(a, list.head);
714            assert_ptr_eq!(a, list.tail);
715
716            assert!(a.pointers.get_next().is_none());
717            assert!(a.pointers.get_prev().is_none());
718
719            let items = collect_list(&mut list);
720            assert_eq!([5].to_vec(), items);
721        }
722
723        unsafe {
724            // Remove last item
725            let mut list = LinkedList::new();
726
727            push_all(&mut list, &[a.as_ref()]);
728
729            assert!(list.remove(ptr(&a)).is_some());
730            assert_clean!(a);
731
732            assert!(list.head.is_none());
733            assert!(list.tail.is_none());
734            let items = collect_list(&mut list);
735            assert!(items.is_empty());
736        }
737
738        unsafe {
739            // Remove missing
740            let mut list = LinkedList::<&Entry, <&Entry as Link>::Target>::new();
741
742            list.push_front(b.as_ref());
743            list.push_front(a.as_ref());
744
745            assert!(list.remove(ptr(&c)).is_none());
746        }
747    }
748
749    /// This is a fuzz test. You run it by entering `cargo fuzz run fuzz_linked_list` in CLI in `/tokio/` module.
750    #[cfg(fuzzing)]
751    pub fn fuzz_linked_list(ops: &[u8]) {
752        enum Op {
753            Push,
754            Pop,
755            Remove(usize),
756        }
757        use std::collections::VecDeque;
758
759        let ops = ops
760            .iter()
761            .map(|i| match i % 3u8 {
762                0 => Op::Push,
763                1 => Op::Pop,
764                2 => Op::Remove((i / 3u8) as usize),
765                _ => unreachable!(),
766            })
767            .collect::<Vec<_>>();
768
769        let mut ll = LinkedList::<&Entry, <&Entry as Link>::Target>::new();
770        let mut reference = VecDeque::new();
771
772        let entries: Vec<_> = (0..ops.len()).map(|i| entry(i as i32)).collect();
773
774        for (i, op) in ops.iter().enumerate() {
775            match op {
776                Op::Push => {
777                    reference.push_front(i as i32);
778                    assert_eq!(entries[i].val, i as i32);
779
780                    ll.push_front(entries[i].as_ref());
781                }
782                Op::Pop => {
783                    if reference.is_empty() {
784                        assert!(ll.is_empty());
785                        continue;
786                    }
787
788                    let v = reference.pop_back();
789                    assert_eq!(v, ll.pop_back().map(|v| v.val));
790                }
791                Op::Remove(n) => {
792                    if reference.is_empty() {
793                        assert!(ll.is_empty());
794                        continue;
795                    }
796
797                    let idx = n % reference.len();
798                    let expect = reference.remove(idx).unwrap();
799
800                    unsafe {
801                        let entry = ll.remove(ptr(&entries[expect as usize])).unwrap();
802                        assert_eq!(expect, entry.val);
803                    }
804                }
805            }
806        }
807    }
808}