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}