diff --git a/src/lib.rs b/src/lib.rs index 59eb7c7..ed55793 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,2 +1,3 @@ pub mod bad; pub mod ok; +pub mod persistent; diff --git a/src/persistent.rs b/src/persistent.rs new file mode 100644 index 0000000..20f9a62 --- /dev/null +++ b/src/persistent.rs @@ -0,0 +1,105 @@ +use std::sync::Arc; + +pub struct List { + head: Link, +} + +type Link = Option>>; + +struct Node { + value: T, + next: Link, +} + +impl List { + pub fn new () -> Self { + List { head: None } + } + + pub fn prepend (&self, value: T) -> List { + List { head: Some(Arc::new(Node { + value, 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.value) + } + + pub fn iter (&self) -> Iter { + Iter { next: self.head.as_deref()} + } +} + +pub struct Iter <'a, T> { + next: Option<&'a 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_deref(); + &node.value + }) + } +} + +impl Drop for List { + fn drop (&mut self) { + let mut head = self.head.take(); + + while let Some(node) = head { + if let Ok(mut node) = Arc::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.prepend(1).prepend(2).prepend(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().prepend(1).prepend(2).prepend(3); + + let mut iter = list.iter(); + assert_eq!(iter.next(), Some(&3)); + assert_eq!(iter.next(), Some(&2)); + assert_eq!(iter.next(), Some(&1)); + } + + +}