pub const MAX_COOKIES: usize = 8;
#[derive(Default, PartialEq, Eq)]
pub(crate) struct CookieStash {
cookies: [Vec<u8>; MAX_COOKIES],
read: usize,
valid: usize,
}
impl std::fmt::Debug for CookieStash {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("CookieStash")
.field("cookies", &self.cookies.len())
.field("read", &self.read)
.field("valid", &self.valid)
.finish()
}
}
impl CookieStash {
pub fn store(&mut self, cookie: Vec<u8>) {
let wpos = (self.read + self.valid) % self.cookies.len();
self.cookies[wpos] = cookie;
if self.valid < self.cookies.len() {
self.valid += 1;
} else {
debug_assert!(self.valid == self.cookies.len());
self.read = (self.read + 1) % self.cookies.len();
}
}
pub fn get(&mut self) -> Option<Vec<u8>> {
if self.valid == 0 {
None
} else {
let result = std::mem::take(&mut self.cookies[self.read]);
self.read = (self.read + 1) % self.cookies.len();
self.valid -= 1;
Some(result)
}
}
pub fn gap(&self) -> u8 {
(self.cookies.len() - self.valid) as u8
}
pub fn len(&self) -> usize {
self.valid
}
pub fn is_empty(&self) -> bool {
self.valid == 0
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_empty_read() {
let mut stash = CookieStash::default();
assert_eq!(stash.get(), None);
}
#[test]
fn test_overfill() {
let mut stash = CookieStash::default();
for i in 0..10_u8 {
stash.store(vec![i]);
}
assert_eq!(stash.get(), Some(vec![2]));
assert_eq!(stash.get(), Some(vec![3]));
}
#[test]
fn test_normal_op() {
let mut stash = CookieStash::default();
for i in 0..8_u8 {
stash.store(vec![i]);
assert_eq!(stash.gap(), 7 - i);
}
for i in 8_u8..32_u8 {
assert_eq!(stash.get(), Some(vec![i - 8]));
assert_eq!(stash.gap(), 1);
stash.store(vec![i]);
assert_eq!(stash.gap(), 0);
}
}
}