Skip to main content

cranpose_core/
applier.rs

1use std::any::{Any, TypeId};
2
3use crate::{Node, NodeError, NodeId, RecycleOrigin, RecycledNode, RecycledNodeInsertion};
4
5/// Stores the nodes that a composition builds and applies changes to them. The UI layer supplies an
6/// applier; [`MemoryApplier`](crate::MemoryApplier) is the stock one.
7pub trait Applier: Any {
8    /// Stores `node` and returns its new id.
9    fn create(&mut self, node: Box<dyn Node>) -> NodeId;
10    /// Returns the node `id` for change, or an error if there is none.
11    fn get_mut(&mut self, id: NodeId) -> Result<&mut dyn Node, NodeError>;
12    /// Returns the node `id` to read, or an error if there is none.
13    fn get_ref(&self, id: NodeId) -> Result<&dyn Node, NodeError>;
14    /// Removes the node `id` and the nodes below it.
15    fn remove(&mut self, id: NodeId) -> Result<(), NodeError>;
16
17    /// Opens a batch of commands, in which no layout pass runs: within it a
18    /// dirty bubble may stop at an ancestor an earlier one passed
19    /// ([`Self::note_bubble_pass`]). Batches nest.
20    fn begin_bubble_batch(&mut self) {}
21
22    /// Notes that a dirty bubble marked `id` as needing measure or layout,
23    /// or carried the dirt of `id` to its ancestors, for a layout pass that
24    /// starts from the dirty nodes. An applier that keeps no notes ignores
25    /// it.
26    fn note_layout_dirt(&mut self, _id: NodeId) {}
27
28    /// Closes the batch [`Self::begin_bubble_batch`] opened.
29    fn end_bubble_batch(&mut self) {}
30
31    /// Forgets what the open batch's bubbles passed: a node changed its
32    /// parent, or other code ran, so their marks may no longer reach the root.
33    fn forget_bubble_passes(&mut self) {}
34
35    /// Notes that a dirty bubble carrying `flags` passed the ancestor `id`.
36    /// `true` when one carrying all of them passed it earlier in the open
37    /// batch: that one marked every ancestor above `id`, so this one may
38    /// stop. An applier that keeps no notes answers `false`.
39    fn note_bubble_pass(&mut self, _id: NodeId, _flags: u8) -> bool {
40        false
41    }
42
43    /// The node `id` for a dirty bubble to mark, or `None` when it is
44    /// missing or, with `note`, when [`Self::note_bubble_pass`] says a
45    /// bubble carrying `flags` passed it earlier in the open batch.
46    fn bubble_node(&mut self, id: NodeId, flags: u8, note: bool) -> Option<&mut dyn Node> {
47        if note && self.note_bubble_pass(id, flags) {
48            return None;
49        }
50        self.get_mut(id).ok()
51    }
52
53    /// Records that `parent_id`'s child list changed structurally this frame
54    /// (insert, remove, move, or reparent). Incremental scene consumers drain
55    /// the recorded parents and re-patch those subtrees so removed nodes are
56    /// evicted from a persistent render graph even when the frame's scene
57    /// update is otherwise scoped to unrelated dirty nodes.
58    fn record_structural_change(&mut self, _parent_id: NodeId) {}
59
60    /// Returns the current generation for a node index.
61    /// Generation is incremented when an index is reused from the freelist,
62    /// preventing stale slot entries from matching recycled nodes.
63    fn node_generation(&self, id: NodeId) -> u32;
64
65    /// Stores `node` as a virtual node, one that lays out nothing itself
66    /// while its parent lays out its children, and returns its new id.
67    fn create_virtual(&mut self, node: Box<dyn Node>) -> NodeId;
68
69    /// Reinserts a recycled node at its retained stable ID, or creates a fresh ID if that
70    /// retained ID is no longer available.
71    fn insert_recycled_node_or_create(
72        &mut self,
73        stable_id: NodeId,
74        node: Box<dyn Node>,
75    ) -> RecycledNodeInsertion {
76        let id = self.create(node);
77        RecycledNodeInsertion::fresh(id, Some(NodeError::AlreadyExists { id: stable_id }))
78    }
79
80    /// Returns the applier as `Any`, for downcasting to its concrete type.
81    fn as_any(&self) -> &dyn Any
82    where
83        Self: Sized,
84    {
85        self
86    }
87
88    /// Returns the applier as `Any`, for downcasting to its concrete type.
89    fn as_any_mut(&mut self) -> &mut dyn Any
90    where
91        Self: Sized,
92    {
93        self
94    }
95
96    /// Trim trailing tombstones/unused capacity after structural changes.
97    fn compact(&mut self) {}
98
99    /// Returns a previously recycled node shell and its stable ID for the requested concrete type.
100    fn take_recycled_node(&mut self, _key: TypeId) -> Option<RecycledNode> {
101        None
102    }
103
104    /// Marks whether a reinserted recycled node originated from the warm recycle path.
105    fn set_recycled_node_origin(&mut self, _id: NodeId, _origin: RecycleOrigin) {}
106
107    /// Seeds a warm recyclable shell for future reuse without requiring a prior removal.
108    fn seed_recycled_node_shell(
109        &mut self,
110        _key: TypeId,
111        _recycle_pool_limit: Option<usize>,
112        _shell: Box<dyn Node>,
113    ) {
114    }
115
116    /// Records that the current apply pass had to allocate a fresh recyclable shell for this type.
117    fn record_fresh_recyclable_creation(&mut self, _key: TypeId) {}
118
119    /// Drops any recyclable shells that should not survive beyond the current apply pass.
120    fn clear_recycled_nodes(&mut self) {}
121}