stack_trait/lib.rs
1/// A convenience type alias that should be easier to read and understand.
2pub type LIFOVecEntry<'a, T> = LIFOEntry<'a, Vec<T>>;
3
4/// An "entry" object corresponding to the top element of the stack.
5///
6/// Existence of this object guarantees that the stack is not empty.
7///
8/// In a vector, this is an object representing the last element.
9pub struct LIFOEntry<'a, C: ?Sized>(&'a mut C);
10
11impl<'a, C: ?Sized + Stack> LIFOEntry<'a, C> {
12 /// Creates a new "entry" object from the mutable reference to the container.
13 ///
14 /// ## Safety
15 ///
16 /// The stack must not be empty.
17 pub unsafe fn new(stack: &'a mut C) -> Self {
18 // SAFETY: The stack is not empty, so the call is safe.
19 Self(stack)
20 }
21
22 /// Pops the LIFO element from the stack.
23 pub fn pop_pointee(self) -> C::Item {
24 let LIFOEntry(stack) = self;
25 // SAFETY: The stack is not empty by the virtue of
26 // existence of the LIFOEntry object, so the call is safe.
27 unsafe { stack.s_pop_unchecked() }
28 }
29}
30
31impl<'a, C: ?Sized + Stack> std::ops::Deref for LIFOEntry<'a, C> {
32 type Target = C::Item;
33
34 fn deref(&self) -> &Self::Target {
35 let LIFOEntry(stack) = self;
36 // SAFETY: The stack is not empty, so the call is safe.
37 unsafe { stack.lifo_ref_unchecked() }
38 }
39}
40
41impl<'a, C: ?Sized + Stack> std::ops::DerefMut for LIFOEntry<'a, C> {
42 fn deref_mut(&mut self) -> &mut Self::Target {
43 let LIFOEntry(stack) = self;
44 // SAFETY: The stack is not empty, so the call is safe.
45 unsafe { stack.lifo_mut_unchecked() }
46 }
47}
48
49/// Implementors of this method can be used as a [stack] in DSA terms.
50///
51/// [stack]: https://www.geeksforgeeks.org/stack-data-structure/
52pub trait Stack {
53 /// The type of the items stored in the stack.
54 type Item;
55
56 /// Returns `true` if the stack is empty.
57 fn s_is_empty(&self) -> bool;
58
59 /// Pushes an item to the stack.
60 ///
61 /// For vector, use [`Vec::push`] instead.
62 ///
63 /// ## Also see
64 ///
65 /// * [`Stack::s_push_checked`]
66 // s_ prefix prevents name collision with Vec::push
67 fn s_push(&mut self, item: Self::Item);
68
69 /// Pushes an item to the stack.
70 ///
71 /// ## Notes
72 ///
73 /// For vector, use [`Vec::push`] instead. It is meant primarily for the `heapless::Vec`.
74 ///
75 /// ## Also see
76 ///
77 /// * [`Stack::s_push`]
78 fn s_push_checked(&mut self, item: Self::Item) -> Option<()> {
79 self.s_push(item);
80 Some(())
81 }
82
83 // we don't create chain push because Extend::extend_one API will be better
84
85 /// Pushes an item to the stack and returns an the "entry" object
86 /// corresponding to the pushed element.
87 fn lifo_push(&mut self, item: Self::Item) -> LIFOEntry<Self>;
88
89 /// Pops an item from the stack.
90 ///
91 /// ## Notes
92 ///
93 /// For vector, use [`Vec::pop`] instead.
94 ///
95 /// ## Also see
96 ///
97 /// * [`Stack::s_pop_unchecked`].
98 fn s_pop(&mut self) -> Option<Self::Item>;
99
100 /// Pops an item from the stack without checking if the stack is empty.
101 ///
102 /// ## Safety
103 ///
104 /// The stack must not be empty.
105 ///
106 /// ## Also see
107 ///
108 /// * [`Stack::s_pop`]
109 #[inline]
110 unsafe fn s_pop_unchecked(&mut self) -> Self::Item {
111 self.s_pop().unwrap_unchecked()
112 }
113
114 /// Returns an "entry" object corresponding to the top element of the stack.
115 ///
116 /// ## Notes
117 ///
118 /// This is useful when the entry might need to be used to be dereferenced to
119 /// `&T` and/or `&mut T` and/or be promoted to `T` by popping the item from the stack.
120 ///
121 /// ## Also see
122 ///
123 /// * [`Stack::lifo_unchecked`]
124 #[inline]
125 fn lifo(&mut self) -> Option<LIFOEntry<Self>> {
126 if self.s_is_empty() {
127 None
128 } else {
129 Some(unsafe { LIFOEntry::new(self) })
130 }
131 }
132
133 /// Returns an "entry" object corresponding to the top element of the stack
134 /// without checking if the stack is empty.
135 ///
136 /// ## Safety
137 ///
138 /// The stack must not be empty.
139 ///
140 /// ## Also see
141 ///
142 /// * [`Stack::lifo`]
143 #[inline]
144 unsafe fn lifo_unchecked(&mut self) -> LIFOEntry<Self> {
145 self.lifo().unwrap_unchecked()
146 }
147
148 /// Returns a shared reference to the top element of the stack.
149 ///
150 /// ## Also see
151 ///
152 /// * [`Stack::lifo_ref_unchecked`]
153 /// * [`Stack::lifo`]
154 /// * [`Stack::s_pop`]
155 /// * [`Stack::lifo_mut`]
156 fn lifo_ref(&self) -> Option<&Self::Item>;
157
158 /// Returns a shared reference to the top element of the stack without checking if the stack is empty.
159 ///
160 /// ## Safety
161 ///
162 /// The stack must not be empty.
163 ///
164 /// ## Also see
165 ///
166 /// * [`Stack::lifo_ref`]
167 #[inline]
168 unsafe fn lifo_ref_unchecked(&self) -> &Self::Item {
169 self.lifo_ref().unwrap_unchecked()
170 }
171
172 /// Returns a mutable reference to the top element of the stack.
173 ///
174 /// ## Also see
175 ///
176 /// * [`Stack::lifo_ref`]
177 /// * [`Stack::lifo_mut_unchecked`]
178 /// * [`Stack::lifo`]
179 /// * [`Stack::s_pop`]
180 fn lifo_mut(&mut self) -> Option<&mut Self::Item>;
181
182 /// Returns a mutable reference to the top element of the stack without checking if the stack is empty.
183 ///
184 /// ## Safety
185 ///
186 /// The stack must not be empty.
187 #[inline]
188 unsafe fn lifo_mut_unchecked(&mut self) -> &mut Self::Item {
189 self.lifo_mut().unwrap_unchecked()
190 }
191}
192
193impl<T> Stack for Vec<T> {
194 type Item = T;
195
196 #[inline]
197 fn s_is_empty(&self) -> bool {
198 self.is_empty()
199 }
200
201 #[inline]
202 fn s_push(&mut self, item: Self::Item) {
203 self.push(item);
204 }
205
206 #[inline]
207 fn lifo_push(&mut self, item: Self::Item) -> LIFOEntry<Self> {
208 self.push(item);
209 // We just pushed to the vector, so the vector is not empty.
210 unsafe { self.lifo_unchecked() }
211 }
212
213 #[inline]
214 fn s_pop(&mut self) -> Option<Self::Item> {
215 self.pop()
216 }
217
218 #[inline]
219 fn lifo_ref(&self) -> Option<&Self::Item> {
220 self.last()
221 }
222
223 #[inline]
224 fn lifo_mut(&mut self) -> Option<&mut Self::Item> {
225 self.last_mut()
226 }
227}
228
229#[cfg(test)]
230mod tests {
231 use super::*;
232
233 #[test]
234 fn get_or_insert() {
235 let mut stack = vec![1, 2, 3];
236 let mut entry = stack.lifo_push(4);
237 assert_eq!(*entry, 4);
238 *entry = 5;
239 assert_eq!(*entry, 5);
240 drop(entry);
241 assert_eq!(stack, vec![1, 2, 3, 5]);
242 let entry = stack.lifo().unwrap();
243 assert_eq!(entry.pop_pointee(), 5);
244 assert_eq!(stack, vec![1, 2, 3]);
245 }
246}