fsmy 0.1.0

A finite state machine library
use std::collections::VecDeque;

/// A stack data structure that forgets its oldest
/// elements instead of overflowing
#[derive(Debug, Clone)]
#[allow(dead_code)]
pub struct Stack<S> {
    inner: VecDeque<S>,
    max_size: usize,
}

impl<S> Default for Stack<S> {
    fn default() -> Self {
        Self::with_max_size(usize::MAX - 1)
    }
}

impl<S> FromIterator<S> for Stack<S> {
    fn from_iter<T: IntoIterator<Item = S>>(iter: T) -> Self {
        let mut stack = Self::default();
        for item in iter {
            stack.push(item);
        }

        stack
    }
}

#[allow(dead_code)]
impl<S> Stack<S> {
    pub fn new(initial_item: S) -> Self {
        let mut stack = Self::default();
        stack.push(initial_item);

        stack
    }

    /// Creates a stack with a maximum number of retained elements
    pub fn with_max_size(max_size: usize) -> Self {
        Self {
            inner: VecDeque::with_capacity(10),
            max_size,
        }
    }

    /// Push an item onto the stack
    pub fn push(&mut self, value: S) -> bool {
        let overflow = self.inner.len() >= self.max_size;
        if overflow {
            self.inner.pop_front();
        }

        self.inner.push_back(value);

        overflow
    }

    /// Pops an item from the stack
    pub fn pop(&mut self) -> Option<S> {
        self.inner.pop_back()
    }

    /// The current size of the stack - the number of elements in it
    pub fn len(&self) -> usize {
        self.inner.len()
    }

    pub fn top(&self) -> Option<&S> {
        self.inner.get(self.len() - 1)
    }

    pub fn top_mut(&mut self) -> Option<&mut S> {
        self.inner.get_mut(self.len() - 1)
    }

    pub fn bottom(&self) -> Option<&S> {
        self.inner.front()
    }
}

impl<S> Stack<S>
where
    S: PartialEq,
{
    pub fn contains(&self, item: &S) -> bool {
        self.inner.contains(item)
    }
}

#[cfg(test)]
mod test {
    use crate::stack::Stack;

    #[test]
    fn checked_overflow() {
        let mut stack = Stack::with_max_size(4);
        assert!(!stack.push(1));
        assert!(!stack.push(2));
        assert!(!stack.push(3));
        assert!(!stack.push(4));
        assert!(stack.push(5));
        assert!(stack.push(6));
        assert!(stack.push(7));
        assert_eq!(stack.len(), 4);
        assert_eq!(stack.top(), Some(&7));
        assert_eq!(stack.bottom(), Some(&4));
    }

    #[test]
    fn checked_overflow_big_ass_structure() {
        let high = 1_000_000;
        let mut stack = Stack::with_max_size(high);
        for i in 0..high + 100 {
            stack.push(i);
        }

        assert_eq!(stack.len(), high);
    }
}