diff --git a/Cargo.toml b/Cargo.toml index 68d2930..d6a6f69 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,12 +1,14 @@ [package] -name = "linked_list" -version = "0.1.0" +name = "linked_list_r4l" +version = "0.2.0" edition = "2021" -authors = ["Wedson Almeida Filho "] +authors = ["Wedson Almeida Filho ", "WeiKang Guo "] description = "Linked lists that supports arbitrary removal in constant time" license = "GPL-2.0-or-later" homepage = "https://github.com/arceos-org/arceos" -repository = "https://github.com/arceos-org/linked_list" -documentation = "https://arceos-org.github.io/linked_list" +repository = "https://github.com/arceos-org/linked_list_r4l" +documentation = "https://docs.rs/linked_list_r4l" +keywords = ["list"] +categories = ["no-std", "rust-patterns"] [dependencies] diff --git a/README.md b/README.md new file mode 100644 index 0000000..b22a17e --- /dev/null +++ b/README.md @@ -0,0 +1,64 @@ +# LinkedList + +[![Crates.io](https://img.shields.io/crates/v/linked_list_r4l)](https://crates.io/crates/linked_list_r4l) +[![Doc.rs](https://docs.rs/linked_list_r4l/badge.svg)](https://docs.rs/linked_list_r4l) +[![CI](https://github.com/arceos-org/linked_list_r4l/actions/workflows/ci.yml/badge.svg?branch=main)](https://github.com/arceos-org/linked_list_r4l/actions/workflows/ci.yml) + + Linked lists that supports arbitrary removal in constant time. + + It is based on the linked list implementation in [Rust-for-Linux][1]. + + [1]: https://github.com/Rust-for-Linux/linux/blob/rust/rust/kernel/linked_list.rs + +## Examples + + ```rust + use linked_list_r4l::{GetLinks, Links, List}; + + type InnerType = usize; + + pub struct ExampleNode { + pub inner: InnerType, + links: Links, + } + + impl GetLinks for ExampleNode { + type EntryType = Self; + + fn get_links(t: &Self) -> &Links { + &t.links + } + } + + impl ExampleNode { + fn new(inner: InnerType) -> Self { + Self { + inner, + links: Links::new() + } + } + + fn inner(&self) -> &InnerType { + &self.inner + } + } + + let node1 = Box::new(ExampleNode::new(0)); + let node2 = Box::new(ExampleNode::new(1)); + let mut list = List::>::new(); + + list.push_back(node1); + list.push_back(node2); + + // Support Iter + for (i,e) in list.iter().enumerate() { + assert!(*e.inner() == i); + } + + // Pop drop + assert!(*list.pop_front().unwrap().inner() == 0); + assert!(*list.pop_front().unwrap().inner() == 1); + + ``` + + diff --git a/src/lib.rs b/src/lib.rs index 9fb264e..8fb8e00 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,14 +1,178 @@ -//! Linked lists that supports arbitrary removal in constant time. -//! -//! It is based on the linked list implementation in [Rust-for-Linux][1]. -//! -//! [1]: https://github.com/Rust-for-Linux/linux/blob/rust/rust/kernel/linked_list.rs - -#![no_std] +#![cfg_attr(not(test), no_std)] +#![doc = include_str!("../README.md")] mod linked_list; +mod raw_list; +pub use linked_list::List; +pub use raw_list::{GetLinks, Links}; + +#[macro_export(local_inner_macros)] +#[doc(hidden)] +macro_rules! __def_node_internal { + ($(#[$meta:meta])* $vis:vis struct $name:ident($type:ty);) => { + $(#[$meta])* + $vis struct $name { + inner: $type, + links: $crate::Links, + } + + impl $crate::GetLinks for $name { + type EntryType = Self; + + #[inline] + fn get_links(t: &Self) -> &$crate::Links { + &t.links + } + } + + impl $name { + #[doc = "Create a node"] + pub const fn new(inner: $type) -> Self { + Self { + inner, + links: $crate::Links::new(), + } + } + + #[inline] + #[doc = "Return the referece of wrapped inner"] + pub const fn inner(&self) -> &$type { + &self.inner + } + + #[inline] + #[doc = "Consumes the `node`, returning the wrapped inner"] + pub fn into_inner(self) -> $type { + self.inner + } + } + + impl core::ops::Deref for $name { + type Target = $type; + + #[inline] + fn deref(&self) -> &Self::Target { + &self.inner + } + } + }; + + ($(#[$meta:meta])* $vis:vis struct $name:ident<$gen:ident>($type:ty);) => { + $(#[$meta])* + $vis struct $name<$gen> { + inner: $type, + links: $crate::Links, + } + + impl<$gen> $crate::GetLinks for $name<$gen> { + type EntryType = Self; + + #[inline] + fn get_links(t: &Self) -> &$crate::Links { + &t.links + } + } + + impl<$gen> $name<$gen> { + #[doc = "Create a node"] + pub const fn new(inner: $type) -> Self { + Self { + inner, + links: $crate::Links::new(), + } + } + + #[inline] + #[doc = "Return the referece of wrapped inner"] + pub const fn inner(&self) -> &$type { + &self.inner + } + + #[inline] + #[doc = "Consumes the `node`, returning the wrapped inner"] + pub fn into_inner(self) -> $type { + self.inner + } + } + + impl<$gen> core::ops::Deref for $name<$gen> { + type Target = $type; -pub mod unsafe_list; + #[inline] + fn deref(&self) -> &Self::Target { + &self.inner + } + } + }; +} -pub use self::linked_list::{AdapterWrapped, List, Wrapper}; -pub use unsafe_list::{Adapter, Cursor, Links}; +/// A macro for create a node type that can be used in List. +/// +/// # Syntax +/// +/// ```ignore +/// def_node! { +/// /// A node with usize value. +/// [pub] struct UsizedNode(usize); +/// /// A node with generic inner type. +/// [pub] struct WrapperNode(T); +/// } +/// ``` +/// +/// # Example +/// +/// ```rust +/// use linked_list_r4l::{def_node, List}; +/// +/// def_node!{ +/// /// An example Node with usize +/// struct ExampleNode(usize); +/// /// An example Node with generic Inner type and pub(crate) +/// pub(crate) struct NativeGenericNode(usize); +/// /// An example Node with generic Inner type and pub vis +/// pub struct GenericNode(T); +/// } +/// +/// let node1 = Box::new(ExampleNode::new(0)); +/// let node2 = Box::new(ExampleNode::new(1)); +/// let mut list = List::>::new(); +/// +/// list.push_back(node1); +/// list.push_back(node2); +/// +/// for (i,e) in list.iter().enumerate() { +/// assert!(*e.inner() == i); +/// } +/// +/// let node1 = list.pop_front().unwrap(); +/// let node2 = list.pop_front().unwrap(); +/// +/// assert!(node1.into_inner() == 0); +/// assert!(node2.into_inner() == 1); +/// assert!(list.pop_front().is_none()); +/// +/// let node1 = Box::new(GenericNode::new(0)); +/// let node2 = Box::new(GenericNode::new(1)); +/// +/// let mut list = List::>>::new(); +/// +/// list.push_back(node1); +/// list.push_back(node2); +/// +/// for (i,e) in list.iter().enumerate() { +/// assert!(*e.inner() == i); +/// } +/// ``` +/// +#[macro_export(local_inner_macros)] +macro_rules! def_node { + ($(#[$meta:meta])* $vis:vis struct $name:ident($type:ty); $($t:tt)*) => { + __def_node_internal!($(#[$meta])* $vis struct $name($type);); + def_node!($($t)*); + }; + ($(#[$meta:meta])* $vis:vis struct $name:ident<$gen:ident>($type:ty); $($t:tt)*) => { + __def_node_internal!($(#[$meta])* $vis struct $name<$gen>($type);); + def_node!($($t)*); + }; + () => () +} diff --git a/src/linked_list.rs b/src/linked_list.rs index 0c18803..1f4b9fb 100644 --- a/src/linked_list.rs +++ b/src/linked_list.rs @@ -2,17 +2,16 @@ //! Linked lists. //! -//! Based on linux/rust/kernel/linked_list.rs, but use -//! [`unsafe_list::List`] as the inner implementation. +//! Based on linux/rust/kernel/linked_list.rs //! //! TODO: This module is a work in progress. extern crate alloc; use alloc::{boxed::Box, sync::Arc}; -use core::ptr::NonNull; +use core::{iter, ptr::NonNull}; -use crate::unsafe_list::{self, Adapter, Cursor, Links}; +use crate::{raw_list, raw_list::RawList, GetLinks, Links}; // TODO: Use the one from `kernel::file_operations::PointerWrapper` instead. /// Wraps an object to be inserted in a linked list. @@ -84,40 +83,40 @@ impl Wrapper for &T { } /// A descriptor of wrapped list elements. -pub trait AdapterWrapped: Adapter { +pub trait GetLinksWrapped: GetLinks { /// Specifies which wrapper (e.g., `Box` and `Arc`) wraps the list entries. type Wrapped: Wrapper; } -impl AdapterWrapped for Box +impl GetLinksWrapped for Box where - Box: Adapter, + Box: GetLinks, { - type Wrapped = Box< as Adapter>::EntryType>; + type Wrapped = Box< as GetLinks>::EntryType>; } -unsafe impl Adapter for Box { +impl GetLinks for Box { type EntryType = T::EntryType; #[inline] - fn to_links(data: &Self::EntryType) -> &Links { - ::to_links(data) + fn get_links(data: &Self::EntryType) -> &Links { + ::get_links(data) } } -impl AdapterWrapped for Arc +impl GetLinksWrapped for Arc where - Arc: Adapter, + Arc: GetLinks, { - type Wrapped = Arc< as Adapter>::EntryType>; + type Wrapped = Arc< as GetLinks>::EntryType>; } -unsafe impl Adapter for Arc { +impl GetLinks for Arc { type EntryType = T::EntryType; #[inline] - fn to_links(data: &Self::EntryType) -> &Links { - ::to_links(data) + fn get_links(data: &Self::EntryType) -> &Links { + ::get_links(data) } } @@ -125,20 +124,24 @@ unsafe impl Adapter for Arc { /// /// Elements in the list are wrapped and ownership is transferred to the list while the element is /// in the list. -pub struct List { - list: unsafe_list::List, +pub struct List { + list: RawList, } -impl List { +impl List { /// Constructs a new empty linked list. pub const fn new() -> Self { Self { - list: unsafe_list::List::new(), + list: RawList::new(), } } + /// Returns an iterator for the list starting at the first entry. + pub fn iter(&self) -> Iterator<'_, G> { + Iterator::new(self) + } + /// Returns whether the list is empty. - #[inline] pub const fn is_empty(&self) -> bool { self.list.is_empty() } @@ -151,7 +154,11 @@ impl List { let ptr = data.into_pointer(); // SAFETY: We took ownership of the entry, so it is safe to insert it. - unsafe { self.list.push_back(ptr.as_ref()) } + if !unsafe { self.list.push_back(ptr.as_ref()) } { + // If insertion failed, rebuild object so that it can be freed. + // SAFETY: We just called `into_pointer` above. + unsafe { G::Wrapped::from_pointer(ptr) }; + } } /// Inserts the given object after `existing`. @@ -162,59 +169,172 @@ impl List { /// # Safety /// /// Callers must ensure that `existing` points to a valid entry that is on the list. - pub unsafe fn insert_after(&mut self, existing: NonNull, data: G::Wrapped) { + pub unsafe fn insert_after(&mut self, existing: &G::Wrapped, data: G::Wrapped) { let ptr = data.into_pointer(); - unsafe { self.list.insert_after(existing, ptr.as_ref()) } + let entry = Wrapper::as_ref(existing); + if unsafe { !self.list.insert_after(entry, ptr.as_ref()) } { + // If insertion failed, rebuild object so that it can be freed. + unsafe { G::Wrapped::from_pointer(ptr) }; + } } /// Removes the given entry. /// /// # Safety /// - /// Callers must ensure that `data` is either on this list. It being on another + /// Callers must ensure that `data` is either on this list or in no list. It being on another /// list leads to memory unsafety. pub unsafe fn remove(&mut self, data: &G::Wrapped) -> Option { let entry_ref = Wrapper::as_ref(data); - unsafe { self.list.remove(entry_ref) }; - Some(unsafe { G::Wrapped::from_pointer(NonNull::from(entry_ref)) }) + if unsafe { self.list.remove(entry_ref) } { + Some(unsafe { G::Wrapped::from_pointer(NonNull::from(entry_ref)) }) + } else { + None + } } /// Removes the element currently at the front of the list and returns it. /// /// Returns `None` if the list is empty. pub fn pop_front(&mut self) -> Option { - let entry_ref = unsafe { self.list.front()?.as_ref() }; - unsafe { self.list.remove(entry_ref) }; - Some(unsafe { G::Wrapped::from_pointer(NonNull::from(entry_ref)) }) + let front = self.list.pop_front()?; + // SAFETY: Elements on the list were inserted after a call to `into_pointer `. + Some(unsafe { G::Wrapped::from_pointer(front) }) } - /// Returns the first element of the list, if one exists. - #[inline] - pub fn front(&self) -> Option<&G::EntryType> { - self.list.front().map(|ptr| unsafe { ptr.as_ref() }) - } - - /// Returns the last element of the list, if one exists. - #[inline] - pub fn back(&self) -> Option<&G::EntryType> { - self.list.back().map(|ptr| unsafe { ptr.as_ref() }) - } - - /// Returns a cursor starting on the first (front) element of the list. - #[inline] - pub fn cursor_front(&self) -> Cursor<'_, G> { - self.list.cursor_front() + /// Returns a mutable cursor starting on the first (front) element of the list. + pub fn cursor_front_mut(&mut self) -> CursorMut<'_, G> { + CursorMut::new(self.list.cursor_front_mut()) } } -impl Default for List { +impl Default for List { fn default() -> Self { Self::new() } } -impl Drop for List { +impl Drop for List { fn drop(&mut self) { while self.pop_front().is_some() {} } } + +/// A list cursor that allows traversing a linked list and inspecting & mutating elements. +pub struct CursorMut<'a, G: GetLinksWrapped> { + cursor: raw_list::CursorMut<'a, G>, +} + +impl<'a, G: GetLinksWrapped> CursorMut<'a, G> { + const fn new(cursor: raw_list::CursorMut<'a, G>) -> Self { + Self { cursor } + } + + /// Returns the element the cursor is currently positioned on. + pub fn current(&mut self) -> Option<&mut G::EntryType> { + self.cursor.current() + } + + /// Removes the element the cursor is currently positioned on. + /// + /// After removal, it advances the cursor to the next element. + pub fn remove_current(&mut self) -> Option { + let ptr = self.cursor.remove_current()?; + + // SAFETY: Elements on the list were inserted after a call to `into_pointer `. + Some(unsafe { G::Wrapped::from_pointer(ptr) }) + } + + /// Returns the element immediately after the one the cursor is positioned on. + pub fn peek_next(&mut self) -> Option<&mut G::EntryType> { + self.cursor.peek_next() + } + + /// Returns the element immediately before the one the cursor is positioned on. + pub fn peek_prev(&mut self) -> Option<&mut G::EntryType> { + self.cursor.peek_prev() + } + + /// Moves the cursor to the next element. + pub fn move_next(&mut self) { + self.cursor.move_next(); + } +} + +/// An iterator for the linked list. +pub struct Iterator<'a, G: GetLinksWrapped> { + iter: raw_list::Iterator<'a, G>, +} + +impl<'a, G: GetLinksWrapped> Iterator<'a, G> { + fn new(list: &'a List) -> Self { + Self { + iter: list.list.iter(), + } + } +} + +impl<'a, G: GetLinksWrapped> iter::Iterator for Iterator<'a, G> { + type Item = &'a G::EntryType; + + fn next(&mut self) -> Option { + self.iter.next() + } +} + +impl iter::DoubleEndedIterator for Iterator<'_, G> { + fn next_back(&mut self) -> Option { + self.iter.next_back() + } +} + +#[cfg(test)] +mod tests { + use super::{GetLinks, Links, List}; + + struct Example { + inner: usize, + links: Links, + } + + impl GetLinks for Example { + type EntryType = Self; + fn get_links(obj: &Self) -> &Links { + &obj.links + } + } + + #[track_caller] + fn assert_list_contents(list: &List>, n: usize) { + // Assert that the list is ok going forward. + let mut count = 0; + for (i, e) in list.iter().enumerate() { + assert_eq!(i + 1, e.inner); + count += 1; + } + assert_eq!(count, n); + + // Assert that the list is ok going backwards. + let mut count = n; + for e in list.iter().rev() { + assert_eq!(count, e.inner); + count -= 1; + } + assert_eq!(count, 0); + } + + #[track_caller] + #[test] + fn test_push_back() { + const MAX: usize = 10; + let mut list = List::>::new(); + + for n in 1..=MAX { + list.push_back(Box::new(Example { + inner: n, + links: Links::new(), + })); + } + assert_list_contents(&list, MAX); + } +} diff --git a/src/raw_list.rs b/src/raw_list.rs new file mode 100644 index 0000000..4218ce1 --- /dev/null +++ b/src/raw_list.rs @@ -0,0 +1,562 @@ +// SPDX-License-Identifier: GPL-2.0 + +//! Raw lists. +//! +//! Copied from linux/rust/kernel/raw_list.rs. +//! +//! TODO: This module is a work in progress. + +use core::{ + cell::UnsafeCell, + iter, ptr, + ptr::NonNull, + sync::atomic::{AtomicBool, Ordering}, +}; + +/// A descriptor of list elements. +/// +/// It describes the type of list elements and provides a function to determine how to get the +/// links to be used on a list. +/// +/// A type that may be in multiple lists simultaneously needs to implement one of these for each +/// simultaneous list. +pub trait GetLinks { + /// The type of the entries in the list. + type EntryType: ?Sized; + + /// Returns the links to be used when linking an entry within a list. + fn get_links(data: &Self::EntryType) -> &Links; +} + +/// The links used to link an object on a linked list. +/// +/// Instances of this type are usually embedded in structures and returned in calls to +/// [`GetLinks::get_links`]. +pub struct Links { + inserted: AtomicBool, + entry: UnsafeCell>, +} + +// SAFETY: `Links` can be safely sent to other threads but we restrict it to being `Send` only when +// the list entries it points to are also `Send`. +unsafe impl Send for Links {} + +// SAFETY: `Links` is usable from other threads via references but we restrict it to being `Sync` +// only when the list entries it points to are also `Sync`. +unsafe impl Sync for Links {} + +impl Links { + /// Constructs a new [`Links`] instance that isn't inserted on any lists yet. + pub const fn new() -> Self { + Self { + inserted: AtomicBool::new(false), + entry: UnsafeCell::new(ListEntry::new()), + } + } + + fn acquire_for_insertion(&self) -> bool { + self.inserted + .compare_exchange(false, true, Ordering::Acquire, Ordering::Relaxed) + .is_ok() + } + + fn release_after_removal(&self) { + self.inserted.store(false, Ordering::Release); + } +} + +impl Default for Links { + fn default() -> Self { + Self::new() + } +} + +struct ListEntry { + next: Option>, + prev: Option>, +} + +impl ListEntry { + const fn new() -> Self { + Self { + next: None, + prev: None, + } + } +} + +/// A linked list. +/// +/// # Invariants +/// +/// The links of objects added to a list are owned by the list. +pub(crate) struct RawList { + head: Option>, +} + +impl RawList { + pub(crate) const fn new() -> Self { + Self { head: None } + } + + /// Returns an iterator for the list starting at the first entry. + pub(crate) fn iter(&self) -> Iterator<'_, G> { + Iterator::new(self.cursor_front(), self.cursor_back()) + } + + pub(crate) const fn is_empty(&self) -> bool { + self.head.is_none() + } + + fn insert_after_priv( + &mut self, + existing: &G::EntryType, + new_entry: &mut ListEntry, + new_ptr: Option>, + ) { + { + // SAFETY: It's safe to get the previous entry of `existing` because the list cannot + // change. + let existing_links = unsafe { &mut *G::get_links(existing).entry.get() }; + new_entry.next = existing_links.next; + existing_links.next = new_ptr; + } + + new_entry.prev = Some(NonNull::from(existing)); + + // SAFETY: It's safe to get the next entry of `existing` because the list cannot change. + let next_links = + unsafe { &mut *G::get_links(new_entry.next.unwrap().as_ref()).entry.get() }; + next_links.prev = new_ptr; + } + + /// Inserts the given object after `existing`. + /// + /// # Safety + /// + /// Callers must ensure that `existing` points to a valid entry that is on the list. + pub(crate) unsafe fn insert_after( + &mut self, + existing: &G::EntryType, + new: &G::EntryType, + ) -> bool { + let links = G::get_links(new); + if !links.acquire_for_insertion() { + // Nothing to do if already inserted. + return false; + } + + // SAFETY: The links are now owned by the list, so it is safe to get a mutable reference. + let new_entry = unsafe { &mut *links.entry.get() }; + self.insert_after_priv(existing, new_entry, Some(NonNull::from(new))); + true + } + + fn push_back_internal(&mut self, new: &G::EntryType) -> bool { + let links = G::get_links(new); + if !links.acquire_for_insertion() { + // Nothing to do if already inserted. + return false; + } + + // SAFETY: The links are now owned by the list, so it is safe to get a mutable reference. + let new_entry = unsafe { &mut *links.entry.get() }; + let new_ptr = Some(NonNull::from(new)); + match self.back() { + // SAFETY: `back` is valid as the list cannot change. + Some(back) => self.insert_after_priv(unsafe { back.as_ref() }, new_entry, new_ptr), + None => { + self.head = new_ptr; + new_entry.next = new_ptr; + new_entry.prev = new_ptr; + } + } + true + } + + pub(crate) unsafe fn push_back(&mut self, new: &G::EntryType) -> bool { + self.push_back_internal(new) + } + + fn remove_internal(&mut self, data: &G::EntryType) -> bool { + let links = G::get_links(data); + + // SAFETY: The links are now owned by the list, so it is safe to get a mutable reference. + let entry = unsafe { &mut *links.entry.get() }; + let next = if let Some(next) = entry.next { + next + } else { + // Nothing to do if the entry is not on the list. + return false; + }; + + if ptr::eq(data, next.as_ptr()) { + // We're removing the only element. + self.head = None + } else { + // Update the head if we're removing it. + if let Some(raw_head) = self.head { + if ptr::eq(data, raw_head.as_ptr()) { + self.head = Some(next); + } + } + + // SAFETY: It's safe to get the previous entry because the list cannot change. + unsafe { &mut *G::get_links(entry.prev.unwrap().as_ref()).entry.get() }.next = + entry.next; + + // SAFETY: It's safe to get the next entry because the list cannot change. + unsafe { &mut *G::get_links(next.as_ref()).entry.get() }.prev = entry.prev; + } + + // Reset the links of the element we're removing so that we know it's not on any list. + entry.next = None; + entry.prev = None; + links.release_after_removal(); + true + } + + /// Removes the given entry. + /// + /// # Safety + /// + /// Callers must ensure that `data` is either on this list or in no list. It being on another + /// list leads to memory unsafety. + pub(crate) unsafe fn remove(&mut self, data: &G::EntryType) -> bool { + self.remove_internal(data) + } + + fn pop_front_internal(&mut self) -> Option> { + let head = self.head?; + // SAFETY: The head is on the list as we just got it from there and it cannot change. + unsafe { self.remove(head.as_ref()) }; + Some(head) + } + + /// Get and Remove the first element of the list. + pub(crate) fn pop_front(&mut self) -> Option> { + self.pop_front_internal() + } + + /// Just Get and not remove the first element of the list. + pub(crate) fn front(&self) -> Option> { + self.head + } + + /// Just Get and not remove the last element of the list. + pub(crate) fn back(&self) -> Option> { + // SAFETY: The links of head are owned by the list, so it is safe to get a reference. + unsafe { &*G::get_links(self.head?.as_ref()).entry.get() }.prev + } + + /// Returns a cursor starting on the first element of the list. + pub(crate) fn cursor_front(&self) -> Cursor<'_, G> { + Cursor::new(self, self.front()) + } + + /// Returns a cursor starting on the last element of the list. + pub(crate) fn cursor_back(&self) -> Cursor<'_, G> { + Cursor::new(self, self.back()) + } + + /// Returns a mut cursor starting on the first element of the list. + pub(crate) fn cursor_front_mut(&mut self) -> CursorMut<'_, G> { + CursorMut::new(self, self.front()) + } +} + +struct CommonCursor { + cur: Option>, +} + +impl CommonCursor { + const fn new(cur: Option>) -> Self { + Self { cur } + } + + fn move_next(&mut self, list: &RawList) { + match self.cur.take() { + None => self.cur = list.head, + Some(cur) => { + if let Some(head) = list.head { + // SAFETY: We have a shared ref to the linked list, so the links can't change. + let links = unsafe { &*G::get_links(cur.as_ref()).entry.get() }; + if !ptr::addr_eq(links.next.unwrap().as_ptr(), head.as_ptr()) { + self.cur = links.next; + } + } + } + } + } + + fn move_prev(&mut self, list: &RawList) { + match list.head { + None => self.cur = None, + Some(head) => { + let next = match self.cur.take() { + None => head, + Some(cur) => { + if ptr::addr_eq(cur.as_ptr(), head.as_ptr()) { + return; + } + cur + } + }; + // SAFETY: There's a shared ref to the list, so the links can't change. + let links = unsafe { &*G::get_links(next.as_ref()).entry.get() }; + self.cur = links.prev; + } + } + } +} + +// SAFETY: The list is itself can be safely sent to other threads but we restrict it to being `Send` +// only when its entries are also `Send`. +unsafe impl Send for RawList where G::EntryType: Send {} + +// SAFETY: The list is itself usable from other threads via references but we restrict it to being +// `Sync` only when its entries are also `Sync`. +unsafe impl Sync for RawList where G::EntryType: Sync {} + +/// A list cursor that allows traversing a linked list and inspecting elements. +pub(crate) struct Cursor<'a, G: GetLinks> { + cursor: CommonCursor, + list: &'a RawList, +} + +impl<'a, G: GetLinks> Cursor<'a, G> { + pub(crate) fn new(list: &'a RawList, cur: Option>) -> Self { + Self { + list, + cursor: CommonCursor::new(cur), + } + } + + /// Returns the element the cursor is currently positioned on. + pub(crate) fn current(&self) -> Option<&'a G::EntryType> { + let cur = self.cursor.cur?; + // SAFETY: Objects must be kept alive while on the list. + Some(unsafe { &*cur.as_ptr() }) + } + + /// Moves the cursor to the next element. + pub(crate) fn move_next(&mut self) { + self.cursor.move_next(self.list); + } + + /// Moves the cursor to the prev element. + #[allow(dead_code)] + pub(crate) fn move_prev(&mut self) { + self.cursor.move_prev(self.list); + } +} + +pub(crate) struct CursorMut<'a, G: GetLinks> { + cursor: CommonCursor, + list: &'a mut RawList, +} + +impl<'a, G: GetLinks> CursorMut<'a, G> { + fn new(list: &'a mut RawList, cur: Option>) -> Self { + Self { + list, + cursor: CommonCursor::new(cur), + } + } + + pub(crate) fn current(&mut self) -> Option<&mut G::EntryType> { + let cur = self.cursor.cur?; + // SAFETY: Objects must be kept alive while on the list. + Some(unsafe { &mut *cur.as_ptr() }) + } + + /// Removes the entry the cursor is pointing to and advances the cursor to the next entry. It + /// returns a raw pointer to the removed element (if one is removed). + pub(crate) fn remove_current(&mut self) -> Option> { + let entry = self.cursor.cur?; + self.cursor.move_next(self.list); + // SAFETY: The entry is on the list as we just got it from there and it cannot change. + unsafe { self.list.remove(entry.as_ref()) }; + Some(entry) + } + + pub(crate) fn peek_next(&mut self) -> Option<&mut G::EntryType> { + let mut new = CommonCursor::new(self.cursor.cur); + new.move_next(self.list); + // SAFETY: Objects must be kept alive while on the list. + Some(unsafe { &mut *new.cur?.as_ptr() }) + } + + pub(crate) fn peek_prev(&mut self) -> Option<&mut G::EntryType> { + let mut new = CommonCursor::new(self.cursor.cur); + new.move_prev(self.list); + // SAFETY: Objects must be kept alive while on the list. + Some(unsafe { &mut *new.cur?.as_ptr() }) + } + + pub(crate) fn move_next(&mut self) { + self.cursor.move_next(self.list); + } + + #[allow(dead_code)] + pub(crate) fn move_prev(&mut self) { + self.cursor.move_prev(self.list); + } +} + +impl<'a, G: GetLinks> iter::IntoIterator for &'a RawList { + type Item = &'a G::EntryType; + type IntoIter = Iterator<'a, G>; + fn into_iter(self) -> Self::IntoIter { + self.iter() + } +} + +/// An iterator for the linked list. +pub(crate) struct Iterator<'a, G: GetLinks> { + cursor_front: Cursor<'a, G>, + cursor_back: Cursor<'a, G>, +} + +impl<'a, G: GetLinks> Iterator<'a, G> { + const fn new(cursor_front: Cursor<'a, G>, cursor_back: Cursor<'a, G>) -> Self { + Self { + cursor_front, + cursor_back, + } + } +} + +impl<'a, G: GetLinks> iter::Iterator for Iterator<'a, G> { + type Item = &'a G::EntryType; + + fn next(&mut self) -> Option { + let ret = self.cursor_front.current()?; + self.cursor_front.move_next(); + Some(ret) + } +} + +impl iter::DoubleEndedIterator for Iterator<'_, G> { + fn next_back(&mut self) -> Option { + let ret = self.cursor_back.current()?; + self.cursor_back.move_prev(); + Some(ret) + } +} + +#[cfg(test)] +mod tests { + extern crate alloc; + use alloc::{boxed::Box, vec::Vec}; + + struct Example { + links: super::Links, + } + + // SAFETY: This is the only adapter that uses `Example::links`. + impl super::GetLinks for Example { + type EntryType = Self; + fn get_links(obj: &Self) -> &super::Links { + &obj.links + } + } + + fn build_vector(size: usize) -> Vec> { + let mut v = Vec::new(); + v.reserve(size); + for _ in 0..size { + v.push(Box::new(Example { + links: super::Links::new(), + })); + } + v + } + + #[track_caller] + fn assert_list_contents(v: &[Box], list: &super::RawList) { + let n = v.len(); + + // Assert that the list is ok going forward. + let mut count = 0; + for (i, e) in list.iter().enumerate() { + assert!(core::ptr::eq(e, &*v[i])); + count += 1; + } + assert_eq!(count, n); + + // Assert that the list is ok going backwards. + let mut count = 0; + for (i, e) in list.iter().rev().enumerate() { + assert!(core::ptr::eq(e, &*v[n - 1 - i])); + count += 1; + } + assert_eq!(count, n); + } + + #[track_caller] + fn test_each_element( + min_len: usize, + max_len: usize, + test: impl Fn(&mut Vec>, &mut super::RawList, usize, Box), + ) { + for n in min_len..=max_len { + for i in 0..n { + let extra = Box::new(Example { + links: super::Links::new(), + }); + let mut v = build_vector(n); + let mut list = super::RawList::::new(); + + // Build list. + for j in 0..n { + // SAFETY: The entry was allocated above, it's not in any lists yet, is never + // moved, and outlives the list. + unsafe { list.push_back(&v[j]) }; + } + + // Call the test case. + test(&mut v, &mut list, i, extra); + + // Check that the list is ok. + assert_list_contents(&v, &list); + } + } + } + + #[test] + fn test_push_back() { + const MAX: usize = 10; + let v = build_vector(MAX); + let mut list = super::RawList::::new(); + + for n in 1..=MAX { + // SAFETY: The entry was allocated above, it's not in any lists yet, is never moved, + // and outlives the list. + unsafe { list.push_back(&v[n - 1]) }; + assert_list_contents(&v[..n], &list); + } + } + + #[test] + fn test_one_removal() { + test_each_element(1, 10, |v, list, i, _| { + // Remove the i-th element. + // SAFETY: The i-th element was added to the list above, and wasn't removed yet. + unsafe { list.remove(&v[i]) }; + v.remove(i); + }); + } + + #[test] + fn test_one_insert_after() { + test_each_element(1, 10, |v, list, i, extra| { + // Insert after the i-th element. + // SAFETY: The i-th element was added to the list above, and wasn't removed yet. + // Additionally, the new element isn't in any list yet, isn't moved, and outlives + // the list. + unsafe { list.insert_after(&*v[i], &*extra) }; + v.insert(i + 1, extra); + }); + } +} diff --git a/src/unsafe_list.rs b/src/unsafe_list.rs deleted file mode 100644 index af91f36..0000000 --- a/src/unsafe_list.rs +++ /dev/null @@ -1,683 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 - -//! Intrusive circular doubly-linked lists. -//! -//! Copied from linux/rust/kernel/unsafe_list.rs. -//! -//! We don't use the C version for two main reasons: -//! - Next/prev pointers do not support `?Sized` types, so wouldn't be able to have a list of, for -//! example, `dyn Trait`. -//! - It would require the list head to be pinned (in addition to the list entries). - -use core::{cell::UnsafeCell, iter, marker::PhantomPinned, mem::MaybeUninit, ptr::NonNull}; - -/// An intrusive circular doubly-linked list. -/// -/// Membership of elements of the list must be tracked by the owner of the list. -/// -/// While elements of the list must remain pinned while in the list, the list itself does not -/// require pinning. In other words, users are allowed to move instances of [`List`]. -/// -/// # Invariants -/// -/// The links of an entry are wrapped in [`UnsafeCell`] and they are acessible when the list itself -/// is. For example, when a thread has a mutable reference to a list, it may also safely get -/// mutable references to the links of the elements in the list. -/// -/// The links of an entry are also wrapped in [`MaybeUninit`] and they are initialised when they -/// are present in a list. Otherwise they are uninitialised. -/// -/// # Examples -/// -/// ``` -/// # use linked_list::unsafe_list::{Adapter, Links, List}; -/// -/// struct Example { -/// v: usize, -/// links: Links, -/// } -/// -/// // SAFETY: This adapter is the only one that uses `Example::links`. -/// unsafe impl Adapter for Example { -/// type EntryType = Self; -/// fn to_links(obj: &Self) -> &Links { -/// &obj.links -/// } -/// } -/// -/// let a = Example { -/// v: 0, -/// links: Links::new(), -/// }; -/// let b = Example { -/// v: 1, -/// links: Links::new(), -/// }; -/// -/// let mut list = List::::new(); -/// assert!(list.is_empty()); -/// -/// // SAFETY: `a` was declared above, it's not in any lists yet, is never moved, and outlives the -/// // list. -/// unsafe { list.push_back(&a) }; -/// -/// // SAFETY: `b` was declared above, it's not in any lists yet, is never moved, and outlives the -/// // list. -/// unsafe { list.push_back(&b) }; -/// -/// assert!(core::ptr::eq(&a, list.front().unwrap().as_ptr())); -/// assert!(core::ptr::eq(&b, list.back().unwrap().as_ptr())); -/// -/// for (i, e) in list.iter().enumerate() { -/// assert_eq!(i, e.v); -/// } -/// -/// for e in &list { -/// println!("{}", e.v); -/// } -/// -/// // SAFETY: `b` was added to the list above and wasn't removed yet. -/// unsafe { list.remove(&b) }; -/// -/// assert!(core::ptr::eq(&a, list.front().unwrap().as_ptr())); -/// assert!(core::ptr::eq(&a, list.back().unwrap().as_ptr())); -/// ``` -pub struct List { - first: Option>, -} - -// SAFETY: The list is itself can be safely sent to other threads but we restrict it to being `Send` -// only when its entries are also `Send`. -unsafe impl Send for List where A::EntryType: Send {} - -// SAFETY: The list is itself usable from other threads via references but we restrict it to being -// `Sync` only when its entries are also `Sync`. -unsafe impl Sync for List where A::EntryType: Sync {} - -impl List { - /// Constructs a new empty list. - pub const fn new() -> Self { - Self { first: None } - } - - /// Determines if the list is empty. - pub const fn is_empty(&self) -> bool { - self.first.is_none() - } - - /// Inserts the only entry to a list. - /// - /// This must only be called when the list is empty. - pub fn insert_only_entry(&mut self, obj: &A::EntryType) { - let obj_ptr = NonNull::from(obj); - - // SAFETY: We have mutable access to the list, so we also have access to the entry - // we're about to insert (and it's not in any other lists per the function safety - // requirements). - let obj_inner = unsafe { &mut *A::to_links(obj).0.get() }; - - // INVARIANTS: All fields of the links of the newly-inserted object are initialised - // below. - obj_inner.write(LinksInner { - next: obj_ptr, - prev: obj_ptr, - _pin: PhantomPinned, - }); - self.first = Some(obj_ptr); - } - - /// Adds the given object to the end of the list. - /// - /// # Safety - /// - /// Callers must ensure that: - /// - The object is not currently in any lists. - /// - The object remains alive until it is removed from the list. - /// - The object is not moved until it is removed from the list. - pub unsafe fn push_back(&mut self, obj: &A::EntryType) { - if let Some(first) = self.first { - // SAFETY: The previous entry to the first one is necessarily present in the list (it - // may in fact be the first entry itself as this is a circular list). The safety - // requirements of this function regarding `obj` satisfy those of `insert_after`. - unsafe { self.insert_after(self.inner_ref(first).prev, obj) }; - } else { - self.insert_only_entry(obj); - } - } - - /// Adds the given object to the beginning of the list. - /// - /// # Safety - /// - /// Callers must ensure that: - /// - The object is not currently in any lists. - /// - The object remains alive until it is removed from the list. - /// - The object is not moved until it is removed from the list. - pub unsafe fn push_front(&mut self, obj: &A::EntryType) { - if let Some(first) = self.first { - // SAFETY: The safety requirements of this function regarding `obj` satisfy those of - // `insert_before`. Additionally, `first` is in the list. - unsafe { self.insert_before(first, obj) }; - } else { - self.insert_only_entry(obj); - } - } - - /// Removes the given object from the list. - /// - /// # Safety - /// - /// The object must be in the list. In other words, the object must have previously been - /// inserted into this list and not removed yet. - pub unsafe fn remove(&mut self, entry: &A::EntryType) { - // SAFETY: Per the function safety requirements, `entry` is in the list. - let inner = unsafe { self.inner_ref(NonNull::from(entry)) }; - let next = inner.next; - let prev = inner.prev; - - // SAFETY: We have mutable access to the list, so we also have access to the entry we're - // about to remove (which we know is in the list per the function safety requirements). - let inner = unsafe { &mut *A::to_links(entry).0.get() }; - - // SAFETY: Since the entry was in the list, it was initialised. - unsafe { inner.assume_init_drop() }; - - if core::ptr::eq(next.as_ptr(), entry) { - // Removing the only element. - self.first = None; - } else { - // SAFETY: `prev` is in the list because it is pointed at by the entry being removed. - unsafe { self.inner(prev).next = next }; - // SAFETY: `next` is in the list because it is pointed at by the entry being removed. - unsafe { self.inner(next).prev = prev }; - - if core::ptr::eq(self.first.unwrap().as_ptr(), entry) { - // Update the pointer to the first element as we're removing it. - self.first = Some(next); - } - } - } - - /// Adds the given object after another object already in the list. - /// - /// # Safety - /// - /// Callers must ensure that: - /// - The existing object is currently in the list. - /// - The new object is not currently in any lists. - /// - The new object remains alive until it is removed from the list. - /// - The new object is not moved until it is removed from the list. - pub unsafe fn insert_after(&mut self, existing: NonNull, new: &A::EntryType) { - // SAFETY: We have mutable access to the list, so we also have access to the entry we're - // about to insert (and it's not in any other lists per the function safety requirements). - let new_inner = unsafe { &mut *A::to_links(new).0.get() }; - - // SAFETY: Per the function safety requirements, `existing` is in the list. - let existing_inner = unsafe { self.inner(existing) }; - let next = existing_inner.next; - - // INVARIANTS: All fields of the links of the newly-inserted object are initialised below. - new_inner.write(LinksInner { - next, - prev: existing, - _pin: PhantomPinned, - }); - - existing_inner.next = NonNull::from(new); - - // SAFETY: `next` is in the list because it's pointed at by the existing entry. - unsafe { self.inner(next).prev = NonNull::from(new) }; - } - - /// Adds the given object before another object already in the list. - /// - /// # Safety - /// - /// Callers must ensure that: - /// - The existing object is currently in the list. - /// - The new object is not currently in any lists. - /// - The new object remains alive until it is removed from the list. - /// - The new object is not moved until it is removed from the list. - pub unsafe fn insert_before(&mut self, existing: NonNull, new: &A::EntryType) { - // SAFETY: The safety requirements of this function satisfy those of `insert_after`. - unsafe { self.insert_after(self.inner_ref(existing).prev, new) }; - - if core::ptr::eq(self.first.unwrap().as_ptr(), existing.as_ptr()) { - // Update the pointer to the first element as we're inserting before it. - self.first = Some(NonNull::from(new)); - } - } - - /// Returns the first element of the list, if one exists. - pub fn front(&self) -> Option> { - self.first - } - - /// Returns the last element of the list, if one exists. - pub fn back(&self) -> Option> { - // SAFETY: Having a pointer to it guarantees that the object is in the list. - self.first.map(|f| unsafe { self.inner_ref(f).prev }) - } - - /// Returns an iterator for the list starting at the first entry. - pub fn iter(&self) -> Iterator<'_, A> { - Iterator::new(self.cursor_front()) - } - - /// Returns an iterator for the list starting at the last entry. - pub fn iter_back(&self) -> impl iter::DoubleEndedIterator { - Iterator::new(self.cursor_back()) - } - - /// Returns a cursor starting on the first (front) element of the list. - pub fn cursor_front(&self) -> Cursor<'_, A> { - // SAFETY: `front` is in the list (or is `None`) because we've read it from the list head - // and the list cannot have changed because we hold a shared reference to it. - unsafe { Cursor::new(self, self.front()) } - } - - /// Returns a cursor starting on the last (back) element of the list. - pub fn cursor_back(&self) -> Cursor<'_, A> { - // SAFETY: `back` is in the list (or is `None`) because we've read it from the list head - // and the list cannot have changed because we hold a shared reference to it. - unsafe { Cursor::new(self, self.back()) } - } - - /// Returns a mutable reference to the links of a given object. - /// - /// # Safety - /// - /// Callers must ensure that the element is in the list. - unsafe fn inner(&mut self, ptr: NonNull) -> &mut LinksInner { - // SAFETY: The safety requirements guarantee that we the links are initialised because - // that's part of the type invariants. Additionally, the type invariants also guarantee - // that having a mutable reference to the list guarantees that the links are mutably - // accessible as well. - unsafe { (*A::to_links(ptr.as_ref()).0.get()).assume_init_mut() } - } - - /// Returns a shared reference to the links of a given object. - /// - /// # Safety - /// - /// Callers must ensure that the element is in the list. - unsafe fn inner_ref(&self, ptr: NonNull) -> &LinksInner { - // SAFETY: The safety requirements guarantee that we the links are initialised because - // that's part of the type invariants. Additionally, the type invariants also guarantee - // that having a shared reference to the list guarantees that the links are accessible in - // shared mode as well. - unsafe { (*A::to_links(ptr.as_ref()).0.get()).assume_init_ref() } - } -} - -impl<'a, A: Adapter + ?Sized> iter::IntoIterator for &'a List { - type Item = &'a A::EntryType; - type IntoIter = Iterator<'a, A>; - fn into_iter(self) -> Self::IntoIter { - self.iter() - } -} - -/// An iterator for the linked list. -pub struct Iterator<'a, A: Adapter + ?Sized> { - cursor: Cursor<'a, A>, -} - -impl<'a, A: Adapter + ?Sized> Iterator<'a, A> { - fn new(cursor: Cursor<'a, A>) -> Self { - Self { cursor } - } -} - -impl<'a, A: Adapter + ?Sized> iter::Iterator for Iterator<'a, A> { - type Item = &'a A::EntryType; - - fn next(&mut self) -> Option { - let ret = self.cursor.current()?; - self.cursor.move_next(); - Some(ret) - } -} - -impl iter::DoubleEndedIterator for Iterator<'_, A> { - fn next_back(&mut self) -> Option { - let ret = self.cursor.current()?; - self.cursor.move_prev(); - Some(ret) - } -} - -/// A linked-list adapter. -/// -/// It is a separate type (as opposed to implemented by the type of the elements of the list) -/// so that a given type can be inserted into multiple lists at the same time; in such cases, each -/// list needs its own adapter that returns a different pointer to links. -/// -/// It may, however, be implemented by the type itself to be inserted into lists, which makes it -/// more readable. -/// -/// # Safety -/// -/// Implementers must ensure that the links returned by [`Adapter::to_links`] are unique to the -/// adapter. That is, different adapters must return different links for a given object. -/// -/// The reason for this requirement is to avoid confusion that may lead to UB. In particular, if -/// two adapters were to use the same links, a user may have two lists (one for each adapter) and -/// try to insert the same object into both at the same time; although this clearly violates the -/// list safety requirements (e.g., those in [`List::push_back`]), for users to notice it, they'd -/// have to dig into the details of the two adapters. -/// -/// By imposing the requirement on the adapter, we make it easier for users to check compliance -/// with the requirements when using the list. -/// -/// # Examples -/// -/// ``` -/// # use linked_list::unsafe_list::{Adapter, Links, List}; -/// -/// struct Example { -/// a: u32, -/// b: u32, -/// links1: Links, -/// links2: Links, -/// } -/// -/// // SAFETY: This adapter is the only one that uses `Example::links1`. -/// unsafe impl Adapter for Example { -/// type EntryType = Self; -/// fn to_links(obj: &Self) -> &Links { -/// &obj.links1 -/// } -/// } -/// -/// struct ExampleAdapter; -/// -/// // SAFETY: This adapter is the only one that uses `Example::links2`. -/// unsafe impl Adapter for ExampleAdapter { -/// type EntryType = Example; -/// fn to_links(obj: &Example) -> &Links { -/// &obj.links2 -/// } -/// } -/// -/// static LIST1: List = List::new(); -/// static LIST2: List = List::new(); -/// ``` -pub unsafe trait Adapter { - /// The type of the enties in the list. - type EntryType: ?Sized; - - /// Retrieves the linked list links for the given object. - fn to_links(obj: &Self::EntryType) -> &Links; -} - -struct LinksInner { - next: NonNull, - prev: NonNull, - _pin: PhantomPinned, -} - -/// Links of a linked list. -/// -/// List entries need one of these per concurrent list. -pub struct Links(UnsafeCell>>); - -// SAFETY: `Links` can be safely sent to other threads but we restrict it to being `Send` only when -// the list entries it points to are also `Send`. -unsafe impl Send for Links {} - -// SAFETY: `Links` is usable from other threads via references but we restrict it to being `Sync` -// only when the list entries it points to are also `Sync`. -unsafe impl Sync for Links {} - -impl Links { - /// Constructs a new instance of the linked-list links. - pub const fn new() -> Self { - Self(UnsafeCell::new(MaybeUninit::uninit())) - } -} - -pub(crate) struct CommonCursor { - pub(crate) cur: Option>, -} - -impl CommonCursor { - pub(crate) fn new(cur: Option>) -> Self { - Self { cur } - } - - /// Moves the cursor to the next entry of the list. - /// - /// # Safety - /// - /// Callers must ensure that the cursor is either [`None`] or points to an entry that is in - /// `list`. - pub(crate) unsafe fn move_next(&mut self, list: &List) { - match self.cur.take() { - None => self.cur = list.first, - Some(cur) => { - if let Some(head) = list.first { - // SAFETY: Per the function safety requirements, `cur` is in the list. - let links = unsafe { list.inner_ref(cur) }; - if !core::ptr::eq(links.next.as_ptr(), head.as_ptr()) { - self.cur = Some(links.next); - } - } - } - } - } - - /// Moves the cursor to the previous entry of the list. - /// - /// # Safety - /// - /// Callers must ensure that the cursor is either [`None`] or points to an entry that is in - /// `list`. - pub(crate) unsafe fn move_prev(&mut self, list: &List) { - match list.first { - None => self.cur = None, - Some(head) => { - let next = match self.cur.take() { - None => head, - Some(cur) => { - if core::ptr::eq(cur.as_ptr(), head.as_ptr()) { - return; - } - cur - } - }; - // SAFETY: `next` is either `head` or `cur`. The former is in the list because it's - // its head; the latter is in the list per the function safety requirements. - self.cur = Some(unsafe { list.inner_ref(next) }.prev); - } - } - } -} - -/// A list cursor that allows traversing a linked list and inspecting elements. -pub struct Cursor<'a, A: Adapter + ?Sized> { - cursor: CommonCursor, - list: &'a List, -} - -impl<'a, A: Adapter + ?Sized> Cursor<'a, A> { - /// Creates a new cursor. - /// - /// # Safety - /// - /// Callers must ensure that `cur` is either [`None`] or points to an entry in `list`. - pub(crate) unsafe fn new(list: &'a List, cur: Option>) -> Self { - Self { - list, - cursor: CommonCursor::new(cur), - } - } - - /// Returns the element the cursor is currently positioned on. - pub fn current(&self) -> Option<&'a A::EntryType> { - let cur = self.cursor.cur?; - // SAFETY: `cursor` starts off in the list and only changes within the list. Additionally, - // the list cannot change because we hold a shared reference to it, so the cursor is always - // within the list. - Some(unsafe { cur.as_ref() }) - } - - /// Moves the cursor to the next element. - pub fn move_next(&mut self) { - // SAFETY: `cursor` starts off in the list and only changes within the list. Additionally, - // the list cannot change because we hold a shared reference to it, so the cursor is always - // within the list. - unsafe { self.cursor.move_next(self.list) }; - } - - /// Moves the cursor to the previous element. - pub fn move_prev(&mut self) { - // SAFETY: `cursor` starts off in the list and only changes within the list. Additionally, - // the list cannot change because we hold a shared reference to it, so the cursor is always - // within the list. - unsafe { self.cursor.move_prev(self.list) }; - } -} - -#[cfg(test)] -mod tests { - extern crate alloc; - use alloc::{boxed::Box, vec::Vec}; - use core::ptr::NonNull; - - struct Example { - links: super::Links, - } - - // SAFETY: This is the only adapter that uses `Example::links`. - unsafe impl super::Adapter for Example { - type EntryType = Self; - fn to_links(obj: &Self) -> &super::Links { - &obj.links - } - } - - fn build_vector(size: usize) -> Vec> { - let mut v = Vec::new(); - v.reserve(size); - for _ in 0..size { - v.push(Box::new(Example { - links: super::Links::new(), - })); - } - v - } - - #[track_caller] - fn assert_list_contents(v: &[Box], list: &super::List) { - let n = v.len(); - - // Assert that the list is ok going forward. - let mut count = 0; - for (i, e) in list.iter().enumerate() { - assert!(core::ptr::eq(e, &*v[i])); - count += 1; - } - assert_eq!(count, n); - - // Assert that the list is ok going backwards. - let mut count = 0; - for (i, e) in list.iter_back().rev().enumerate() { - assert!(core::ptr::eq(e, &*v[n - 1 - i])); - count += 1; - } - assert_eq!(count, n); - } - - #[track_caller] - fn test_each_element( - min_len: usize, - max_len: usize, - test: impl Fn(&mut Vec>, &mut super::List, usize, Box), - ) { - for n in min_len..=max_len { - for i in 0..n { - let extra = Box::new(Example { - links: super::Links::new(), - }); - let mut v = build_vector(n); - let mut list = super::List::::new(); - - // Build list. - for j in 0..n { - // SAFETY: The entry was allocated above, it's not in any lists yet, is never - // moved, and outlives the list. - unsafe { list.push_back(&v[j]) }; - } - - // Call the test case. - test(&mut v, &mut list, i, extra); - - // Check that the list is ok. - assert_list_contents(&v, &list); - } - } - } - - #[test] - fn test_push_back() { - const MAX: usize = 10; - let v = build_vector(MAX); - let mut list = super::List::::new(); - - for n in 1..=MAX { - // SAFETY: The entry was allocated above, it's not in any lists yet, is never moved, - // and outlives the list. - unsafe { list.push_back(&v[n - 1]) }; - assert_list_contents(&v[..n], &list); - } - } - - #[test] - fn test_push_front() { - const MAX: usize = 10; - let v = build_vector(MAX); - let mut list = super::List::::new(); - - for n in 1..=MAX { - // SAFETY: The entry was allocated above, it's not in any lists yet, is never moved, - // and outlives the list. - unsafe { list.push_front(&v[MAX - n]) }; - assert_list_contents(&v[MAX - n..], &list); - } - } - - #[test] - fn test_one_removal() { - test_each_element(1, 10, |v, list, i, _| { - // Remove the i-th element. - // SAFETY: The i-th element was added to the list above, and wasn't removed yet. - unsafe { list.remove(&v[i]) }; - v.remove(i); - }); - } - - #[test] - fn test_one_insert_after() { - test_each_element(1, 10, |v, list, i, extra| { - // Insert after the i-th element. - // SAFETY: The i-th element was added to the list above, and wasn't removed yet. - // Additionally, the new element isn't in any list yet, isn't moved, and outlives - // the list. - unsafe { list.insert_after(NonNull::from(&*v[i]), &*extra) }; - v.insert(i + 1, extra); - }); - } - - #[test] - fn test_one_insert_before() { - test_each_element(1, 10, |v, list, i, extra| { - // Insert before the i-th element. - // SAFETY: The i-th element was added to the list above, and wasn't removed yet. - // Additionally, the new element isn't in any list yet, isn't moved, and outlives - // the list. - unsafe { list.insert_before(NonNull::from(&*v[i]), &*extra) }; - v.insert(i, extra); - }); - } -}