Circular Doubly Linked List
A high-performance, memory-safe Circular Doubly Linked List implementation written in Rust. This crate provides a safe API wrapper around unsafe core operations, following patterns similar to Rust's standard library collections.
Table of Contents
- Overview
- Features
- Installation
- Quick Start
- API Documentation
- Safety Guarantees
- Performance
- Use Cases
- Testing
- Contributing
- License
Overview
A circular doubly linked list is a data structure where each node contains:
- A data element of type
T - A pointer to the next node in the sequence
- A pointer to the previous node in the sequence
The list is "circular" because the last node points back to the first node, and the first node points back to the last node, forming a closed loop. This design enables O(1) access to both ends of the list and efficient rotation operations.
Features
- O(1) insertion and deletion at both front and back ends
- O(1) access to front and back elements via explicit head and tail pointers
- O(1) rotation operations (left and right)
- Safe API wrappers around unsafe core pointer operations
- Full iterator support (
Iter,IterMut,IntoIter) - Double-ended iteration support (
DoubleEndedIterator) no_stdcompatible (does not require the Rust standard library)- Comprehensive test coverage with edge case handling
- Implements standard traits (
Clone,Debug,Extend,FromIterator,IntoIterator,Default)
📦 Installation
Add this to your Cargo.toml:
[]
= "0.1.0"
Or install via cargo:
Quick Start
use CircularDoublyLinkedList;
API Documentation
Core Operations
Creation
// Create a new empty list
let list: = new;
// Create with capacity hint (doesn't pre-allocate)
let list = with_capacity;
// Create using Default trait
let list = default;
Insertion
let mut list = new;
// Push to front (O(1))
list.push_front;
list.push_front;
// Push to back (O(1))
list.push_back;
list.push_back;
// Insert at specific position (O(n))
list.insert_after; // Insert 100 after position 1
Access
let mut list = new;
list.push_back;
list.push_back;
list.push_back;
// Immutable access (O(1))
assert_eq!;
assert_eq!;
// Mutable access (O(1))
if let Some = list.front_mut
if let Some = list.back_mut
Removal
let mut list = new;
list.push_back;
list.push_back;
list.push_back;
// Pop from front (O(1))
assert_eq!;
// Pop from back (O(1))
assert_eq!;
// Remove at position (O(n))
assert_eq!;
// Remove from empty list
assert_eq!;
Rotation
let mut list = new;
list.push_back;
list.push_back;
list.push_back;
// Rotate left: [1, 2, 3] → [2, 3, 1]
list.rotate_left;
// Rotate right: [2, 3, 1] → [1, 2, 3]
list.rotate_right;
Iterator Support
let mut list = new;
list.push_back;
list.push_back;
list.push_back;
// Immutable iteration
for item in list.iter
// Mutable iteration
for item in list.iter_mut
// Consuming iteration
for item in list.into_iter
// Reverse iteration
for item in list.iter.rev
// Iterator adapters
let sum: i32 = list.iter.filter.sum;
let vec: = list.iter.map.collect;
Trait Implementations
// Clone
let list1 = from_iter;
let list2 = list1.clone;
// Debug
println!; // Output: [1, 2, 3]
// Extend
let mut list = new;
list.extend;
// FromIterator / collect
let list: = .collect;
// IntoIterator
let vec: = list.into_iter.collect;
Safety Guarantees
This implementation uses unsafe code internally for raw pointer manipulation. However, all public APIs are safe and enforce Rust's ownership and borrowing rules. The unsafe blocks are carefully audited to prevent:
| Issue | Prevention |
|---|---|
| Use-after-free | Nodes are only accessed while valid |
| Double-free | Each node is deallocated exactly once |
| Data races | Single-threaded design with no shared mutable state |
| Null pointer dereferences | All pointers are NonNull and validated |
| Memory leaks | Drop implementation ensures all nodes are freed |
Internal Invariants
The following invariants are maintained throughout the list's lifetime:
- If the list is non-empty, both
headandtailpoint to valid nodes - If the list is empty, both
headandtailareNone - If the list has one element,
head == tail - If the list has multiple elements:
tail.next == head(circular forward link)head.prev == tail(circular backward link)
- The
lengthfield accurately reflects the number of nodes
Performance Characteristics
| Operation | Time Complexity | Space Complexity |
|---|---|---|
new() |
O(1) | O(1) |
push_front() |
O(1) | O(1) |
push_back() |
O(1) | O(1) |
pop_front() |
O(1) | O(1) |
pop_back() |
O(1) | O(1) |
front() |
O(1) | O(1) |
back() |
O(1) | O(1) |
insert_after() |
O(n) | O(1) |
remove_at() |
O(n) | O(1) |
len() |
O(1) | O(1) |
is_empty() |
O(1) | O(1) |
clear() |
O(n) | O(1) |
rotate_left() |
O(1) | O(1) |
rotate_right() |
O(1) | O(1) |
Use Cases
Queue (FIFO)
let mut queue = new;
// Enqueue
queue.push_back;
queue.push_back;
queue.push_back;
// Dequeue
while let Some = queue.pop_front
Stack (LIFO)
let mut stack = new;
// Push
stack.push_front;
stack.push_front;
stack.push_front;
// Pop
while let Some = stack.pop_front
Deque (Double-Ended Queue)
let mut deque = new;
// Add from both ends
deque.push_front;
deque.push_back;
deque.push_front;
deque.push_back;
// Remove from both ends
deque.pop_front;
deque.pop_back;
Circular Buffer
let mut buffer = new;
// Initialize buffer
for i in 0..5
// Rotate through all positions
for _ in 0..5
Testing
Run the test suite:
# Run all tests
# Run with output
# Run specific test category
Documentation
Generate and view the documentation locally:
# Generate documentation
# Open in browser
Online documentation is available at docs.rs.
Contributing
Contributions are welcome! Please follow these guidelines:
Reporting Issues
- Check existing issues before creating a new one
- Provide a clear description of the problem
- Include minimal reproducible examples when possible
- Specify your Rust version and platform
Submitting Pull Requests
- Fork the repository
- Create a feature branch (
git checkout -b feature/amazing-feature) - Make your changes with comprehensive tests
- Ensure all tests pass (
cargo test) - Run clippy for linting (
cargo clippy) - Format your code (
cargo fmt) - Submit a pull request with a clear description
Code Style
- Follow Rust standard library conventions
- Document all public APIs with rustdoc comments
- Include examples in documentation
- Maintain test coverage for new features
License
This project is licensed under the MIT License - see the LICENSE file for details.
at your option.