//! Linked list impl. //! //! An intrusive double linked list of data //! //! The data structure supports tracking pinned nodes. Most of the data //! structure's APIs are `unsafe` as they require the caller to ensure the //! specified node is actually contained by the list. // Heavily borrowed from tokio. // Copyright (c) 2021 Tokio Contributors, licensed under the MIT license. #![allow(unused)] use core::{ cell::UnsafeCell, fmt, marker::{PhantomData, PhantomPinned}, mem::ManuallyDrop, ptr::{self, NonNull}, }; /// An intrusive linked list. /// /// Currently, the list is not emptied on drop. It is the caller's /// responsibility to ensure the list is empty before dropping it. pub(crate) struct LinkedList { /// Linked list head head: Option>, /// Linked list tail tail: Option>, /// Node type marker. _marker: PhantomData<*const L>, } /// Defines how a type is tracked within a linked list. /// /// In order to support storing a single type within multiple lists, accessing /// the list pointers is decoupled from the entry type. /// /// # Safety /// /// Implementations must guarantee that `Target` types are pinned in memory. In /// other words, when a node is inserted, the value will not be moved as long as /// it is stored in the list. pub(crate) unsafe trait Link { /// Handle to the list entry. /// /// This is usually a pointer-ish type. type Handle; /// Node type type Target; /// Convert the handle to a raw pointer without consuming the handle #[allow(clippy::wrong_self_convention)] fn as_raw(handle: &Self::Handle) -> NonNull; /// Convert the raw pointer to a handle unsafe fn from_raw(ptr: NonNull) -> Self::Handle; /// Return the pointers for a node unsafe fn pointers(target: NonNull) -> NonNull>; } /// Previous / next pointers pub(crate) struct Pointers { inner: UnsafeCell>, } /// We do not want the compiler to put the `noalias` attribute on mutable /// references to this type, so the type has been made `!Unpin` with a /// `PhantomPinned` field. /// /// Additionally, we never access the `prev` or `next` fields directly, as any /// such access would implicitly involve the creation of a reference to the /// field, which we want to avoid since the fields are not `!Unpin`, and would /// hence be given the `noalias` attribute if we were to do such an access. /// As an alternative to accessing the fields directly, the `Pointers` type /// provides getters and setters for the two fields, and those are implemented /// using raw pointer casts and offsets, which is valid since the struct is /// #[repr(C)]. /// /// See this link for more information: /// #[repr(C)] struct PointersInner { /// The previous node in the list. null if there is no previous node. /// /// This field is accessed through pointer manipulation, so it is not dead /// code. #[allow(dead_code)] prev: Option>, /// The next node in the list. null if there is no previous node. /// /// This field is accessed through pointer manipulation, so it is not dead /// code. #[allow(dead_code)] next: Option>, /// This type is !Unpin due to the heuristic from: /// _pin: PhantomPinned, } // ===== impl LinkedList ===== impl LinkedList { /// Creates an empty linked list. pub(crate) const fn new() -> LinkedList { LinkedList { head: None, tail: None, _marker: PhantomData, } } } impl LinkedList { /// Adds an element first in the list. pub(crate) fn push_front(&mut self, val: L::Handle) { // The value should not be dropped, it is being inserted into the list let val = ManuallyDrop::new(val); let ptr = L::as_raw(&val); assert_ne!(self.head, Some(ptr)); unsafe { L::pointers(ptr).as_mut().set_next(self.head); L::pointers(ptr).as_mut().set_prev(None); if let Some(head) = self.head { L::pointers(head).as_mut().set_prev(Some(ptr)); } self.head = Some(ptr); if self.tail.is_none() { self.tail = Some(ptr); } } } /// Removes the last element from a list and returns it, or None if it is /// empty. pub(crate) fn pop_back(&mut self) -> Option { unsafe { let last = self.tail?; self.tail = L::pointers(last).as_ref().get_prev(); if let Some(prev) = L::pointers(last).as_ref().get_prev() { L::pointers(prev).as_mut().set_next(None); } else { self.head = None } L::pointers(last).as_mut().set_prev(None); L::pointers(last).as_mut().set_next(None); Some(L::from_raw(last)) } } /// Returns whether the linked list does not contain any node pub(crate) fn is_empty(&self) -> bool { if self.head.is_some() { return false; } assert!(self.tail.is_none()); true } /// Removes the specified node from the list /// /// # Safety /// /// The caller **must** ensure that `node` is currently contained by /// `self` or not contained by any other list. pub(crate) unsafe fn remove(&mut self, node: NonNull) -> Option { if let Some(prev) = L::pointers(node).as_ref().get_prev() { debug_assert_eq!(L::pointers(prev).as_ref().get_next(), Some(node)); L::pointers(prev) .as_mut() .set_next(L::pointers(node).as_ref().get_next()); } else { if self.head != Some(node) { return None; } self.head = L::pointers(node).as_ref().get_next(); } if let Some(next) = L::pointers(node).as_ref().get_next() { debug_assert_eq!(L::pointers(next).as_ref().get_prev(), Some(node)); L::pointers(next) .as_mut() .set_prev(L::pointers(node).as_ref().get_prev()); } else { // This might be the last item in the list if self.tail != Some(node) { return None; } self.tail = L::pointers(node).as_ref().get_prev(); } L::pointers(node).as_mut().set_next(None); L::pointers(node).as_mut().set_prev(None); Some(L::from_raw(node)) } } impl fmt::Debug for LinkedList { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("LinkedList") .field("head", &self.head) .field("tail", &self.tail) .finish() } } impl LinkedList { pub(crate) fn last(&self) -> Option<&L::Target> { let tail = self.tail.as_ref()?; unsafe { Some(&*tail.as_ptr()) } } } impl Default for LinkedList { fn default() -> Self { Self::new() } } // ===== impl DrainFilter ===== pub(crate) struct DrainFilter<'a, T: Link, F> { list: &'a mut LinkedList, filter: F, curr: Option>, } impl LinkedList { pub(crate) fn drain_filter(&mut self, filter: F) -> DrainFilter<'_, T, F> where F: FnMut(&mut T::Target) -> bool, { let curr = self.head; DrainFilter { curr, filter, list: self, } } } impl<'a, T, F> Iterator for DrainFilter<'a, T, F> where T: Link, F: FnMut(&mut T::Target) -> bool, { type Item = T::Handle; fn next(&mut self) -> Option { while let Some(curr) = self.curr { // safety: the pointer references data contained by the list self.curr = unsafe { T::pointers(curr).as_ref() }.get_next(); // safety: the value is still owned by the linked list. if (self.filter)(unsafe { &mut *curr.as_ptr() }) { return unsafe { self.list.remove(curr) }; } } None } } // ===== impl Pointers ===== impl Pointers { /// Create a new set of empty pointers pub(crate) fn new() -> Pointers { Pointers { inner: UnsafeCell::new(PointersInner { prev: None, next: None, _pin: PhantomPinned, }), } } fn get_prev(&self) -> Option> { // SAFETY: prev is the first field in PointersInner, which is #[repr(C)]. unsafe { let inner = self.inner.get(); let prev = inner as *const Option>; ptr::read(prev) } } fn get_next(&self) -> Option> { // SAFETY: next is the second field in PointersInner, which is #[repr(C)]. unsafe { let inner = self.inner.get(); let prev = inner as *const Option>; let next = prev.add(1); ptr::read(next) } } fn set_prev(&mut self, value: Option>) { // SAFETY: prev is the first field in PointersInner, which is #[repr(C)]. unsafe { let inner = self.inner.get(); let prev = inner as *mut Option>; ptr::write(prev, value); } } fn set_next(&mut self, value: Option>) { // SAFETY: next is the second field in PointersInner, which is #[repr(C)]. unsafe { let inner = self.inner.get(); let prev = inner as *mut Option>; let next = prev.add(1); ptr::write(next, value); } } } impl fmt::Debug for Pointers { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { let prev = self.get_prev(); let next = self.get_next(); f.debug_struct("Pointers") .field("prev", &prev) .field("next", &next) .finish() } } #[cfg(test)] mod tests { use std::pin::Pin; use super::*; #[derive(Debug)] struct Entry { pointers: Pointers, val: i32, } unsafe impl<'a> Link for &'a Entry { type Handle = Pin<&'a Entry>; type Target = Entry; fn as_raw(handle: &Pin<&'_ Entry>) -> NonNull { NonNull::from(handle.get_ref()) } unsafe fn from_raw(ptr: NonNull) -> Pin<&'a Entry> { Pin::new_unchecked(&*ptr.as_ptr()) } unsafe fn pointers(mut target: NonNull) -> NonNull> { NonNull::from(&mut target.as_mut().pointers) } } fn entry(val: i32) -> Pin> { Box::pin(Entry { pointers: Pointers::new(), val, }) } fn ptr(r: &Pin>) -> NonNull { r.as_ref().get_ref().into() } fn collect_list(list: &mut LinkedList<&'_ Entry, <&'_ Entry as Link>::Target>) -> Vec { let mut ret = vec![]; while let Some(entry) = list.pop_back() { ret.push(entry.val); } ret } fn push_all<'a>( list: &mut LinkedList<&'a Entry, <&'_ Entry as Link>::Target>, entries: &[Pin<&'a Entry>], ) { for entry in entries.iter() { list.push_front(*entry); } } macro_rules! assert_clean { ($e:ident) => {{ assert!($e.pointers.get_next().is_none()); assert!($e.pointers.get_prev().is_none()); }}; } macro_rules! assert_ptr_eq { ($a:expr, $b:expr) => {{ // Deal with mapping a Pin<&mut T> -> Option> assert_eq!(Some($a.as_ref().get_ref().into()), $b) }}; } #[test] fn const_new() { const _: LinkedList<&Entry, <&Entry as Link>::Target> = LinkedList::new(); } #[test] fn push_and_drain() { let a = entry(5); let b = entry(7); let c = entry(31); let mut list = LinkedList::new(); assert!(list.is_empty()); list.push_front(a.as_ref()); assert!(!list.is_empty()); list.push_front(b.as_ref()); list.push_front(c.as_ref()); let items: Vec = collect_list(&mut list); assert_eq!([5, 7, 31].to_vec(), items); assert!(list.is_empty()); } #[test] fn push_pop_push_pop() { let a = entry(5); let b = entry(7); let mut list = LinkedList::<&Entry, <&Entry as Link>::Target>::new(); list.push_front(a.as_ref()); let entry = list.pop_back().unwrap(); assert_eq!(5, entry.val); assert!(list.is_empty()); list.push_front(b.as_ref()); let entry = list.pop_back().unwrap(); assert_eq!(7, entry.val); assert!(list.is_empty()); assert!(list.pop_back().is_none()); } #[test] fn remove_by_address() { let a = entry(5); let b = entry(7); let c = entry(31); unsafe { // Remove first let mut list = LinkedList::new(); push_all(&mut list, &[c.as_ref(), b.as_ref(), a.as_ref()]); assert!(list.remove(ptr(&a)).is_some()); assert_clean!(a); // `a` should be no longer there and can't be removed twice assert!(list.remove(ptr(&a)).is_none()); assert!(!list.is_empty()); assert!(list.remove(ptr(&b)).is_some()); assert_clean!(b); // `b` should be no longer there and can't be removed twice assert!(list.remove(ptr(&b)).is_none()); assert!(!list.is_empty()); assert!(list.remove(ptr(&c)).is_some()); assert_clean!(c); // `b` should be no longer there and can't be removed twice assert!(list.remove(ptr(&c)).is_none()); assert!(list.is_empty()); } unsafe { // Remove middle let mut list = LinkedList::new(); push_all(&mut list, &[c.as_ref(), b.as_ref(), a.as_ref()]); assert!(list.remove(ptr(&a)).is_some()); assert_clean!(a); assert_ptr_eq!(b, list.head); assert_ptr_eq!(c, b.pointers.get_next()); assert_ptr_eq!(b, c.pointers.get_prev()); let items = collect_list(&mut list); assert_eq!([31, 7].to_vec(), items); } unsafe { // Remove middle let mut list = LinkedList::new(); push_all(&mut list, &[c.as_ref(), b.as_ref(), a.as_ref()]); assert!(list.remove(ptr(&b)).is_some()); assert_clean!(b); assert_ptr_eq!(c, a.pointers.get_next()); assert_ptr_eq!(a, c.pointers.get_prev()); let items = collect_list(&mut list); assert_eq!([31, 5].to_vec(), items); } unsafe { // Remove last // Remove middle let mut list = LinkedList::new(); push_all(&mut list, &[c.as_ref(), b.as_ref(), a.as_ref()]); assert!(list.remove(ptr(&c)).is_some()); assert_clean!(c); assert!(b.pointers.get_next().is_none()); assert_ptr_eq!(b, list.tail); let items = collect_list(&mut list); assert_eq!([7, 5].to_vec(), items); } unsafe { // Remove first of two let mut list = LinkedList::new(); push_all(&mut list, &[b.as_ref(), a.as_ref()]); assert!(list.remove(ptr(&a)).is_some()); assert_clean!(a); // a should be no longer there and can't be removed twice assert!(list.remove(ptr(&a)).is_none()); assert_ptr_eq!(b, list.head); assert_ptr_eq!(b, list.tail); assert!(b.pointers.get_next().is_none()); assert!(b.pointers.get_prev().is_none()); let items = collect_list(&mut list); assert_eq!([7].to_vec(), items); } unsafe { // Remove last of two let mut list = LinkedList::new(); push_all(&mut list, &[b.as_ref(), a.as_ref()]); assert!(list.remove(ptr(&b)).is_some()); assert_clean!(b); assert_ptr_eq!(a, list.head); assert_ptr_eq!(a, list.tail); assert!(a.pointers.get_next().is_none()); assert!(a.pointers.get_prev().is_none()); let items = collect_list(&mut list); assert_eq!([5].to_vec(), items); } unsafe { // Remove last item let mut list = LinkedList::new(); push_all(&mut list, &[a.as_ref()]); assert!(list.remove(ptr(&a)).is_some()); assert_clean!(a); assert!(list.head.is_none()); assert!(list.tail.is_none()); let items = collect_list(&mut list); assert!(items.is_empty()); } unsafe { // Remove missing let mut list = LinkedList::<&Entry, <&Entry as Link>::Target>::new(); list.push_front(b.as_ref()); list.push_front(a.as_ref()); assert!(list.remove(ptr(&c)).is_none()); } } }