Skip to content

Commit

Permalink
macro def_node with new format
Browse files Browse the repository at this point in the history
Signed-off-by: guoweikang <[email protected]>
  • Loading branch information
guoweikang committed Oct 21, 2024
1 parent 5d853ff commit 02e5d46
Show file tree
Hide file tree
Showing 3 changed files with 163 additions and 135 deletions.
64 changes: 64 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -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<Self>,
}

impl GetLinks for ExampleNode {
type EntryType = Self;

fn get_links(t: &Self) -> &Links<Self> {
&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::<Box<ExampleNode>>::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);

```


230 changes: 96 additions & 134 deletions src/lib.rs
Original file line number Diff line number Diff line change
@@ -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<Self>,
//! }
//!
//! impl GetLinks for ExampleNode {
//! type EntryType = Self;
//!
//! fn get_links(t: &Self) -> &Links<Self> {
//! &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::<Box<ExampleNode>>::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::<Box<ExampleNode>>::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<Self>,
}

impl $crate::GetLinks for $struct_name {
impl $crate::GetLinks for $name {
type EntryType = Self;

#[inline]
Expand All @@ -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(),
Expand All @@ -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]
Expand All @@ -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::<Box<GenericExampleNode<usize>>>::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<T> {
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<Self>,
}

impl<T> $crate::GetLinks for $struct_name<T> {
impl<$gen> $crate::GetLinks for $name<$gen> {
type EntryType = Self;

#[inline]
Expand All @@ -179,9 +67,9 @@ macro_rules! def_generic_node {
}
}

impl<T> $struct_name<T> {
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(),
Expand All @@ -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<T> core::ops::Deref for $struct_name<T> {
type Target = T;
impl<$gen> core::ops::Deref for $name<$gen> {
type Target = $type;

#[inline]
fn deref(&self) -> &Self::Target {
Expand All @@ -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>(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>(T);
/// );
///
/// let node1 = Box::new(ExampleNode::new(0));
/// let node2 = Box::new(ExampleNode::new(1));
/// let mut list = List::<Box<ExampleNode>>::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::<Box<GenericNode<usize>>>::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)*);

};
() => ()
}
4 changes: 3 additions & 1 deletion src/linked_list.rs
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,8 @@ where

impl<T: GetLinks + ?Sized> GetLinks for Box<T> {
type EntryType = T::EntryType;

#[inline]
fn get_links(data: &Self::EntryType) -> &Links<Self::EntryType> {
<T as GetLinks>::get_links(data)
}
Expand Down Expand Up @@ -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 }
}

Expand Down

0 comments on commit 02e5d46

Please sign in to comment.