mini_linked_list/
lib.rs

1//! # Linked List
2//! 
3//! Implements a simple linked list using Heap memory.
4//! Currently, there's an implementation only for the i32 primitive type.
5pub struct LinkedList<T> {
6    pub val: Option<T>,
7    pub next: Option<Box<LinkedList<T>>>,
8}
9pub struct PopLeftResult<T> {
10    pub val: Option<T>,
11    pub list: Option<Box<LinkedList<T>>>
12}
13
14impl LinkedList<i32> {
15    /// # Creates an empty LinkedList that may hold i32 values
16    /// 
17    /// # Example
18    /// ```
19    /// let list = mini_linked_list::LinkedList::<i32>::new();
20    /// ```
21    pub fn new() -> LinkedList<i32>{
22        LinkedList {
23            val: None,
24            next: None,
25        }
26    }
27    /// # Adds an element to the right side of the list
28    /// 
29    /// This method uses O(N) operations, as it needs to traverse
30    /// the entire list before appending the new value to the end of the list.
31    /// 
32    /// # Example
33    /// ```
34    /// let mut list = mini_linked_list::LinkedList::<i32>::new();
35    /// list.push_right(1);
36    /// list.push_right(2);
37    /// list.push_right(3);
38    /// list.push_right(4);
39    /// assert_eq!(list.collect(), vec![1,2,3,4]);
40    /// ```
41    pub fn push_right(&mut self, x: i32) {
42        let mut node = self;
43        while node.next.is_some() {
44            node = node.next.as_mut().unwrap();
45        }
46        node.next = Some(Box::new(LinkedList{
47            val: Some(x),
48            next: None,
49        }))
50    }
51    /// # Adds an element to the left side of the list
52    /// 
53    /// This method works in O(1) operation, as it replaces the head of the list
54    /// with a new one and no traversal thus is required.
55    /// 
56    /// The method returns the new memory address of the list that must be handled
57    /// by the caller (typically reassigning the variable).
58    /// 
59    /// # Example
60    /// ```
61    /// use mini_linked_list::LinkedList;
62    /// let mut list: LinkedList<i32> = LinkedList::<i32>::new();
63    /// list = list.push_left(1);
64    /// list = list.push_left(2);
65    /// list = list.push_left(3);
66    /// list = list.push_left(4);
67    /// assert_eq!(list.collect(), vec![4,3,2,1]);
68    /// ```
69    pub fn push_left(self, x: i32) -> LinkedList<i32>{
70        let node= LinkedList::<i32> {
71            val: Some(x),
72            next: Some(Box::new(self))
73        };
74        node
75    }
76
77    /// # Pops the List head on the left side, returning a PopLeftResult
78    /// 
79    /// This operation works in O(1), as it only pops the head and
80    /// no traversal is required.
81    /// 
82    /// It's usage is not so straightforward, however, as it requires
83    /// the caller to replace the reference to the list head with the
84    /// address returned by this method, inside `PopLeftResult.list`
85    /// 
86    /// It's advised to not call `unwrap` directly in `PopLeftResult.list``
87    /// directly, but rather rely on safer `Option` methods.
88    /// 
89    /// # Example
90    /// 
91    /// ```
92    /// use mini_linked_list::{LinkedList, PopLeftResult};
93    /// let mut list: LinkedList<i32> = LinkedList::<i32>::new();
94    /// list.push_right(1);
95    /// list.push_right(2);
96    /// 
97    /// let result: PopLeftResult<i32> = list.pop_left();
98    /// let list = result.list.unwrap();
99    /// 
100    /// assert_eq!(list.collect(), vec![2]);
101    /// assert_eq!(result.val.unwrap(), 1);
102    /// 
103    /// let result: PopLeftResult<i32> = list.pop_left();
104    /// let list = result.list;
105    /// 
106    /// assert_eq!(list.is_none(), true);
107    /// assert_eq!(result.val.unwrap(), 2);
108    /// ```
109
110    pub fn pop_left(self) -> PopLeftResult<i32> {
111        if self.val.is_some() {
112            return PopLeftResult { val: self.val, list: self.next }
113        }
114        match self.next {
115            Some(node) => PopLeftResult { val: node.val, list: node.next },
116            None => PopLeftResult { val: self.val, list: None }
117        }
118    }
119
120    /// # Pops the List head on the right side.
121    /// 
122    /// This operation works in O(N), as it requires a full traversal
123    /// of the list.
124    /// 
125    /// Whenever possible, prefer relying on the `pop_left` method, as it is more
126    /// efficient.
127    /// 
128    /// # Example
129    /// 
130    /// ```
131    /// use mini_linked_list::LinkedList;
132    /// let mut list: LinkedList<i32> = LinkedList::<i32>::new();
133    /// list.push_right(1);
134    /// list.push_right(2);
135    /// assert_eq!(list.pop_right().unwrap(), 2);
136    /// assert_eq!(list.pop_right().unwrap(), 1);
137    /// assert_eq!(list.pop_right().is_none(), true);
138    /// ```
139    pub fn pop_right(&mut self) -> Option<i32>{
140        let mut node: &mut Option<Box<LinkedList<i32>>> = &mut self.next;
141        let x: Option<i32>;
142        // no next node, need to try to pop self
143        if node.is_none() {
144            let val = self.val;
145            self.val = None;
146            return val
147        }
148        // only one next node, we should return it
149        if node.as_mut().unwrap().next.is_none() {
150            x = node.as_mut().unwrap().val;
151            node.as_mut().unwrap().next = None;
152            node.as_mut().unwrap().val = None;
153            return x;
154        }
155        // we can assume we have at least two valid next aheads
156        else {
157            while node.as_mut().unwrap().next.as_mut().unwrap().next.is_some() {
158                node = &mut node.as_mut().unwrap().next;
159            }
160            x = node.as_mut().unwrap().next.as_mut().unwrap().val;
161            node.as_mut().unwrap().next = None;
162        }
163        return x
164    }
165
166    /// # Collects the list into an Array
167    /// 
168    /// This method is used mostly for debugging and testing,
169    /// but can also be used to iterate over the list without popping
170    /// it's values.
171    /// 
172    /// It's not memory efficient, however, as it copies the entire
173    /// data.
174    /// 
175    /// # Example
176    /// ```
177    /// use mini_linked_list::LinkedList;
178    /// let mut list: LinkedList<i32> = LinkedList::<i32>::new();
179    /// list.push_right(1);
180    /// list.push_right(2);
181    /// assert_eq!(list.collect(), vec![1,2]);
182    /// ```
183    pub fn collect(&self) -> Vec<i32> {
184        let mut result = Vec::<i32>::new();
185        let mut node = self;
186
187        match node.val {
188            Some(val) => result.push(val),
189            _ => ()
190        }
191        while node.next.is_some() {
192            node = node.next.as_ref().unwrap();
193            match node.val {
194                Some(val) => result.push(val),
195                _ => ()
196            }
197        }
198
199        return result;
200
201    }
202}
203
204#[cfg(test)]
205mod tests {
206    use super::*;
207
208    #[test]
209    fn test_linked_list_push_right() {
210        let mut list: LinkedList<i32> = LinkedList::<i32>::new();
211        list.push_right(1);
212        list.push_right(2);
213        list.push_right(3);
214        list.push_right(4);
215        assert_eq!(list.collect(), vec![1,2,3,4]);
216    }
217    #[test]
218    fn test_linked_list_push_left() {
219        let mut list: LinkedList<i32> = LinkedList::<i32>::new();
220        list = list.push_left(1);
221        list = list.push_left(2);
222        list = list.push_left(3);
223        list = list.push_left(4);
224        assert_eq!(list.collect(), vec![4,3,2,1]);
225    }
226    
227    #[test]
228    fn test_linked_list_pop_left() {
229        let mut list: LinkedList<i32> = LinkedList::<i32>::new();
230        list.push_right(1);
231        list.push_right(2);
232        list.push_right(3);
233        list.push_right(4);
234
235        let result = list.pop_left();
236        let list = result.list.unwrap();
237
238        assert_eq!(list.collect(), vec![2,3,4]);
239        assert_eq!(result.val.unwrap(), 1);
240
241        let result = list.pop_left();
242        let list = result.list.unwrap();
243
244        assert_eq!(list.collect(), vec![3,4]);
245        assert_eq!(result.val.unwrap(), 2);
246
247        let result = list.pop_left();
248        let list = result.list.unwrap();
249
250        assert_eq!(list.collect(), vec![4]);
251        assert_eq!(result.val.unwrap(), 3);
252
253        let result = list.pop_left();
254        assert_eq!(result.list.is_none(), true);
255        assert_eq!(result.val.unwrap(), 4);
256
257    }
258
259    #[test]
260    fn test_linked_list_pop_right() {
261        let mut list: LinkedList<i32> = LinkedList::<i32>::new();
262        list.push_right(1);
263        list.push_right(2);
264        list.push_right(3);
265        list.push_right(4);
266 
267        assert_eq!(list.pop_right().unwrap(), 4);
268        assert_eq!(list.pop_right().unwrap(), 3);
269        assert_eq!(list.pop_right().unwrap(), 2);
270        assert_eq!(list.pop_right().unwrap(), 1);
271        assert_eq!(list.pop_right().is_none(), true);
272    }
273
274    #[test]
275    fn test_several_apis() {
276        let mut list: LinkedList<i32> = LinkedList::<i32>::new();
277        list.push_right(1);
278        list.push_right(2);
279        list.push_right(3);
280        list.push_right(4);
281        assert_eq!(list.collect(), vec![1,2,3,4]);
282
283        list = list.push_left(1);
284        list = list.push_left(2);
285        list = list.push_left(3);
286        list = list.push_left(4);
287        assert_eq!(list.collect(), vec![4,3,2,1,1,2,3,4]);
288        let x = list.pop_right();
289        assert_eq!(x.unwrap(), 4);
290        assert_eq!(list.collect(), vec![4,3,2,1,1,2,3]);
291
292        let result = list.pop_left();
293        let list = result.list.unwrap();
294        assert_eq!(list.collect(), vec![3,2,1,1,2,3]);
295        assert_eq!(result.val.unwrap(), 4);
296
297    }
298}