use crate::argv::Argv;
use crate::argv_view::ArgvView;
const MAX_POOLED: usize = 8192;
const MAX_POOLED_BYTES: usize = 4096;
#[derive(Default)]
pub struct ArgvPool {
free: Vec<Argv>,
}
impl ArgvPool {
pub fn new() -> Self {
Self::default()
}
pub fn take_filled<A: ArgvView + ?Sized>(&mut self, view: &A) -> Argv {
let mut argv = self.free.pop().unwrap_or_default();
view.copy_into(&mut argv);
argv
}
pub fn put(&mut self, argv: Argv) {
if self.free.len() < MAX_POOLED && argv.buf_capacity() <= MAX_POOLED_BYTES {
self.free.push(argv);
}
}
}
#[cfg(test)]
mod tests {
use super::*;
fn argv_of(args: &[&[u8]]) -> Argv {
let mut a = Argv::default();
for arg in args {
a.push(arg);
}
a
}
#[test]
fn take_filled_matches_to_argv() {
let mut pool = ArgvPool::new();
let src = argv_of(&[b"SET", b"k", b"v"]);
let got = pool.take_filled(&src);
assert_eq!(got, src.to_argv());
}
#[test]
fn recycled_argv_is_refilled_clean() {
let mut pool = ArgvPool::new();
pool.put(argv_of(&[b"SET", b"stale-key", b"stale-value"]));
let src = argv_of(&[b"GET", b"k"]);
let got = pool.take_filled(&src);
assert_eq!(got.len(), 2);
assert_eq!(got.get(0), Some(b"GET" as &[u8]));
assert_eq!(got.get(1), Some(b"k" as &[u8]));
}
#[test]
fn pool_count_is_capped() {
let mut pool = ArgvPool::new();
for _ in 0..(MAX_POOLED + 100) {
pool.put(argv_of(&[b"GET", b"k"]));
}
assert_eq!(pool.free.len(), MAX_POOLED);
}
#[test]
fn oversized_buffers_are_not_retained() {
let mut pool = ArgvPool::new();
let big = vec![b'x'; MAX_POOLED_BYTES + 1];
pool.put(argv_of(&[b"SET", b"k", &big]));
assert!(pool.free.is_empty());
}
#[test]
fn copy_into_reuses_capacity() {
let src = argv_of(&[b"SET", b"key", b"value"]);
let mut out = Argv::default();
src.copy_into(&mut out);
let cap = out.buf_capacity();
src.copy_into(&mut out);
assert_eq!(out.buf_capacity(), cap);
assert_eq!(out, src);
}
}