use std::cell::RefCell;
use crate::graph::{LayerNode, PrimitiveEntry, PrimitiveNode, RenderNode, TextPrimitiveNode};
#[derive(Default)]
#[expect(
clippy::vec_box,
reason = "the boxes are the allocations the pool keeps for reuse"
)]
struct Pool {
layers: Vec<Box<LayerNode>>,
texts: Vec<Box<TextPrimitiveNode>>,
lists: Vec<Vec<RenderNode>>,
}
thread_local! {
static POOL: RefCell<Pool> = RefCell::new(Pool::default());
}
impl Pool {
fn recycle_layer(&mut self, mut layer: Box<LayerNode>) {
let replaced = std::mem::take(layer.as_mut());
self.recycle_list(replaced.children);
self.layers.push(layer);
}
fn recycle_list(&mut self, mut list: Vec<RenderNode>) {
for child in list.drain(..) {
match child {
RenderNode::Layer(layer) => self.recycle_layer(layer),
RenderNode::Primitive(PrimitiveEntry {
node: PrimitiveNode::Text(text),
..
}) => self.texts.push(text),
RenderNode::Primitive(_) | RenderNode::DrawRun(_) => {}
}
}
if list.capacity() > 0 {
self.lists.push(list);
}
}
}
pub(crate) fn recycle_children(layer: &mut LayerNode) {
let children = std::mem::take(&mut layer.children);
POOL.with(|pool| pool.borrow_mut().recycle_list(children));
}
pub(crate) fn recycle(layer: Box<LayerNode>) {
POOL.with(|pool| pool.borrow_mut().recycle_layer(layer));
}
pub(crate) fn recycle_list(list: Vec<RenderNode>) {
debug_assert!(list.is_empty(), "only an emptied list is recycled");
if list.capacity() > 0 {
POOL.with(|pool| pool.borrow_mut().lists.push(list));
}
}
pub(crate) fn child_list(capacity: usize) -> Vec<RenderNode> {
let mut list = POOL
.with(|pool| pool.borrow_mut().lists.pop())
.unwrap_or_default();
list.reserve(capacity);
list
}
pub(crate) fn boxed(layer: LayerNode) -> Box<LayerNode> {
refill(POOL.with(|pool| pool.borrow_mut().layers.pop()), layer)
}
pub(crate) fn boxed_text(text: TextPrimitiveNode) -> Box<TextPrimitiveNode> {
refill(POOL.with(|pool| pool.borrow_mut().texts.pop()), text)
}
fn refill<T>(recycled: Option<Box<T>>, value: T) -> Box<T> {
match recycled {
Some(mut recycled) => {
*recycled = value;
recycled
}
None => Box::new(value),
}
}
pub(crate) fn release() {
POOL.with(|pool| {
let mut pool = pool.borrow_mut();
pool.layers.clear();
pool.texts.clear();
pool.lists.clear();
});
}