Skip to content

Commit b585375

Browse files
Add stack from graph-collections crate
1 parent 27e5b79 commit b585375

4 files changed

Lines changed: 382 additions & 0 deletions

File tree

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
[package]
2+
name = "graph-collections"
3+
version.workspace = true
4+
edition.workspace = true
5+
license.workspace = true
6+
repository.workspace = true
7+
description = "Low-level collections for graph-rs: Stack, Queue, Heap, DisjointSet"
8+
9+
[features]
10+
default = []
11+
12+
[dependencies]
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
#![warn(missing_docs)]
2+
3+
//! # graph-collections
4+
//!
5+
//! Low-level collections for graph-rs: Stack, Queue, Heap, DisjointSet.
6+
7+
mod stack;
8+
pub use stack::Stack;
Lines changed: 121 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,121 @@
1+
/// A LIFO stack backed by a [`Vec`].
2+
///
3+
/// Elements are pushed and popped from the top of the stack.
4+
/// All operations are O(1) amortized.
5+
///
6+
/// # Examples
7+
/// ```
8+
/// use graph_collections::Stack;
9+
/// let mut s: Stack<i32> = Stack::new();
10+
/// s.push(1);
11+
/// s.push(2);
12+
/// assert_eq!(s.pop(), Some(2));
13+
/// assert_eq!(s.len(), 1);
14+
/// assert!(!s.is_empty());
15+
/// ```
16+
#[derive(Debug, Clone, PartialEq)]
17+
pub struct Stack<T> {
18+
data: Vec<T>,
19+
}
20+
21+
impl<T> Default for Stack<T> {
22+
fn default() -> Self {
23+
Self { data: Vec::new() }
24+
}
25+
}
26+
27+
impl<T> From<Vec<T>> for Stack<T> {
28+
fn from(data: Vec<T>) -> Self {
29+
Self { data }
30+
}
31+
}
32+
33+
impl<T> Stack<T> {
34+
/// Creates a new empty stack.
35+
///
36+
/// # Examples
37+
/// ```
38+
/// use graph_collections::Stack;
39+
/// let s: Stack<i32> = Stack::new();
40+
/// assert!(s.is_empty());
41+
/// ```
42+
pub fn new() -> Self {
43+
Self::default()
44+
}
45+
46+
/// Pushes a value onto the top of the stack.
47+
///
48+
/// # Examples
49+
/// ```
50+
/// use graph_collections::Stack;
51+
/// let mut s: Stack<i32> = Stack::new();
52+
/// s.push(10);
53+
/// assert_eq!(s.peek(), Some(&10));
54+
/// ```
55+
pub fn push(&mut self, value: T) {
56+
self.data.push(value);
57+
}
58+
59+
/// Removes and returns the top value, or `None` if the stack is empty.
60+
///
61+
/// # Examples
62+
/// ```
63+
/// use graph_collections::Stack;
64+
/// let mut s: Stack<i32> = Stack::new();
65+
/// s.push(1);
66+
/// s.push(2);
67+
/// assert_eq!(s.pop(), Some(2));
68+
/// assert_eq!(s.pop(), Some(1));
69+
/// assert_eq!(s.pop(), None);
70+
/// ```
71+
#[must_use]
72+
pub fn pop(&mut self) -> Option<T> {
73+
self.data.pop()
74+
}
75+
76+
/// Returns a reference to the top value without removing it,
77+
/// or `None` if the stack is empty.
78+
///
79+
/// # Examples
80+
/// ```
81+
/// use graph_collections::Stack;
82+
/// let mut s: Stack<i32> = Stack::new();
83+
/// s.push(5);
84+
/// assert_eq!(s.peek(), Some(&5));
85+
/// assert_eq!(s.len(), 1); // peek does not remove
86+
/// ```
87+
#[must_use]
88+
pub fn peek(&self) -> Option<&T> {
89+
self.data.last()
90+
}
91+
92+
/// Returns `true` if the stack contains no elements.
93+
///
94+
/// # Examples
95+
/// ```
96+
/// use graph_collections::Stack;
97+
/// let mut s: Stack<i32> = Stack::new();
98+
/// assert!(s.is_empty());
99+
/// s.push(1);
100+
/// assert!(!s.is_empty());
101+
/// ```
102+
#[must_use]
103+
pub fn is_empty(&self) -> bool {
104+
self.data.is_empty()
105+
}
106+
107+
/// Returns the number of elements in the stack.
108+
///
109+
/// # Examples
110+
/// ```
111+
/// use graph_collections::Stack;
112+
/// let mut s: Stack<i32> = Stack::new();
113+
/// s.push(1);
114+
/// s.push(2);
115+
/// assert_eq!(s.len(), 2);
116+
/// ```
117+
#[must_use]
118+
pub fn len(&self) -> usize {
119+
self.data.len()
120+
}
121+
}
Lines changed: 241 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,241 @@
1+
use graph_collections::Stack;
2+
3+
// ── Construction ─────────────────────────────────────────────────────────────
4+
5+
#[test]
6+
fn new_is_empty() {
7+
let s: Stack<i32> = Stack::new();
8+
assert!(s.is_empty());
9+
assert_eq!(s.len(), 0);
10+
}
11+
12+
#[test]
13+
fn default_is_empty() {
14+
let s: Stack<i32> = Stack::default();
15+
assert!(s.is_empty());
16+
assert_eq!(s.len(), 0);
17+
}
18+
19+
#[test]
20+
fn from_vec_empty() {
21+
let s: Stack<i32> = Stack::from(vec![]);
22+
assert!(s.is_empty());
23+
}
24+
25+
#[test]
26+
fn from_vec_preserves_lifo_order() {
27+
let mut s = Stack::from(vec![1, 2, 3]);
28+
// last element of vec becomes top of stack
29+
assert_eq!(s.pop(), Some(3));
30+
assert_eq!(s.pop(), Some(2));
31+
assert_eq!(s.pop(), Some(1));
32+
assert_eq!(s.pop(), None);
33+
}
34+
35+
// ── Push ─────────────────────────────────────────────────────────────────────
36+
37+
#[test]
38+
fn push_single_element() {
39+
let mut s = Stack::new();
40+
s.push(1);
41+
assert!(!s.is_empty());
42+
assert_eq!(s.len(), 1);
43+
}
44+
45+
#[test]
46+
fn push_increases_len() {
47+
let mut s = Stack::new();
48+
s.push(1);
49+
s.push(2);
50+
s.push(3);
51+
assert_eq!(s.len(), 3);
52+
}
53+
54+
#[test]
55+
fn push_many_elements() {
56+
let mut s = Stack::new();
57+
for i in 0..1000 {
58+
s.push(i);
59+
}
60+
assert_eq!(s.len(), 1000);
61+
}
62+
63+
// ── Pop ──────────────────────────────────────────────────────────────────────
64+
65+
#[test]
66+
fn pop_empty_returns_none() {
67+
let mut s: Stack<i32> = Stack::new();
68+
assert_eq!(s.pop(), None);
69+
}
70+
71+
#[test]
72+
fn pop_returns_lifo_order() {
73+
let mut s = Stack::new();
74+
s.push(1);
75+
s.push(2);
76+
s.push(3);
77+
assert_eq!(s.pop(), Some(3));
78+
assert_eq!(s.pop(), Some(2));
79+
assert_eq!(s.pop(), Some(1));
80+
}
81+
82+
#[test]
83+
fn pop_decreases_len() {
84+
let mut s = Stack::new();
85+
s.push(1);
86+
s.push(2);
87+
let _ = s.pop();
88+
assert_eq!(s.len(), 1);
89+
}
90+
91+
#[test]
92+
fn pop_until_empty() {
93+
let mut s = Stack::new();
94+
s.push(1);
95+
s.push(2);
96+
let _ = s.pop();
97+
let _ = s.pop();
98+
assert!(s.is_empty());
99+
assert_eq!(s.pop(), None); // extra pop on empty is safe
100+
}
101+
102+
// ── Peek ─────────────────────────────────────────────────────────────────────
103+
104+
#[test]
105+
fn peek_empty_returns_none() {
106+
let s: Stack<i32> = Stack::new();
107+
assert_eq!(s.peek(), None);
108+
}
109+
110+
#[test]
111+
fn peek_returns_top() {
112+
let mut s = Stack::new();
113+
s.push(1);
114+
s.push(2);
115+
assert_eq!(s.peek(), Some(&2));
116+
}
117+
118+
#[test]
119+
fn peek_does_not_remove() {
120+
let mut s = Stack::new();
121+
s.push(42);
122+
assert_eq!(s.peek(), Some(&42));
123+
assert_eq!(s.peek(), Some(&42)); // still there
124+
assert_eq!(s.len(), 1);
125+
}
126+
127+
#[test]
128+
fn peek_reflects_latest_push() {
129+
let mut s = Stack::new();
130+
s.push(1);
131+
assert_eq!(s.peek(), Some(&1));
132+
s.push(2);
133+
assert_eq!(s.peek(), Some(&2)); // updated after new push
134+
}
135+
136+
// ── is_empty / len ───────────────────────────────────────────────────────────
137+
138+
#[test]
139+
fn is_empty_true_on_new() {
140+
let s: Stack<i32> = Stack::new();
141+
assert!(s.is_empty());
142+
}
143+
144+
#[test]
145+
fn is_empty_false_after_push() {
146+
let mut s = Stack::new();
147+
s.push(1);
148+
assert!(!s.is_empty());
149+
}
150+
151+
#[test]
152+
fn is_empty_true_after_full_drain() {
153+
let mut s = Stack::new();
154+
s.push(1);
155+
let _ = s.pop();
156+
assert!(s.is_empty());
157+
}
158+
159+
// ── Clone / PartialEq ────────────────────────────────────────────────────────
160+
161+
#[test]
162+
fn clone_is_independent() {
163+
let mut original = Stack::new();
164+
original.push(1);
165+
original.push(2);
166+
167+
let mut cloned = original.clone();
168+
cloned.push(3);
169+
170+
// original is unaffected
171+
assert_eq!(original.len(), 2);
172+
assert_eq!(cloned.len(), 3);
173+
}
174+
175+
#[test]
176+
fn equality_same_elements() {
177+
let mut a = Stack::new();
178+
a.push(1);
179+
a.push(2);
180+
181+
let mut b = Stack::new();
182+
b.push(1);
183+
b.push(2);
184+
185+
assert_eq!(a, b);
186+
}
187+
188+
#[test]
189+
fn inequality_different_elements() {
190+
let mut a = Stack::new();
191+
a.push(1);
192+
193+
let mut b = Stack::new();
194+
b.push(2);
195+
196+
assert_ne!(a, b);
197+
}
198+
199+
#[test]
200+
fn inequality_different_lengths() {
201+
let mut a = Stack::new();
202+
a.push(1);
203+
a.push(2);
204+
205+
let mut b = Stack::new();
206+
b.push(1);
207+
208+
assert_ne!(a, b);
209+
}
210+
211+
// ── Edge Cases ───────────────────────────────────────────────────────────────
212+
213+
#[test]
214+
fn push_pop_interleaved() {
215+
let mut s = Stack::new();
216+
s.push(1);
217+
s.push(2);
218+
assert_eq!(s.pop(), Some(2));
219+
s.push(3);
220+
assert_eq!(s.pop(), Some(3));
221+
assert_eq!(s.pop(), Some(1));
222+
assert_eq!(s.pop(), None);
223+
}
224+
225+
#[test]
226+
fn works_with_strings() {
227+
let mut s = Stack::new();
228+
s.push("hello");
229+
s.push("world");
230+
assert_eq!(s.pop(), Some("world"));
231+
assert_eq!(s.pop(), Some("hello"));
232+
}
233+
234+
#[test]
235+
fn works_with_option_type() {
236+
let mut s: Stack<Option<i32>> = Stack::new();
237+
s.push(Some(1));
238+
s.push(None);
239+
assert_eq!(s.pop(), Some(None));
240+
assert_eq!(s.pop(), Some(Some(1)));
241+
}

0 commit comments

Comments
 (0)