use crate::{
allocator::{biggest_region_allocator, count_allocator, AllocError, Allocator},
behavior::Behavior,
Checked, IdAble, Wrapping,
};
use core::{marker::PhantomData, ops::Range};
#[cfg(feature = "serde")]
use serde::{Deserialize, Serialize};
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct Pool<B: Behavior> {
alloc: Allocator<B::Id>,
#[allow(dead_code)]
parent_channel: Option<()>,
pub(crate) buffer: Range<B::Id>, pub(crate) original_range: Range<B::Id>, pub(crate) one: B::Id, _p: PhantomData<B>,
}
impl<B: Behavior> Pool<B> {
pub fn new(range: Range<B::Id>) -> Self {
Pool {
alloc: Allocator::new(range.start..range.start),
parent_channel: None,
buffer: range.clone(),
original_range: range,
one: B::Id::from(1),
_p: PhantomData::default(),
}
}
#[cfg(feature = "num-traits")]
pub fn new_full() -> Self
where
B::Id: num_traits::Bounded,
{
use crate::num_traits::Bounded;
let range = B::Id::min_value()..B::Id::max_value();
Self::new(range)
}
pub fn next(&mut self) -> B::Return { B::next(self) }
pub fn subpool(&mut self, size: B::Id) -> Result<Self, AllocError<B::Id>> {
self.unused_to_alloc();
match self.alloc.alloc(size) {
Ok(alloc_range) => {
let pool = Pool::new(alloc_range);
self.re_buffer();
Ok(pool)
},
Err(e) => {
self.re_buffer();
Err(e)
},
}
}
fn unused_to_alloc(&mut self) {
self.alloc.free(self.buffer.clone());
self.buffer.end = self.buffer.start;
}
fn re_buffer(&mut self) {
let size = biggest_region_allocator(&self.alloc);
let r = self.alloc.alloc(size);
debug_assert!(r.is_ok());
self.buffer = r.unwrap();
}
}
#[allow(dead_code)]
pub fn subpool_wrapping<Id: IdAble>(
pool: &mut Pool<Checked<Id>>,
size: Id,
) -> Result<Pool<Wrapping<Id>>, AllocError<Id>> {
if size < Id::from(1) {
return Err(AllocError::SizeNotAvailable(size));
}
pool.unused_to_alloc();
match pool.alloc.alloc(size) {
Ok(alloc_range) => {
let wpool = Pool::new(alloc_range);
pool.re_buffer();
Ok(wpool)
},
Err(e) => {
pool.re_buffer();
Err(e)
},
}
}
impl<B: Behavior> core::fmt::Debug for Pool<B>
where
B::Id: core::fmt::Display,
{
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
let size = count_allocator(&self.alloc) + self.buffer.end - self.buffer.start;
write!(f, "Pool({})", size)
}
}
impl<B: Behavior> core::fmt::Display for Pool<B>
where
B::Id: core::fmt::Display,
{
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
let size = count_allocator(&self.alloc) + self.buffer.end - self.buffer.start;
write!(f, "Pool({})", size)
}
}
impl<B: Behavior> Drop for Pool<B> {
fn drop(&mut self) {
self.unused_to_alloc();
}
}
#[cfg(test)]
mod tests {
use crate::{allocator::*, behavior::*, pool::*};
#[test]
fn subpool() {
let mut pool = Pool::<Checked<u64>>::new(0..10);
assert!(pool.subpool(3).is_ok());
assert_eq!(pool.next(), Ok(3));
assert!(pool.subpool(3).is_ok());
assert_eq!(pool.next(), Ok(7));
assert_eq!(pool.next(), Ok(8));
assert_eq!(pool.next(), Ok(9));
}
#[test]
fn subpool_checked_to_wrapping() {
let mut pool = Pool::<Checked<u64>>::new(0..8);
assert!(pool.subpool(3).is_ok());
assert_eq!(pool.next(), Ok(3));
let wrapping = subpool_wrapping(&mut pool, 2);
assert!(wrapping.is_ok());
let mut wrapping = wrapping.unwrap();
assert_eq!(pool.next(), Ok(6));
assert_eq!(pool.next(), Ok(7));
assert_eq!(pool.next(), Err(CheckedError::PoolEmpty));
assert_eq!(pool.next(), Err(CheckedError::PoolEmpty));
assert_eq!(wrapping.next(), 4);
assert_eq!(wrapping.next(), 5);
assert_eq!(wrapping.next(), 4);
assert_eq!(wrapping.next(), 5);
assert_eq!(wrapping.next(), 4);
assert_eq!(wrapping.next(), 5);
}
#[test]
fn subpool_checked_to_wrapping_invalid() {
let mut pool = Pool::<Checked<u64>>::new(0..8);
assert!(pool.subpool(3).is_ok());
let wrapping = subpool_wrapping(&mut pool, 0);
assert!(wrapping.is_err());
assert_eq!(wrapping.unwrap_err(), AllocError::SizeNotAvailable(0));
let wrapping = subpool_wrapping(&mut pool, 999);
assert!(wrapping.is_err());
assert_eq!(wrapping.unwrap_err(), AllocError::SizeNotAvailable(999));
}
#[test]
fn subpool_error() {
let mut pool = Pool::<Checked<u64>>::new(0..10);
assert!(pool.subpool(3).is_ok());
assert_eq!(pool.next(), Ok(3));
assert!(pool.subpool(3).is_ok());
assert_eq!(pool.next(), Ok(7));
assert!(pool.subpool(3).is_err());
assert_eq!(pool.next(), Ok(8));
assert_eq!(pool.next(), Ok(9));
assert_eq!(pool.next(), Err(CheckedError::PoolEmpty));
}
#[test]
fn subpool_format() {
let pool = Pool::<Checked<u64>>::new(0..10);
assert_eq!(format!("{}", pool), "Pool(10)");
assert_eq!(format!("{:?}", pool), "Pool(10)");
}
}