pub struct List<T: Linked<Links<T>> + ?Sized> { /* private fields */ }
Expand description

An intrusive doubly-linked list.

This data structure may be used as a first-in, first-out queue by using the List::push_front and List::pop_back methods. It also supports random-access removals using the List::remove method.

This data structure can also be used as a stack or doubly-linked list by using the List::pop_front and List::push_back methods.

In order to be part of a List, a type T must implement Linked for list::Links<T>.

Examples

Implementing the Linked trait for an entry type:

use cordyceps::{
    Linked,
    list::{self, List},
};

// This example uses the Rust standard library for convenience, but
// the doubly-linked list itself does not require std.
use std::{pin::Pin, ptr::{self, NonNull}, thread, sync::Arc};

/// A simple queue entry that stores an `i32`.
#[derive(Debug, Default)]
struct Entry {
   links: list::Links<Entry>,
   val: i32,
}

// Implement the `Linked` trait for our entry type so that it can be used
// as a queue entry.
unsafe impl Linked<list::Links<Entry>> for Entry {
    // In this example, our entries will be "owned" by a `Box`, but any
    // heap-allocated type that owns an element may be used.
    //
    // An element *must not* move while part of an intrusive data
    // structure. In many cases, `Pin` may be used to enforce this.
    type Handle = Pin<Box<Self>>;

    /// Convert an owned `Handle` into a raw pointer
    fn into_ptr(handle: Pin<Box<Entry>>) -> NonNull<Entry> {
       unsafe { NonNull::from(Box::leak(Pin::into_inner_unchecked(handle))) }
    }

    /// Convert a raw pointer back into an owned `Handle`.
    unsafe fn from_ptr(ptr: NonNull<Entry>) -> Pin<Box<Entry>> {
        // Safety: if this function is only called by the linked list
        // implementation (and it is not intended for external use), we can
        // expect that the `NonNull` was constructed from a reference which
        // was pinned.
        //
        // If other callers besides `List`'s internals were to call this on
        // some random `NonNull<Entry>`, this would not be the case, and
        // this could be constructing an erroneous `Pin` from a referent
        // that may not be pinned!
        Pin::new_unchecked(Box::from_raw(ptr.as_ptr()))
    }

    /// Access an element's `Links`.
    unsafe fn links(target: NonNull<Entry>) -> NonNull<list::Links<Entry>> {
        // Using `ptr::addr_of_mut!` permits us to avoid creating a temporary
        // reference without using layout-dependent casts.
        let links = ptr::addr_of_mut!((*target.as_ptr()).links);

        // `NonNull::new_unchecked` is safe to use here, because the pointer that
        // we offset was not null, implying that the pointer produced by offsetting
        // it will also not be null.
        NonNull::new_unchecked(links)
    }
}

impl Entry {
    fn new(val: i32) -> Self {
        Self {
            val,
            ..Self::default()
        }
    }
}

Using a List as a first-in, first-out (FIFO) queue with List::push_back and List::pop_front:

// Now that we've implemented the `Linked` trait for our `Entry` type, we can
// create a `List` of entries:
let mut list = List::<Entry>::new();

// Push some entries to the list:
for i in 0..5 {
    list.push_back(Box::pin(Entry::new(i)));
}

// The list is a doubly-ended queue. We can use the `pop_front` method with
// `push_back` to dequeue elements in FIFO order:
for i in 0..5 {
    let entry = list.pop_front()
        .expect("the list should have 5 entries in it");
    assert_eq!(entry.val, i, "entries are dequeued in FIFO order");
}

assert!(list.is_empty());

Using a List as a last-in, first-out (LIFO) stack with List::push_back and List::pop_back:

let mut list = List::<Entry>::new();

// Push some entries to the list:
for i in 0..5 {
    list.push_back(Box::pin(Entry::new(i)));
}

// Note that we have reversed the direction of the iterator, since
// we are popping from the *back* of the list:
for i in (0..5).into_iter().rev() {
    let entry = list.pop_back()
        .expect("the list should have 5 entries in it");
    assert_eq!(entry.val, i, "entries are dequeued in LIFO order");
}

assert!(list.is_empty());

Implementations

Returns a new empty list.

Moves all elements from other to the end of the list.

This reuses all the nodes from other and moves them into self. After this operation, other becomes empty.

This operation should compute in O(1) time and O(1) memory.

Attempts to split the list into two at the given index (inclusive).

Returns everything after the given index (including the node at that index), or None if the index is greater than the list’s length.

This operation should compute in O(n) time.

Returns
  • Some(List<T>) with a new list containing every element after at, if at <= self.len()
  • None if at > self.len()

Split the list into two at the given index (inclusive).

Returns everything after the given index (including the node at that index).

This operation should compute in O(1) time and O(1) memory.

Panics

If at > self.len().

Returns true if this list is empty.

Returns the number of elements in the list.

Asserts as many of the linked list’s invariants as possible.

Removes an item from the tail of the list.

This operation should compute in O(n) time.

This returns a Handle that owns the popped element. Dropping the Handle will drop the element.

Remove an item from the head of the list.

This operation should compute in O(n) time.

This returns a Handle that owns the popped element. Dropping the Handle will drop the element.

Appends an item to the tail of the list.

This operation should compute in O(n) time.

This takes a Handle that owns the appended item. While the element is in the list, it is owned by the list, and will be dropped when the list is dropped. If the element is removed or otherwise unlinked from the list, ownership is assigned back to the Handle.

Appends an item to the head of the list.

This operation should compute in O(n) time.

This takes a Handle that owns the appended item. While the element is in the list, it is owned by the list, and will be dropped when the list is dropped. If the element is removed or otherwise unlinked from the list, ownership is assigned back to the Handle.

Returns a reference to the first element in the list, or None if the list is empty.

The node is Pinned in memory, as moving it to a different memory location while it is in the list would corrupt the links pointing to that node.

This operation should complete in O(1) time.

Returns a mutable reference to the first element in the list, or None if the list is empty.

The node is Pinned in memory, as moving it to a different memory location while it is in the list would corrupt the links pointing to that node.

This operation should complete in O(1) time.

Returns a reference to the last element in the list, or None if the list is empty.

The node is Pinned in memory, as moving it to a different memory location while it is in the list would corrupt the links pointing to that node.

This operation should complete in O(1) time.

Returns a mutable reference to the last element in the list, or None if the list is empty.

The node is Pinned in memory, as moving it to a different memory location while it is in the list would corrupt the links pointing to that node.

This operation should complete in O(1) time.

Remove an arbitrary node from the list.

This returns a Handle that owns the popped element. Dropping the Handle will drop the element.

Safety

The caller must ensure that the removed node is an element of this linked list, and not any other linked list.

Returns a CursorMut starting at the first element.

The CursorMut type can be used as a mutable Iterator. In addition, however, it also permits modifying the structure of the list by inserting or removing elements at the cursor’s current position.

Returns a CursorMut s+tarting at the last element.

The CursorMut type can be used as a mutable Iterator. In addition, however, it also permits modifying the structure of the list by inserting or removing elements at the cursor’s current position.

Returns a Cursor starting at the first element.

The Cursor type can be used as Iterator over this list. In addition, it may be seeked back and forth to an arbitrary position in the list.

Returns a CursorMut s+tarting at the last element.

The Cursor type can be used as Iterator over this list. In addition, it may be seeked back and forth to an arbitrary position in the list.

Returns an iterator over the items in this list, by reference.

Returns an iterator over the items in this list, by mutable reference.

Returns an iterator which uses a closure to determine if an element should be removed from the list.

If the closure returns true, then the element is removed and yielded. If the closure returns false, the element will remain in the list and will not be yielded by the iterator.

Note that unlike the drain_filter method on std::collections::LinkedList, the closure is not permitted to mutate the elements of the list, as a mutable reference could be used to improperly unlink list nodes.

Trait Implementations

Formats the value using the given formatter. Read more

Executes the destructor for this type. Read more

Extends a collection with the contents of an iterator. Read more

🔬This is a nightly-only experimental API. (extend_one)

Extends a collection with exactly one element.

🔬This is a nightly-only experimental API. (extend_one)

Reserves capacity in a collection for the given number of additional elements. Read more

Creates a value from an iterator. Read more

The type of the elements being iterated over.

Which kind of iterator are we turning this into?

Creates an iterator from a value. Read more

The type of the elements being iterated over.

Which kind of iterator are we turning this into?

Creates an iterator from a value. Read more

The type of the elements being iterated over.

Which kind of iterator are we turning this into?

Creates an iterator from a value. Read more

Auto Trait Implementations

Blanket Implementations

Gets the TypeId of self. Read more

Immutably borrows from an owned value. Read more

Mutably borrows from an owned value. Read more

Returns the argument unchanged.

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

The type returned in the event of a conversion error.

Performs the conversion.

The type returned in the event of a conversion error.

Performs the conversion.