diff --git a/src/lib.rs b/src/lib.rs index 3d1ba28..fd2f177 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,2 +1,3 @@ pub mod first; pub mod second; +pub mod third; diff --git a/src/third.rs b/src/third.rs new file mode 100644 index 0000000..21bdd67 --- /dev/null +++ b/src/third.rs @@ -0,0 +1,108 @@ +use std::rc::Rc; + +pub struct List { + head: Link, +} + +pub struct Iter<'a, T:'a> { + next: Option<&'a Node>, +} + +type Link = Option>>; + +struct Node { + elem: T, + next: Link, +} + +impl List { + pub fn new() -> Self { + List { head: None } + } + + pub fn append(&self, elem: T) -> List { + List { + head: Some(Rc::new(Node { + elem, + next: self.head.clone(), + })) + } + } + + pub fn tail(&self) -> List { + List { + head: self.head.as_ref().and_then(|node| node.next.clone()) + } + } + + pub fn head(&self) -> Option<&T> { + self.head.as_ref().map(|node| &node.elem ) + } + + pub fn iter(&self) -> Iter { + Iter { + next: self.head.as_ref().map(|node| &**node) + } + } +} + +impl<'a, T> Iterator for Iter<'a, T> { + type Item = &'a T; + + fn next(&mut self) -> Option { + self.next.map(|node| { + self.next = node.next.as_ref().map(|node| &**node); + &node.elem + }) + } +} + +impl Drop for List { + fn drop(&mut self) { + let mut head = self.head.take(); + while let Some(node) = head { + if let Ok(mut node) = Rc::try_unwrap(node) { + head = node.next.take(); + } else { + break; + } + } + } +} + +#[cfg(test)] +mod test { + use super::List; + + #[test] + fn basics() { + let list = List::new(); + assert_eq!(list.head(), None); + + let list = list.append(1).append(2).append(3); + assert_eq!(list.head(), Some(&3)); + + let list = list.tail(); + assert_eq!(list.head(), Some(&2)); + + let list = list.tail(); + assert_eq!(list.head(), Some(&1)); + + let list = list.tail(); + assert_eq!(list.head(), None); + + // Make sure empty tail works + let list = list.tail(); + assert_eq!(list.head(), None); + } + + #[test] + fn iter() { + let list = List::new().append(1).append(2).append(3); + + let mut iter = list.iter(); + assert_eq!(iter.next(), Some(&3)); + assert_eq!(iter.next(), Some(&2)); + assert_eq!(iter.next(), Some(&1)); + } +}