use super::TaskPool;
use core::alloc::Layout;
use core::ptr::NonNull;
use hicollections::{list, List, ListNode};
use hierr::Result;
use hipool::{Boxed, MemPool, NullAlloc};
struct CacheNode {
node: ListNode,
pool: *mut MemPool,
layout: Layout,
}
impl CacheNode {
fn new(pool: TaskPool) -> Boxed<'static, Self, MemPool> {
let pool = MemPool::reset_boxed(pool);
let (pool, layout, _) = pool.leak();
let ptr: *mut MemPool = pool;
Boxed::new_in(
pool,
Self {
node: ListNode::new(),
pool: ptr,
layout,
},
)
.unwrap()
}
unsafe fn release(&self) -> TaskPool {
let pool = Boxed::from_with(NonNull::new_unchecked(self.pool), self.layout, &NullAlloc);
MemPool::reset_boxed(pool)
}
}
pub(crate) struct PoolCache {
caches: List<CacheNode>,
size: usize,
max_size: usize,
}
impl PoolCache {
pub fn new(max_size: usize) -> Self {
Self {
caches: list!(CacheNode, node),
size: 0,
max_size,
}
}
pub fn push(&mut self, pool: TaskPool) {
if self.max_size == 0 {
return;
}
let node = CacheNode::new(pool).leak().0;
unsafe { self.caches.add_head(node) };
if self.size < self.max_size {
self.size += 1;
} else {
let cache = self.caches.last().unwrap();
unsafe { self.caches.del(cache) };
let _ = unsafe { cache.release() };
}
}
pub fn pop(&mut self) -> Result<TaskPool> {
if let Some(cache) = self.caches.first() {
unsafe { self.caches.del(cache) };
self.size -= 1;
Ok(unsafe { cache.release() })
} else {
MemPool::new_boxed(0)
}
}
}
impl Drop for PoolCache {
fn drop(&mut self) {
while let Some(cache) = self.caches.first() {
unsafe { self.caches.del(cache) };
unsafe { cache.release() };
}
}
}