pub use crate::List::{Cons, Nil};
use std::fmt::Display;
#[derive(Debug, Default, PartialEq, PartialOrd)]
pub enum List<T> {
#[default]
Nil,
Cons(T, Box<List<T>>),
}
#[macro_export]
macro_rules! list {
[] => {
List::Nil
};
[ $head:expr ] => {
List::Cons($head, Box::new(Nil))
};
[$head:expr, $($tail:expr),+] => {
List::Cons($head, Box::new( list!($($tail), +) ))
};
}
#[macro_export]
macro_rules! list_rev {
[ $( $x:expr ), *] => {
{
let list = List::Nil;
$(
let list = List::Cons($x, Box::new(list));
)*
list
}
};
}
impl<T: Display> Display for List<T> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let mut list = self;
fn is_empty<T>(list: &Box<List<T>>) -> bool {
match **list {
List::Nil => true,
List::Cons(_, _) => false,
}
}
write!(f, "list![").ok();
while let Cons(head, tail) = list {
if is_empty(tail) {
write!(f, "{}", head).ok();
} else {
write!(f, "{}, ", head).ok();
}
list = tail;
}
write!(f, "]")
}
}
impl<T> IntoIterator for List<T> {
type Item = T;
type IntoIter = ListIntoIter<T>;
fn into_iter(self) -> Self::IntoIter {
ListIntoIter { list: self }
}
}
pub struct ListIntoIter<T> {
list: List<T>,
}
impl<T> Iterator for ListIntoIter<T> {
type Item = T;
fn next(&mut self) -> Option<Self::Item> {
let list = std::mem::take(&mut self.list);
match list {
Cons(head, tail) => {
self.list = *tail; Some(head)
}
Nil => None,
}
}
}
impl<'a, T> Iterator for &'a List<T> {
type Item = &'a T;
fn next(&mut self) -> Option<Self::Item> {
match self {
Nil => None,
Cons(head, tail) => {
let _ = std::mem::replace(self, tail);
Some(head)
}
}
}
}
impl<T> FromIterator<T> for List<T> {
fn from_iter<U: IntoIterator<Item = T>>(iter: U) -> Self {
iter.into_iter() .fold(Nil, |xs, x| cons(x, xs))
.into_iter() .fold(Nil, |xs, x| cons(x, xs))
}
}
pub fn nil<T>() -> List<T> {
List::Nil
}
pub fn cons<T>(x: T, xs: List<T>) -> List<T> {
List::Cons(x, Box::new(xs))
}
impl<T> List<T> {
pub fn new() -> List<T> {
Nil
}
pub fn into_rev(list: List<T>) -> List<T> {
list.into_iter().fold(Nil, |xs, x| cons(x, xs))
}
pub fn borrow_rev<'a>(list: &'a List<T>) -> List<&'a T> {
list.fold(Nil, |xs, x| cons(x, xs))
}
pub fn is_empty(&self) -> bool {
match self {
Nil => true,
_ => false,
}
}
pub fn len(&self) -> usize {
self.count()
}
pub fn last(&self) -> Option<&T> {
let mut last = None;
let mut next = self;
while let Cons(x, xs) = next {
last = Some(x);
next = xs;
}
last
}
pub fn push(&mut self, x: T) {
let xs = std::mem::take(self);
*self = Cons(x, Box::new(xs));
}
pub fn pop(&mut self) -> Option<T> {
let list = std::mem::take(self);
match list {
Nil => None,
Cons(head, tail) => {
*self = *tail;
Some(head)
}
}
}
pub fn append(&mut self, list: List<T>) {
let mut curr = self;
while let Cons(_, next) = curr {
curr = next;
}
let _ = std::mem::replace(curr, list);
}
pub fn reverse(&mut self) {
let list = std::mem::take(self);
*self = list.into_iter().fold(Nil, |xs, x| cons(x, xs))
}
pub fn rfold<U, F>(self, init: U, mut f: F) -> U
where
F: FnMut(U, T) -> U,
{
fn recurse<T, U, F>(list: List<T>, init: U, f: &mut F) -> U
where
F: FnMut(U, T) -> U,
{
match list {
Nil => init,
Cons(x, xs) => {
let y = recurse(*xs, init, f);
f(y, x)
}
}
}
recurse(self, init, &mut f)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn construction() {
let list = Cons(2, Box::new(Nil));
assert_eq!(list, Cons(2, Box::new(Nil)));
let list = Cons(1, Box::new(list));
assert_eq!(list, Cons(1, Box::new(Cons(2, Box::new(Nil)))));
}
#[test]
fn macro_empty() {
let empty: List<i32> = Nil;
assert_eq!(empty, list![]);
}
#[test]
fn macro_singleton() {
let singleton: List<i32> = Cons(1, Box::new(Nil));
assert_eq!(singleton, list![1]);
}
#[test]
fn macro_multiple() {
let xs = Cons(2, Box::new(Cons(3, Box::new(Nil))));
assert_eq!(xs, list![2, 3]);
let xs = Cons(1, Box::new(xs));
assert_eq!(xs, list![1, 2, 3]);
}
#[test]
fn display() {
let xs = list![1, 2, 3, 4, 5];
assert_eq!("list![1, 2, 3, 4, 5]", xs.to_string());
}
#[test]
fn iter() {
let xs = list![Some(1), Some(2), Some(3)];
for x in xs.enumerate() {
println!("{:?}", x);
}
for x in &xs {
println!("{:?}", x);
}
assert_eq!(xs, list![Some(1), Some(2), Some(3)])
}
#[test]
fn for_loop() {
let xs = list![1, 2, 3, 4, 5];
let mut ys: List<i32> = nil();
for x in xs {
ys.push(x * 2);
}
assert_eq!(ys, list![10, 8, 6, 4, 2])
}
#[test]
fn into_iter() {
let xs = list![1, 2, 3];
let v: Vec<_> = xs.into_iter().collect();
assert_eq!(v, vec![1, 2, 3]);
}
#[test]
fn from_iter() {
let xs = list![1, 2, 3];
let ys: List<_> = xs.map(|x| x * 2).collect();
assert_eq!(ys, list![2, 4, 6])
}
#[test]
fn len() {
let xs: List<i32> = list![];
assert_eq!(0, xs.len());
let xs = list![2];
assert_eq!(1, xs.len());
let xs = list![1, 2, 3, 4];
assert_eq!(4, xs.len());
let xs = list![Some(1), Some(2), Some(3)];
assert_eq!(3, xs.len());
}
#[test]
fn push() {
let mut list = list![2, 3, 4];
list.push(1);
assert_eq!(list, list![1, 2, 3, 4]);
}
#[test]
fn pop() {
let mut list = list![1, 2, 3];
let head = list.pop();
assert_eq!(head, Some(1));
assert_eq!(list, list![2, 3]);
}
#[test]
fn into_rev() {
let list = list![None, Some(1), Some(2), Some(3)];
let list = List::into_rev(list);
assert_eq!(list![Some(3), Some(2), Some(1), None], list);
}
#[test]
fn borrow_rev() {
let list = list![None, Some(1), Some(2), Some(3)];
let list = List::borrow_rev(&list);
println!("{:?}", list);
assert_eq!(list![&Some(3), &Some(2), &Some(1), &None], list);
}
#[test]
fn append() {
let mut xs = list![Some(1), Some(2)];
let ys = list![Some(3), Some(4), Some(5)];
xs.append(ys);
assert_eq!(xs, list![Some(1), Some(2), Some(3), Some(4), Some(5)]);
}
#[test]
fn filter() {
let xs = list![1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
let ys: List<_> = xs.into_iter().filter(|x| *x <= 5).collect();
let zs: List<_> = ys.filter(|y| **y >= 3).collect();
assert_eq!(ys, list![1, 2, 3, 4, 5]);
assert_eq!(zs, list![&3, &4, &5]);
}
#[test]
fn map() {
let xs = list![1, 2, 3, 4, 5];
let ys: List<_> = xs.map(|x| x * 2).collect();
assert_eq!(ys, list![2, 4, 6, 8, 10]);
}
#[test]
fn fold() {
let xs = list![Some(1), None, Some(3), None, Some(5)];
let sum = xs.fold(0, |sum, x| match x {
Some(y) => y + sum,
None => sum,
});
assert_eq!(sum, 9);
}
#[test]
fn rfold() {
let xs = list![Some(10), None, Some(3), None, Some(5)];
let id = xs.rfold(Nil, |ys, x| cons(x, ys));
assert_eq!(id, list![Some(10), None, Some(3), None, Some(5)]);
}
}