use std::{cell::RefCell, rc::Rc}; /// Definition of an element of the list /// /// Contain one stored item and the previous/next element of the list struct ListNode { item: T, next: Link, prev: Link, } impl ListNode { fn new(item: T) -> Self { Self { item, next: None, prev: None, } } } type Link = Option>>>; /// Defintion of the generic linked list #[derive(Default)] pub struct DoublyLinkedList { head: Link, tail: Link, size: usize, } impl DoublyLinkedList { pub fn new() -> Self { Self { head: None, tail: None, size: 0, } } pub fn is_empty(&self) -> bool { self.len() == 0 } pub fn len(&self) -> usize { self.size } /// Add the item at the end of the list pub fn push_back(&mut self, item: T) { let node = Rc::new(RefCell::new(ListNode::new(item))); if let Some(prev_tail) = self.tail.take() { prev_tail.borrow_mut().next = Some(Rc::clone(&node)); node.borrow_mut().prev = Some(prev_tail); self.tail = Some(node); self.size += 1; } else { self.head = Some(Rc::clone(&node)); self.tail = Some(node); self.size = 1; } } /// Add the item at the start of the list pub fn push_front(&mut self, item: T) { let node = Rc::new(RefCell::new(ListNode::new(item))); if let Some(prev_head) = self.head.take() { prev_head.borrow_mut().prev = Some(Rc::clone(&node)); node.borrow_mut().next = Some(prev_head); self.head = Some(node); self.size += 1; } else { self.head = Some(Rc::clone(&node)); self.tail = Some(node); self.size = 1; } } /// Retrieve and remove the item at the end of the list pub fn pop_back(&mut self) -> Option { self.tail.take().map(|prev_tail| { self.size -= 1; match prev_tail.borrow_mut().prev.take() { Some(node) => { node.borrow_mut().next = None; self.tail = Some(node); } None => { self.head.take(); } } Rc::try_unwrap(prev_tail).ok().unwrap().into_inner().item }) } /// Retrieve and remove the item at the start of the list pub fn pop_front(&mut self) -> Option { self.head.take().map(|prev_head| { self.size -= 1; match prev_head.borrow_mut().next.take() { Some(node) => { node.borrow_mut().prev = None; self.head = Some(node); } None => { self.tail.take(); } } Rc::try_unwrap(prev_head).ok().unwrap().into_inner().item }) } } impl Drop for DoublyLinkedList { /// list destructor, safely desallocate smart pointer Rc fn drop(&mut self) { while let Some(node) = self.head.take() { let _ = node.borrow_mut().prev.take(); self.head = node.borrow_mut().next.take(); } self.tail.take(); } } impl IntoIterator for DoublyLinkedList { type Item = as Iterator>::Item; type IntoIter = ListIterator; fn into_iter(self) -> Self::IntoIter { Self::IntoIter::new(self) } } pub struct ListIterator { list: DoublyLinkedList, } impl ListIterator { fn new(list: DoublyLinkedList) -> Self { Self { list } } } impl Iterator for ListIterator { type Item = T; fn next(&mut self) -> Option { self.list.pop_front() } } impl DoubleEndedIterator for ListIterator { fn next_back(&mut self) -> Option { self.list.pop_back() } } pub type List = DoublyLinkedList; pub type ListInt = List; #[cfg(test)] mod test { use super::DoublyLinkedList; #[test] fn test_list_push() { let mut list = DoublyLinkedList::new(); list.push_back(5); list.push_front(45); assert_eq!(list.pop_front().unwrap(), 45); assert_eq!(list.pop_front().unwrap(), 5); } }