aven 0.1.13

Local-first task manager CLI and sync server
Documentation
use std::collections::VecDeque;

pub(super) struct BoundedHistory<T> {
    entries: VecDeque<T>,
    capacity: usize,
}

impl<T> BoundedHistory<T> {
    pub(super) fn new(capacity: usize) -> Self {
        assert!(capacity > 0, "history capacity must be greater than zero");
        Self {
            entries: VecDeque::with_capacity(capacity),
            capacity,
        }
    }

    pub(super) fn clear(&mut self) {
        self.entries.clear();
    }

    pub(super) fn pop(&mut self) -> Option<T> {
        self.entries.pop_back()
    }
}

impl<T: PartialEq> BoundedHistory<T> {
    pub(super) fn push(&mut self, entry: T) {
        if self.entries.back() == Some(&entry) {
            return;
        }
        if self.entries.len() == self.capacity {
            self.entries.pop_front();
        }
        self.entries.push_back(entry);
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn push_discards_adjacent_duplicates() {
        let mut history = BoundedHistory::new(3);

        history.push("first");
        history.push("first");
        history.push("second");

        assert_eq!(history.pop(), Some("second"));
        assert_eq!(history.pop(), Some("first"));
        assert_eq!(history.pop(), None);
    }

    #[test]
    fn push_discards_oldest_entry_at_capacity() {
        let mut history = BoundedHistory::new(2);

        history.push("first");
        history.push("second");
        history.push("third");

        assert_eq!(history.pop(), Some("third"));
        assert_eq!(history.pop(), Some("second"));
        assert_eq!(history.pop(), None);
    }
}