cranpose_foundation/
modifier.rs

1//! Modifier node scaffolding for Cranpose.
2//!
3//! This module defines the foundational pieces of the future
4//! `Modifier.Node` system described in the project roadmap. It introduces
5//! traits for modifier nodes and their contexts as well as a light-weight
6//! chain container that can reconcile nodes across updates. The
7//! implementation focuses on the core runtime plumbing so UI crates can
8//! begin migrating without expanding the public API surface.
9
10use std::any::{type_name, Any, TypeId};
11use std::cell::{Cell, RefCell};
12use std::collections::hash_map::DefaultHasher;
13use std::collections::HashMap;
14use std::fmt;
15use std::hash::{Hash, Hasher};
16use std::ops::{BitOr, BitOrAssign};
17use std::rc::Rc;
18
19pub use cranpose_ui_graphics::DrawScope;
20pub use cranpose_ui_graphics::Size;
21pub use cranpose_ui_layout::{Constraints, Measurable};
22
23use crate::nodes::input::types::PointerEvent;
24// use cranpose_core::NodeId;
25
26/// Identifies which part of the rendering pipeline should be invalidated
27/// after a modifier node changes state.
28#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
29pub enum InvalidationKind {
30    Layout,
31    Draw,
32    PointerInput,
33    Semantics,
34    Focus,
35}
36
37/// Runtime services exposed to modifier nodes while attached to a tree.
38pub trait ModifierNodeContext {
39    /// Requests that a particular pipeline stage be invalidated.
40    fn invalidate(&mut self, _kind: InvalidationKind) {}
41
42    /// Requests that the node's `update` method run again outside of a
43    /// regular composition pass.
44    fn request_update(&mut self) {}
45
46    /// Returns the ID of the layout node this modifier is attached to, if known.
47    /// This is used by modifiers that need to register callbacks for invalidation (e.g. Scroll).
48    fn node_id(&self) -> Option<cranpose_core::NodeId> {
49        None
50    }
51
52    /// Signals that a node with `capabilities` is about to interact with this context.
53    fn push_active_capabilities(&mut self, _capabilities: NodeCapabilities) {}
54
55    /// Signals that the most recent node interaction has completed.
56    fn pop_active_capabilities(&mut self) {}
57}
58
59/// Lightweight [`ModifierNodeContext`] implementation that records
60/// invalidation requests and update signals.
61///
62/// The context intentionally avoids leaking runtime details so the core
63/// crate can evolve independently from higher level UI crates. It simply
64/// stores the sequence of requested invalidation kinds and whether an
65/// explicit update was requested. Callers can inspect or drain this state
66/// after driving a [`ModifierNodeChain`] reconciliation pass.
67#[derive(Default, Debug, Clone)]
68pub struct BasicModifierNodeContext {
69    invalidations: Vec<ModifierInvalidation>,
70    update_requested: bool,
71    active_capabilities: Vec<NodeCapabilities>,
72    node_id: Option<cranpose_core::NodeId>,
73}
74
75impl BasicModifierNodeContext {
76    /// Creates a new empty context.
77    pub fn new() -> Self {
78        Self::default()
79    }
80
81    /// Returns the ordered list of invalidation kinds that were requested
82    /// since the last call to [`clear_invalidations`]. Duplicate requests for
83    /// the same kind are coalesced.
84    pub fn invalidations(&self) -> &[ModifierInvalidation] {
85        &self.invalidations
86    }
87
88    /// Removes all currently recorded invalidation kinds.
89    pub fn clear_invalidations(&mut self) {
90        self.invalidations.clear();
91    }
92
93    /// Drains the recorded invalidations and returns them to the caller.
94    pub fn take_invalidations(&mut self) -> Vec<ModifierInvalidation> {
95        std::mem::take(&mut self.invalidations)
96    }
97
98    /// Returns whether an update was requested since the last call to
99    /// [`take_update_requested`].
100    pub fn update_requested(&self) -> bool {
101        self.update_requested
102    }
103
104    /// Returns whether an update was requested and clears the flag.
105    pub fn take_update_requested(&mut self) -> bool {
106        std::mem::take(&mut self.update_requested)
107    }
108
109    /// Sets the node ID associated with this context.
110    pub fn set_node_id(&mut self, id: Option<cranpose_core::NodeId>) {
111        self.node_id = id;
112    }
113
114    fn push_invalidation(&mut self, kind: InvalidationKind) {
115        let mut capabilities = self.current_capabilities();
116        capabilities.insert(NodeCapabilities::for_invalidation(kind));
117        if let Some(existing) = self
118            .invalidations
119            .iter_mut()
120            .find(|entry| entry.kind() == kind)
121        {
122            let updated = existing.capabilities() | capabilities;
123            *existing = ModifierInvalidation::new(kind, updated);
124        } else {
125            self.invalidations
126                .push(ModifierInvalidation::new(kind, capabilities));
127        }
128    }
129
130    fn current_capabilities(&self) -> NodeCapabilities {
131        self.active_capabilities
132            .last()
133            .copied()
134            .unwrap_or_else(NodeCapabilities::empty)
135    }
136}
137
138impl ModifierNodeContext for BasicModifierNodeContext {
139    fn invalidate(&mut self, kind: InvalidationKind) {
140        self.push_invalidation(kind);
141    }
142
143    fn request_update(&mut self) {
144        self.update_requested = true;
145    }
146
147    fn push_active_capabilities(&mut self, capabilities: NodeCapabilities) {
148        self.active_capabilities.push(capabilities);
149    }
150
151    fn pop_active_capabilities(&mut self) {
152        self.active_capabilities.pop();
153    }
154
155    fn node_id(&self) -> Option<cranpose_core::NodeId> {
156        self.node_id
157    }
158}
159
160#[derive(Clone, Debug, PartialEq, Eq)]
161pub(crate) struct NodePath {
162    entry: usize,
163    delegates: Vec<usize>,
164}
165
166impl NodePath {
167    fn root(entry: usize) -> Self {
168        Self {
169            entry,
170            delegates: Vec::new(),
171        }
172    }
173
174    fn from_slice(entry: usize, path: &[usize]) -> Self {
175        Self {
176            entry,
177            delegates: path.to_vec(),
178        }
179    }
180
181    fn entry(&self) -> usize {
182        self.entry
183    }
184
185    fn delegates(&self) -> &[usize] {
186        &self.delegates
187    }
188}
189
190#[derive(Clone, Debug, PartialEq, Eq)]
191pub(crate) enum NodeLink {
192    Head,
193    Tail,
194    Entry(NodePath),
195}
196
197/// Runtime state tracked for every [`ModifierNode`].
198///
199/// This type is part of the internal node system API and should not be directly
200/// constructed or manipulated by external code. Modifier nodes automatically receive
201/// and manage their NodeState through the modifier chain infrastructure.
202#[derive(Debug)]
203pub struct NodeState {
204    aggregate_child_capabilities: Cell<NodeCapabilities>,
205    capabilities: Cell<NodeCapabilities>,
206    parent: RefCell<Option<NodeLink>>,
207    child: RefCell<Option<NodeLink>>,
208    attached: Cell<bool>,
209    is_sentinel: bool,
210}
211
212impl Default for NodeState {
213    fn default() -> Self {
214        Self::new()
215    }
216}
217
218impl NodeState {
219    pub const fn new() -> Self {
220        Self {
221            aggregate_child_capabilities: Cell::new(NodeCapabilities::empty()),
222            capabilities: Cell::new(NodeCapabilities::empty()),
223            parent: RefCell::new(None),
224            child: RefCell::new(None),
225            attached: Cell::new(false),
226            is_sentinel: false,
227        }
228    }
229
230    pub const fn sentinel() -> Self {
231        Self {
232            aggregate_child_capabilities: Cell::new(NodeCapabilities::empty()),
233            capabilities: Cell::new(NodeCapabilities::empty()),
234            parent: RefCell::new(None),
235            child: RefCell::new(None),
236            attached: Cell::new(true),
237            is_sentinel: true,
238        }
239    }
240
241    pub fn set_capabilities(&self, capabilities: NodeCapabilities) {
242        self.capabilities.set(capabilities);
243    }
244
245    pub fn capabilities(&self) -> NodeCapabilities {
246        self.capabilities.get()
247    }
248
249    pub fn set_aggregate_child_capabilities(&self, capabilities: NodeCapabilities) {
250        self.aggregate_child_capabilities.set(capabilities);
251    }
252
253    pub fn aggregate_child_capabilities(&self) -> NodeCapabilities {
254        self.aggregate_child_capabilities.get()
255    }
256
257    pub(crate) fn set_parent_link(&self, parent: Option<NodeLink>) {
258        *self.parent.borrow_mut() = parent;
259    }
260
261    pub(crate) fn parent_link(&self) -> Option<NodeLink> {
262        self.parent.borrow().clone()
263    }
264
265    pub(crate) fn set_child_link(&self, child: Option<NodeLink>) {
266        *self.child.borrow_mut() = child;
267    }
268
269    pub(crate) fn child_link(&self) -> Option<NodeLink> {
270        self.child.borrow().clone()
271    }
272
273    pub fn set_attached(&self, attached: bool) {
274        self.attached.set(attached);
275    }
276
277    pub fn is_attached(&self) -> bool {
278        self.attached.get()
279    }
280
281    pub fn is_sentinel(&self) -> bool {
282        self.is_sentinel
283    }
284}
285
286/// Provides traversal helpers that mirror Jetpack Compose's [`DelegatableNode`] contract.
287pub trait DelegatableNode {
288    fn node_state(&self) -> &NodeState;
289    fn aggregate_child_capabilities(&self) -> NodeCapabilities {
290        self.node_state().aggregate_child_capabilities()
291    }
292}
293
294/// Core trait implemented by modifier nodes.
295///
296/// # Capability-Driven Architecture
297///
298/// This trait follows Jetpack Compose's `Modifier.Node` pattern where nodes declare
299/// their capabilities via [`NodeCapabilities`] and implement specialized traits
300/// ([`DrawModifierNode`], [`PointerInputNode`], [`SemanticsNode`], [`FocusNode`], etc.)
301/// to participate in specific pipeline stages.
302///
303/// ## How to Implement a Modifier Node
304///
305/// 1. **Declare capabilities** in your [`ModifierNodeElement::capabilities()`] implementation
306/// 2. **Implement specialized traits** for the capabilities you declared
307/// 3. **Use helper macros** to reduce boilerplate (recommended)
308///
309/// ### Example: Draw Node
310///
311/// ```text
312/// use cranpose_foundation::*;
313///
314/// struct MyDrawNode {
315///     state: NodeState,
316///     color: Color,
317/// }
318///
319/// impl DelegatableNode for MyDrawNode {
320///     fn node_state(&self) -> &NodeState {
321///         &self.state
322///     }
323/// }
324///
325/// impl ModifierNode for MyDrawNode {
326///     // Use the helper macro instead of manual as_* implementations
327///     impl_modifier_node!(draw);
328/// }
329///
330/// impl DrawModifierNode for MyDrawNode {
331///     fn draw(&mut self, _context: &mut dyn ModifierNodeContext, draw_scope: &mut dyn DrawScope) {
332///         // Drawing logic here
333///     }
334/// }
335/// ```
336///
337/// ### Example: Multi-Capability Node
338///
339/// ```text
340/// impl ModifierNode for MyComplexNode {
341///     // This node participates in draw, pointer input, and semantics
342///     impl_modifier_node!(draw, pointer_input, semantics);
343/// }
344/// ```
345///
346/// ## Lifecycle Callbacks
347///
348/// Nodes receive lifecycle callbacks when they attach to or detach from a
349/// composition and may optionally react to resets triggered by the runtime
350/// (for example, when reusing nodes across modifier list changes).
351pub trait ModifierNode: Any + DelegatableNode {
352    fn on_attach(&mut self, _context: &mut dyn ModifierNodeContext) {}
353
354    fn on_detach(&mut self) {}
355
356    fn on_reset(&mut self) {}
357
358    /// Returns this node as a draw modifier if it implements the trait.
359    fn as_draw_node(&self) -> Option<&dyn DrawModifierNode> {
360        None
361    }
362
363    /// Returns this node as a mutable draw modifier if it implements the trait.
364    fn as_draw_node_mut(&mut self) -> Option<&mut dyn DrawModifierNode> {
365        None
366    }
367
368    /// Returns this node as a pointer-input modifier if it implements the trait.
369    fn as_pointer_input_node(&self) -> Option<&dyn PointerInputNode> {
370        None
371    }
372
373    /// Returns this node as a mutable pointer-input modifier if it implements the trait.
374    fn as_pointer_input_node_mut(&mut self) -> Option<&mut dyn PointerInputNode> {
375        None
376    }
377
378    /// Returns this node as a semantics modifier if it implements the trait.
379    fn as_semantics_node(&self) -> Option<&dyn SemanticsNode> {
380        None
381    }
382
383    /// Returns this node as a mutable semantics modifier if it implements the trait.
384    fn as_semantics_node_mut(&mut self) -> Option<&mut dyn SemanticsNode> {
385        None
386    }
387
388    /// Returns this node as a focus modifier if it implements the trait.
389    fn as_focus_node(&self) -> Option<&dyn FocusNode> {
390        None
391    }
392
393    /// Returns this node as a mutable focus modifier if it implements the trait.
394    fn as_focus_node_mut(&mut self) -> Option<&mut dyn FocusNode> {
395        None
396    }
397
398    /// Returns this node as a layout modifier if it implements the trait.
399    fn as_layout_node(&self) -> Option<&dyn LayoutModifierNode> {
400        None
401    }
402
403    /// Returns this node as a mutable layout modifier if it implements the trait.
404    fn as_layout_node_mut(&mut self) -> Option<&mut dyn LayoutModifierNode> {
405        None
406    }
407
408    /// Visits every delegate node owned by this modifier.
409    fn for_each_delegate<'b>(&'b self, _visitor: &mut dyn FnMut(&'b dyn ModifierNode)) {}
410
411    /// Visits every delegate node mutably.
412    fn for_each_delegate_mut<'b>(&'b mut self, _visitor: &mut dyn FnMut(&'b mut dyn ModifierNode)) {
413    }
414}
415
416/// Marker trait for layout-specific modifier nodes.
417///
418/// Layout nodes participate in the measure and layout passes of the render
419/// pipeline. They can intercept and modify the measurement and placement of
420/// their wrapped content.
421pub trait LayoutModifierNode: ModifierNode {
422    /// Measures the wrapped content and returns both the size this modifier
423    /// occupies and where the wrapped content should be placed.
424    ///
425    /// The node receives a measurable representing the wrapped content and
426    /// the incoming constraints from the parent.
427    ///
428    /// Returns a `LayoutModifierMeasureResult` containing:
429    /// - `size`: The final size this modifier will occupy
430    /// - `placement_offset_x/y`: Where to place the wrapped content relative
431    ///   to this modifier's top-left corner
432    ///
433    /// For example, a padding modifier would:
434    /// - Measure child with deflated constraints
435    /// - Return size = child size + padding
436    /// - Return placement offset = (padding.left, padding.top)
437    ///
438    /// The default implementation delegates to the wrapped content without
439    /// modification (size = child size, offset = 0).
440    ///
441    /// NOTE: This takes `&self` not `&mut self` to match Jetpack Compose semantics.
442    /// Nodes that need mutable state should use interior mutability (Cell/RefCell).
443    fn measure(
444        &self,
445        _context: &mut dyn ModifierNodeContext,
446        measurable: &dyn Measurable,
447        constraints: Constraints,
448    ) -> cranpose_ui_layout::LayoutModifierMeasureResult {
449        // Default: pass through to wrapped content by measuring the child.
450        let placeable = measurable.measure(constraints);
451        cranpose_ui_layout::LayoutModifierMeasureResult::with_size(Size {
452            width: placeable.width(),
453            height: placeable.height(),
454        })
455    }
456
457    /// Returns the minimum intrinsic width of this modifier node.
458    fn min_intrinsic_width(&self, _measurable: &dyn Measurable, _height: f32) -> f32 {
459        0.0
460    }
461
462    /// Returns the maximum intrinsic width of this modifier node.
463    fn max_intrinsic_width(&self, _measurable: &dyn Measurable, _height: f32) -> f32 {
464        0.0
465    }
466
467    /// Returns the minimum intrinsic height of this modifier node.
468    fn min_intrinsic_height(&self, _measurable: &dyn Measurable, _width: f32) -> f32 {
469        0.0
470    }
471
472    /// Returns the maximum intrinsic height of this modifier node.
473    fn max_intrinsic_height(&self, _measurable: &dyn Measurable, _width: f32) -> f32 {
474        0.0
475    }
476
477    /// Creates a measurement proxy for this node that can perform measurement
478    /// without holding a borrow to the modifier chain.
479    ///
480    /// This method enables custom layout modifiers to work with the coordinator
481    /// chain while respecting Rust's borrow checker constraints. The proxy
482    /// should capture a snapshot of the node's current configuration.
483    ///
484    /// The default implementation returns `None`, which causes the coordinator
485    /// to use a passthrough strategy that delegates directly to the wrapped
486    /// content.
487    ///
488    /// # Example
489    ///
490    /// ```text
491    /// impl LayoutModifierNode for MyCustomLayoutNode {
492    ///     fn create_measurement_proxy(&self) -> Option<Box<dyn MeasurementProxy>> {
493    ///         Some(Box::new(MyCustomLayoutProxy {
494    ///             // Snapshot node configuration here
495    ///             padding: self.padding,
496    ///         }))
497    ///     }
498    /// }
499    /// ```
500    fn create_measurement_proxy(
501        &self,
502    ) -> Option<Box<dyn crate::measurement_proxy::MeasurementProxy>> {
503        None
504    }
505}
506
507/// Marker trait for draw-specific modifier nodes.
508///
509/// Draw nodes participate in the draw pass of the render pipeline. They can
510/// intercept and modify the drawing operations of their wrapped content.
511///
512/// Following Jetpack Compose's design, `draw()` is called during the actual
513/// render pass with a live DrawScope, not during layout/slice collection.
514pub trait DrawModifierNode: ModifierNode {
515    /// Draws this modifier node into the provided DrawScope.
516    ///
517    /// This is called during the render pass for each node with DRAW capability.
518    /// The node should draw directly into the scope using methods like
519    /// `draw_scope.draw_rect_at()`.
520    ///
521    /// Takes `&self` to work with immutable chain iteration - use interior
522    /// mutability (RefCell) for any state that needs mutation during draw.
523    fn draw(&self, _draw_scope: &mut dyn DrawScope) {
524        // Default: no custom drawing
525    }
526
527    /// Creates a closure for deferred drawing that will be evaluated at render time.
528    ///
529    /// This is the preferred method for nodes with dynamic content like:
530    /// - Blinking cursors (visibility changes over time)
531    /// - Live selection during drag (selection changes during mouse move)
532    ///
533    /// The returned closure captures the node's internal state (via Rc) and
534    /// evaluates at render time, not at slice collection time.
535    ///
536    /// Returns None by default. Override for nodes needing deferred draw.
537    fn create_draw_closure(
538        &self,
539    ) -> Option<Rc<dyn Fn(Size) -> Vec<cranpose_ui_graphics::DrawPrimitive>>> {
540        None
541    }
542}
543
544/// Marker trait for pointer input modifier nodes.
545///
546/// Pointer input nodes participate in hit-testing and pointer event
547/// dispatch. They can intercept pointer events and handle them before
548/// they reach the wrapped content.
549pub trait PointerInputNode: ModifierNode {
550    /// Called when a pointer event occurs within the bounds of this node.
551    /// Returns true if the event was consumed and should not propagate further.
552    fn on_pointer_event(
553        &mut self,
554        _context: &mut dyn ModifierNodeContext,
555        _event: &PointerEvent,
556    ) -> bool {
557        false
558    }
559
560    /// Returns true if this node should participate in hit-testing for the
561    /// given pointer position.
562    fn hit_test(&self, _x: f32, _y: f32) -> bool {
563        true
564    }
565
566    /// Returns an event handler closure if the node wants to participate in pointer dispatch.
567    fn pointer_input_handler(&self) -> Option<Rc<dyn Fn(PointerEvent)>> {
568        None
569    }
570}
571
572/// Marker trait for semantics modifier nodes.
573///
574/// Semantics nodes participate in the semantics tree construction. They can
575/// add or modify semantic properties of their wrapped content for
576/// accessibility and testing purposes.
577pub trait SemanticsNode: ModifierNode {
578    /// Merges semantic properties into the provided configuration.
579    fn merge_semantics(&self, _config: &mut SemanticsConfiguration) {
580        // Default: no semantics added
581    }
582}
583
584/// Focus state of a focus target node.
585///
586/// This mirrors Jetpack Compose's FocusState enum which tracks whether
587/// a node is focused, has a focused child, or is inactive.
588#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Default)]
589pub enum FocusState {
590    /// The focusable component is currently active (i.e. it receives key events).
591    Active,
592    /// One of the descendants of the focusable component is Active.
593    ActiveParent,
594    /// The focusable component is currently active (has focus), and is in a state
595    /// where it does not want to give up focus. (Eg. a text field with an invalid
596    /// phone number).
597    Captured,
598    /// The focusable component does not receive any key events. (ie it is not active,
599    /// nor are any of its descendants active).
600    #[default]
601    Inactive,
602}
603
604impl FocusState {
605    /// Returns whether the component is focused (Active or Captured).
606    pub fn is_focused(self) -> bool {
607        matches!(self, FocusState::Active | FocusState::Captured)
608    }
609
610    /// Returns whether this node or any descendant has focus.
611    pub fn has_focus(self) -> bool {
612        matches!(
613            self,
614            FocusState::Active | FocusState::ActiveParent | FocusState::Captured
615        )
616    }
617
618    /// Returns whether focus is captured.
619    pub fn is_captured(self) -> bool {
620        matches!(self, FocusState::Captured)
621    }
622}
623
624/// Marker trait for focus modifier nodes.
625///
626/// Focus nodes participate in focus management. They can request focus,
627/// track focus state, and participate in focus traversal.
628pub trait FocusNode: ModifierNode {
629    /// Returns the current focus state of this node.
630    fn focus_state(&self) -> FocusState;
631
632    /// Called when focus state changes for this node.
633    fn on_focus_changed(&mut self, _context: &mut dyn ModifierNodeContext, _state: FocusState) {
634        // Default: no action on focus change
635    }
636}
637
638/// Semantics configuration for accessibility.
639#[derive(Clone, Debug, Default, PartialEq)]
640pub struct SemanticsConfiguration {
641    pub content_description: Option<String>,
642    pub is_button: bool,
643    pub is_clickable: bool,
644}
645
646impl SemanticsConfiguration {
647    pub fn merge(&mut self, other: &SemanticsConfiguration) {
648        if let Some(description) = &other.content_description {
649            self.content_description = Some(description.clone());
650        }
651        self.is_button |= other.is_button;
652        self.is_clickable |= other.is_clickable;
653    }
654}
655
656impl fmt::Debug for dyn ModifierNode {
657    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
658        f.debug_struct("ModifierNode").finish_non_exhaustive()
659    }
660}
661
662impl dyn ModifierNode {
663    pub fn as_any(&self) -> &dyn Any {
664        self
665    }
666
667    pub fn as_any_mut(&mut self) -> &mut dyn Any {
668        self
669    }
670}
671
672/// Strongly typed modifier elements that can create and update nodes while
673/// exposing equality/hash/inspector contracts that mirror Jetpack Compose.
674pub trait ModifierNodeElement: fmt::Debug + Hash + PartialEq + 'static {
675    type Node: ModifierNode;
676
677    /// Creates a new modifier node instance for this element.
678    fn create(&self) -> Self::Node;
679
680    /// Brings an existing modifier node up to date with the element's data.
681    fn update(&self, node: &mut Self::Node);
682
683    /// Optional key used to disambiguate multiple instances of the same element type.
684    fn key(&self) -> Option<u64> {
685        None
686    }
687
688    /// Human readable name surfaced to inspector tooling.
689    fn inspector_name(&self) -> &'static str {
690        type_name::<Self>()
691    }
692
693    /// Records inspector properties for tooling.
694    fn inspector_properties(&self, _inspector: &mut dyn FnMut(&'static str, String)) {}
695
696    /// Returns the capabilities of nodes created by this element.
697    /// Override this to indicate which specialized traits the node implements.
698    fn capabilities(&self) -> NodeCapabilities {
699        NodeCapabilities::default()
700    }
701
702    /// Whether this element requires `update` to be called even if `eq` returns true.
703    ///
704    /// This is useful for elements that ignore certain fields in `eq` (e.g. closures)
705    /// to allow node reuse, but still need those fields updated in the existing node.
706    /// Defaults to `false`.
707    fn always_update(&self) -> bool {
708        false
709    }
710}
711
712/// Transitional alias so existing call sites that refer to `ModifierElement`
713/// keep compiling while the ecosystem migrates to `ModifierNodeElement`.
714pub trait ModifierElement: ModifierNodeElement {}
715
716impl<T> ModifierElement for T where T: ModifierNodeElement {}
717
718/// Capability flags indicating which specialized traits a modifier node implements.
719#[derive(Clone, Copy, PartialEq, Eq, Hash)]
720pub struct NodeCapabilities(u32);
721
722impl NodeCapabilities {
723    /// No capabilities.
724    pub const NONE: Self = Self(0);
725    /// Modifier participates in measure/layout.
726    pub const LAYOUT: Self = Self(1 << 0);
727    /// Modifier participates in draw.
728    pub const DRAW: Self = Self(1 << 1);
729    /// Modifier participates in pointer input.
730    pub const POINTER_INPUT: Self = Self(1 << 2);
731    /// Modifier participates in semantics tree construction.
732    pub const SEMANTICS: Self = Self(1 << 3);
733    /// Modifier participates in modifier locals.
734    pub const MODIFIER_LOCALS: Self = Self(1 << 4);
735    /// Modifier participates in focus management.
736    pub const FOCUS: Self = Self(1 << 5);
737
738    /// Returns an empty capability set.
739    pub const fn empty() -> Self {
740        Self::NONE
741    }
742
743    /// Returns whether all bits in `other` are present in `self`.
744    pub const fn contains(self, other: Self) -> bool {
745        (self.0 & other.0) == other.0
746    }
747
748    /// Returns whether any bit in `other` is present in `self`.
749    pub const fn intersects(self, other: Self) -> bool {
750        (self.0 & other.0) != 0
751    }
752
753    /// Inserts the requested capability bits.
754    pub fn insert(&mut self, other: Self) {
755        self.0 |= other.0;
756    }
757
758    /// Returns the raw bit representation.
759    pub const fn bits(self) -> u32 {
760        self.0
761    }
762
763    /// Returns true when no capabilities are set.
764    pub const fn is_empty(self) -> bool {
765        self.0 == 0
766    }
767
768    /// Returns the capability bit mask required for the given invalidation.
769    pub const fn for_invalidation(kind: InvalidationKind) -> Self {
770        match kind {
771            InvalidationKind::Layout => Self::LAYOUT,
772            InvalidationKind::Draw => Self::DRAW,
773            InvalidationKind::PointerInput => Self::POINTER_INPUT,
774            InvalidationKind::Semantics => Self::SEMANTICS,
775            InvalidationKind::Focus => Self::FOCUS,
776        }
777    }
778}
779
780impl Default for NodeCapabilities {
781    fn default() -> Self {
782        Self::NONE
783    }
784}
785
786impl fmt::Debug for NodeCapabilities {
787    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
788        f.debug_struct("NodeCapabilities")
789            .field("layout", &self.contains(Self::LAYOUT))
790            .field("draw", &self.contains(Self::DRAW))
791            .field("pointer_input", &self.contains(Self::POINTER_INPUT))
792            .field("semantics", &self.contains(Self::SEMANTICS))
793            .field("modifier_locals", &self.contains(Self::MODIFIER_LOCALS))
794            .field("focus", &self.contains(Self::FOCUS))
795            .finish()
796    }
797}
798
799impl BitOr for NodeCapabilities {
800    type Output = Self;
801
802    fn bitor(self, rhs: Self) -> Self::Output {
803        Self(self.0 | rhs.0)
804    }
805}
806
807impl BitOrAssign for NodeCapabilities {
808    fn bitor_assign(&mut self, rhs: Self) {
809        self.0 |= rhs.0;
810    }
811}
812
813/// Records an invalidation request together with the capability mask that triggered it.
814#[derive(Clone, Copy, Debug, PartialEq, Eq)]
815pub struct ModifierInvalidation {
816    kind: InvalidationKind,
817    capabilities: NodeCapabilities,
818}
819
820impl ModifierInvalidation {
821    /// Creates a new modifier invalidation entry.
822    pub const fn new(kind: InvalidationKind, capabilities: NodeCapabilities) -> Self {
823        Self { kind, capabilities }
824    }
825
826    /// Returns the invalidated pipeline kind.
827    pub const fn kind(self) -> InvalidationKind {
828        self.kind
829    }
830
831    /// Returns the capability mask associated with the invalidation.
832    pub const fn capabilities(self) -> NodeCapabilities {
833        self.capabilities
834    }
835}
836
837/// Type-erased modifier element used by the runtime to reconcile chains.
838pub trait AnyModifierElement: fmt::Debug {
839    fn node_type(&self) -> TypeId;
840
841    fn element_type(&self) -> TypeId;
842
843    fn create_node(&self) -> Box<dyn ModifierNode>;
844
845    fn update_node(&self, node: &mut dyn ModifierNode);
846
847    fn key(&self) -> Option<u64>;
848
849    fn capabilities(&self) -> NodeCapabilities {
850        NodeCapabilities::default()
851    }
852
853    fn hash_code(&self) -> u64;
854
855    fn equals_element(&self, other: &dyn AnyModifierElement) -> bool;
856
857    fn inspector_name(&self) -> &'static str;
858
859    fn record_inspector_properties(&self, visitor: &mut dyn FnMut(&'static str, String));
860
861    fn requires_update(&self) -> bool;
862
863    fn as_any(&self) -> &dyn Any;
864}
865
866struct TypedModifierElement<E: ModifierNodeElement> {
867    element: E,
868}
869
870impl<E: ModifierNodeElement> TypedModifierElement<E> {
871    fn new(element: E) -> Self {
872        Self { element }
873    }
874}
875
876impl<E> fmt::Debug for TypedModifierElement<E>
877where
878    E: ModifierNodeElement,
879{
880    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
881        f.debug_struct("TypedModifierElement")
882            .field("type", &type_name::<E>())
883            .finish()
884    }
885}
886
887impl<E> AnyModifierElement for TypedModifierElement<E>
888where
889    E: ModifierNodeElement,
890{
891    fn node_type(&self) -> TypeId {
892        TypeId::of::<E::Node>()
893    }
894
895    fn element_type(&self) -> TypeId {
896        TypeId::of::<E>()
897    }
898
899    fn create_node(&self) -> Box<dyn ModifierNode> {
900        Box::new(self.element.create())
901    }
902
903    fn update_node(&self, node: &mut dyn ModifierNode) {
904        let typed = node
905            .as_any_mut()
906            .downcast_mut::<E::Node>()
907            .expect("modifier node type mismatch");
908        self.element.update(typed);
909    }
910
911    fn key(&self) -> Option<u64> {
912        self.element.key()
913    }
914
915    fn capabilities(&self) -> NodeCapabilities {
916        self.element.capabilities()
917    }
918
919    fn hash_code(&self) -> u64 {
920        let mut hasher = DefaultHasher::new();
921        self.element.hash(&mut hasher);
922        hasher.finish()
923    }
924
925    fn equals_element(&self, other: &dyn AnyModifierElement) -> bool {
926        other
927            .as_any()
928            .downcast_ref::<Self>()
929            .map(|typed| typed.element == self.element)
930            .unwrap_or(false)
931    }
932
933    fn inspector_name(&self) -> &'static str {
934        self.element.inspector_name()
935    }
936
937    fn record_inspector_properties(&self, visitor: &mut dyn FnMut(&'static str, String)) {
938        self.element.inspector_properties(visitor);
939    }
940
941    fn requires_update(&self) -> bool {
942        self.element.always_update()
943    }
944
945    fn as_any(&self) -> &dyn Any {
946        self
947    }
948}
949
950/// Convenience helper for callers to construct a type-erased modifier
951/// element without having to mention the internal wrapper type.
952pub fn modifier_element<E: ModifierNodeElement>(element: E) -> DynModifierElement {
953    Rc::new(TypedModifierElement::new(element))
954}
955
956/// Boxed type-erased modifier element.
957pub type DynModifierElement = Rc<dyn AnyModifierElement>;
958
959#[derive(Clone, Copy, Debug, PartialEq, Eq)]
960enum TraversalDirection {
961    Forward,
962    Backward,
963}
964
965/// Iterator walking a modifier chain either from head-to-tail or tail-to-head.
966pub struct ModifierChainIter<'a> {
967    next: Option<ModifierChainNodeRef<'a>>,
968    direction: TraversalDirection,
969}
970
971impl<'a> ModifierChainIter<'a> {
972    fn new(start: Option<ModifierChainNodeRef<'a>>, direction: TraversalDirection) -> Self {
973        Self {
974            next: start,
975            direction,
976        }
977    }
978}
979
980impl<'a> Iterator for ModifierChainIter<'a> {
981    type Item = ModifierChainNodeRef<'a>;
982
983    fn next(&mut self) -> Option<Self::Item> {
984        let current = self.next.take()?;
985        if current.is_sentinel() {
986            self.next = None;
987            return None;
988        }
989        self.next = match self.direction {
990            TraversalDirection::Forward => current.child(),
991            TraversalDirection::Backward => current.parent(),
992        };
993        Some(current)
994    }
995}
996
997impl<'a> std::iter::FusedIterator for ModifierChainIter<'a> {}
998
999#[derive(Debug)]
1000struct ModifierNodeEntry {
1001    element_type: TypeId,
1002    key: Option<u64>,
1003    hash_code: u64,
1004    element: DynModifierElement,
1005    node: Rc<RefCell<Box<dyn ModifierNode>>>,
1006    capabilities: NodeCapabilities,
1007}
1008
1009impl ModifierNodeEntry {
1010    fn new(
1011        element_type: TypeId,
1012        key: Option<u64>,
1013        element: DynModifierElement,
1014        node: Box<dyn ModifierNode>,
1015        hash_code: u64,
1016        capabilities: NodeCapabilities,
1017    ) -> Self {
1018        // Wrap the boxed node in Rc<RefCell<>> for shared ownership
1019        let node_rc = Rc::new(RefCell::new(node));
1020        let entry = Self {
1021            element_type,
1022            key,
1023            hash_code,
1024            element,
1025            node: Rc::clone(&node_rc),
1026            capabilities,
1027        };
1028        entry
1029            .node
1030            .borrow()
1031            .node_state()
1032            .set_capabilities(entry.capabilities);
1033        entry
1034    }
1035}
1036
1037fn visit_node_tree_mut(
1038    node: &mut dyn ModifierNode,
1039    visitor: &mut dyn FnMut(&mut dyn ModifierNode),
1040) {
1041    visitor(node);
1042    node.for_each_delegate_mut(&mut |child| visit_node_tree_mut(child, visitor));
1043}
1044
1045fn nth_delegate(node: &dyn ModifierNode, target: usize) -> Option<&dyn ModifierNode> {
1046    let mut current = 0usize;
1047    let mut result: Option<&dyn ModifierNode> = None;
1048    node.for_each_delegate(&mut |child| {
1049        if result.is_none() && current == target {
1050            result = Some(child);
1051        }
1052        current += 1;
1053    });
1054    result
1055}
1056
1057fn nth_delegate_mut(node: &mut dyn ModifierNode, target: usize) -> Option<&mut dyn ModifierNode> {
1058    let mut current = 0usize;
1059    let mut result: Option<&mut dyn ModifierNode> = None;
1060    node.for_each_delegate_mut(&mut |child| {
1061        if result.is_none() && current == target {
1062            result = Some(child);
1063        }
1064        current += 1;
1065    });
1066    result
1067}
1068
1069fn with_node_context<F, R>(
1070    node: &mut dyn ModifierNode,
1071    context: &mut dyn ModifierNodeContext,
1072    f: F,
1073) -> R
1074where
1075    F: FnOnce(&mut dyn ModifierNode, &mut dyn ModifierNodeContext) -> R,
1076{
1077    context.push_active_capabilities(node.node_state().capabilities());
1078    let result = f(node, context);
1079    context.pop_active_capabilities();
1080    result
1081}
1082
1083fn request_auto_invalidations(
1084    context: &mut dyn ModifierNodeContext,
1085    capabilities: NodeCapabilities,
1086) {
1087    if capabilities.is_empty() {
1088        return;
1089    }
1090
1091    context.push_active_capabilities(capabilities);
1092
1093    if capabilities.contains(NodeCapabilities::LAYOUT) {
1094        context.invalidate(InvalidationKind::Layout);
1095    }
1096    if capabilities.contains(NodeCapabilities::DRAW) {
1097        context.invalidate(InvalidationKind::Draw);
1098    }
1099    if capabilities.contains(NodeCapabilities::POINTER_INPUT) {
1100        context.invalidate(InvalidationKind::PointerInput);
1101    }
1102    if capabilities.contains(NodeCapabilities::SEMANTICS) {
1103        context.invalidate(InvalidationKind::Semantics);
1104    }
1105    if capabilities.contains(NodeCapabilities::FOCUS) {
1106        context.invalidate(InvalidationKind::Focus);
1107    }
1108
1109    context.pop_active_capabilities();
1110}
1111
1112/// Attaches a node tree by calling on_attach for all unattached nodes.
1113///
1114/// # Safety
1115/// Callers must ensure no immutable RefCell borrows are held on the node
1116/// when calling this function. The on_attach callback may trigger mutations
1117/// (invalidations, state updates, etc.) that require mutable access, which
1118/// would panic if an immutable borrow is held across the call.
1119fn attach_node_tree(node: &mut dyn ModifierNode, context: &mut dyn ModifierNodeContext) {
1120    visit_node_tree_mut(node, &mut |n| {
1121        if !n.node_state().is_attached() {
1122            n.node_state().set_attached(true);
1123            with_node_context(n, context, |node, ctx| node.on_attach(ctx));
1124        }
1125    });
1126}
1127
1128fn reset_node_tree(node: &mut dyn ModifierNode) {
1129    visit_node_tree_mut(node, &mut |n| n.on_reset());
1130}
1131
1132fn detach_node_tree(node: &mut dyn ModifierNode) {
1133    visit_node_tree_mut(node, &mut |n| {
1134        if n.node_state().is_attached() {
1135            n.on_detach();
1136            n.node_state().set_attached(false);
1137        }
1138        n.node_state().set_parent_link(None);
1139        n.node_state().set_child_link(None);
1140        n.node_state()
1141            .set_aggregate_child_capabilities(NodeCapabilities::empty());
1142    });
1143}
1144
1145/// Chain of modifier nodes attached to a layout node.
1146///
1147/// The chain tracks ownership of modifier nodes and reuses them across
1148/// updates when the incoming element list still contains a node of the
1149/// same type. Removed nodes detach automatically so callers do not need
1150/// to manually manage their lifetimes.
1151pub struct ModifierNodeChain {
1152    entries: Vec<ModifierNodeEntry>,
1153    aggregated_capabilities: NodeCapabilities,
1154    head_aggregate_child_capabilities: NodeCapabilities,
1155    head_sentinel: Box<SentinelNode>,
1156    tail_sentinel: Box<SentinelNode>,
1157    ordered_nodes: Vec<NodeLink>,
1158}
1159
1160struct SentinelNode {
1161    state: NodeState,
1162}
1163
1164impl SentinelNode {
1165    fn new() -> Self {
1166        Self {
1167            state: NodeState::sentinel(),
1168        }
1169    }
1170}
1171
1172impl DelegatableNode for SentinelNode {
1173    fn node_state(&self) -> &NodeState {
1174        &self.state
1175    }
1176}
1177
1178impl ModifierNode for SentinelNode {}
1179
1180#[derive(Clone)]
1181pub struct ModifierChainNodeRef<'a> {
1182    chain: &'a ModifierNodeChain,
1183    link: NodeLink,
1184}
1185
1186impl Default for ModifierNodeChain {
1187    fn default() -> Self {
1188        Self::new()
1189    }
1190}
1191
1192/// Index structure for O(1) modifier entry lookups during update.
1193///
1194/// This avoids O(n²) complexity by pre-building hash maps that allow constant-time
1195/// lookups for matching entries by key, hash, or type.
1196struct EntryIndex {
1197    /// Map (TypeId, key) → index for keyed entries
1198    keyed: HashMap<(TypeId, u64), Vec<usize>>,
1199    /// Map (TypeId, hash) → indices for unkeyed entries with specific hash
1200    hashed: HashMap<(TypeId, u64), Vec<usize>>,
1201    /// Map TypeId → indices for all unkeyed entries of that type
1202    typed: HashMap<TypeId, Vec<usize>>,
1203}
1204
1205impl EntryIndex {
1206    fn build(entries: &[ModifierNodeEntry]) -> Self {
1207        let mut keyed = HashMap::new();
1208        let mut hashed = HashMap::new();
1209        let mut typed = HashMap::new();
1210
1211        for (i, entry) in entries.iter().enumerate() {
1212            if let Some(key_value) = entry.key {
1213                // Keyed entry
1214                keyed
1215                    .entry((entry.element_type, key_value))
1216                    .or_insert_with(Vec::new)
1217                    .push(i);
1218            } else {
1219                // Unkeyed entry - add to both hash and type indices
1220                hashed
1221                    .entry((entry.element_type, entry.hash_code))
1222                    .or_insert_with(Vec::new)
1223                    .push(i);
1224                typed
1225                    .entry(entry.element_type)
1226                    .or_insert_with(Vec::new)
1227                    .push(i);
1228            }
1229        }
1230
1231        Self {
1232            keyed,
1233            hashed,
1234            typed,
1235        }
1236    }
1237
1238    /// Find the best matching entry for reuse.
1239    ///
1240    /// Matching priority (from highest to lowest):
1241    /// 1. Keyed match: same type + same key
1242    /// 2. Exact match: same type + no key + same hash + equals_element
1243    /// 3. Type match: same type + no key (will require update)
1244    fn find_match(
1245        &self,
1246        entries: &[ModifierNodeEntry],
1247        used: &[bool],
1248        element_type: TypeId,
1249        key: Option<u64>,
1250        hash_code: u64,
1251        element: &DynModifierElement,
1252    ) -> Option<usize> {
1253        if let Some(key_value) = key {
1254            // Priority 1: Keyed lookup - O(1)
1255            if let Some(candidates) = self.keyed.get(&(element_type, key_value)) {
1256                for &i in candidates {
1257                    if !used[i] {
1258                        return Some(i);
1259                    }
1260                }
1261            }
1262        } else {
1263            // Priority 2: Exact match (hash + equality) - O(1) lookup + O(k) equality checks
1264            if let Some(candidates) = self.hashed.get(&(element_type, hash_code)) {
1265                for &i in candidates {
1266                    if !used[i] && entries[i].element.as_ref().equals_element(element.as_ref()) {
1267                        return Some(i);
1268                    }
1269                }
1270            }
1271
1272            // Priority 3: Type match only - O(1) lookup + O(k) scan
1273            if let Some(candidates) = self.typed.get(&element_type) {
1274                for &i in candidates {
1275                    if !used[i] {
1276                        return Some(i);
1277                    }
1278                }
1279            }
1280        }
1281
1282        None
1283    }
1284}
1285
1286impl ModifierNodeChain {
1287    pub fn new() -> Self {
1288        let mut chain = Self {
1289            entries: Vec::new(),
1290            aggregated_capabilities: NodeCapabilities::empty(),
1291            head_aggregate_child_capabilities: NodeCapabilities::empty(),
1292            head_sentinel: Box::new(SentinelNode::new()),
1293            tail_sentinel: Box::new(SentinelNode::new()),
1294            ordered_nodes: Vec::new(),
1295        };
1296        chain.sync_chain_links();
1297        chain
1298    }
1299
1300    /// Detaches all nodes in the chain.
1301    pub fn detach_nodes(&mut self) {
1302        for entry in &self.entries {
1303            detach_node_tree(&mut **entry.node.borrow_mut());
1304        }
1305    }
1306
1307    /// Attaches all nodes in the chain.
1308    pub fn attach_nodes(&mut self, context: &mut dyn ModifierNodeContext) {
1309        for entry in &self.entries {
1310            attach_node_tree(&mut **entry.node.borrow_mut(), context);
1311        }
1312    }
1313
1314    /// Rebuilds the internal chain links (parent/child relationships).
1315    /// This should be called if nodes have been detached but are intended to be reused.
1316    pub fn repair_chain(&mut self) {
1317        self.sync_chain_links();
1318    }
1319
1320    /// Reconcile the chain against the provided elements, attaching newly
1321    /// created nodes and detaching nodes that are no longer required.
1322    ///
1323    /// This method delegates to `update_from_ref_iter` which handles the
1324    /// actual reconciliation logic.
1325    pub fn update_from_slice(
1326        &mut self,
1327        elements: &[DynModifierElement],
1328        context: &mut dyn ModifierNodeContext,
1329    ) {
1330        self.update_from_ref_iter(elements.iter(), context);
1331    }
1332
1333    /// Reconcile the chain against the provided iterator of element references.
1334    ///
1335    /// This is the preferred method as it avoids requiring a collected slice,
1336    /// enabling zero-allocation traversal of modifier trees.
1337    pub fn update_from_ref_iter<'a, I>(
1338        &mut self,
1339        elements: I,
1340        context: &mut dyn ModifierNodeContext,
1341    ) where
1342        I: Iterator<Item = &'a DynModifierElement>,
1343    {
1344        let mut old_entries = std::mem::take(&mut self.entries);
1345        let mut old_used = vec![false; old_entries.len()];
1346        let mut new_entries: Vec<ModifierNodeEntry> = Vec::new();
1347
1348        // Build index for O(1) lookups - O(m) where m = old_entries.len()
1349        let index = EntryIndex::build(&old_entries);
1350
1351        // Track which old entry index maps to which position in new list
1352        let mut match_order: Vec<Option<usize>> = vec![None; old_entries.len()];
1353
1354        // Track element count as we iterate
1355        let mut element_count = 0usize;
1356
1357        // Process each new element, reusing old entries where possible - O(n)
1358        for (new_pos, element) in elements.enumerate() {
1359            element_count = new_pos + 1;
1360            let element_type = element.element_type();
1361            let key = element.key();
1362            let hash_code = element.hash_code();
1363            let capabilities = element.capabilities();
1364
1365            // Find best matching old entry via index - O(1) amortized
1366            let matched_idx = index.find_match(
1367                &old_entries,
1368                &old_used,
1369                element_type,
1370                key,
1371                hash_code,
1372                element,
1373            );
1374
1375            if let Some(idx) = matched_idx {
1376                // Reuse existing entry
1377                old_used[idx] = true;
1378                match_order[idx] = Some(new_pos);
1379                let entry = &mut old_entries[idx];
1380
1381                // Check if element actually changed
1382                let same_element = entry.element.as_ref().equals_element(element.as_ref());
1383
1384                // Re-attach node if it was detached during a previous update
1385                {
1386                    let node_borrow = entry.node.borrow();
1387                    if !node_borrow.node_state().is_attached() {
1388                        drop(node_borrow);
1389                        attach_node_tree(&mut **entry.node.borrow_mut(), context);
1390                    }
1391                }
1392
1393                // Optimize updates: only call update_node if element changed OR
1394                // if the element type explicitly requests forced updates
1395                let needs_update = !same_element || element.requires_update();
1396                if needs_update {
1397                    element.update_node(&mut **entry.node.borrow_mut());
1398                    entry.element = element.clone();
1399                    entry.hash_code = hash_code;
1400                    request_auto_invalidations(context, capabilities);
1401                }
1402
1403                // Always update metadata
1404                entry.key = key;
1405                entry.element_type = element_type;
1406                entry.capabilities = capabilities;
1407                entry
1408                    .node
1409                    .borrow()
1410                    .node_state()
1411                    .set_capabilities(capabilities);
1412            } else {
1413                // Create new entry
1414                let entry = ModifierNodeEntry::new(
1415                    element_type,
1416                    key,
1417                    element.clone(),
1418                    element.create_node(),
1419                    hash_code,
1420                    capabilities,
1421                );
1422                attach_node_tree(&mut **entry.node.borrow_mut(), context);
1423                element.update_node(&mut **entry.node.borrow_mut());
1424                request_auto_invalidations(context, capabilities);
1425                new_entries.push(entry);
1426            }
1427        }
1428
1429        // Assemble final list in correct order
1430        let mut matched_entries: Vec<(usize, ModifierNodeEntry)> = Vec::new();
1431        for (entry, (used, order)) in old_entries
1432            .into_iter()
1433            .zip(old_used.into_iter().zip(match_order))
1434        {
1435            if used {
1436                matched_entries.push((order.unwrap(), entry));
1437            } else {
1438                detach_node_tree(&mut **entry.node.borrow_mut());
1439            }
1440        }
1441
1442        matched_entries.sort_by_key(|(pos, _)| *pos);
1443
1444        // Merge matched entries with newly created entries
1445        let mut final_entries: Vec<ModifierNodeEntry> = Vec::with_capacity(element_count);
1446        let mut matched_iter = matched_entries.into_iter();
1447        let mut new_iter = new_entries.into_iter();
1448        let mut next_matched = matched_iter.next();
1449        let mut next_new = new_iter.next();
1450
1451        for pos in 0..element_count {
1452            if let Some((matched_pos, _)) = next_matched {
1453                if matched_pos == pos {
1454                    final_entries.push(next_matched.take().unwrap().1);
1455                    next_matched = matched_iter.next();
1456                    continue;
1457                }
1458            }
1459
1460            if let Some(entry) = next_new.take() {
1461                final_entries.push(entry);
1462                next_new = new_iter.next();
1463            }
1464        }
1465
1466        self.entries = final_entries;
1467        self.sync_chain_links();
1468    }
1469
1470    /// Convenience wrapper that accepts any iterator of type-erased
1471    /// modifier elements. Elements are collected into a temporary vector
1472    /// before reconciliation.
1473    pub fn update<I>(&mut self, elements: I, context: &mut dyn ModifierNodeContext)
1474    where
1475        I: IntoIterator<Item = DynModifierElement>,
1476    {
1477        let collected: Vec<DynModifierElement> = elements.into_iter().collect();
1478        self.update_from_slice(&collected, context);
1479    }
1480
1481    /// Resets all nodes in the chain. This mirrors the behaviour of
1482    /// Jetpack Compose's `onReset` callback.
1483    pub fn reset(&mut self) {
1484        for entry in &mut self.entries {
1485            reset_node_tree(&mut **entry.node.borrow_mut());
1486        }
1487    }
1488
1489    /// Detaches every node in the chain and clears internal storage.
1490    pub fn detach_all(&mut self) {
1491        for entry in std::mem::take(&mut self.entries) {
1492            detach_node_tree(&mut **entry.node.borrow_mut());
1493            {
1494                let node_borrow = entry.node.borrow();
1495                let state = node_borrow.node_state();
1496                state.set_capabilities(NodeCapabilities::empty());
1497            }
1498        }
1499        self.aggregated_capabilities = NodeCapabilities::empty();
1500        self.head_aggregate_child_capabilities = NodeCapabilities::empty();
1501        self.ordered_nodes.clear();
1502        self.sync_chain_links();
1503    }
1504
1505    pub fn len(&self) -> usize {
1506        self.entries.len()
1507    }
1508
1509    pub fn is_empty(&self) -> bool {
1510        self.entries.is_empty()
1511    }
1512
1513    /// Returns the aggregated capability mask for the entire chain.
1514    pub fn capabilities(&self) -> NodeCapabilities {
1515        self.aggregated_capabilities
1516    }
1517
1518    /// Returns true if the chain contains at least one node with the requested capability.
1519    pub fn has_capability(&self, capability: NodeCapabilities) -> bool {
1520        self.aggregated_capabilities.contains(capability)
1521    }
1522
1523    /// Returns the sentinel head reference for traversal.
1524    pub fn head(&self) -> ModifierChainNodeRef<'_> {
1525        self.make_node_ref(NodeLink::Head)
1526    }
1527
1528    /// Returns the sentinel tail reference for traversal.
1529    pub fn tail(&self) -> ModifierChainNodeRef<'_> {
1530        self.make_node_ref(NodeLink::Tail)
1531    }
1532
1533    /// Iterates over the chain from head to tail, skipping sentinels.
1534    pub fn head_to_tail(&self) -> ModifierChainIter<'_> {
1535        ModifierChainIter::new(self.head().child(), TraversalDirection::Forward)
1536    }
1537
1538    /// Iterates over the chain from tail to head, skipping sentinels.
1539    pub fn tail_to_head(&self) -> ModifierChainIter<'_> {
1540        ModifierChainIter::new(self.tail().parent(), TraversalDirection::Backward)
1541    }
1542
1543    /// Calls `f` for every node in insertion order.
1544    pub fn for_each_forward<F>(&self, mut f: F)
1545    where
1546        F: FnMut(ModifierChainNodeRef<'_>),
1547    {
1548        for node in self.head_to_tail() {
1549            f(node);
1550        }
1551    }
1552
1553    /// Calls `f` for every node containing any capability from `mask`.
1554    pub fn for_each_forward_matching<F>(&self, mask: NodeCapabilities, mut f: F)
1555    where
1556        F: FnMut(ModifierChainNodeRef<'_>),
1557    {
1558        if mask.is_empty() {
1559            self.for_each_forward(f);
1560            return;
1561        }
1562
1563        if !self.head().aggregate_child_capabilities().intersects(mask) {
1564            return;
1565        }
1566
1567        for node in self.head_to_tail() {
1568            if node.kind_set().intersects(mask) {
1569                f(node);
1570            }
1571        }
1572    }
1573
1574    /// Calls `f` for every node containing any capability from `mask`, providing the node ref.
1575    pub fn for_each_node_with_capability<F>(&self, mask: NodeCapabilities, mut f: F)
1576    where
1577        F: FnMut(ModifierChainNodeRef<'_>, &dyn ModifierNode),
1578    {
1579        self.for_each_forward_matching(mask, |node_ref| {
1580            node_ref.with_node(|node| f(node_ref.clone(), node));
1581        });
1582    }
1583
1584    /// Calls `f` for every node in reverse insertion order.
1585    pub fn for_each_backward<F>(&self, mut f: F)
1586    where
1587        F: FnMut(ModifierChainNodeRef<'_>),
1588    {
1589        for node in self.tail_to_head() {
1590            f(node);
1591        }
1592    }
1593
1594    /// Calls `f` for every node in reverse order that matches `mask`.
1595    pub fn for_each_backward_matching<F>(&self, mask: NodeCapabilities, mut f: F)
1596    where
1597        F: FnMut(ModifierChainNodeRef<'_>),
1598    {
1599        if mask.is_empty() {
1600            self.for_each_backward(f);
1601            return;
1602        }
1603
1604        if !self.head().aggregate_child_capabilities().intersects(mask) {
1605            return;
1606        }
1607
1608        for node in self.tail_to_head() {
1609            if node.kind_set().intersects(mask) {
1610                f(node);
1611            }
1612        }
1613    }
1614
1615    /// Returns a node reference for the entry at `index`.
1616    pub fn node_ref_at(&self, index: usize) -> Option<ModifierChainNodeRef<'_>> {
1617        if index >= self.entries.len() {
1618            None
1619        } else {
1620            Some(self.make_node_ref(NodeLink::Entry(NodePath::root(index))))
1621        }
1622    }
1623
1624    /// Returns the node reference that owns `node`.
1625    pub fn find_node_ref(&self, node: &dyn ModifierNode) -> Option<ModifierChainNodeRef<'_>> {
1626        fn node_data_ptr(node: &dyn ModifierNode) -> *const () {
1627            node as *const dyn ModifierNode as *const ()
1628        }
1629
1630        let target = node_data_ptr(node);
1631        for (index, entry) in self.entries.iter().enumerate() {
1632            if node_data_ptr(&**entry.node.borrow()) == target {
1633                return Some(self.make_node_ref(NodeLink::Entry(NodePath::root(index))));
1634            }
1635        }
1636
1637        self.ordered_nodes.iter().find_map(|link| {
1638            if matches!(link, NodeLink::Entry(path) if path.delegates().is_empty()) {
1639                return None;
1640            }
1641            let matches_target = match link {
1642                NodeLink::Head => node_data_ptr(self.head_sentinel.as_ref()) == target,
1643                NodeLink::Tail => node_data_ptr(self.tail_sentinel.as_ref()) == target,
1644                NodeLink::Entry(path) => {
1645                    let node_borrow = self.entries[path.entry()].node.borrow();
1646                    node_data_ptr(&**node_borrow) == target
1647                }
1648            };
1649            if matches_target {
1650                Some(self.make_node_ref(link.clone()))
1651            } else {
1652                None
1653            }
1654        })
1655    }
1656
1657    /// Downcasts the node at `index` to the requested type.
1658    /// Returns a `Ref` guard that dereferences to the node type.
1659    pub fn node<N: ModifierNode + 'static>(&self, index: usize) -> Option<std::cell::Ref<'_, N>> {
1660        self.entries.get(index).and_then(|entry| {
1661            std::cell::Ref::filter_map(entry.node.borrow(), |boxed_node| {
1662                boxed_node.as_any().downcast_ref::<N>()
1663            })
1664            .ok()
1665        })
1666    }
1667
1668    /// Downcasts the node at `index` to the requested mutable type.
1669    /// Returns a `RefMut` guard that dereferences to the node type.
1670    pub fn node_mut<N: ModifierNode + 'static>(
1671        &self,
1672        index: usize,
1673    ) -> Option<std::cell::RefMut<'_, N>> {
1674        self.entries.get(index).and_then(|entry| {
1675            std::cell::RefMut::filter_map(entry.node.borrow_mut(), |boxed_node| {
1676                boxed_node.as_any_mut().downcast_mut::<N>()
1677            })
1678            .ok()
1679        })
1680    }
1681
1682    /// Returns an Rc clone of the node at the given index for shared ownership.
1683    /// This is used by coordinators to hold direct references to nodes.
1684    pub fn get_node_rc(&self, index: usize) -> Option<Rc<RefCell<Box<dyn ModifierNode>>>> {
1685        self.entries.get(index).map(|entry| Rc::clone(&entry.node))
1686    }
1687
1688    /// Returns true if the chain contains any nodes matching the given invalidation kind.
1689    pub fn has_nodes_for_invalidation(&self, kind: InvalidationKind) -> bool {
1690        self.aggregated_capabilities
1691            .contains(NodeCapabilities::for_invalidation(kind))
1692    }
1693
1694    /// Visits every node in insertion order together with its capability mask.
1695    pub fn visit_nodes<F>(&self, mut f: F)
1696    where
1697        F: FnMut(&dyn ModifierNode, NodeCapabilities),
1698    {
1699        for link in &self.ordered_nodes {
1700            match link {
1701                NodeLink::Head => {
1702                    let node = self.head_sentinel.as_ref();
1703                    f(node, node.node_state().capabilities());
1704                }
1705                NodeLink::Tail => {
1706                    let node = self.tail_sentinel.as_ref();
1707                    f(node, node.node_state().capabilities());
1708                }
1709                NodeLink::Entry(path) => {
1710                    let node_borrow = self.entries[path.entry()].node.borrow();
1711                    // Navigate through delegates if path has them
1712                    if path.delegates().is_empty() {
1713                        f(&**node_borrow, node_borrow.node_state().capabilities());
1714                    } else {
1715                        // Navigate to the delegate node
1716                        let mut current: &dyn ModifierNode = &**node_borrow;
1717                        for &delegate_index in path.delegates() {
1718                            if let Some(delegate) = nth_delegate(current, delegate_index) {
1719                                current = delegate;
1720                            } else {
1721                                return; // Invalid delegate path
1722                            }
1723                        }
1724                        f(current, current.node_state().capabilities());
1725                    }
1726                }
1727            }
1728        }
1729    }
1730
1731    /// Visits every node mutably in insertion order together with its capability mask.
1732    pub fn visit_nodes_mut<F>(&mut self, mut f: F)
1733    where
1734        F: FnMut(&mut dyn ModifierNode, NodeCapabilities),
1735    {
1736        for index in 0..self.ordered_nodes.len() {
1737            let link = self.ordered_nodes[index].clone();
1738            match link {
1739                NodeLink::Head => {
1740                    let node = self.head_sentinel.as_mut();
1741                    let capabilities = node.node_state().capabilities();
1742                    f(node, capabilities);
1743                }
1744                NodeLink::Tail => {
1745                    let node = self.tail_sentinel.as_mut();
1746                    let capabilities = node.node_state().capabilities();
1747                    f(node, capabilities);
1748                }
1749                NodeLink::Entry(path) => {
1750                    let mut node_borrow = self.entries[path.entry()].node.borrow_mut();
1751                    // Navigate through delegates if path has them
1752                    if path.delegates().is_empty() {
1753                        let capabilities = node_borrow.node_state().capabilities();
1754                        f(&mut **node_borrow, capabilities);
1755                    } else {
1756                        // Navigate to the delegate node mutably
1757                        let mut current: &mut dyn ModifierNode = &mut **node_borrow;
1758                        for &delegate_index in path.delegates() {
1759                            if let Some(delegate) = nth_delegate_mut(current, delegate_index) {
1760                                current = delegate;
1761                            } else {
1762                                return; // Invalid delegate path
1763                            }
1764                        }
1765                        let capabilities = current.node_state().capabilities();
1766                        f(current, capabilities);
1767                    }
1768                }
1769            }
1770        }
1771    }
1772
1773    fn make_node_ref(&self, link: NodeLink) -> ModifierChainNodeRef<'_> {
1774        ModifierChainNodeRef { chain: self, link }
1775    }
1776
1777    fn sync_chain_links(&mut self) {
1778        self.rebuild_ordered_nodes();
1779
1780        self.head_sentinel.node_state().set_parent_link(None);
1781        self.tail_sentinel.node_state().set_child_link(None);
1782
1783        if self.ordered_nodes.is_empty() {
1784            self.head_sentinel
1785                .node_state()
1786                .set_child_link(Some(NodeLink::Tail));
1787            self.tail_sentinel
1788                .node_state()
1789                .set_parent_link(Some(NodeLink::Head));
1790            self.aggregated_capabilities = NodeCapabilities::empty();
1791            self.head_aggregate_child_capabilities = NodeCapabilities::empty();
1792            self.head_sentinel
1793                .node_state()
1794                .set_aggregate_child_capabilities(NodeCapabilities::empty());
1795            self.tail_sentinel
1796                .node_state()
1797                .set_aggregate_child_capabilities(NodeCapabilities::empty());
1798            return;
1799        }
1800
1801        let mut previous = NodeLink::Head;
1802        for link in self.ordered_nodes.iter().cloned() {
1803            // Set child link on previous
1804            match &previous {
1805                NodeLink::Head => self
1806                    .head_sentinel
1807                    .node_state()
1808                    .set_child_link(Some(link.clone())),
1809                NodeLink::Tail => self
1810                    .tail_sentinel
1811                    .node_state()
1812                    .set_child_link(Some(link.clone())),
1813                NodeLink::Entry(path) => {
1814                    let node_borrow = self.entries[path.entry()].node.borrow();
1815                    // Navigate to delegate if needed
1816                    if path.delegates().is_empty() {
1817                        node_borrow.node_state().set_child_link(Some(link.clone()));
1818                    } else {
1819                        let mut current: &dyn ModifierNode = &**node_borrow;
1820                        for &delegate_index in path.delegates() {
1821                            if let Some(delegate) = nth_delegate(current, delegate_index) {
1822                                current = delegate;
1823                            }
1824                        }
1825                        current.node_state().set_child_link(Some(link.clone()));
1826                    }
1827                }
1828            }
1829            // Set parent link on current
1830            match &link {
1831                NodeLink::Head => self
1832                    .head_sentinel
1833                    .node_state()
1834                    .set_parent_link(Some(previous.clone())),
1835                NodeLink::Tail => self
1836                    .tail_sentinel
1837                    .node_state()
1838                    .set_parent_link(Some(previous.clone())),
1839                NodeLink::Entry(path) => {
1840                    let node_borrow = self.entries[path.entry()].node.borrow();
1841                    // Navigate to delegate if needed
1842                    if path.delegates().is_empty() {
1843                        node_borrow
1844                            .node_state()
1845                            .set_parent_link(Some(previous.clone()));
1846                    } else {
1847                        let mut current: &dyn ModifierNode = &**node_borrow;
1848                        for &delegate_index in path.delegates() {
1849                            if let Some(delegate) = nth_delegate(current, delegate_index) {
1850                                current = delegate;
1851                            }
1852                        }
1853                        current.node_state().set_parent_link(Some(previous.clone()));
1854                    }
1855                }
1856            }
1857            previous = link;
1858        }
1859
1860        // Set child link on last node to Tail
1861        match &previous {
1862            NodeLink::Head => self
1863                .head_sentinel
1864                .node_state()
1865                .set_child_link(Some(NodeLink::Tail)),
1866            NodeLink::Tail => self
1867                .tail_sentinel
1868                .node_state()
1869                .set_child_link(Some(NodeLink::Tail)),
1870            NodeLink::Entry(path) => {
1871                let node_borrow = self.entries[path.entry()].node.borrow();
1872                // Navigate to delegate if needed
1873                if path.delegates().is_empty() {
1874                    node_borrow
1875                        .node_state()
1876                        .set_child_link(Some(NodeLink::Tail));
1877                } else {
1878                    let mut current: &dyn ModifierNode = &**node_borrow;
1879                    for &delegate_index in path.delegates() {
1880                        if let Some(delegate) = nth_delegate(current, delegate_index) {
1881                            current = delegate;
1882                        }
1883                    }
1884                    current.node_state().set_child_link(Some(NodeLink::Tail));
1885                }
1886            }
1887        }
1888        self.tail_sentinel
1889            .node_state()
1890            .set_parent_link(Some(previous.clone()));
1891        self.tail_sentinel.node_state().set_child_link(None);
1892
1893        let mut aggregate = NodeCapabilities::empty();
1894        for link in self.ordered_nodes.iter().rev() {
1895            match link {
1896                NodeLink::Head => {
1897                    let state = self.head_sentinel.node_state();
1898                    aggregate |= state.capabilities();
1899                    state.set_aggregate_child_capabilities(aggregate);
1900                }
1901                NodeLink::Tail => {
1902                    let state = self.tail_sentinel.node_state();
1903                    aggregate |= state.capabilities();
1904                    state.set_aggregate_child_capabilities(aggregate);
1905                }
1906                NodeLink::Entry(path) => {
1907                    let node_borrow = self.entries[path.entry()].node.borrow();
1908                    // Navigate to delegate if needed
1909                    let state = if path.delegates().is_empty() {
1910                        node_borrow.node_state()
1911                    } else {
1912                        let mut current: &dyn ModifierNode = &**node_borrow;
1913                        for &delegate_index in path.delegates() {
1914                            if let Some(delegate) = nth_delegate(current, delegate_index) {
1915                                current = delegate;
1916                            }
1917                        }
1918                        current.node_state()
1919                    };
1920                    aggregate |= state.capabilities();
1921                    state.set_aggregate_child_capabilities(aggregate);
1922                }
1923            }
1924        }
1925
1926        self.aggregated_capabilities = aggregate;
1927        self.head_aggregate_child_capabilities = aggregate;
1928        self.head_sentinel
1929            .node_state()
1930            .set_aggregate_child_capabilities(aggregate);
1931        self.tail_sentinel
1932            .node_state()
1933            .set_aggregate_child_capabilities(NodeCapabilities::empty());
1934    }
1935
1936    fn rebuild_ordered_nodes(&mut self) {
1937        self.ordered_nodes.clear();
1938        for (index, entry) in self.entries.iter().enumerate() {
1939            let mut path = Vec::new();
1940            let node_borrow = entry.node.borrow();
1941            Self::enumerate_link_order(&**node_borrow, index, &mut path, &mut self.ordered_nodes);
1942        }
1943    }
1944
1945    fn enumerate_link_order(
1946        node: &dyn ModifierNode,
1947        entry: usize,
1948        path: &mut Vec<usize>,
1949        out: &mut Vec<NodeLink>,
1950    ) {
1951        out.push(NodeLink::Entry(NodePath::from_slice(entry, path)));
1952        let mut delegate_index = 0usize;
1953        node.for_each_delegate(&mut |child| {
1954            path.push(delegate_index);
1955            Self::enumerate_link_order(child, entry, path, out);
1956            path.pop();
1957            delegate_index += 1;
1958        });
1959    }
1960}
1961
1962impl<'a> ModifierChainNodeRef<'a> {
1963    /// Helper to get NodeState, properly handling RefCell for entries.
1964    /// Returns NodeState values by calling a closure with the state.
1965    fn with_state<R>(&self, f: impl FnOnce(&NodeState) -> R) -> R {
1966        match &self.link {
1967            NodeLink::Head => f(self.chain.head_sentinel.node_state()),
1968            NodeLink::Tail => f(self.chain.tail_sentinel.node_state()),
1969            NodeLink::Entry(path) => {
1970                let node_borrow = self.chain.entries[path.entry()].node.borrow();
1971                // Navigate through delegates if path has them
1972                if path.delegates().is_empty() {
1973                    f(node_borrow.node_state())
1974                } else {
1975                    // Navigate to the delegate node
1976                    let mut current: &dyn ModifierNode = &**node_borrow;
1977                    for &delegate_index in path.delegates() {
1978                        if let Some(delegate) = nth_delegate(current, delegate_index) {
1979                            current = delegate;
1980                        } else {
1981                            // Fallback to root node state if delegate path is invalid
1982                            return f(node_borrow.node_state());
1983                        }
1984                    }
1985                    f(current.node_state())
1986                }
1987            }
1988        }
1989    }
1990
1991    /// Provides access to the node via a closure, properly handling RefCell borrows.
1992    /// Returns None for sentinel nodes.
1993    pub fn with_node<R>(&self, f: impl FnOnce(&dyn ModifierNode) -> R) -> Option<R> {
1994        match &self.link {
1995            NodeLink::Head => None, // Head sentinel
1996            NodeLink::Tail => None, // Tail sentinel
1997            NodeLink::Entry(path) => {
1998                let node_borrow = self.chain.entries[path.entry()].node.borrow();
1999                // Navigate through delegates if path has them
2000                if path.delegates().is_empty() {
2001                    Some(f(&**node_borrow))
2002                } else {
2003                    // Navigate to the delegate node
2004                    let mut current: &dyn ModifierNode = &**node_borrow;
2005                    for &delegate_index in path.delegates() {
2006                        if let Some(delegate) = nth_delegate(current, delegate_index) {
2007                            current = delegate;
2008                        } else {
2009                            // Return None if delegate path is invalid
2010                            return None;
2011                        }
2012                    }
2013                    Some(f(current))
2014                }
2015            }
2016        }
2017    }
2018
2019    /// Returns the parent reference, including sentinel head when applicable.
2020    pub fn parent(&self) -> Option<Self> {
2021        self.with_state(|state| state.parent_link())
2022            .map(|link| self.chain.make_node_ref(link))
2023    }
2024
2025    /// Returns the child reference, including sentinel tail for the last entry.
2026    pub fn child(&self) -> Option<Self> {
2027        self.with_state(|state| state.child_link())
2028            .map(|link| self.chain.make_node_ref(link))
2029    }
2030
2031    /// Returns the capability mask for this specific node.
2032    pub fn kind_set(&self) -> NodeCapabilities {
2033        self.with_state(|state| {
2034            if state.is_sentinel() {
2035                NodeCapabilities::empty()
2036            } else {
2037                state.capabilities()
2038            }
2039        })
2040    }
2041
2042    /// Returns the entry index backing this node when it is part of the chain.
2043    pub fn entry_index(&self) -> Option<usize> {
2044        match &self.link {
2045            NodeLink::Entry(path) => Some(path.entry()),
2046            _ => None,
2047        }
2048    }
2049
2050    /// Returns how many delegate hops separate this node from its root element.
2051    pub fn delegate_depth(&self) -> usize {
2052        match &self.link {
2053            NodeLink::Entry(path) => path.delegates().len(),
2054            _ => 0,
2055        }
2056    }
2057
2058    /// Returns the aggregated capability mask for the subtree rooted at this node.
2059    pub fn aggregate_child_capabilities(&self) -> NodeCapabilities {
2060        if self.is_tail() {
2061            NodeCapabilities::empty()
2062        } else {
2063            self.with_state(|state| state.aggregate_child_capabilities())
2064        }
2065    }
2066
2067    /// Returns true if this reference targets the sentinel head.
2068    pub fn is_head(&self) -> bool {
2069        matches!(self.link, NodeLink::Head)
2070    }
2071
2072    /// Returns true if this reference targets the sentinel tail.
2073    pub fn is_tail(&self) -> bool {
2074        matches!(self.link, NodeLink::Tail)
2075    }
2076
2077    /// Returns true if this reference targets either sentinel.
2078    pub fn is_sentinel(&self) -> bool {
2079        self.with_state(|state| state.is_sentinel())
2080    }
2081
2082    /// Returns true if this node has any capability bits present in `mask`.
2083    pub fn has_capability(&self, mask: NodeCapabilities) -> bool {
2084        !mask.is_empty() && self.kind_set().intersects(mask)
2085    }
2086
2087    /// Visits descendant nodes, optionally including `self`, in insertion order.
2088    pub fn visit_descendants<F>(self, include_self: bool, mut f: F)
2089    where
2090        F: FnMut(ModifierChainNodeRef<'a>),
2091    {
2092        let mut current = if include_self {
2093            Some(self)
2094        } else {
2095            self.child()
2096        };
2097        while let Some(node) = current {
2098            if node.is_tail() {
2099                break;
2100            }
2101            if !node.is_sentinel() {
2102                f(node.clone());
2103            }
2104            current = node.child();
2105        }
2106    }
2107
2108    /// Visits descendant nodes that match `mask`, short-circuiting when possible.
2109    pub fn visit_descendants_matching<F>(self, include_self: bool, mask: NodeCapabilities, mut f: F)
2110    where
2111        F: FnMut(ModifierChainNodeRef<'a>),
2112    {
2113        if mask.is_empty() {
2114            self.visit_descendants(include_self, f);
2115            return;
2116        }
2117
2118        if !self.aggregate_child_capabilities().intersects(mask) {
2119            return;
2120        }
2121
2122        self.visit_descendants(include_self, |node| {
2123            if node.kind_set().intersects(mask) {
2124                f(node);
2125            }
2126        });
2127    }
2128
2129    /// Visits ancestor nodes up to (but excluding) the sentinel head.
2130    pub fn visit_ancestors<F>(self, include_self: bool, mut f: F)
2131    where
2132        F: FnMut(ModifierChainNodeRef<'a>),
2133    {
2134        let mut current = if include_self {
2135            Some(self)
2136        } else {
2137            self.parent()
2138        };
2139        while let Some(node) = current {
2140            if node.is_head() {
2141                break;
2142            }
2143            f(node.clone());
2144            current = node.parent();
2145        }
2146    }
2147
2148    /// Visits ancestor nodes that match `mask`.
2149    pub fn visit_ancestors_matching<F>(self, include_self: bool, mask: NodeCapabilities, mut f: F)
2150    where
2151        F: FnMut(ModifierChainNodeRef<'a>),
2152    {
2153        if mask.is_empty() {
2154            self.visit_ancestors(include_self, f);
2155            return;
2156        }
2157
2158        self.visit_ancestors(include_self, |node| {
2159            if node.kind_set().intersects(mask) {
2160                f(node);
2161            }
2162        });
2163    }
2164
2165    /// Finds the nearest ancestor focus target node.
2166    ///
2167    /// This is useful for focus navigation to find the parent focusable
2168    /// component in the tree.
2169    pub fn find_parent_focus_target(&self) -> Option<ModifierChainNodeRef<'a>> {
2170        let mut result = None;
2171        self.clone()
2172            .visit_ancestors_matching(false, NodeCapabilities::FOCUS, |node| {
2173                if result.is_none() {
2174                    result = Some(node);
2175                }
2176            });
2177        result
2178    }
2179
2180    /// Finds the first descendant focus target node.
2181    ///
2182    /// This is useful for focus navigation to find the first focusable
2183    /// child component in the tree.
2184    pub fn find_first_focus_target(&self) -> Option<ModifierChainNodeRef<'a>> {
2185        let mut result = None;
2186        self.clone()
2187            .visit_descendants_matching(false, NodeCapabilities::FOCUS, |node| {
2188                if result.is_none() {
2189                    result = Some(node);
2190                }
2191            });
2192        result
2193    }
2194
2195    /// Returns true if this node or any ancestor has focus capability.
2196    pub fn has_focus_capability_in_ancestors(&self) -> bool {
2197        let mut found = false;
2198        self.clone()
2199            .visit_ancestors_matching(true, NodeCapabilities::FOCUS, |_| {
2200                found = true;
2201            });
2202        found
2203    }
2204}
2205
2206#[cfg(test)]
2207#[path = "tests/modifier_tests.rs"]
2208mod tests;