#[derive(Clone, Debug, PartialEq)]
pub struct Pool<T> {
items: Vec<T>,
limit: usize,
}
impl<T> Pool<T> {
pub fn with_capacity(capacity: usize) -> Pool<T> {
Pool {
items: Vec::with_capacity(capacity),
limit: capacity,
}
}
pub fn push(&mut self, item: T) -> Result<(), T> {
if self.items.len() < self.limit {
self.items.push(item);
Ok(())
} else {
Err(item)
}
}
pub fn len(&self) -> usize {
self.items.len()
}
pub fn clear(&mut self) {
self.items.clear();
}
pub fn is_empty(&self) -> bool {
self.items.is_empty()
}
pub fn is_full(&self) -> bool {
self.items.len() >= self.limit
}
pub fn capacity(&self) -> usize {
self.limit
}
pub fn retain<F: FnMut(&T) -> bool>(&mut self, keep: F) {
self.items.retain(keep);
}
pub fn get(&self, index: usize) -> Option<&T> {
self.items.get(index)
}
pub fn get_mut(&mut self, index: usize) -> Option<&mut T> {
self.items.get_mut(index)
}
pub fn iter(&self) -> std::slice::Iter<'_, T> {
self.items.iter()
}
pub fn iter_mut(&mut self) -> std::slice::IterMut<'_, T> {
self.items.iter_mut()
}
}
impl<'a, T> IntoIterator for &'a Pool<T> {
type Item = &'a T;
type IntoIter = std::slice::Iter<'a, T>;
fn into_iter(self) -> Self::IntoIter {
self.items.iter()
}
}
impl<'a, T> IntoIterator for &'a mut Pool<T> {
type Item = &'a mut T;
type IntoIter = std::slice::IterMut<'a, T>;
fn into_iter(self) -> Self::IntoIter {
self.items.iter_mut()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn push_fills_to_capacity_then_hands_items_back() {
let mut pool = Pool::with_capacity(3);
assert_eq!(pool.push(1), Ok(()));
assert_eq!(pool.push(2), Ok(()));
assert_eq!(pool.push(3), Ok(()));
assert!(pool.is_full());
assert_eq!(pool.push(4), Err(4));
assert_eq!(pool.len(), 3);
}
#[test]
fn retain_keeps_the_survivors_in_their_order() {
let mut pool = Pool::with_capacity(6);
for i in [5, 2, 8, 1, 9, 4] {
pool.push(i).unwrap();
}
pool.retain(|&x| x > 3);
let kept: Vec<i32> = pool.iter().copied().collect();
assert_eq!(kept, vec![5, 8, 9, 4]);
}
#[test]
fn a_zero_capacity_pool_is_always_full() {
let mut pool: Pool<u8> = Pool::with_capacity(0);
assert!(pool.is_full());
assert!(pool.is_empty());
assert_eq!(pool.push(1), Err(1));
pool.retain(|_| true);
assert_eq!(pool.len(), 0);
}
#[test]
fn clear_empties_the_pool_but_keeps_its_capacity() {
let mut pool = Pool::with_capacity(2);
pool.push(1).unwrap();
pool.push(2).unwrap();
pool.clear();
assert!(pool.is_empty());
assert_eq!(pool.capacity(), 2);
assert_eq!(pool.push(3), Ok(()));
assert_eq!(pool.push(4), Ok(()));
assert_eq!(pool.push(5), Err(5));
}
#[test]
fn get_and_get_mut_return_none_past_the_end() {
let mut pool = Pool::with_capacity(2);
pool.push('a').unwrap();
assert_eq!(pool.get(0), Some(&'a'));
assert_eq!(pool.get(1), None);
*pool.get_mut(0).unwrap() = 'b';
assert_eq!(pool.get(0), Some(&'b'));
assert!(pool.get_mut(5).is_none());
}
#[test]
fn a_pool_can_be_looped_over_by_reference() {
let mut pool = Pool::with_capacity(3);
pool.push(10).unwrap();
pool.push(20).unwrap();
let mut total = 0;
for x in &pool {
total += x;
}
assert_eq!(total, 30);
for x in &mut pool {
*x += 1;
}
assert_eq!(pool.iter().copied().collect::<Vec<_>>(), vec![11, 21]);
}
#[test]
fn many_push_and_retain_cycles_never_reallocate() {
let mut pool: Pool<u32> = Pool::with_capacity(100);
let storage_before = pool.items.capacity();
for i in 0..10_000 {
if pool.push(i).is_err() {
pool.retain(|x| x % 3 != 0);
}
}
assert_eq!(pool.capacity(), 100);
assert_eq!(pool.items.capacity(), storage_before);
}
}