Skip to main content

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