1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
//! A list of nested pairs.
//! 
//! The type [`List`] represents a Cons-style structure.
//! Every [`List`] is either [`Cons`] and contains a value and
//! another [`List`], or [`Nil`], which contains nothing.
#![warn(missing_docs)]
pub use List::{Cons, Nil};

/// An enum that represents a `Cons` list.
/// See [the module level documentation](self) for more.
#[derive(Debug, PartialEq, Eq, Clone)]
pub enum List<T> {
    /// A value of type `T`, and a Box containing another list.
    Cons(T, Box<List<T>>),
    /// Nothing.
    Nil
}

impl<T> List<T> {
    /// Returns true if the List is a [`Cons`] value.
    ///
    /// # Examples
    /// ```
    /// use cons_rs::{List, Cons, Nil};
    ///
    /// let x: List<i32> = Cons(5, Box::new(Nil));
    /// assert_eq!(x.is_cons(), true);
    ///
    /// let x: List<i32> = Nil;
    /// assert_eq!(x.is_cons(), false);
    /// ```
    pub const fn is_cons(&self) -> bool {
        matches!(self, Cons(_, _))
    }

    /// Returns true if the List is a [`Nil`] value.
    ///
    /// # Examples:
    /// ```
    /// use cons_rs::{List, Cons, Nil};
    ///
    /// let x: List<i32> = Cons(5, Box::new(Nil));
    /// assert_eq!(x.is_nil(), false);
    ///
    /// let x: List<i32> = Nil;
    /// assert_eq!(x.is_nil(), true);
    /// ```
    pub const fn is_nil(&self) -> bool {
        !self.is_cons()
    }

    /// Gets the value and next List,
    /// by consuming a given List.
    ///
    /// # Panics
    ///
    /// Panics if self is Nil.
    pub fn unwrap(self) -> (T, List<T>) {
        if let Cons(val, next) = self {
            (val, *next)
        } else {
            panic!("List should not be Nil.")
        }
    }
}

impl<T: Clone> IntoIterator for List<T> {
    type Item = T;
    type IntoIter = ListIterator<T>;

    fn into_iter(self) -> Self::IntoIter {
        ListIterator::new(self)
    }
}

/// An iterator over a List<T>.
/// 
/// It is created by the [`into_iter`] method on [`List<T>`].
///
/// [`iter`]: List::iter
pub struct ListIterator<T> {
    next: Box<List<T>>
}

impl<T> ListIterator<T> {
    fn new(list: List<T>) -> ListIterator<T> {
        ListIterator {
            next: Box::new(list)
        }
    }
}

impl<T: Clone> Iterator for ListIterator<T> {
    type Item = T;

    fn next(&mut self) -> Option<Self::Item> {
        if let Cons(val, next) = &*self.next {
            let tmp = val.clone();
            self.next = next.clone();
            Some(tmp)
        } else {
            None
        }
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    
    #[test]
    fn is_cons() {
        let list = Cons(3, Box::new(Nil));
        assert!(list.is_cons());
        assert!(!list.is_nil());
    }

    #[test]
    fn is_nil() {
        let list: List<i32> = Nil;
        assert!(list.is_nil());
        assert!(!list.is_cons());
    }

    #[test]
    fn iter() {
        let list = Cons(2, Box::new(Cons(4, Box::new(Nil))));
        let mut iterator = list.into_iter();
        assert_eq!(iterator.next(), Some(2));
        assert_eq!(iterator.next(), Some(4));
        assert_eq!(iterator.next(), None);
    }

    #[test]
    fn iter_loop() {
        let list = Cons(0, Box::new(Cons(2, Box::new(Cons(4, Box::new(Nil))))));
        for (i, val) in list.into_iter().enumerate() {
            assert_eq!(val, i * 2);
        }
    }

    #[test]
    fn for_loop() {
        let list = Cons(0, Box::new(Cons(1, Box::new(Cons(2, Box::new(Nil))))));
        let mut i = 0;
        for val in list {
            assert_eq!(val, i);
            i += 1;
        }
    }
}