Created
August 29, 2018 07:21
-
-
Save Jeffrey04/85d992570297646cc24b22902ad51582 to your computer and use it in GitHub Desktop.
Implementing Simple Linked List @ Exercism
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
pub struct SimpleLinkedList<T> { | |
head: Option<Box<Node<T>>>, | |
} | |
pub struct Node<T> { | |
data: T, | |
next: Option<Box<Node<T>>>, | |
} | |
impl<T> SimpleLinkedList<T> { | |
pub fn new() -> Self { | |
Self { head: None } | |
} | |
pub fn len(&self) -> usize { | |
self.head.as_ref().map_or(0, |x| x.len()) | |
} | |
pub fn push(&mut self, _element: T) { | |
if self.head.is_none() { | |
std::mem::replace(&mut self.head, Some(Box::new(Node::new(_element)))); | |
} else { | |
let next = self.head.take().unwrap(); | |
std::mem::replace(&mut self.head, Some(Box::new(next.push(_element)))); | |
} | |
} | |
pub fn pop(&mut self) -> Option<T> { | |
if self.head.is_none() { | |
None | |
} else { | |
let mut node = self.head.take().unwrap(); | |
std::mem::swap(&mut node.next, &mut self.head); | |
Some(node.data) | |
} | |
} | |
pub fn peek(&self) -> Option<&T> { | |
match self.head { | |
None => None, | |
ref node => node.as_ref().map(|x| &x.data), | |
} | |
} | |
} | |
impl<T> Node<T> { | |
pub fn new(data: T) -> Self { | |
Self { | |
data: data, | |
next: None, | |
} | |
} | |
fn len(&self) -> usize { | |
1 + self.next.as_ref().map_or(0, |x| x.len()) | |
} | |
fn push(self, _element: T) -> Self { | |
Self { | |
data: _element, | |
next: Some(Box::new(self)), | |
} | |
} | |
} | |
impl<T: Clone> SimpleLinkedList<T> { | |
pub fn rev(&self) -> SimpleLinkedList<T> { | |
rev_recurse(&mut vec![], &self.head).into_iter().fold( | |
SimpleLinkedList::new(), | |
|mut current, incoming| { | |
// this clone is possibly not needed | |
current.push(incoming.clone()); | |
current | |
}, | |
) | |
} | |
} | |
impl<'a, T: Clone> From<&'a [T]> for SimpleLinkedList<T> { | |
fn from(_item: &[T]) -> Self { | |
_item | |
.to_vec() | |
.into_iter() | |
.fold(SimpleLinkedList::new(), |mut current, incoming| { | |
current.push(incoming); | |
current | |
}) | |
} | |
} | |
impl<T> Into<Vec<T>> for SimpleLinkedList<T> { | |
fn into(self) -> Vec<T> { | |
into_recurse(vec![], self.head) | |
} | |
} | |
pub fn rev_recurse<'a, T: Clone>( | |
result: &'a mut Vec<T>, | |
node: &Option<Box<Node<T>>>, | |
) -> &'a Vec<T> { | |
match node { | |
None => result, | |
Some(ref node) => { | |
result.push(node.data.clone()); | |
rev_recurse(result, &node.next) | |
} | |
} | |
} | |
fn into_recurse<T>(mut result: Vec<T>, node: Option<Box<Node<T>>>) -> Vec<T> { | |
match node { | |
None => result, | |
Some(mut node) => { | |
let next = node.next.take(); | |
result.insert(0, node.data); | |
into_recurse(result, next) | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
extern crate simple_linked_list; | |
use simple_linked_list::SimpleLinkedList; | |
#[test] | |
fn test_new_list_is_empty() { | |
let list: SimpleLinkedList<u32> = SimpleLinkedList::new(); | |
assert_eq!(list.len(), 0, "list's length must be 0"); | |
} | |
#[test] | |
fn test_push_increments_length() { | |
let mut list: SimpleLinkedList<u32> = SimpleLinkedList::new(); | |
list.push(1); | |
assert_eq!(list.len(), 1, "list's length must be 1"); | |
list.push(2); | |
assert_eq!(list.len(), 2, "list's length must be 2"); | |
} | |
#[test] | |
fn test_pop_decrements_length() { | |
let mut list: SimpleLinkedList<u32> = SimpleLinkedList::new(); | |
list.push(1); | |
list.push(2); | |
list.pop(); | |
assert_eq!(list.len(), 1, "list's length must be 1"); | |
list.pop(); | |
assert_eq!(list.len(), 0, "list's length must be 0"); | |
} | |
#[test] | |
fn test_pop_returns_last_added_element() { | |
let mut list: SimpleLinkedList<u32> = SimpleLinkedList::new(); | |
list.push(1); | |
list.push(2); | |
assert_eq!(list.pop(), Some(2), "Element must be 2"); | |
assert_eq!(list.pop(), Some(1), "Element must be 1"); | |
assert_eq!(list.pop(), None, "No element should be contained in list"); | |
} | |
#[test] | |
fn test_peek_returns_head_element() { | |
let mut list: SimpleLinkedList<u32> = SimpleLinkedList::new(); | |
assert_eq!(list.peek(), None, "No element should be contained in list"); | |
list.push(2); | |
assert_eq!(list.peek(), Some(&2), "Element must be 2"); | |
assert_eq!(list.peek(), Some(&2), "Element must be still 2"); | |
} | |
#[test] | |
fn test_from_slice() { | |
let array = ["1", "2", "3", "4"]; | |
let mut list = SimpleLinkedList::from(array.as_ref()); | |
assert_eq!(list.pop(), Some("4")); | |
assert_eq!(list.pop(), Some("3")); | |
assert_eq!(list.pop(), Some("2")); | |
assert_eq!(list.pop(), Some("1")); | |
} | |
#[test] | |
fn test_reverse() { | |
let mut list: SimpleLinkedList<u32> = SimpleLinkedList::new(); | |
list.push(1); | |
list.push(2); | |
list.push(3); | |
let mut rev_list = list.rev(); | |
assert_eq!(rev_list.pop(), Some(1)); | |
assert_eq!(rev_list.pop(), Some(2)); | |
assert_eq!(rev_list.pop(), Some(3)); | |
assert_eq!(rev_list.pop(), None); | |
} | |
#[test] | |
fn test_into_vector() { | |
let mut v = Vec::new(); | |
let mut s = SimpleLinkedList::new(); | |
for i in 1..4 { | |
v.push(i); | |
s.push(i); | |
} | |
let s_as_vec: Vec<i32> = s.into(); | |
assert_eq!(v, s_as_vec); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment