use std::collections::VecDeque;
use pamoja_core::{Error, Result, Store};
#[derive(Clone, Debug, Default)]
pub struct MemoryStore {
records: VecDeque<Vec<u8>>,
capacity: Option<usize>,
}
impl MemoryStore {
pub fn new() -> Self {
Self::default()
}
pub fn with_capacity(capacity: usize) -> Self {
Self {
records: VecDeque::new(),
capacity: Some(capacity),
}
}
}
impl Store for MemoryStore {
async fn append(&mut self, record: &[u8]) -> Result<()> {
if let Some(capacity) = self.capacity {
if self.records.len() >= capacity {
return Err(Error::Io("store is at capacity".to_owned()));
}
}
self.records.push_back(record.to_vec());
Ok(())
}
async fn peek(&self) -> Result<Option<Vec<u8>>> {
Ok(self.records.front().cloned())
}
async fn pop(&mut self) -> Result<Option<Vec<u8>>> {
Ok(self.records.pop_front())
}
async fn len(&self) -> Result<usize> {
Ok(self.records.len())
}
}
#[cfg(test)]
mod tests {
use super::*;
#[tokio::test]
async fn drains_in_first_in_first_out_order() {
let mut store = MemoryStore::new();
store.append(b"a").await.expect("append");
store.append(b"b").await.expect("append");
store.append(b"c").await.expect("append");
assert_eq!(store.len().await.expect("len"), 3);
assert_eq!(store.pop().await.expect("pop"), Some(b"a".to_vec()));
assert_eq!(store.pop().await.expect("pop"), Some(b"b".to_vec()));
assert_eq!(store.pop().await.expect("pop"), Some(b"c".to_vec()));
assert_eq!(store.pop().await.expect("pop"), None);
}
#[tokio::test]
async fn peek_returns_the_oldest_without_removing_it() {
let mut store = MemoryStore::new();
assert_eq!(store.peek().await.expect("peek"), None);
store.append(b"a").await.expect("append");
store.append(b"b").await.expect("append");
assert_eq!(store.peek().await.expect("peek"), Some(b"a".to_vec()));
assert_eq!(store.len().await.expect("len"), 2);
assert_eq!(store.pop().await.expect("pop"), Some(b"a".to_vec()));
}
#[tokio::test]
async fn empty_store_reports_empty() {
let store = MemoryStore::new();
assert_eq!(store.len().await.expect("len"), 0);
assert!(store.is_empty().await.expect("is_empty"));
}
#[tokio::test]
async fn bounded_store_rejects_when_full() {
let mut store = MemoryStore::with_capacity(1);
store.append(b"first").await.expect("append");
assert!(matches!(store.append(b"second").await, Err(Error::Io(_))));
assert_eq!(store.len().await.expect("len"), 1);
assert_eq!(store.pop().await.expect("pop"), Some(b"first".to_vec()));
store.append(b"second").await.expect("append after drain");
assert_eq!(store.pop().await.expect("pop"), Some(b"second".to_vec()));
}
}