Skip to content

Commit c32a24c

Browse files
Congyu WANGCongyu WANG
authored andcommitted
update readme
1 parent c054aa4 commit c32a24c

File tree

1 file changed

+22
-111
lines changed

1 file changed

+22
-111
lines changed

README.md

Lines changed: 22 additions & 111 deletions
Original file line numberDiff line numberDiff line change
@@ -1,126 +1,37 @@
1-
# Intrusive Circular Doubly Linked List in Rust
1+
# Intrusive Circular Linked List in Rust
22

3-
Learning how to do cdlist in Rust:
4-
Let the elements hold the ownership, instead of the collection.
3+
## Introduction
54

6-
## Usage
5+
The `cdlist` crate implements a non-thread-safe, intrusive, doubly-linked list in Rust. Its primary characteristic is the inclusion of link pointers within the data structures themselves, rather than in separate node wrappers. This approach enhances memory and performance efficiency but requires careful handling of ownership and safety, which this crate has taken care of.
76

8-
See tests as examples.
7+
## Characteristics
98

10-
```rust
11-
use cdlist::LinkNode;
9+
- **Intrusive Design**: Nodes contain links to their neighbors, reducing overhead.
10+
- **Non-Thread-Safe**: Optimized for single-threaded environments, avoiding the complexity and overhead of synchronization.
11+
- **Self-Ownership**: Nodes own their data and their position within the list. Dropping a data automatically delists it.
12+
- **Memory Safety**: Utilizes pinning to maintain the integrity of self-references within nodes, ensuring safe usage of the data structure.
1213

13-
#[test]
14-
fn deref_mut() {
15-
let mut node0 = LinkNode::new(1);
16-
let node1 = LinkNode::new(2);
17-
*node0 += *node1;
18-
assert_eq!(3, *node0);
19-
}
20-
21-
#[test]
22-
fn iter_single() {
23-
let node0 = LinkNode::new(0);
24-
assert_eq!(collect(&node0), vec![0]);
25-
}
14+
## Example Usage
2615

27-
#[test]
28-
fn iter() {
29-
let mut nodes = (0..10).map(LinkNode::new).collect::<Vec<_>>();
30-
connect_all(&mut nodes, 0, 10);
31-
assert_eq!(collect(&nodes[0]), (0..10).collect::<Vec<_>>());
32-
assert_eq!(collect_rev(&nodes[9]), (0..10).rev().collect::<Vec<_>>());
33-
}
34-
35-
#[test]
36-
fn iter_mut() {
37-
let mut nodes = (0..10).map(LinkNode::new).collect::<Vec<_>>();
38-
connect_all(&mut nodes, 0, 10);
39-
let mut j = 0;
40-
nodes[5].for_each_mut(|i| {
41-
*i += j;
42-
j += 1;
43-
});
44-
j = 0;
45-
assert_eq!(collect(&nodes[0]), vec![5, 7, 9, 11, 13, 5, 7, 9, 11, 13]);
46-
nodes[9].for_each_mut_rev(|i| {
47-
*i += j;
48-
j += 1;
49-
});
50-
assert_eq!(
51-
collect(&nodes[0]),
52-
vec![14, 15, 16, 17, 18, 9, 10, 11, 12, 13]
53-
);
54-
}
16+
```rust
17+
use cdlist::LinkNode;
5518

56-
#[test]
57-
fn pop_self() {
58-
let mut node0 = LinkNode::new(0);
59-
node0.take();
60-
assert_eq!(collect(&node0), vec![0]);
61-
}
19+
fn main() {
20+
let mut node1 = LinkNode::new(1);
21+
let mut node2 = LinkNode::new(2);
6222

63-
#[test]
64-
fn requeue() {
65-
let mut n0 = LinkNode::new(0);
66-
let mut n1 = LinkNode::new(1);
67-
let mut n2 = LinkNode::new(2);
68-
n0.add(&mut n1);
69-
n1.add(&mut n2);
70-
assert_eq!(collect(&n0), vec![0, 1, 2]);
71-
n2.add(&mut n1);
72-
assert_eq!(collect(&n0), vec![0, 2, 1]);
73-
assert_eq!(collect(&n2), vec![2, 1, 0]);
74-
}
23+
node1.add(&mut node2); // Adds node2 after node1
7524

76-
#[test]
77-
fn take() {
78-
let mut nodes = (0..10).map(LinkNode::new).collect::<Vec<_>>();
79-
connect_all(&mut nodes, 0, 10);
80-
assert_eq!(collect(&nodes[0]), (0..10).collect::<Vec<_>>());
81-
let to_take = [0, 2, 4, 6, 8];
82-
for i in to_take {
83-
nodes[i].take();
84-
}
85-
for i in to_take {
86-
assert_eq!(collect(&nodes[i]), vec![i]);
87-
}
88-
assert_eq!(collect(&nodes[1]), vec![1, 3, 5, 7, 9]);
25+
node1.for_each(|&data| println!("{}", data)); // Prints: 1 2
8926
}
27+
```
9028

91-
#[test]
92-
fn add() {
93-
let mut nodes = (0..10).map(LinkNode::new).collect::<Vec<_>>();
94-
connect_all(&mut nodes, 0, 5);
95-
connect_all(&mut nodes, 5, 10);
96-
assert_eq!(collect(&nodes[0]), (0..5).collect::<Vec<_>>());
97-
assert_eq!(collect(&nodes[5]), (5..10).collect::<Vec<_>>());
98-
let (n0, n1) = nodes.split_at_mut(5);
99-
n0[2].add(&mut n1[2]);
100-
assert_eq!(collect(&nodes[0]), vec![0, 1, 2, 7, 3, 4]);
101-
assert_eq!(collect_rev(&nodes[4]), vec![4, 3, 7, 2, 1, 0]);
102-
assert_eq!(collect(&nodes[5]), vec![5, 6, 8, 9]);
103-
assert_eq!(collect_rev(&nodes[9]), vec![9, 8, 6, 5]);
104-
}
29+
## Implementation Insights
10530

106-
// helper functions
31+
- **Pinning**: Nodes are pinned (`Pin<Box<Inner<T>>>`) to prevent invalidation of references due to memory movement, crucial for the safety of self-referential structures.
10732

108-
fn collect<T: Copy>(node: &LinkNode<T>) -> Vec<T> {
109-
let mut vec = vec![];
110-
node.for_each(|&i| vec.push(i));
111-
vec
112-
}
33+
## Next Steps
11334

114-
fn collect_rev<T: Copy>(node: &LinkNode<T>) -> Vec<T> {
115-
let mut vec = vec![];
116-
node.for_each_rev(|&i| vec.push(i));
117-
vec
118-
}
35+
To really make this crate useful, it needs to allow multi-threading, which can be enabled behind a feature flag. Though, this would involves a lot of work to ensure racing-conditions are handled correctly.
11936

120-
fn connect_all<T>(nodes: &mut [LinkNode<T>], start: usize, end: usize) {
121-
for i in start..(end - 1) {
122-
let (ni, nj) = nodes[i..].split_at_mut(1);
123-
ni[0].add(&mut nj[0])
124-
}
125-
}
126-
```
37+
This crate is mainly a learning exercise.

0 commit comments

Comments
 (0)