Skip to content

Commit da0b20f

Browse files
committed
Add too-many-lists
1 parent 34bc5cc commit da0b20f

File tree

13 files changed

+2527
-0
lines changed

13 files changed

+2527
-0
lines changed

README.org

+5
Original file line numberDiff line numberDiff line change
@@ -63,3 +63,8 @@ The official rust book - [[https://github.com/rust-lang/book][The Rust Programmi
6363
- [[file:the-book/minigrep/src/main.rs][chapter 12: building a command line program]]
6464
- [[file:the-book/add/adder/src/main.rs][chapter 14.3: cargo workspaces]]
6565
- [[file:the-book/hello/src/bin/main.rs][chapter 20: building a multithreaded web server]]
66+
67+
* Learn Rust With Entirely Too Many Linked Lists
68+
- [[https://rust-unofficial.github.io/too-many-lists/][tutorial]]
69+
- [[https://course.rs/too-many-lists/intro.html][tutorial (cn)]]
70+
- [[file:too-many-lists/lists/src/lib.rs][code]]

too-many-lists/lists/Cargo.lock

+7
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

too-many-lists/lists/Cargo.toml

+8
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
[package]
2+
name = "lists"
3+
version = "0.1.0"
4+
edition = "2021"
5+
6+
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
7+
8+
[dependencies]

too-many-lists/lists/src/fifth.rs

+109
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
use std::ptr;
2+
3+
// pub struct List<'a, T> {
4+
pub struct List<T> {
5+
head: Link<T>,
6+
// tail: Option<&'a mut Node<T>>,
7+
tail: *mut Node<T>, // DANGER
8+
}
9+
10+
type Link<T> = Option<Box<Node<T>>>;
11+
12+
struct Node<T> {
13+
elem: T,
14+
next: Link<T>,
15+
}
16+
17+
// impl<'a, T> List<'a, T> {
18+
impl<T> List<T> {
19+
pub fn new() -> Self {
20+
Self {
21+
head: None,
22+
// tail: None,
23+
tail: ptr::null_mut(),
24+
}
25+
}
26+
27+
// pub fn push(&'a mut self, elem: T) {
28+
pub fn push(&mut self, elem: T) {
29+
// let new_tail = Box::new(Node { elem, next: None });
30+
// let new_tail = match self.tail.take() {
31+
// Some(mut old_tail) => {
32+
// old_tail.next = Some(new_tail);
33+
// old_tail.next.as_deref_mut()
34+
// }
35+
// None => {
36+
// self.head = Some(new_tail);
37+
// self.head.as_deref_mut()
38+
// }
39+
// };
40+
// self.tail = new_tail;
41+
42+
let mut new_tail = Box::new(Node { elem, next: None });
43+
44+
let raw_tail: *mut _ = &mut *new_tail;
45+
if !self.tail.is_null() {
46+
unsafe {
47+
(*self.tail).next = Some(new_tail);
48+
}
49+
} else {
50+
self.head = Some(new_tail);
51+
}
52+
self.tail = raw_tail;
53+
}
54+
55+
pub fn pop(&mut self) -> Option<T> {
56+
self.head.take().map(|head| {
57+
let head = *head;
58+
self.head = head.next;
59+
if self.head.is_none() {
60+
// self.tail = None;
61+
self.tail = ptr::null_mut();
62+
}
63+
head.elem
64+
})
65+
}
66+
}
67+
68+
#[cfg(test)]
69+
mod tests {
70+
use super::*;
71+
72+
#[test]
73+
fn basics() {
74+
let mut list = List::new();
75+
76+
// Check empty list behaves right
77+
assert_eq!(list.pop(), None);
78+
79+
// Populate list
80+
list.push(1);
81+
list.push(2);
82+
list.push(3);
83+
84+
// Check noraml removal
85+
assert_eq!(list.pop(), Some(1));
86+
assert_eq!(list.pop(), Some(2));
87+
88+
// Push some more just to make sure nothing's corrupted
89+
list.push(4);
90+
list.push(5);
91+
92+
// Check normal removal
93+
assert_eq!(list.pop(), Some(3));
94+
assert_eq!(list.pop(), Some(4));
95+
96+
// Check exhaustion
97+
assert_eq!(list.pop(), Some(5));
98+
assert_eq!(list.pop(), None);
99+
100+
// Check the exhaustion case fixed the pointer right
101+
list.push(6);
102+
list.push(7);
103+
104+
// Check normal removal
105+
assert_eq!(list.pop(), Some(6));
106+
assert_eq!(list.pop(), Some(7));
107+
assert_eq!(list.pop(), None);
108+
}
109+
}

0 commit comments

Comments
 (0)