astack 0.3.5

astack offers a Stack data structure with fixed capacity capable of fast LIFO operations.
Documentation
// No need to annotate this with #[cfg(test)] as the 'tests' dir is special for rustc
//
// All the examples have been tested with MIRI with cargo +nightly miri test --all-features
// No leaks or UB have been detected so far. Great!

mod tests {
    use astack::*;

    #[test]
    fn unsafe_stack() {
        unsafe {
            let mut stack = Stack::<String, 4>::new();
            stack.push_unchecked("String".into());
            stack.push_unchecked("Another one!".into());
            assert_eq!(stack.tos_unchecked(), "Another one!");
            assert_eq!(stack.len(), 2);
            stack.pop_unchecked();
            stack.pop_unchecked();
            assert_eq!(stack.tos(), None);
            assert!(stack.is_empty());
        }
    }

    #[test]
    fn modify_popped() {
        let mut stack = Stack::<String, 4>::new();
        stack.push("Test!".into()).unwrap();
        let mut string = stack.pop().unwrap();
        string.push_str("Test again!");
        assert_eq!(string, "Test!Test again!");
    }

    #[test]
    fn test_stack_macro() {
        let _empty = stack![&str; 10];
        let _another_one = stack! {
            [usize; 10] = [1, 2, 3]
        };
        println!("{:#?}", _empty);
        println!("{:#?}", _another_one);
    }

    #[test]
    fn test_drop() {
        #[derive(Debug)]
        struct Droppable;

        impl Drop for Droppable {
            fn drop(&mut self) {
                println!("Dropped!");
            }
        }

        let mut stack = stack![Droppable; 10];
        stack.push(Droppable).unwrap();
        stack.push(Droppable).unwrap();
        stack.pop();
        stack.pop();
        assert!(stack.pop().is_none());
        println!("Here");
        println!("{:#?}", stack);
    }

    #[test]
    fn const_assert_test() {
        stack! { [i32; 3] = [1] };
        stack! { [i32; 3] = [1, 2] };
        stack! { [i32; 3] = [1, 2, 4] };
        // stack! { [i32; 3] = [1, 2, 4, 8] };
        println!("{:#?}", stack! { [i32; 3] = [1, 2, 4] });
    }

    #[test]
    fn test_eq() {
        let stack1 = stack! {
            [String; 10] = ["a".into()]
        };
        let stack2 = stack! {
            [String; 10] = ["a".into()]
        };
        assert_eq!(stack1, stack2);

        let stack_ne = stack! {
            [String; 10] = ["a".into(), "b".into()]
        };
        assert_ne!(stack1, stack_ne);
        assert_ne!(stack2, stack_ne);

        let stack3 = stack! {
            [char; 10] = ['z', 'y', 'z']
        };
        let stack4 = stack! {
            [char; 10] = ['z', 'y', 'x']
        };
        assert_ne!(stack3, stack4);
    }

    #[test]
    fn struct_test() {
        use std::{cell::RefCell, rc::Rc};

        #[derive(PartialEq, Debug)]
        struct Yo<T>(Rc<RefCell<T>>);
        impl<T> Yo<T> {
            fn new(x: T) -> Self {
                Self(Rc::new(RefCell::new(x)))
            }
        }

        let stack = stack! {
            [Yo<u32>; 4] = [Yo::new(0)]
        };
        let tos = unsafe { stack.tos_unchecked() };

        *RefCell::<_>::borrow_mut(&tos.0) = 10;
        assert_eq!(stack.tos(), Some(&Yo::new(10)));

        let stack = stack! {
            [Yo<String>; 4] = [Yo::new("Hello!".into())]
        };

        let tos = unsafe { stack.tos_unchecked() };

        *RefCell::<_>::borrow_mut(&tos.0) = "World!".into();
        assert_eq!(stack.tos(), Some(&Yo::new("World!".into())));
    }

    #[test]
    fn full_stack() {
        let mut stack = Stack::<String, 100>::fill_with_fn(|i| i.to_string());
        assert!(stack.push(Default::default()).is_err());
        stack.clear();
        assert!(stack.pop().is_none());
    }

    #[test]
    fn swap_tos_test() {
        let mut stack = Stack::<String, 100>::fill_with_fn(|i| i.to_string());
        stack.swap_tos("new_tos".into()).unwrap();
        stack.clear();
        assert!(stack.swap_tos("item".into()).is_err());
    }

    #[test]
    fn test_extend_array() {
        let x: [String; 0] = [];
        assert_eq!(stack![String; 0], x);
        let mut stack = stack![String; 10];
        stack
            .extend_array(["Test1".to_string(), "Test2".to_string()])
            .unwrap();
        assert_eq!(stack, ["Test1", "Test2"]);
        stack
            .extend_array(["Test3".to_string(), "Test4".to_string()])
            .unwrap();
        assert_eq!(stack, ["Test1", "Test2", "Test3", "Test4"]);
        stack.clear();
        stack.extend_array(["Final Test!".to_string()]).unwrap();
        assert_eq!(stack.tos(), Some(&String::from("Final Test!")));
    }

    #[test]
    fn truncate_items() {
        let mut stack = Stack::<String, 10>::fill_with_default();
        assert_eq!(stack.truncate(15), Err(StackError::Underflow));
        stack.truncate(0).unwrap();
        assert!(stack.is_empty());
        stack
            .extend_array([
                "Test1".into(),
                "Test2".into(),
                "Test3".into(),
                "Test4".into(),
            ])
            .unwrap();
        assert_eq!(stack.len(), 4);
    }

    #[test]
    fn cut_items() {
        let mut stack = Stack::<String, 10>::fill_with_default();
        let top_three = stack.cut::<3>();
        assert_eq!(top_three, Ok(<[String; 3]>::default()));
        assert_eq!(stack, <[String; 7]>::default());
        assert_eq!(stack.cut::<8>(), Err(StackError::Underflow));
        let _others = stack.cut::<7>();
        assert!(stack.is_empty());
    }

    #[test]
    fn extend_items() {
        let mut stack = stack![String; 10];
        let it = (0..10).map(|n| (n * n).to_string());
        assert_eq!(stack.extend(it), Ok(()));
        assert!(stack.is_full());
        let it = (0..10).map(|n| (n * n).to_string());
        assert_eq!(stack.extend(it), Err(StackError::Overflow));
    }

    #[test]
    fn test_clone() {
        let stack = stack! {
                [String; 5] = ["Test1".to_string(), "Test2".to_string()]
        };
        let clone = stack.clone();
        assert_eq!(clone, stack);
    }

    #[cfg(feature = "std")]
    #[test]
    fn std_test() {
        fn accepts_error(_err: &dyn std::error::Error) {}
        accepts_error(&StackError::Overflow);
    }

    #[cfg(feature = "std")]
    #[test]
    fn vec_into_stack() {
        let vec = std::vec![1, 2, 3, 4, 5, 6];
        let stack = Stack::<i32, 8>::try_from(vec);
        assert!(stack.is_ok());

        let bigger_vec = std::vec![6, 7, 8, 9, 0, 1, 2, 3];
        let smaller_stack = Stack::<i32, 4>::try_from(bigger_vec);
        assert!(smaller_stack.is_err());
    }

    #[cfg(feature = "std")]
    #[test]
    fn stack_into_vec() {
        let stack = stack! {
            [String; 4] = ["Hello".to_string(), "world".to_string()]
        };
        assert_eq!(stack.tos(), Some(&String::from("world")));
        let v = Vec::from(stack.clone());
        dbg!(&v);
        dbg!(&stack);
        // dbg!(stack.tos());
        // dbg!(v.last());
        // let test = ["world".to_string(), "Hello".to_string()];
        // dbg!(&test[0]);
        assert_eq!(v, ["Hello".to_string(), "world".to_string()]);
        assert_eq!(stack.tos(), v.last());
    }

    #[cfg(feature = "std")]
    #[test]
    fn stack_into_iter_leak() {
        let stack = stack! {
            [String; 10] = ["1".into(), "3".into(), "5".into()]
        };
        let _it = stack.into_iter();
    }

    #[cfg(feature = "std")]
    #[test]
    fn stack_into_iter() {
        let stack = stack! {
            [String; 10] = ["1".into(), "3".into(), "5".into()]
        };
        assert_eq!(stack.tos(), Some(&String::from("5")));
        let mut it = stack.into_iter();
        assert_eq!(it.next(), Some(String::from("5")));
        assert_eq!(it.next_back(), Some(String::from("1")));
        assert_eq!(it.next_back(), Some(String::from("3")));
        assert_eq!(it.next(), None);
        assert_eq!(it.next_back(), None);

        let another_one = Stack::<String, 12>::try_from(vec![
            "1".to_string(),
            "2".to_string(),
            "3".to_string(),
            "4".to_string(),
            "5".to_string(),
            "6".to_string(),
            "7".to_string(),
            "8".to_string(),
            "9".to_string(),
            "10".to_string(),
        ])
        .unwrap();
        assert_eq!(another_one.tos(), Some(&String::from("10")));

        let mut it = another_one.into_iter();
        assert_eq!(it.next(), Some(String::from("10")));
        assert_eq!(it.next_back(), Some(String::from("1")));
        assert_eq!(it.next(), Some(String::from("9")));
        assert_eq!(it.next_back(), Some(String::from("2")));

        dbg!(&it);

        assert_eq!(
            it.rev().collect::<Vec<_>>(),
            vec![
                "3".to_string(),
                "4".to_string(),
                "5".to_string(),
                "6".to_string(),
                "7".to_string(),
                "8".to_string(),
            ]
        );
    }

    #[cfg(feature = "std")]
    #[test]
    fn stack_iter_clone() {
        let stack = stack! {
            [String; 4] = [
                "1".to_string(),
                "2".to_string(),
                "3".to_string(),
                "4".to_string(),
            ]
        };

        let it = stack.into_iter();
        let cloned = it.clone();
        assert_eq!(it, cloned);
        for (item1, item2) in it.zip(cloned) {
            assert_eq!(item1, item2);
        }

        let mut it = stack![String; 0].into_iter();
        assert_eq!(it.next(), None);
        assert_eq!(it.next_back(), None);
        assert_eq!(it.next(), None);
        assert_eq!(it.next_back(), None);
    }
}