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>) {
self.recycle_children(&mut layer);
layer.hit_test = None;
self.layers.push(layer);
}
fn recycle_children(&mut self, layer: &mut LayerNode) {
while let Some(child) = layer.children.pop() {
match child {
RenderNode::Layer(layer) => self.recycle_layer(layer),
RenderNode::Primitive(PrimitiveEntry {
node: PrimitiveNode::Text(text),
..
}) => self.texts.push(text),
RenderNode::Primitive(_) | RenderNode::DrawRun(_) => {}
}
}
}
}
pub(crate) fn recycle_children(layer: &mut LayerNode) {
POOL.with(|pool| pool.borrow_mut().recycle_children(layer));
}
pub(crate) fn recycle_primitives(layer: &mut LayerNode) {
POOL.with(|pool| {
let texts = &mut pool.borrow_mut().texts;
for child in layer
.children
.extract_if(.., |child| !matches!(child, RenderNode::Layer(_)))
{
if let RenderNode::Primitive(PrimitiveEntry {
node: PrimitiveNode::Text(text),
..
}) = child
{
texts.push(text);
}
}
});
}
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 layer_box() -> Box<LayerNode> {
POOL.with(|pool| pool.borrow_mut().layers.pop())
.unwrap_or_default()
}
pub(crate) fn boxed_text(text: TextPrimitiveNode) -> Box<TextPrimitiveNode> {
match POOL.with(|pool| pool.borrow_mut().texts.pop()) {
Some(mut recycled) => {
*recycled = text;
recycled
}
None => Box::new(text),
}
}
pub(crate) fn release() {
POOL.with(|pool| {
let mut pool = pool.borrow_mut();
pool.layers.clear();
pool.texts.clear();
pool.lists.clear();
});
}