Documentation
pub struct List {
  head: Link,
}

#[allow(dead_code)]
enum Link {
    Empty,
    More(Box<Node>),
}

#[allow(dead_code)]
struct Node {
  elem: i32,
  next: Link,
}

impl List {
    pub fn new() -> Self {
      List { head: Link::Empty }
    }

    pub fn push(&mut self, elem: i32) {
      let new_node = Box::new(Node {
        elem: elem,
        next: std::mem::replace(&mut self.head, Link::Empty)
      });

      self.head = Link::More(new_node);
    }

    pub fn pop(&mut self) -> Option<i32> {
      match std::mem::replace(&mut self.head, Link::Empty) {
          Link::Empty => None,
          Link::More(node) => {
            self.head = node.next;
            Some(node.elem)
          }
      }
    }

    pub fn peek(&self) -> Option<i32> {
      match &self.head {
        Link::Empty => None,
        Link::More(node) => {
          Some(node.elem)
        }
      }
    }

}

impl Drop for List {
  fn drop(&mut self) {
    let mut cur_link = std::mem::replace(&mut self.head, Link::Empty);
    while let Link::More(mut boxed_node) = cur_link {
      cur_link = std::mem::replace(&mut boxed_node.next, Link::Empty);
    }
  }
}


#[cfg(test)]
mod test {
  use super::*;

  #[test]
  fn basics() {
    let mut list = List::new();
    assert_eq!(list.pop(), None);
  }

  #[test]
  fn basc_push_pop() {
    let mut list = List::new();

    list.push(1);
    list.push(2);
    list.push(3);

    assert_eq!(list.peek(), Some(3));

    assert_eq!(list.pop(), Some(3));
    assert_eq!(list.pop(), Some(2));

    list.push(4);
    assert_eq!(list.pop(), Some(4));
    assert_eq!(list.pop(), Some(1));
    assert_eq!(list.pop(), None);

  }
  
}