From 72d51250c215f4995b17122b8d2f829ea508e2c3 Mon Sep 17 00:00:00 2001 From: Timothy Warren Date: Wed, 13 Mar 2019 09:33:34 -0400 Subject: [PATCH] Add fourth example --- src/first.rs | 1 + src/fourth.rs | 238 ++++++++++++++++++++++++++++++++++++++++++++++++++ src/lib.rs | 1 + src/second.rs | 1 + src/third.rs | 1 + 5 files changed, 242 insertions(+) create mode 100644 src/fourth.rs diff --git a/src/first.rs b/src/first.rs index 9e3fb27..4df9c1c 100644 --- a/src/first.rs +++ b/src/first.rs @@ -1,3 +1,4 @@ +//! # A Bad Stack use std::mem; pub struct List { diff --git a/src/fourth.rs b/src/fourth.rs new file mode 100644 index 0000000..6cea449 --- /dev/null +++ b/src/fourth.rs @@ -0,0 +1,238 @@ +//! # A Bad Safe Deque +use std::rc::Rc; +use std::cell::{Ref, RefCell, RefMut}; + +pub struct List { + head: Link, + tail: Link, +} + +type Link = Option>>>; + +struct Node { + elem: T, + next: Link, + prev: Link, +} + +pub struct IntoIter(List); + +impl Node { + fn new(elem: T) -> Rc> { + Rc::new(RefCell::new(Node { + elem, + prev: None, + next: None, + })) + } +} + +impl List { + pub fn new() -> Self { + List { + head: None, + tail: None, + } + } + + pub fn push_front(&mut self, elem: T) { + let new_head = Node::new(elem); + match self.head.take() { + Some(old_head) => { + old_head.borrow_mut().prev = Some(new_head.clone()); + new_head.borrow_mut().next = Some(old_head); + self.head = Some(new_head); + } + None => { + self.tail = Some(new_head.clone()); + self.head = Some(new_head); + } + } + } + + pub fn pop_front(&mut self) -> Option { + self.head.take().map(|old_head| { + match old_head.borrow_mut().next.take() { + Some(new_head) => { + new_head.borrow_mut().prev.take(); + self.head = Some(new_head); + } + None => { + self.tail.take(); + } + } + Rc::try_unwrap(old_head).ok().unwrap().into_inner().elem + }) + } + + pub fn push_back(&mut self, elem: T) { + let new_tail = Node::new(elem); + match self.tail.take() { + Some(old_tail) => { + old_tail.borrow_mut().next = Some(new_tail.clone()); + new_tail.borrow_mut().prev = Some(old_tail); + self.tail = Some(new_tail); + } + None => { + self.head = Some(new_tail.clone()); + self.tail = Some(new_tail); + } + } + } + + pub fn pop_back(&mut self) -> Option { + self.tail.take().map(|old_tail| { + match old_tail.borrow_mut().prev.take() { + Some(new_tail) => { + new_tail.borrow_mut().next.take(); + self.tail = Some(new_tail); + } + None => { + self.head.take(); + } + } + Rc::try_unwrap(old_tail).ok().unwrap().into_inner().elem + }) + } + + pub fn peek_front(&self) -> Option> { + self.head.as_ref().map(|node| { + Ref::map(node.borrow(), |node| &node.elem) + }) + } + + pub fn peek_front_mut(&mut self) -> Option> { + self.head.as_ref().map(|node| { + RefMut::map(node.borrow_mut(), |node| &mut node.elem) + }) + } + + pub fn peek_back(&self) -> Option> { + self.tail.as_ref().map(|node| { + Ref::map(node.borrow(), |node| &node.elem) + }) + } + + pub fn peek_back_mut(&mut self) -> Option> { + self.tail.as_ref().map(|node| { + RefMut::map(node.borrow_mut(), |node| &mut node.elem) + }) + } + + pub fn into_iter(self) -> IntoIter { + IntoIter(self) + } +} + +impl Drop for List { + fn drop(&mut self) { + while self.pop_front().is_some() {} + } +} + +impl Iterator for IntoIter { + type Item = T; + fn next(&mut self) -> Option { + self.0.pop_front() + } +} + +impl DoubleEndedIterator for IntoIter { + fn next_back(&mut self) -> Option { + self.0.pop_back() + } +} + +#[cfg(test)] +mod test { + use super::List; + + #[test] + fn basics() { + let mut list = List::new(); + + // Check empty list behaves right + assert_eq!(list.pop_front(), None); + + // Populate list + list.push_front(1); + list.push_front(2); + list.push_front(3); + + // Check normal removal + assert_eq!(list.pop_front(), Some(3)); + assert_eq!(list.pop_front(), Some(2)); + + // Push some more just to make sure nothing's corrupted + list.push_front(4); + list.push_front(5); + + // Check normal removal + assert_eq!(list.pop_front(), Some(5)); + assert_eq!(list.pop_front(), Some(4)); + + // Check exhaustion + assert_eq!(list.pop_front(), Some(1)); + assert_eq!(list.pop_front(), None); + + // ---- back ----- + + // Check empty list behaves right + assert_eq!(list.pop_front(), None); + + // Populate list + list.push_back(1); + list.push_back(2); + list.push_back(3); + + // Check normal removal + assert_eq!(list.pop_back(), Some(3)); + assert_eq!(list.pop_back(), Some(2)); + + // Push some more just to make sure nothing's corrupted + list.push_back(4); + list.push_back(5); + + // Check normal removal + assert_eq!(list.pop_back(), Some(5)); + assert_eq!(list.pop_back(), Some(4)); + + // Check exhaustion + assert_eq!(list.pop_back(), Some(1)); + assert_eq!(list.pop_back(), None); + } + + #[test] + fn peek() { + let mut list = List::new(); + assert!(list.peek_front().is_none()); + assert!(list.peek_back().is_none()); + assert!(list.peek_front_mut().is_none()); + assert!(list.peek_back_mut().is_none()); + + list.push_front(1); + list.push_front(2); + list.push_front(3); + + assert_eq!(&*list.peek_front().unwrap(), &3); + assert_eq!(&mut *list.peek_front_mut().unwrap(), &mut 3); + assert_eq!(&*list.peek_back().unwrap(), &1); + assert_eq!(&mut *list.peek_back_mut().unwrap(), &mut 1); + } + + #[test] + fn into_iter() { + let mut list = List::new(); + + list.push_front(1); + list.push_front(2); + list.push_front(3); + + let mut iter = list.into_iter(); + assert_eq!(iter.next(), Some(3)); + assert_eq!(iter.next_back(), Some(1)); + assert_eq!(iter.next(), Some(2)); + assert_eq!(iter.next_back(), None); + assert_eq!(iter.next(), None); + } +} diff --git a/src/lib.rs b/src/lib.rs index fd2f177..3770e8a 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,3 +1,4 @@ pub mod first; pub mod second; pub mod third; +pub mod fourth; diff --git a/src/second.rs b/src/second.rs index d571b69..706b8cb 100644 --- a/src/second.rs +++ b/src/second.rs @@ -1,3 +1,4 @@ +//! # An Ok Stack pub struct List { head: Link, } diff --git a/src/third.rs b/src/third.rs index 21bdd67..4f08ddf 100644 --- a/src/third.rs +++ b/src/third.rs @@ -1,3 +1,4 @@ +//! # A Persistent Stack use std::rc::Rc; pub struct List {