From afc15dec271ac83eb3494d31c0882ca857b58395 Mon Sep 17 00:00:00 2001 From: guoweikang Date: Mon, 14 Oct 2024 11:45:58 +0800 Subject: [PATCH 01/25] Synchronize r4l linked_lists latest code Signed-off-by: guoweikang --- src/linked_list.rs | 155 +++++++++++-------- src/raw_list.rs | 363 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 454 insertions(+), 64 deletions(-) create mode 100644 src/raw_list.rs diff --git a/src/linked_list.rs b/src/linked_list.rs index 0c18803..d51525b 100644 --- a/src/linked_list.rs +++ b/src/linked_list.rs @@ -2,19 +2,15 @@ //! Linked lists. //! -//! Based on linux/rust/kernel/linked_list.rs, but use -//! [`unsafe_list::List`] as the inner implementation. -//! //! TODO: This module is a work in progress. -extern crate alloc; - -use alloc::{boxed::Box, sync::Arc}; +use alloc::boxed::Box; use core::ptr::NonNull; -use crate::unsafe_list::{self, Adapter, Cursor, Links}; +pub use crate::raw_list::{Cursor, GetLinks, Links}; +use crate::{raw_list, raw_list::RawList, sync::Arc}; -// TODO: Use the one from `kernel::file_operations::PointerWrapper` instead. +// TODO: Use the one from `kernel::file_operations::ForeignOwnable` instead. /// Wraps an object to be inserted in a linked list. pub trait Wrapper { /// Converts the wrapped object into a pointer that represents it. @@ -32,92 +28,80 @@ pub trait Wrapper { } impl Wrapper for Box { - #[inline] fn into_pointer(self) -> NonNull { NonNull::new(Box::into_raw(self)).unwrap() } - #[inline] unsafe fn from_pointer(ptr: NonNull) -> Self { unsafe { Box::from_raw(ptr.as_ptr()) } } - #[inline] fn as_ref(&self) -> &T { AsRef::as_ref(self) } } impl Wrapper for Arc { - #[inline] fn into_pointer(self) -> NonNull { NonNull::new(Arc::into_raw(self) as _).unwrap() } - #[inline] unsafe fn from_pointer(ptr: NonNull) -> Self { // SAFETY: The safety requirements of `from_pointer` satisfy the ones from `Arc::from_raw`. unsafe { Arc::from_raw(ptr.as_ptr() as _) } } - #[inline] fn as_ref(&self) -> &T { AsRef::as_ref(self) } } impl Wrapper for &T { - #[inline] fn into_pointer(self) -> NonNull { NonNull::from(self) } - #[inline] unsafe fn from_pointer(ptr: NonNull) -> Self { unsafe { &*ptr.as_ptr() } } - #[inline] fn as_ref(&self) -> &T { self } } /// 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,21 +109,20 @@ 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 { + pub fn new() -> Self { Self { - list: unsafe_list::List::new(), + list: RawList::new(), } } /// Returns whether the list is empty. - #[inline] - pub const fn is_empty(&self) -> bool { + pub fn is_empty(&self) -> bool { self.list.is_empty() } @@ -151,7 +134,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`. @@ -164,57 +151,97 @@ impl List { /// 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) { let ptr = data.into_pointer(); - unsafe { self.list.insert_after(existing, ptr.as_ref()) } + let entry = unsafe { &*existing.as_ptr() }; + 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)) }) - } - - /// 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() }) + 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 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() {} + 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> { + 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(); } } diff --git a/src/raw_list.rs b/src/raw_list.rs new file mode 100644 index 0000000..fefc914 --- /dev/null +++ b/src/raw_list.rs @@ -0,0 +1,363 @@ +// 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, + 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>, +} + +impl Links { + /// Constructs a new [`Links`] instance that isn't inserted on any lists yet. + pub 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 { + 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) fn new() -> Self { + Self { head: None } + } + + pub(crate) 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) + } + + pub(crate) fn pop_front(&mut self) -> Option> { + self.pop_front_internal() + } + + pub(crate) fn front(&self) -> Option> { + self.head + } + + 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 + } + + pub(crate) fn cursor_front(&self) -> Cursor<'_, G> { + Cursor::new(self, self.front()) + } + + pub(crate) fn cursor_front_mut(&mut self) -> CursorMut<'_, G> { + CursorMut::new(self, self.front()) + } +} + +struct CommonCursor { + cur: Option>, +} + +impl CommonCursor { + 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 links.next.unwrap() != head { + 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 cur == head { + 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; + } + } + } +} + +/// A list cursor that allows traversing a linked list and inspecting elements. +pub struct Cursor<'a, G: GetLinks> { + cursor: CommonCursor, + list: &'a RawList, +} + +impl<'a, G: GetLinks> Cursor<'a, G> { + fn new(list: &'a RawList, cur: Option>) -> Self { + Self { + list, + cursor: CommonCursor::new(cur), + } + } + + /// Returns the element the cursor is currently positioned on. + pub 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 fn move_next(&mut self) { + self.cursor.move_next(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); + } +} From db2898dd378c6cdc64f7b0c64dc2b7bae61e299d Mon Sep 17 00:00:00 2001 From: guoweikang Date: Tue, 15 Oct 2024 14:30:43 +0800 Subject: [PATCH 02/25] Update LinkedList to make it easier to use -------- 1 add List sample code 2 add more test case 3 remove iter_back,use iter().rev() Signed-off-by: guoweikang --- src/lib.rs | 61 +++++++++++-- src/linked_list.rs | 121 +++++++++++++++++++++---- src/raw_list.rs | 219 ++++++++++++++++++++++++++++++++++++++++++--- 3 files changed, 370 insertions(+), 31 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 9fb264e..2db95d5 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -3,12 +3,61 @@ //! 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 +//! +//! In more general use cases, shoud not use RawList directly, +//! suggest use smart pointers of nodes and move ownership of smart +//! pointers to List: +//! +//! ``` +//! use linked_list::{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() +//! } +//! } +//! } +//! +//! 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); +//! +//! +//! ``` +//! -#![no_std] +#![cfg_attr(not(test), no_std)] mod linked_list; - -pub mod unsafe_list; - -pub use self::linked_list::{AdapterWrapped, List, Wrapper}; -pub use unsafe_list::{Adapter, Cursor, Links}; +mod raw_list; +pub use linked_list::List; +pub use raw_list::{GetLinks, Links}; diff --git a/src/linked_list.rs b/src/linked_list.rs index d51525b..a3e91b0 100644 --- a/src/linked_list.rs +++ b/src/linked_list.rs @@ -2,15 +2,18 @@ //! Linked lists. //! +//! Based on linux/rust/kernel/linked_list.rs +//! //! TODO: This module is a work in progress. -use alloc::boxed::Box; -use core::ptr::NonNull; +extern crate alloc; + +use alloc::{boxed::Box, sync::Arc}; +use core::{iter, ptr::NonNull}; -pub use crate::raw_list::{Cursor, GetLinks, Links}; -use crate::{raw_list, raw_list::RawList, sync::Arc}; +use crate::{raw_list, raw_list::RawList, GetLinks, Links}; -// TODO: Use the one from `kernel::file_operations::ForeignOwnable` instead. +// TODO: Use the one from `kernel::file_operations::PointerWrapper` instead. /// Wraps an object to be inserted in a linked list. pub trait Wrapper { /// Converts the wrapped object into a pointer that represents it. @@ -28,43 +31,52 @@ pub trait Wrapper { } impl Wrapper for Box { + #[inline] fn into_pointer(self) -> NonNull { NonNull::new(Box::into_raw(self)).unwrap() } + #[inline] unsafe fn from_pointer(ptr: NonNull) -> Self { unsafe { Box::from_raw(ptr.as_ptr()) } } + #[inline] fn as_ref(&self) -> &T { AsRef::as_ref(self) } } impl Wrapper for Arc { + #[inline] fn into_pointer(self) -> NonNull { NonNull::new(Arc::into_raw(self) as _).unwrap() } + #[inline] unsafe fn from_pointer(ptr: NonNull) -> Self { // SAFETY: The safety requirements of `from_pointer` satisfy the ones from `Arc::from_raw`. unsafe { Arc::from_raw(ptr.as_ptr() as _) } } + #[inline] fn as_ref(&self) -> &T { AsRef::as_ref(self) } } impl Wrapper for &T { + #[inline] fn into_pointer(self) -> NonNull { NonNull::from(self) } + #[inline] unsafe fn from_pointer(ptr: NonNull) -> Self { unsafe { &*ptr.as_ptr() } } + #[inline] fn as_ref(&self) -> &T { self } @@ -100,6 +112,7 @@ where impl GetLinks for Arc { type EntryType = T::EntryType; + #[inline] fn get_links(data: &Self::EntryType) -> &Links { ::get_links(data) } @@ -115,12 +128,17 @@ pub struct List { impl List { /// Constructs a new empty linked list. - pub fn new() -> Self { + pub const fn new() -> Self { Self { 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. pub fn is_empty(&self) -> bool { self.list.is_empty() @@ -149,9 +167,9 @@ 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(); - let entry = unsafe { &*existing.as_ptr() }; + 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) }; @@ -182,11 +200,6 @@ impl List { Some(unsafe { G::Wrapped::from_pointer(front) }) } - /// Returns a cursor starting on the first (front) element of the list. - 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()) @@ -201,7 +214,7 @@ impl Default for List { impl Drop for List { fn drop(&mut self) { - while self.pop_front().is_some() {} + while self.pop_front().is_some() {} } } @@ -226,7 +239,7 @@ impl<'a, G: GetLinksWrapped> CursorMut<'a, G> { 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 `. + // SAFETY: Elements on the list were inserted after a call to `into_pointer `. Some(unsafe { G::Wrapped::from_pointer(ptr) }) } @@ -245,3 +258,81 @@ impl<'a, G: GetLinksWrapped> CursorMut<'a, G> { 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 index fefc914..b400f12 100644 --- a/src/raw_list.rs +++ b/src/raw_list.rs @@ -8,7 +8,7 @@ use core::{ cell::UnsafeCell, - ptr, + iter, ptr, ptr::NonNull, sync::atomic::{AtomicBool, Ordering}, }; @@ -37,9 +37,17 @@ pub struct Links { 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 fn new() -> Self { + pub const fn new() -> Self { Self { inserted: AtomicBool::new(false), entry: UnsafeCell::new(ListEntry::new()), @@ -69,7 +77,7 @@ struct ListEntry { } impl ListEntry { - fn new() -> Self { + const fn new() -> Self { Self { next: None, prev: None, @@ -87,10 +95,15 @@ pub(crate) struct RawList { } impl RawList { - pub(crate) fn new() -> Self { + 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) fn is_empty(&self) -> bool { self.head.is_none() } @@ -220,23 +233,33 @@ impl RawList { 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()) } @@ -258,7 +281,7 @@ impl CommonCursor { 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 links.next.unwrap() != head { + if !ptr::addr_eq(links.next.unwrap().as_ptr(), head.as_ptr()) { self.cur = links.next; } } @@ -273,7 +296,7 @@ impl CommonCursor { let next = match self.cur.take() { None => head, Some(cur) => { - if cur == head { + if ptr::addr_eq(cur.as_ptr(), head.as_ptr()) { return; } cur @@ -287,14 +310,22 @@ impl CommonCursor { } } +// 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 struct Cursor<'a, G: GetLinks> { +pub(crate) struct Cursor<'a, G: GetLinks> { cursor: CommonCursor, list: &'a RawList, } impl<'a, G: GetLinks> Cursor<'a, G> { - fn new(list: &'a RawList, cur: Option>) -> Self { + pub(crate) fn new(list: &'a RawList, cur: Option>) -> Self { Self { list, cursor: CommonCursor::new(cur), @@ -302,16 +333,22 @@ impl<'a, G: GetLinks> Cursor<'a, G> { } /// Returns the element the cursor is currently positioned on. - pub fn current(&self) -> Option<&'a G::EntryType> { + 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 fn move_next(&mut self) { + 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> { @@ -360,4 +397,166 @@ impl<'a, G: GetLinks> CursorMut<'a, G> { 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> { + 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); + }); + } } From 16b307330113b127917d7c86fcb6de5ffcd0a652 Mon Sep 17 00:00:00 2001 From: guoweikang Date: Tue, 15 Oct 2024 14:32:55 +0800 Subject: [PATCH 03/25] remove unused unsafe_list source code Signed-off-by: guoweikang --- src/unsafe_list.rs | 683 --------------------------------------------- 1 file changed, 683 deletions(-) delete mode 100644 src/unsafe_list.rs 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); - }); - } -} From 3d826d9df2431c06281ae3bed3d536aa3fcc5ade Mon Sep 17 00:00:00 2001 From: guoweikang Date: Tue, 15 Oct 2024 16:34:02 +0800 Subject: [PATCH 04/25] add macro def_node and def_generic_node Signed-off-by: guoweikang --- src/lib.rs | 108 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 108 insertions(+) diff --git a/src/lib.rs b/src/lib.rs index 2db95d5..b38ec07 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -51,9 +51,39 @@ //! assert!(list.pop_front().unwrap().inner == 0); //! assert!(list.pop_front().unwrap().inner == 1); //! +//! ``` //! +//! use def_list_node macro //! ``` +//! use linked_list::{def_node, def_generic_node, List}; +//! +//! def_node!(ExampleNode, usize); +//! +//! 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); +//! } +//! +//! def_generic_node!(GenericExampleNode); +//! +//! let node1 = Box::new(GenericExampleNode::new(0)); +//! let node2 = Box::new(GenericExampleNode::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); +//! } +//! ``` #![cfg_attr(not(test), no_std)] @@ -61,3 +91,81 @@ mod linked_list; mod raw_list; pub use linked_list::List; pub use raw_list::{GetLinks, Links}; + +#[macro_export] +macro_rules! def_node { + ($struct_name:ident, $type:ty) => { + #[doc = concat!("Struct ", stringify!($struct_name), + "is a Node wrapper for type ", stringify!($type))] + pub struct $struct_name { + pub inner: $type, + links: $crate::Links, + } + + impl $crate::GetLinks for $struct_name { + type EntryType = Self; + + #[inline] + fn get_links(t: &Self) -> &$crate::Links { + &t.links + } + } + + impl $struct_name { + pub const fn new(inner: $type) -> Self { + Self { + inner, + links: $crate::Links::new(), + } + } + } + + impl core::ops::Deref for $struct_name { + type Target = $type; + + #[inline] + fn deref(&self) -> &Self::Target { + &self.inner + } + } + }; +} + +#[macro_export] +macro_rules! def_generic_node { + ($struct_name:ident) => { + #[doc = concat!("Struct ", stringify!($struct_name), + "is a Node wrapper include a generic type")] + pub struct $struct_name { + pub inner: T, + links: $crate::Links, + } + + impl $crate::GetLinks for $struct_name { + type EntryType = Self; + + #[inline] + fn get_links(t: &Self) -> &$crate::Links { + &t.links + } + } + + impl $struct_name { + pub const fn new(inner: T) -> Self { + Self { + inner, + links: $crate::Links::new(), + } + } + } + + impl core::ops::Deref for $struct_name { + type Target = T; + + #[inline] + fn deref(&self) -> &Self::Target { + &self.inner + } + } + }; +} From 5a3f0c4ac2a1c37ed9df9606bb06da9890c6757b Mon Sep 17 00:00:00 2001 From: guoweikang Date: Tue, 15 Oct 2024 16:37:40 +0800 Subject: [PATCH 05/25] fix clippy warnning Signed-off-by: guoweikang --- src/lib.rs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index b38ec07..dc37498 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -95,8 +95,7 @@ pub use raw_list::{GetLinks, Links}; #[macro_export] macro_rules! def_node { ($struct_name:ident, $type:ty) => { - #[doc = concat!("Struct ", stringify!($struct_name), - "is a Node wrapper for type ", stringify!($type))] + #[doc = concat!("Struct ", stringify!($struct_name),"is a Node wrapper for type ", stringify!($type))] pub struct $struct_name { pub inner: $type, links: $crate::Links, @@ -134,8 +133,7 @@ macro_rules! def_node { #[macro_export] macro_rules! def_generic_node { ($struct_name:ident) => { - #[doc = concat!("Struct ", stringify!($struct_name), - "is a Node wrapper include a generic type")] + #[doc = concat!("Struct ", stringify!($struct_name),"is a Node wrapper include a generic type")] pub struct $struct_name { pub inner: T, links: $crate::Links, From b8fb68b5c4da06ee4b2b1accf67b8e67070bf238 Mon Sep 17 00:00:00 2001 From: guoweikang Date: Tue, 15 Oct 2024 16:44:26 +0800 Subject: [PATCH 06/25] fix doc warning Signed-off-by: guoweikang --- src/lib.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/lib.rs b/src/lib.rs index dc37498..c49dc7c 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -92,6 +92,7 @@ mod raw_list; pub use linked_list::List; pub use raw_list::{GetLinks, Links}; +#[allow(missing_docs)] #[macro_export] macro_rules! def_node { ($struct_name:ident, $type:ty) => { @@ -130,6 +131,7 @@ macro_rules! def_node { }; } +#[allow(missing_docs)] #[macro_export] macro_rules! def_generic_node { ($struct_name:ident) => { From aa5cb4cb15e47aea638fddca92089526d868184a Mon Sep 17 00:00:00 2001 From: guoweikang Date: Tue, 15 Oct 2024 18:23:35 +0800 Subject: [PATCH 07/25] add inner() func for node Signed-off-by: guoweikang --- src/lib.rs | 26 ++++++++++++++++++++------ 1 file changed, 20 insertions(+), 6 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index c49dc7c..8131093 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -33,6 +33,10 @@ //! links: Links::new() //! } //! } +//! +//! fn inner(&self) -> &InnerType { +//! &self.inner +//! } //! } //! //! let node1 = Box::new(ExampleNode::new(0)); @@ -44,12 +48,12 @@ //! //! //Support Iter //! for (i,e) in list.iter().enumerate() { -//! assert!(e.inner == i); +//! assert!(*e.inner() == i); //! } //! //! // Pop drop -//! assert!(list.pop_front().unwrap().inner == 0); -//! assert!(list.pop_front().unwrap().inner == 1); +//! assert!(*list.pop_front().unwrap().inner() == 0); +//! assert!(*list.pop_front().unwrap().inner() == 1); //! //! ``` //! @@ -67,7 +71,7 @@ //! list.push_back(node2); //! //! for (i,e) in list.iter().enumerate() { -//! assert!(e.inner == i); +//! assert!(*e.inner() == i); //! } //! //! def_generic_node!(GenericExampleNode); @@ -81,7 +85,7 @@ //! //! //Support Iter //! for (i,e) in list.iter().enumerate() { -//! assert!(e.inner == i); +//! assert!(*e.inner() == i); //! } //! ``` @@ -98,7 +102,7 @@ macro_rules! def_node { ($struct_name:ident, $type:ty) => { #[doc = concat!("Struct ", stringify!($struct_name),"is a Node wrapper for type ", stringify!($type))] pub struct $struct_name { - pub inner: $type, + inner: $type, links: $crate::Links, } @@ -118,6 +122,11 @@ macro_rules! def_node { links: $crate::Links::new(), } } + + #[inline] + pub fn inner(&self) -> &$type { + &self.inner + } } impl core::ops::Deref for $struct_name { @@ -157,6 +166,11 @@ macro_rules! def_generic_node { links: $crate::Links::new(), } } + + #[inline] + pub fn inner(&self) -> &T { + &self.inner + } } impl core::ops::Deref for $struct_name { From 6f38819a2532d6571fe0bc83cb6d582f5c265fd4 Mon Sep 17 00:00:00 2001 From: guoweikang Date: Tue, 15 Oct 2024 18:45:39 +0800 Subject: [PATCH 08/25] create tag and update version -------- crate tag v0.2.0 Signed-off-by: guoweikang --- Cargo.toml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 68d2930..443b0f5 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,8 +1,8 @@ [package] name = "linked_list" -version = "0.1.0" +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" From e01115f9b599cdb70874f9507b23b8496baf4e75 Mon Sep 17 00:00:00 2001 From: guoweikang Date: Wed, 16 Oct 2024 10:45:41 +0800 Subject: [PATCH 09/25] add doc for pub func Signed-off-by: guoweikang --- src/lib.rs | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 8131093..ffe2b6c 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -100,7 +100,7 @@ pub use raw_list::{GetLinks, Links}; #[macro_export] macro_rules! def_node { ($struct_name:ident, $type:ty) => { - #[doc = concat!("Struct ", stringify!($struct_name),"is a Node wrapper for type ", stringify!($type))] + #[doc = "A node wrapper for inner type "] pub struct $struct_name { inner: $type, links: $crate::Links, @@ -116,6 +116,7 @@ macro_rules! def_node { } impl $struct_name { + #[doc = "Create a node"] pub const fn new(inner: $type) -> Self { Self { inner, @@ -124,6 +125,7 @@ macro_rules! def_node { } #[inline] + #[doc = "Get inner"] pub fn inner(&self) -> &$type { &self.inner } @@ -144,7 +146,7 @@ macro_rules! def_node { #[macro_export] macro_rules! def_generic_node { ($struct_name:ident) => { - #[doc = concat!("Struct ", stringify!($struct_name),"is a Node wrapper include a generic type")] + #[doc = "A node wrapper include a generic type"] pub struct $struct_name { pub inner: T, links: $crate::Links, @@ -160,6 +162,7 @@ macro_rules! def_generic_node { } impl $struct_name { + #[doc = "Create a node"] pub const fn new(inner: T) -> Self { Self { inner, @@ -168,6 +171,7 @@ macro_rules! def_generic_node { } #[inline] + #[doc = "Get inner"] pub fn inner(&self) -> &T { &self.inner } From d5641a78f1ddeedbf5df985099e5c86a71601e30 Mon Sep 17 00:00:00 2001 From: guoweikang Date: Wed, 16 Oct 2024 11:10:57 +0800 Subject: [PATCH 10/25] inner not a pub filed, use inner() api access Signed-off-by: guoweikang --- src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib.rs b/src/lib.rs index ffe2b6c..ed9472e 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -148,7 +148,7 @@ macro_rules! def_generic_node { ($struct_name:ident) => { #[doc = "A node wrapper include a generic type"] pub struct $struct_name { - pub inner: T, + inner: T, links: $crate::Links, } From deaebf9a1e37b03e794435ca05cab71266800138 Mon Sep 17 00:00:00 2001 From: guoweikang Date: Thu, 17 Oct 2024 11:51:25 +0800 Subject: [PATCH 11/25] Add DOC and example for def_node macro Signed-off-by: guoweikang --- src/lib.rs | 84 +++++++++++++++++++++++++++++++++--------------------- 1 file changed, 51 insertions(+), 33 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index ed9472e..a91ef44 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -57,37 +57,6 @@ //! //! ``` //! -//! use def_list_node macro -//! ``` -//! use linked_list::{def_node, def_generic_node, List}; -//! -//! def_node!(ExampleNode, usize); -//! -//! 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); -//! } -//! -//! def_generic_node!(GenericExampleNode); -//! -//! let node1 = Box::new(GenericExampleNode::new(0)); -//! let node2 = Box::new(GenericExampleNode::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); -//! } -//! ``` #![cfg_attr(not(test), no_std)] @@ -96,7 +65,31 @@ mod raw_list; pub use linked_list::List; pub use raw_list::{GetLinks, Links}; -#[allow(missing_docs)] +/// Defines a new node type that wraps an inner type and includes links for List. +/// +/// # Parameters +/// +/// - `struct_name`: The name of the struct to define. +/// - `type`: The inner type to wrap. +/// +/// # Example +/// +/// ```rust +/// use linked_list::{def_node, List}; +/// +/// def_node!(ExampleNode, usize); +/// +/// 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); +/// } +/// ``` #[macro_export] macro_rules! def_node { ($struct_name:ident, $type:ty) => { @@ -142,7 +135,32 @@ macro_rules! def_node { }; } -#[allow(missing_docs)] +/// Defines a generic node type that wraps a generic inner type and includes links +/// for List. +/// +/// Similar to [`def_node`], but inner type is generic Type +/// +/// # Parameters +/// +/// - `struct_name`: The name of the struct to define. +/// +/// # Example +/// +/// ```rust +/// use linked_list::{def_generic_node, List}; +/// def_generic_node!(GenericExampleNode); +/// +/// let node1 = Box::new(GenericExampleNode::new(0)); +/// let node2 = Box::new(GenericExampleNode::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] macro_rules! def_generic_node { ($struct_name:ident) => { From 5d853fffc025e8f9f3b62f05fd2d424f333ca401 Mon Sep 17 00:00:00 2001 From: guoweikang Date: Fri, 18 Oct 2024 11:08:53 +0800 Subject: [PATCH 12/25] use const fn for inner and is_empty Signed-off-by: guoweikang --- src/lib.rs | 4 ++-- src/linked_list.rs | 2 +- src/raw_list.rs | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index a91ef44..d8cd79b 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -119,7 +119,7 @@ macro_rules! def_node { #[inline] #[doc = "Get inner"] - pub fn inner(&self) -> &$type { + pub const fn inner(&self) -> &$type { &self.inner } } @@ -190,7 +190,7 @@ macro_rules! def_generic_node { #[inline] #[doc = "Get inner"] - pub fn inner(&self) -> &T { + pub const fn inner(&self) -> &T { &self.inner } } diff --git a/src/linked_list.rs b/src/linked_list.rs index a3e91b0..b963a43 100644 --- a/src/linked_list.rs +++ b/src/linked_list.rs @@ -140,7 +140,7 @@ impl List { } /// Returns whether the list is empty. - pub fn is_empty(&self) -> bool { + pub const fn is_empty(&self) -> bool { self.list.is_empty() } diff --git a/src/raw_list.rs b/src/raw_list.rs index b400f12..fc20384 100644 --- a/src/raw_list.rs +++ b/src/raw_list.rs @@ -104,7 +104,7 @@ impl RawList { Iterator::new(self.cursor_front(), self.cursor_back()) } - pub(crate) fn is_empty(&self) -> bool { + pub(crate) const fn is_empty(&self) -> bool { self.head.is_none() } From 02e5d461192738f0273e56850f9ef381f9598e22 Mon Sep 17 00:00:00 2001 From: guoweikang Date: Mon, 21 Oct 2024 13:17:03 +0800 Subject: [PATCH 13/25] macro def_node with new format Signed-off-by: guoweikang --- README.md | 64 +++++++++++++ src/lib.rs | 230 +++++++++++++++++++-------------------------- src/linked_list.rs | 4 +- 3 files changed, 163 insertions(+), 135 deletions(-) create mode 100644 README.md diff --git a/README.md b/README.md new file mode 100644 index 0000000..3233600 --- /dev/null +++ b/README.md @@ -0,0 +1,64 @@ +# LinkedList + + 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 + + In more general use cases, shoud not use [`RawList`] directly, + suggest use smart pointers of nodes and move ownership of smart + pointers to List. + +## Examples + + ```rust + use linked_list::{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 d8cd79b..9525c66 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,105 +1,22 @@ -//! 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 -//! -//! In more general use cases, shoud not use RawList directly, -//! suggest use smart pointers of nodes and move ownership of smart -//! pointers to List: -//! -//! ``` -//! use linked_list::{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); -//! -//! ``` -//! - #![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}; -/// Defines a new node type that wraps an inner type and includes links for List. -/// -/// # Parameters -/// -/// - `struct_name`: The name of the struct to define. -/// - `type`: The inner type to wrap. -/// -/// # Example -/// -/// ```rust -/// use linked_list::{def_node, List}; -/// -/// def_node!(ExampleNode, usize); -/// -/// 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); -/// } -/// ``` -#[macro_export] -macro_rules! def_node { - ($struct_name:ident, $type:ty) => { - #[doc = "A node wrapper for inner type "] - pub struct $struct_name { +#[macro_export(local_inner_macros)] +#[doc(hidden)] +macro_rules! __def_node_internal { + ($(#[$meta:meta])* ($($vis:tt)*) struct $name:ident($type:ty);) => { + $(#[$meta])* + $($vis)* struct $name { inner: $type, links: $crate::Links, } - impl $crate::GetLinks for $struct_name { + impl $crate::GetLinks for $name { type EntryType = Self; #[inline] @@ -108,9 +25,9 @@ macro_rules! def_node { } } - impl $struct_name { + impl $name { #[doc = "Create a node"] - pub const fn new(inner: $type) -> Self { + $($vis)* const fn new(inner: $type) -> Self { Self { inner, links: $crate::Links::new(), @@ -119,12 +36,12 @@ macro_rules! def_node { #[inline] #[doc = "Get inner"] - pub const fn inner(&self) -> &$type { + $($vis)* const fn inner(&self) -> &$type { &self.inner } } - impl core::ops::Deref for $struct_name { + impl core::ops::Deref for $name { type Target = $type; #[inline] @@ -133,44 +50,15 @@ macro_rules! def_node { } } }; -} -/// Defines a generic node type that wraps a generic inner type and includes links -/// for List. -/// -/// Similar to [`def_node`], but inner type is generic Type -/// -/// # Parameters -/// -/// - `struct_name`: The name of the struct to define. -/// -/// # Example -/// -/// ```rust -/// use linked_list::{def_generic_node, List}; -/// def_generic_node!(GenericExampleNode); -/// -/// let node1 = Box::new(GenericExampleNode::new(0)); -/// let node2 = Box::new(GenericExampleNode::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] -macro_rules! def_generic_node { - ($struct_name:ident) => { - #[doc = "A node wrapper include a generic type"] - pub struct $struct_name { - inner: T, + ($(#[$meta:meta])* ($($vis:tt)*) struct $name:ident<$gen:ident>($type:ty); $($t:tt)*) => { + $(#[$meta])* + $($vis)* struct $name<$gen> { + inner: $type, links: $crate::Links, } - impl $crate::GetLinks for $struct_name { + impl<$gen> $crate::GetLinks for $name<$gen> { type EntryType = Self; #[inline] @@ -179,9 +67,9 @@ macro_rules! def_generic_node { } } - impl $struct_name { + impl<$gen> $name<$gen> { #[doc = "Create a node"] - pub const fn new(inner: T) -> Self { + $($vis)* const fn new(inner: $type) -> Self { Self { inner, links: $crate::Links::new(), @@ -190,13 +78,13 @@ macro_rules! def_generic_node { #[inline] #[doc = "Get inner"] - pub const fn inner(&self) -> &T { + $($vis)* const fn inner(&self) -> &$type { &self.inner } } - impl core::ops::Deref for $struct_name { - type Target = T; + impl<$gen> core::ops::Deref for $name<$gen> { + type Target = $type; #[inline] fn deref(&self) -> &Self::Target { @@ -205,3 +93,77 @@ macro_rules! def_generic_node { } }; } + +/// 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::{def_node, List}; +/// +/// def_node!( +/// /// An example Node with usize +/// struct ExampleNode(usize); +/// /// An example Node with generic Inner type +/// 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 = 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])* struct $name:ident($type:ty); $($t:tt)*) => { + __def_node_internal!($(#[$meta])* () struct $name($type);); + def_node!($($t)*); + + }; + ($(#[$meta:meta])* pub struct $name:ident($type:ty); $($t:tt)*) => { + __def_node_internal!($(#[$meta])* (pub) struct $name($type);$($t)*); + def_node!($($t)*); + + }; + + ($(#[$meta:meta])* struct $name:ident<$gen:ident>($type:ty); $($t:tt)*) => { + __def_node_internal!($(#[$meta])* () struct $name<$gen>($type); $($t)*); + def_node!($($t)*); + + }; + ($(#[$meta:meta])* pub struct $name:ident<$gen:ident>($type:ty); $($t:tt)*) => { + __def_node_internal!($(#[$meta])* (pub) struct $name<$gen>($type);$($t)*); + def_node!($($t)*); + + }; + () => () +} diff --git a/src/linked_list.rs b/src/linked_list.rs index b963a43..1f4b9fb 100644 --- a/src/linked_list.rs +++ b/src/linked_list.rs @@ -97,6 +97,8 @@ where impl GetLinks for Box { type EntryType = T::EntryType; + + #[inline] fn get_links(data: &Self::EntryType) -> &Links { ::get_links(data) } @@ -224,7 +226,7 @@ pub struct CursorMut<'a, G: GetLinksWrapped> { } impl<'a, G: GetLinksWrapped> CursorMut<'a, G> { - fn new(cursor: raw_list::CursorMut<'a, G>) -> Self { + const fn new(cursor: raw_list::CursorMut<'a, G>) -> Self { Self { cursor } } From 58a879b4dc1f457acbe26341b86d4dcc84e6fd41 Mon Sep 17 00:00:00 2001 From: guoweikang Date: Mon, 21 Oct 2024 13:19:34 +0800 Subject: [PATCH 14/25] remove unsed description Signed-off-by: guoweikang --- README.md | 4 ---- 1 file changed, 4 deletions(-) diff --git a/README.md b/README.md index 3233600..2567cc2 100644 --- a/README.md +++ b/README.md @@ -6,10 +6,6 @@ [1]: https://github.com/Rust-for-Linux/linux/blob/rust/rust/kernel/linked_list.rs - In more general use cases, shoud not use [`RawList`] directly, - suggest use smart pointers of nodes and move ownership of smart - pointers to List. - ## Examples ```rust From 606187d13ad3c32bc2dc9b073361a5daf127ce25 Mon Sep 17 00:00:00 2001 From: guoweikang Date: Mon, 21 Oct 2024 13:32:23 +0800 Subject: [PATCH 15/25] support pub(crate) for def_node Signed-off-by: guoweikang --- src/lib.rs | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/lib.rs b/src/lib.rs index 9525c66..d5c3082 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -153,6 +153,11 @@ macro_rules! def_node { __def_node_internal!($(#[$meta])* (pub) struct $name($type);$($t)*); def_node!($($t)*); + }; + ($(#[$meta:meta])* pub ($($vis:tt)+) struct $name:ident($type:ty); $($t:tt)*) => { + __def_node_internal!($(#[$meta])* (pub ($($vis)+)) struct $name($type);$($t)*); + def_node!($($t)*); + }; ($(#[$meta:meta])* struct $name:ident<$gen:ident>($type:ty); $($t:tt)*) => { @@ -164,6 +169,11 @@ macro_rules! def_node { __def_node_internal!($(#[$meta])* (pub) struct $name<$gen>($type);$($t)*); def_node!($($t)*); + }; + ($(#[$meta:meta])* pub ($($vis:tt)+) struct $name:ident<$gen:ident>($type:ty); $($t:tt)*) => { + __def_node_internal!($(#[$meta])* (pub ($($vis)+)) struct $name<$gen>($type);$($t)*); + def_node!($($t)*); + }; () => () } From 33d763c83c48605b1fb620eaf6732beb0200d10c Mon Sep 17 00:00:00 2001 From: guoweikang Date: Mon, 21 Oct 2024 14:58:40 +0800 Subject: [PATCH 16/25] use const for more func Signed-off-by: guoweikang --- src/raw_list.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/raw_list.rs b/src/raw_list.rs index fc20384..4218ce1 100644 --- a/src/raw_list.rs +++ b/src/raw_list.rs @@ -270,7 +270,7 @@ struct CommonCursor { } impl CommonCursor { - fn new(cur: Option>) -> Self { + const fn new(cur: Option>) -> Self { Self { cur } } @@ -419,7 +419,7 @@ pub(crate) struct Iterator<'a, G: GetLinks> { } impl<'a, G: GetLinks> Iterator<'a, G> { - fn new(cursor_front: Cursor<'a, G>, cursor_back: Cursor<'a, G>) -> Self { + const fn new(cursor_front: Cursor<'a, G>, cursor_back: Cursor<'a, G>) -> Self { Self { cursor_front, cursor_back, From c2c354221366fb4c8d2b529e940b44b5e9fd1493 Mon Sep 17 00:00:00 2001 From: guoweikang Date: Mon, 21 Oct 2024 15:32:13 +0800 Subject: [PATCH 17/25] use vis in macro -------- 1 use vis in macro 2 replace def_node node(type) with node{type} Signed-off-by: guoweikang --- src/lib.rs | 40 +++++++++++----------------------------- 1 file changed, 11 insertions(+), 29 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index d5c3082..4df74c7 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -9,7 +9,7 @@ pub use raw_list::{GetLinks, Links}; #[macro_export(local_inner_macros)] #[doc(hidden)] macro_rules! __def_node_internal { - ($(#[$meta:meta])* ($($vis:tt)*) struct $name:ident($type:ty);) => { + ($(#[$meta:meta])* ($($vis:tt)*) struct $name:ident{$type:ty};) => { $(#[$meta])* $($vis)* struct $name { inner: $type, @@ -51,7 +51,7 @@ macro_rules! __def_node_internal { } }; - ($(#[$meta:meta])* ($($vis:tt)*) struct $name:ident<$gen:ident>($type:ty); $($t:tt)*) => { + ($(#[$meta:meta])* ($($vis:tt)*) struct $name:ident<$gen:ident>{$type:ty};) => { $(#[$meta])* $($vis)* struct $name<$gen> { inner: $type, @@ -114,9 +114,11 @@ macro_rules! __def_node_internal { /// /// def_node!( /// /// An example Node with usize -/// struct ExampleNode(usize); -/// /// An example Node with generic Inner type -/// struct GenericNode(T); +/// 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)); @@ -144,34 +146,14 @@ macro_rules! __def_node_internal { /// #[macro_export(local_inner_macros)] macro_rules! def_node { - ($(#[$meta:meta])* struct $name:ident($type:ty); $($t:tt)*) => { - __def_node_internal!($(#[$meta])* () struct $name($type);); - def_node!($($t)*); - - }; - ($(#[$meta:meta])* pub struct $name:ident($type:ty); $($t:tt)*) => { - __def_node_internal!($(#[$meta])* (pub) struct $name($type);$($t)*); - def_node!($($t)*); - - }; - ($(#[$meta:meta])* pub ($($vis:tt)+) struct $name:ident($type:ty); $($t:tt)*) => { - __def_node_internal!($(#[$meta])* (pub ($($vis)+)) struct $name($type);$($t)*); + ($(#[$meta:meta])* $sv:vis struct $name:ident{$type:ty}; $($t:tt)*) => { + __def_node_internal!($(#[$meta])* ($sv) struct $name{$type};); def_node!($($t)*); }; - ($(#[$meta:meta])* struct $name:ident<$gen:ident>($type:ty); $($t:tt)*) => { - __def_node_internal!($(#[$meta])* () struct $name<$gen>($type); $($t)*); - def_node!($($t)*); - - }; - ($(#[$meta:meta])* pub struct $name:ident<$gen:ident>($type:ty); $($t:tt)*) => { - __def_node_internal!($(#[$meta])* (pub) struct $name<$gen>($type);$($t)*); - def_node!($($t)*); - - }; - ($(#[$meta:meta])* pub ($($vis:tt)+) struct $name:ident<$gen:ident>($type:ty); $($t:tt)*) => { - __def_node_internal!($(#[$meta])* (pub ($($vis)+)) struct $name<$gen>($type);$($t)*); + ($(#[$meta:meta])* $sv:vis struct $name:ident<$gen:ident>{$type:ty}; $($t:tt)*) => { + __def_node_internal!($(#[$meta])* ($sv) struct $name<$gen>{$type};); def_node!($($t)*); }; From d66aa7e42a121ce6f6338dcccc39eafe89d462d3 Mon Sep 17 00:00:00 2001 From: guoweikang Date: Tue, 22 Oct 2024 11:15:49 +0800 Subject: [PATCH 18/25] Add CI DOC for linked list -------- 1 linked list push to crates-io 2 add into_inner func for def_node Signed-off-by: guoweikang --- Cargo.toml | 6 ++++-- README.md | 6 +++++- src/lib.rs | 49 +++++++++++++++++++++++++++++++++---------------- 3 files changed, 42 insertions(+), 19 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 443b0f5..b9e10df 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,12 +1,14 @@ [package] name = "linked_list" -version = "0.2.0" +version = "0.1.0" edition = "2021" 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" +documentation = "https://docs.rs/linked_list" +keywords = ["list"] +categories = ["no-std", "rust-patterns"] [dependencies] diff --git a/README.md b/README.md index 2567cc2..6c4911e 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,9 @@ # LinkedList +[![Crates.io](https://img.shields.io/crates/v/linked_list)](https://crates.io/crates/linked_list) +[![Doc.rs](https://docs.rs/linked_list/badge.svg)](https://docs.rs/linked_list) +[![CI](https://github.com/arceos-org/linked_list/actions/workflows/ci.yml/badge.svg?branch=main)](https://github.com/arceos-org/linked_list/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]. @@ -46,7 +50,7 @@ list.push_back(node1); list.push_back(node2); - //Support Iter + // Support Iter for (i,e) in list.iter().enumerate() { assert!(*e.inner() == i); } diff --git a/src/lib.rs b/src/lib.rs index 4df74c7..e8e87dd 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -9,7 +9,7 @@ pub use raw_list::{GetLinks, Links}; #[macro_export(local_inner_macros)] #[doc(hidden)] macro_rules! __def_node_internal { - ($(#[$meta:meta])* ($($vis:tt)*) struct $name:ident{$type:ty};) => { + ($(#[$meta:meta])* ($($vis:tt)*) struct $name:ident($type:ty);) => { $(#[$meta])* $($vis)* struct $name { inner: $type, @@ -35,10 +35,16 @@ macro_rules! __def_node_internal { } #[inline] - #[doc = "Get inner"] + #[doc = "Return the referece of wrapped inner"] $($vis)* const fn inner(&self) -> &$type { &self.inner } + + #[inline] + #[doc = "Consumes the `node`, returning the wrapped inner"] + $($vis)* fn into_inner(self) -> $type { + self.inner + } } impl core::ops::Deref for $name { @@ -51,7 +57,7 @@ macro_rules! __def_node_internal { } }; - ($(#[$meta:meta])* ($($vis:tt)*) struct $name:ident<$gen:ident>{$type:ty};) => { + ($(#[$meta:meta])* ($($vis:tt)*) struct $name:ident<$gen:ident>($type:ty);) => { $(#[$meta])* $($vis)* struct $name<$gen> { inner: $type, @@ -77,10 +83,16 @@ macro_rules! __def_node_internal { } #[inline] - #[doc = "Get inner"] + #[doc = "Return the referece of wrapped inner"] $($vis)* const fn inner(&self) -> &$type { &self.inner } + + #[inline] + #[doc = "Consumes the `node`, returning the wrapped inner"] + $($vis)* fn into_inner(self) -> $type { + self.inner + } } impl<$gen> core::ops::Deref for $name<$gen> { @@ -112,14 +124,14 @@ macro_rules! __def_node_internal { /// ```rust /// use linked_list::{def_node, List}; /// -/// def_node!( +/// def_node!{ /// /// An example Node with usize -/// struct ExampleNode{usize}; +/// struct ExampleNode(usize); /// /// An example Node with generic Inner type and pub(crate) -/// pub(crate) struct NativeGenericNode{usize}; +/// pub(crate) struct NativeGenericNode(usize); /// /// An example Node with generic Inner type and pub vis -/// pub struct GenericNode{T}; -/// ); +/// pub struct GenericNode(T); +/// } /// /// let node1 = Box::new(ExampleNode::new(0)); /// let node2 = Box::new(ExampleNode::new(1)); @@ -131,9 +143,17 @@ macro_rules! __def_node_internal { /// 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); @@ -146,16 +166,13 @@ macro_rules! __def_node_internal { /// #[macro_export(local_inner_macros)] macro_rules! def_node { - ($(#[$meta:meta])* $sv:vis struct $name:ident{$type:ty}; $($t:tt)*) => { - __def_node_internal!($(#[$meta])* ($sv) struct $name{$type};); + ($(#[$meta:meta])* $vis:vis struct $name:ident($type:ty); $($t:tt)*) => { + __def_node_internal!($(#[$meta])* ($vis) struct $name($type);); def_node!($($t)*); - }; - - ($(#[$meta:meta])* $sv:vis struct $name:ident<$gen:ident>{$type:ty}; $($t:tt)*) => { - __def_node_internal!($(#[$meta])* ($sv) struct $name<$gen>{$type};); + ($(#[$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)*); - }; () => () } From 907953bdeffa35ddaa92eddea92368fa6930bea8 Mon Sep 17 00:00:00 2001 From: guoweikang Date: Tue, 22 Oct 2024 11:26:13 +0800 Subject: [PATCH 19/25] modify crates-io package name from linked_list to linked_list_r4l Signed-off-by: guoweikang --- Cargo.toml | 4 ++-- README.md | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index b9e10df..63ce8e5 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,5 +1,5 @@ [package] -name = "linked_list" +name = "linked_list_r4l" version = "0.1.0" edition = "2021" authors = ["Wedson Almeida Filho ", "WeiKang Guo "] @@ -7,7 +7,7 @@ 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://docs.rs/linked_list" +documentation = "https://docs.rs/linked_list_r4l" keywords = ["list"] categories = ["no-std", "rust-patterns"] diff --git a/README.md b/README.md index 6c4911e..a145cc3 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ # LinkedList -[![Crates.io](https://img.shields.io/crates/v/linked_list)](https://crates.io/crates/linked_list) -[![Doc.rs](https://docs.rs/linked_list/badge.svg)](https://docs.rs/linked_list) +[![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/actions/workflows/ci.yml/badge.svg?branch=main)](https://github.com/arceos-org/linked_list/actions/workflows/ci.yml) Linked lists that supports arbitrary removal in constant time. From 0cc8710e36924c2bf44136d186a0ccd09b6f7c15 Mon Sep 17 00:00:00 2001 From: guoweikang Date: Tue, 22 Oct 2024 11:31:25 +0800 Subject: [PATCH 20/25] fix cargo fmt Signed-off-by: guoweikang --- src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib.rs b/src/lib.rs index e8e87dd..65ba7e6 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -143,7 +143,7 @@ macro_rules! __def_node_internal { /// for (i,e) in list.iter().enumerate() { /// assert!(*e.inner() == i); /// } -/// +/// /// let node1 = list.pop_front().unwrap(); /// let node2 = list.pop_front().unwrap(); /// From f71473106557f790b477ee915077e01ee254dc88 Mon Sep 17 00:00:00 2001 From: guoweikang Date: Tue, 22 Oct 2024 11:34:42 +0800 Subject: [PATCH 21/25] fix unitest fail Signed-off-by: guoweikang --- README.md | 2 +- src/lib.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index a145cc3..fae6360 100644 --- a/README.md +++ b/README.md @@ -13,7 +13,7 @@ ## Examples ```rust - use linked_list::{GetLinks, Links, List}; + use linked_list_r4l::{GetLinks, Links, List}; type InnerType = usize; diff --git a/src/lib.rs b/src/lib.rs index 65ba7e6..de139f0 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -122,7 +122,7 @@ macro_rules! __def_node_internal { /// # Example /// /// ```rust -/// use linked_list::{def_node, List}; +/// use linked_list_r4l::{def_node, List}; /// /// def_node!{ /// /// An example Node with usize From d289a9627c3d77c4f9b016aea733f26811ac6162 Mon Sep 17 00:00:00 2001 From: guoweikang Date: Tue, 22 Oct 2024 11:40:49 +0800 Subject: [PATCH 22/25] update package version to 0.2.0 ------- update version for publish to craes-io Signed-off-by: guoweikang --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 63ce8e5..f60cb60 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "linked_list_r4l" -version = "0.1.0" +version = "0.2.0" edition = "2021" authors = ["Wedson Almeida Filho ", "WeiKang Guo "] description = "Linked lists that supports arbitrary removal in constant time" From 3509ccf200325e91c5141b8a8a4c897eae246172 Mon Sep 17 00:00:00 2001 From: guoweikang Date: Tue, 22 Oct 2024 12:46:19 +0800 Subject: [PATCH 23/25] use vis in _def_node_inernal Signed-off-by: guoweikang --- src/lib.rs | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index de139f0..45a73ea 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -9,9 +9,9 @@ pub use raw_list::{GetLinks, Links}; #[macro_export(local_inner_macros)] #[doc(hidden)] macro_rules! __def_node_internal { - ($(#[$meta:meta])* ($($vis:tt)*) struct $name:ident($type:ty);) => { + ($(#[$meta:meta])* $vis:vis struct $name:ident($type:ty);) => { $(#[$meta])* - $($vis)* struct $name { + $vis struct $name { inner: $type, links: $crate::Links, } @@ -27,7 +27,7 @@ macro_rules! __def_node_internal { impl $name { #[doc = "Create a node"] - $($vis)* const fn new(inner: $type) -> Self { + $vis const fn new(inner: $type) -> Self { Self { inner, links: $crate::Links::new(), @@ -36,13 +36,13 @@ macro_rules! __def_node_internal { #[inline] #[doc = "Return the referece of wrapped inner"] - $($vis)* const fn inner(&self) -> &$type { + $vis const fn inner(&self) -> &$type { &self.inner } #[inline] #[doc = "Consumes the `node`, returning the wrapped inner"] - $($vis)* fn into_inner(self) -> $type { + $vis fn into_inner(self) -> $type { self.inner } } @@ -57,9 +57,9 @@ macro_rules! __def_node_internal { } }; - ($(#[$meta:meta])* ($($vis:tt)*) struct $name:ident<$gen:ident>($type:ty);) => { + ($(#[$meta:meta])* $vis:vis struct $name:ident<$gen:ident>($type:ty);) => { $(#[$meta])* - $($vis)* struct $name<$gen> { + $vis struct $name<$gen> { inner: $type, links: $crate::Links, } @@ -75,7 +75,7 @@ macro_rules! __def_node_internal { impl<$gen> $name<$gen> { #[doc = "Create a node"] - $($vis)* const fn new(inner: $type) -> Self { + $vis const fn new(inner: $type) -> Self { Self { inner, links: $crate::Links::new(), @@ -84,13 +84,13 @@ macro_rules! __def_node_internal { #[inline] #[doc = "Return the referece of wrapped inner"] - $($vis)* const fn inner(&self) -> &$type { + $vis const fn inner(&self) -> &$type { &self.inner } #[inline] #[doc = "Consumes the `node`, returning the wrapped inner"] - $($vis)* fn into_inner(self) -> $type { + $vis fn into_inner(self) -> $type { self.inner } } @@ -167,11 +167,11 @@ macro_rules! __def_node_internal { #[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_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_internal!($(#[$meta])* $vis struct $name<$gen>($type);); def_node!($($t)*); }; () => () From 325bf0ad3a49eee2a493e578033f135355780b2b Mon Sep 17 00:00:00 2001 From: guoweikang Date: Tue, 22 Oct 2024 13:40:33 +0800 Subject: [PATCH 24/25] rename repo to linked_list_r4l -------- 1 rename repo to linked_list_r4l 2 change to pub impl for node 3 const fn Signed-off-by: guoweikang --- Cargo.toml | 2 +- README.md | 2 +- src/lib.rs | 12 ++++++------ 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index f60cb60..d6a6f69 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -6,7 +6,7 @@ authors = ["Wedson Almeida Filho ", "WeiKang Guo Self { + pub const fn new(inner: $type) -> Self { Self { inner, links: $crate::Links::new(), @@ -36,13 +36,13 @@ macro_rules! __def_node_internal { #[inline] #[doc = "Return the referece of wrapped inner"] - $vis const fn inner(&self) -> &$type { + pub const fn inner(&self) -> &$type { &self.inner } #[inline] #[doc = "Consumes the `node`, returning the wrapped inner"] - $vis fn into_inner(self) -> $type { + pub const fn into_inner(self) -> $type { self.inner } } @@ -75,7 +75,7 @@ macro_rules! __def_node_internal { impl<$gen> $name<$gen> { #[doc = "Create a node"] - $vis const fn new(inner: $type) -> Self { + pub const fn new(inner: $type) -> Self { Self { inner, links: $crate::Links::new(), @@ -84,13 +84,13 @@ macro_rules! __def_node_internal { #[inline] #[doc = "Return the referece of wrapped inner"] - $vis const fn inner(&self) -> &$type { + pub const fn inner(&self) -> &$type { &self.inner } #[inline] #[doc = "Consumes the `node`, returning the wrapped inner"] - $vis fn into_inner(self) -> $type { + pub fn into_inner(self) -> $type { self.inner } } From 793fdccc1e4b98235755425e031ca6a846b1302d Mon Sep 17 00:00:00 2001 From: guoweikang Date: Tue, 22 Oct 2024 14:09:10 +0800 Subject: [PATCH 25/25] remove const fn for into_innner Signed-off-by: guoweikang --- src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib.rs b/src/lib.rs index 265ea7b..8fb8e00 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -42,7 +42,7 @@ macro_rules! __def_node_internal { #[inline] #[doc = "Consumes the `node`, returning the wrapped inner"] - pub const fn into_inner(self) -> $type { + pub fn into_inner(self) -> $type { self.inner } }