pub mod linked;
use linked::*;
fn main() {
    // new list
    let mut list = List::new();
    println!("{}", list);
    
    list.push("airplane".to_string());
    list.push("broom".to_string());
    list.push("crest".to_string());
    list.push("drum".to_string());
    println!("{}", list);
    for x in list.into_iter() {
        println!("{:?}", x);
    }
}
/// Link is a type alias for `enum Option<Box<Node<T>>>`.
/// It represents two possibilities for a link:
/// either `Some(Box<Node<T>>)` a boxed Node (representing a cons)
/// or a `None` (representing a nill)
type Link<T> = Option<Box<Node<T>>>;
/// `struct List` represents a list itself. It has a `head` filed
/// which points to first node in the actual list. The field `len`
/// contains the size of the list.
#[derive(Debug)]
pub struct List<T> {
    pub head: Link<T>,
    pub len: usize,
}
/// `struct Node` represents a list's node with a `payload` field
/// and a `next` field that points to the next node (or null).
#[derive(Debug)]
pub struct Node<T> {
    pub payload: T,
    pub next: Link<T>
}
impl<T> List<T> {
    /// Makes a new empty list.
    pub fn new() -> Self {
        List {
            head: None,
            len: 0,
        }
    }
    /// Get list size
    pub fn size(&self) -> i32 {
        // list size is usize, but cast it as i32
        *&self.len as i32
    }
    /// Check if the list is empty.
    pub fn is_empty(&self) -> bool {
        self.head.is_none()
    }
    /// Removes all elements from the list.
    pub fn clear(&mut self) {
        *self = Self::new();
    }
    
    /// Removes the first node, returns its payload
    pub fn pop(&mut self) -> Option<T> {
        self.head
            .take()
            .map(|boxed_node| {
              let node = *boxed_node;
              self.head = node.next;
              self.len -= 1;
              node.payload
        })
    }
  
    /// Prepend node onto the list.
    pub fn push(&mut self, payload: T) {
        let new_node = Box::new(Node {
            payload,
            next: self.head.take(),
        });
        self.head = Some(new_node);
        self.len += 1;
    }
  
    /// Returns a reference to the payload of the list's head node
    pub fn peek(&self) -> Option<&T> {
        self.head.as_ref().map(|node| &node.payload)
    }
    
    /// Returns a mutable reference to the payload of the list's head node
    pub fn peek_mut(&mut self) -> Option<&mut T> {
        self.head.as_mut().map(|node| &mut node.payload)
    }
  
    /// Puts a payload in a new node and appends it onto the list.
    pub fn append(&mut self, payload: T) {
        if self.is_empty() {
            self.push(payload);
            return;
        }
        let mut link = self.head.as_mut();
        while let Some(mut_boxed_node) = link {
            if let None = mut_boxed_node.next {
                let new_node = Some(Box::new(Node { payload, next: None }));
                mut_boxed_node.next = new_node;
                self.len += 1;
                break;
            }
            link = mut_boxed_node.next.as_mut();
        }
    }
  
  
} //impl
// Drop
//
impl<T> Drop for List<T> {
    /// Drops the list recursively by node.
    fn drop(&mut self) {
        let mut cur_link = self.head.take();
        while let Some(mut boxed_node) = cur_link {
            cur_link = boxed_node.next.take();
        }
    }
}
// IntoIter
//
pub struct IntoIter<T>(List<T>);
impl<T> List<T> {
    pub fn into_iter(self) -> IntoIter<T> {
        IntoIter(self)
    }
}
impl<T> Iterator for IntoIter<T> {
    type Item = T;
    fn next(&mut self) -> Option<Self::Item> {
        self.0.pop()
    }
} // impl IntoIter
// Display
//
use std::fmt::{self, Display};
impl<T> Display for List<T>
  where T: fmt::Display
{
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let mut cur_link = &self.head;
        write!(f, "List: ")?;
        while let &Some(ref boxed_node) = cur_link {
            write!(f, "[{}] -> ", boxed_node.payload)?;
            cur_link = &boxed_node.next;
        }
        write!(f, "nil")
    }
} // impl Display
// Default
//
impl<T> Default for List<T> {
    /// Creates an empty list.
    fn default() -> Self {
        Self::new()
    }
} // impl Default