Skip to main content

cranpose_foundation/
modifier.rs

1//! Modifier node scaffolding for Cranpose.
2//!
3//! This module defines the foundational pieces of the Cranpose
4//! `Modifier.Node` system. It introduces traits for modifier nodes and their
5//! contexts as well as a lightweight chain container that reconciles nodes
6//! across updates.
7
8use std::any::{type_name, Any, TypeId};
9use std::cell::{Cell, RefCell};
10use std::fmt;
11use std::hash::{Hash, Hasher};
12use std::ops::{BitOr, BitOrAssign};
13use std::rc::Rc;
14
15use cranpose_core::collections::map::HashMap;
16use cranpose_core::hash::default;
17
18pub use cranpose_ui_graphics::DrawScope;
19pub use cranpose_ui_graphics::Size;
20pub use cranpose_ui_layout::{Constraints, Measurable};
21
22use crate::nodes::input::types::PointerEvent;
23// use cranpose_core::NodeId;
24
25/// Identifies which part of the rendering pipeline should be invalidated
26/// after a modifier node changes state.
27#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
28pub enum InvalidationKind {
29    Layout,
30    Draw,
31    PointerInput,
32    Semantics,
33    Focus,
34}
35
36/// Runtime services exposed to modifier nodes while attached to a tree.
37pub trait ModifierNodeContext {
38    /// Requests that a particular pipeline stage be invalidated.
39    fn invalidate(&mut self, _kind: InvalidationKind) {}
40
41    /// Requests that the node's `update` method run again outside of a
42    /// regular composition pass.
43    fn request_update(&mut self) {}
44
45    /// Returns the ID of the layout node this modifier is attached to, if known.
46    /// This is used by modifiers that need to register callbacks for invalidation (e.g. Scroll).
47    fn node_id(&self) -> Option<cranpose_core::NodeId> {
48        None
49    }
50
51    /// Signals that a node with `capabilities` is about to interact with this context.
52    fn push_active_capabilities(&mut self, _capabilities: NodeCapabilities) {}
53
54    /// Signals that the most recent node interaction has completed.
55    fn pop_active_capabilities(&mut self) {}
56}
57
58/// Lightweight [`ModifierNodeContext`] implementation that records
59/// invalidation requests and update signals.
60///
61/// The context intentionally avoids leaking runtime details so the core
62/// crate can evolve independently from higher level UI crates. It simply
63/// stores the sequence of requested invalidation kinds and whether an
64/// explicit update was requested. Callers can inspect or drain this state
65/// after driving a [`ModifierNodeChain`] reconciliation pass.
66#[derive(Default, Debug, Clone)]
67pub struct BasicModifierNodeContext {
68    invalidations: Vec<ModifierInvalidation>,
69    update_requested: bool,
70    active_capabilities: Vec<NodeCapabilities>,
71    node_id: Option<cranpose_core::NodeId>,
72}
73
74impl BasicModifierNodeContext {
75    /// Creates a new empty context.
76    pub fn new() -> Self {
77        Self::default()
78    }
79
80    /// Returns the ordered list of invalidation kinds that were requested
81    /// since the last call to [`clear_invalidations`]. Duplicate requests for
82    /// the same kind are coalesced.
83    pub fn invalidations(&self) -> &[ModifierInvalidation] {
84        &self.invalidations
85    }
86
87    /// Removes all currently recorded invalidation kinds.
88    pub fn clear_invalidations(&mut self) {
89        self.invalidations.clear();
90    }
91
92    /// Drains the recorded invalidations and returns them to the caller.
93    pub fn take_invalidations(&mut self) -> Vec<ModifierInvalidation> {
94        std::mem::take(&mut self.invalidations)
95    }
96
97    /// Returns whether an update was requested since the last call to
98    /// [`take_update_requested`].
99    pub fn update_requested(&self) -> bool {
100        self.update_requested
101    }
102
103    /// Returns whether an update was requested and clears the flag.
104    pub fn take_update_requested(&mut self) -> bool {
105        std::mem::take(&mut self.update_requested)
106    }
107
108    /// Sets the node ID associated with this context.
109    pub fn set_node_id(&mut self, id: Option<cranpose_core::NodeId>) {
110        self.node_id = id;
111    }
112
113    fn push_invalidation(&mut self, kind: InvalidationKind) {
114        let mut capabilities = self.current_capabilities();
115        capabilities.insert(NodeCapabilities::for_invalidation(kind));
116        if let Some(existing) = self
117            .invalidations
118            .iter_mut()
119            .find(|entry| entry.kind() == kind)
120        {
121            let updated = existing.capabilities() | capabilities;
122            *existing = ModifierInvalidation::new(kind, updated);
123        } else {
124            self.invalidations
125                .push(ModifierInvalidation::new(kind, capabilities));
126        }
127    }
128
129    fn current_capabilities(&self) -> NodeCapabilities {
130        self.active_capabilities
131            .last()
132            .copied()
133            .unwrap_or_else(NodeCapabilities::empty)
134    }
135}
136
137impl ModifierNodeContext for BasicModifierNodeContext {
138    fn invalidate(&mut self, kind: InvalidationKind) {
139        self.push_invalidation(kind);
140    }
141
142    fn request_update(&mut self) {
143        self.update_requested = true;
144    }
145
146    fn push_active_capabilities(&mut self, capabilities: NodeCapabilities) {
147        self.active_capabilities.push(capabilities);
148    }
149
150    fn pop_active_capabilities(&mut self) {
151        self.active_capabilities.pop();
152    }
153
154    fn node_id(&self) -> Option<cranpose_core::NodeId> {
155        self.node_id
156    }
157}
158
159/// Path to a node within a modifier chain, supporting delegate navigation.
160/// Fixed-size Copy type — delegate depth is bounded at 3 in practice
161/// (modifier delegation rarely exceeds 2–3 levels).
162const MAX_DELEGATE_DEPTH: usize = 3;
163
164#[derive(Copy, Clone, Debug, PartialEq, Eq)]
165pub(crate) struct NodePath {
166    entry: usize,
167    delegate_buf: [u8; MAX_DELEGATE_DEPTH],
168    delegate_len: u8,
169}
170
171impl NodePath {
172    #[inline]
173    fn root(entry: usize) -> Self {
174        Self {
175            entry,
176            delegate_buf: [0; MAX_DELEGATE_DEPTH],
177            delegate_len: 0,
178        }
179    }
180
181    #[inline]
182    fn from_slice(entry: usize, path: &[usize]) -> Self {
183        debug_assert!(
184            path.len() <= MAX_DELEGATE_DEPTH,
185            "delegate depth {} exceeds MAX_DELEGATE_DEPTH {}",
186            path.len(),
187            MAX_DELEGATE_DEPTH
188        );
189        debug_assert!(
190            path.iter().all(|&i| i <= u8::MAX as usize),
191            "delegate index exceeds u8 range"
192        );
193        let mut delegate_buf = [0u8; MAX_DELEGATE_DEPTH];
194        for (i, &v) in path.iter().enumerate().take(MAX_DELEGATE_DEPTH) {
195            delegate_buf[i] = v as u8;
196        }
197        Self {
198            entry,
199            delegate_buf,
200            delegate_len: path.len().min(MAX_DELEGATE_DEPTH) as u8,
201        }
202    }
203
204    #[inline]
205    fn entry(&self) -> usize {
206        self.entry
207    }
208
209    #[inline]
210    fn delegates(&self) -> &[u8] {
211        &self.delegate_buf[..self.delegate_len as usize]
212    }
213}
214
215#[derive(Copy, Clone, Debug, PartialEq, Eq)]
216pub(crate) enum NodeLink {
217    Head,
218    Tail,
219    Entry(NodePath),
220}
221
222/// Runtime state tracked for every [`ModifierNode`].
223///
224/// This type is part of the internal node system API and should not be directly
225/// constructed or manipulated by external code. Modifier nodes automatically receive
226/// and manage their NodeState through the modifier chain infrastructure.
227#[derive(Debug)]
228pub struct NodeState {
229    aggregate_child_capabilities: Cell<NodeCapabilities>,
230    capabilities: Cell<NodeCapabilities>,
231    parent: RefCell<Option<NodeLink>>,
232    child: RefCell<Option<NodeLink>>,
233    attached: Cell<bool>,
234    is_sentinel: bool,
235}
236
237impl Default for NodeState {
238    fn default() -> Self {
239        Self::new()
240    }
241}
242
243impl NodeState {
244    pub const fn new() -> Self {
245        Self {
246            aggregate_child_capabilities: Cell::new(NodeCapabilities::empty()),
247            capabilities: Cell::new(NodeCapabilities::empty()),
248            parent: RefCell::new(None),
249            child: RefCell::new(None),
250            attached: Cell::new(false),
251            is_sentinel: false,
252        }
253    }
254
255    pub const fn sentinel() -> Self {
256        Self {
257            aggregate_child_capabilities: Cell::new(NodeCapabilities::empty()),
258            capabilities: Cell::new(NodeCapabilities::empty()),
259            parent: RefCell::new(None),
260            child: RefCell::new(None),
261            attached: Cell::new(true),
262            is_sentinel: true,
263        }
264    }
265
266    pub fn set_capabilities(&self, capabilities: NodeCapabilities) {
267        self.capabilities.set(capabilities);
268    }
269
270    #[inline]
271    pub fn capabilities(&self) -> NodeCapabilities {
272        self.capabilities.get()
273    }
274
275    pub fn set_aggregate_child_capabilities(&self, capabilities: NodeCapabilities) {
276        self.aggregate_child_capabilities.set(capabilities);
277    }
278
279    #[inline]
280    pub fn aggregate_child_capabilities(&self) -> NodeCapabilities {
281        self.aggregate_child_capabilities.get()
282    }
283
284    pub(crate) fn set_parent_link(&self, parent: Option<NodeLink>) {
285        *self.parent.borrow_mut() = parent;
286    }
287
288    #[inline]
289    pub(crate) fn parent_link(&self) -> Option<NodeLink> {
290        *self.parent.borrow()
291    }
292
293    pub(crate) fn set_child_link(&self, child: Option<NodeLink>) {
294        *self.child.borrow_mut() = child;
295    }
296
297    #[inline]
298    pub(crate) fn child_link(&self) -> Option<NodeLink> {
299        *self.child.borrow()
300    }
301
302    pub fn set_attached(&self, attached: bool) {
303        self.attached.set(attached);
304    }
305
306    pub fn is_attached(&self) -> bool {
307        self.attached.get()
308    }
309
310    pub fn is_sentinel(&self) -> bool {
311        self.is_sentinel
312    }
313}
314
315/// Provides traversal helpers that mirror Jetpack Compose's [`DelegatableNode`] contract.
316pub trait DelegatableNode {
317    fn node_state(&self) -> &NodeState;
318    fn aggregate_child_capabilities(&self) -> NodeCapabilities {
319        self.node_state().aggregate_child_capabilities()
320    }
321}
322
323/// Core trait implemented by modifier nodes.
324///
325/// # Capability-Driven Architecture
326///
327/// This trait follows Jetpack Compose's `Modifier.Node` pattern where nodes declare
328/// their capabilities via [`NodeCapabilities`] and implement specialized traits
329/// ([`DrawModifierNode`], [`PointerInputNode`], [`SemanticsNode`], [`FocusNode`], etc.)
330/// to participate in specific pipeline stages.
331///
332/// ## How to Implement a Modifier Node
333///
334/// 1. **Declare capabilities** in your [`ModifierNodeElement::capabilities()`] implementation
335/// 2. **Implement specialized traits** for the capabilities you declared
336/// 3. **Use helper macros** to reduce boilerplate (recommended)
337///
338/// ### Example: Draw Node
339///
340/// ```text
341/// use cranpose_foundation::*;
342///
343/// struct MyDrawNode {
344///     state: NodeState,
345///     color: Color,
346/// }
347///
348/// impl DelegatableNode for MyDrawNode {
349///     fn node_state(&self) -> &NodeState {
350///         &self.state
351///     }
352/// }
353///
354/// impl ModifierNode for MyDrawNode {
355///     // Use the helper macro instead of manual as_* implementations
356///     impl_modifier_node!(draw);
357/// }
358///
359/// impl DrawModifierNode for MyDrawNode {
360///     fn draw(&mut self, _context: &mut dyn ModifierNodeContext, draw_scope: &mut dyn DrawScope) {
361///         // Drawing logic here
362///     }
363/// }
364/// ```
365///
366/// ### Example: Multi-Capability Node
367///
368/// ```text
369/// impl ModifierNode for MyComplexNode {
370///     // This node participates in draw, pointer input, and semantics
371///     impl_modifier_node!(draw, pointer_input, semantics);
372/// }
373/// ```
374///
375/// ## Lifecycle Callbacks
376///
377/// Nodes receive lifecycle callbacks when they attach to or detach from a
378/// composition and may optionally react to resets triggered by the runtime
379/// (for example, when reusing nodes across modifier list changes).
380pub trait ModifierNode: Any + DelegatableNode {
381    fn on_attach(&mut self, _context: &mut dyn ModifierNodeContext) {}
382
383    fn on_detach(&mut self) {}
384
385    fn on_reset(&mut self) {}
386
387    /// Returns this node as a draw modifier if it implements the trait.
388    fn as_draw_node(&self) -> Option<&dyn DrawModifierNode> {
389        None
390    }
391
392    /// Returns this node as a mutable draw modifier if it implements the trait.
393    fn as_draw_node_mut(&mut self) -> Option<&mut dyn DrawModifierNode> {
394        None
395    }
396
397    /// Returns this node as a pointer-input modifier if it implements the trait.
398    fn as_pointer_input_node(&self) -> Option<&dyn PointerInputNode> {
399        None
400    }
401
402    /// Returns this node as a mutable pointer-input modifier if it implements the trait.
403    fn as_pointer_input_node_mut(&mut self) -> Option<&mut dyn PointerInputNode> {
404        None
405    }
406
407    /// Returns this node as a semantics modifier if it implements the trait.
408    fn as_semantics_node(&self) -> Option<&dyn SemanticsNode> {
409        None
410    }
411
412    /// Returns this node as a mutable semantics modifier if it implements the trait.
413    fn as_semantics_node_mut(&mut self) -> Option<&mut dyn SemanticsNode> {
414        None
415    }
416
417    /// Returns this node as a focus modifier if it implements the trait.
418    fn as_focus_node(&self) -> Option<&dyn FocusNode> {
419        None
420    }
421
422    /// Returns this node as a mutable focus modifier if it implements the trait.
423    fn as_focus_node_mut(&mut self) -> Option<&mut dyn FocusNode> {
424        None
425    }
426
427    /// Returns this node as a layout modifier if it implements the trait.
428    fn as_layout_node(&self) -> Option<&dyn LayoutModifierNode> {
429        None
430    }
431
432    /// Returns this node as a mutable layout modifier if it implements the trait.
433    fn as_layout_node_mut(&mut self) -> Option<&mut dyn LayoutModifierNode> {
434        None
435    }
436
437    /// Visits every delegate node owned by this modifier.
438    fn for_each_delegate<'b>(&'b self, _visitor: &mut dyn FnMut(&'b dyn ModifierNode)) {}
439
440    /// Visits every delegate node mutably.
441    fn for_each_delegate_mut<'b>(&'b mut self, _visitor: &mut dyn FnMut(&'b mut dyn ModifierNode)) {
442    }
443}
444
445/// Marker trait for layout-specific modifier nodes.
446///
447/// Layout nodes participate in the measure and layout passes of the render
448/// pipeline. They can intercept and modify the measurement and placement of
449/// their wrapped content.
450pub trait LayoutModifierNode: ModifierNode {
451    /// Measures the wrapped content and returns both the size this modifier
452    /// occupies and where the wrapped content should be placed.
453    ///
454    /// The node receives a measurable representing the wrapped content and
455    /// the incoming constraints from the parent.
456    ///
457    /// Returns a `LayoutModifierMeasureResult` containing:
458    /// - `size`: The final size this modifier will occupy
459    /// - `placement_offset_x/y`: Where to place the wrapped content relative
460    ///   to this modifier's top-left corner
461    ///
462    /// For example, a padding modifier would:
463    /// - Measure child with deflated constraints
464    /// - Return size = child size + padding
465    /// - Return placement offset = (padding.left, padding.top)
466    ///
467    /// The default implementation delegates to the wrapped content without
468    /// modification (size = child size, offset = 0).
469    ///
470    /// NOTE: This takes `&self` not `&mut self` to match Jetpack Compose semantics.
471    /// Nodes that need mutable state should use interior mutability (Cell/RefCell).
472    fn measure(
473        &self,
474        _context: &mut dyn ModifierNodeContext,
475        measurable: &dyn Measurable,
476        constraints: Constraints,
477    ) -> cranpose_ui_layout::LayoutModifierMeasureResult {
478        // Default: pass through to wrapped content by measuring the child.
479        let placeable = measurable.measure(constraints);
480        cranpose_ui_layout::LayoutModifierMeasureResult::with_size(Size {
481            width: placeable.width(),
482            height: placeable.height(),
483        })
484    }
485
486    /// Returns the minimum intrinsic width of this modifier node.
487    fn min_intrinsic_width(&self, _measurable: &dyn Measurable, _height: f32) -> f32 {
488        0.0
489    }
490
491    /// Returns the maximum intrinsic width of this modifier node.
492    fn max_intrinsic_width(&self, _measurable: &dyn Measurable, _height: f32) -> f32 {
493        0.0
494    }
495
496    /// Returns the minimum intrinsic height of this modifier node.
497    fn min_intrinsic_height(&self, _measurable: &dyn Measurable, _width: f32) -> f32 {
498        0.0
499    }
500
501    /// Returns the maximum intrinsic height of this modifier node.
502    fn max_intrinsic_height(&self, _measurable: &dyn Measurable, _width: f32) -> f32 {
503        0.0
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    pub is_editable_text: bool,
645    pub text_selection: Option<crate::text::TextRange>,
646}
647
648impl SemanticsConfiguration {
649    pub fn merge(&mut self, other: &SemanticsConfiguration) {
650        if let Some(description) = &other.content_description {
651            self.content_description = Some(description.clone());
652        }
653        self.is_button |= other.is_button;
654        self.is_clickable |= other.is_clickable;
655        self.is_editable_text |= other.is_editable_text;
656        if let Some(selection) = other.text_selection {
657            self.text_selection = Some(selection);
658        }
659    }
660}
661
662impl fmt::Debug for dyn ModifierNode {
663    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
664        f.debug_struct("ModifierNode").finish_non_exhaustive()
665    }
666}
667
668impl dyn ModifierNode {
669    pub fn as_any(&self) -> &dyn Any {
670        self
671    }
672
673    pub fn as_any_mut(&mut self) -> &mut dyn Any {
674        self
675    }
676}
677
678/// Strongly typed modifier elements that can create and update nodes while
679/// exposing equality/hash/inspector contracts that mirror Jetpack Compose.
680pub trait ModifierNodeElement: fmt::Debug + Hash + PartialEq + 'static {
681    type Node: ModifierNode;
682
683    /// Creates a new modifier node instance for this element.
684    fn create(&self) -> Self::Node;
685
686    /// Brings an existing modifier node up to date with the element's data.
687    fn update(&self, node: &mut Self::Node);
688
689    /// Optional key used to disambiguate multiple instances of the same element type.
690    fn key(&self) -> Option<u64> {
691        None
692    }
693
694    /// Human readable name surfaced to inspector tooling.
695    fn inspector_name(&self) -> &'static str {
696        type_name::<Self>()
697    }
698
699    /// Records inspector properties for tooling.
700    fn inspector_properties(&self, _inspector: &mut dyn FnMut(&'static str, String)) {}
701
702    /// Returns the capabilities of nodes created by this element.
703    /// Override this to indicate which specialized traits the node implements.
704    fn capabilities(&self) -> NodeCapabilities {
705        NodeCapabilities::default()
706    }
707
708    /// Whether this element requires `update` to be called even if `eq` returns true.
709    ///
710    /// This is useful for elements that ignore certain fields in `eq` (e.g. closures)
711    /// to allow node reuse, but still need those fields updated in the existing node.
712    /// Defaults to `false`.
713    fn always_update(&self) -> bool {
714        false
715    }
716}
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 can_update_node(&self, node: &dyn ModifierNode) -> bool;
846
847    fn update_node(&self, node: &mut dyn ModifierNode);
848
849    fn key(&self) -> Option<u64>;
850
851    fn capabilities(&self) -> NodeCapabilities {
852        NodeCapabilities::default()
853    }
854
855    fn hash_code(&self) -> u64;
856
857    fn equals_element(&self, other: &dyn AnyModifierElement) -> bool;
858
859    fn inspector_name(&self) -> &'static str;
860
861    fn record_inspector_properties(&self, visitor: &mut dyn FnMut(&'static str, String));
862
863    fn requires_update(&self) -> bool;
864
865    fn as_any(&self) -> &dyn Any;
866}
867
868struct TypedModifierElement<E: ModifierNodeElement> {
869    element: E,
870    cached_hash: u64,
871}
872
873impl<E: ModifierNodeElement> TypedModifierElement<E> {
874    fn new(element: E) -> Self {
875        let mut hasher = default::new();
876        element.hash(&mut hasher);
877        Self {
878            element,
879            cached_hash: hasher.finish(),
880        }
881    }
882}
883
884impl<E> fmt::Debug for TypedModifierElement<E>
885where
886    E: ModifierNodeElement,
887{
888    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
889        f.debug_struct("TypedModifierElement")
890            .field("type", &type_name::<E>())
891            .finish()
892    }
893}
894
895impl<E> AnyModifierElement for TypedModifierElement<E>
896where
897    E: ModifierNodeElement,
898{
899    fn node_type(&self) -> TypeId {
900        TypeId::of::<E::Node>()
901    }
902
903    fn element_type(&self) -> TypeId {
904        TypeId::of::<E>()
905    }
906
907    fn create_node(&self) -> Box<dyn ModifierNode> {
908        Box::new(self.element.create())
909    }
910
911    fn can_update_node(&self, node: &dyn ModifierNode) -> bool {
912        node.as_any().is::<E::Node>()
913    }
914
915    fn update_node(&self, node: &mut dyn ModifierNode) {
916        if let Some(typed) = node.as_any_mut().downcast_mut::<E::Node>() {
917            self.element.update(typed);
918        }
919    }
920
921    fn key(&self) -> Option<u64> {
922        self.element.key()
923    }
924
925    fn capabilities(&self) -> NodeCapabilities {
926        self.element.capabilities()
927    }
928
929    fn hash_code(&self) -> u64 {
930        self.cached_hash
931    }
932
933    fn equals_element(&self, other: &dyn AnyModifierElement) -> bool {
934        other
935            .as_any()
936            .downcast_ref::<Self>()
937            .map(|typed| typed.element == self.element)
938            .unwrap_or(false)
939    }
940
941    fn inspector_name(&self) -> &'static str {
942        self.element.inspector_name()
943    }
944
945    fn record_inspector_properties(&self, visitor: &mut dyn FnMut(&'static str, String)) {
946        self.element.inspector_properties(visitor);
947    }
948
949    fn requires_update(&self) -> bool {
950        self.element.always_update()
951    }
952
953    fn as_any(&self) -> &dyn Any {
954        self
955    }
956}
957
958/// Convenience helper for callers to construct a type-erased modifier
959/// element without having to mention the internal wrapper type.
960pub fn modifier_element<E: ModifierNodeElement>(element: E) -> DynModifierElement {
961    Rc::new(TypedModifierElement::new(element))
962}
963
964/// Boxed type-erased modifier element.
965pub type DynModifierElement = Rc<dyn AnyModifierElement>;
966
967#[derive(Clone, Copy, Debug, PartialEq, Eq)]
968enum TraversalDirection {
969    Forward,
970    Backward,
971}
972
973/// Iterator walking a modifier chain by indexing into `ordered_nodes`.
974///
975/// This avoids the per-step `RefCell::borrow()` + `NodeLink::clone()` cost
976/// of following the linked-list through `NodeState::child`/`parent`.
977pub struct ModifierChainIter<'a> {
978    chain: &'a ModifierNodeChain,
979    /// Current position in `ordered_nodes`. For forward iteration, starts at 0
980    /// and increments; for backward, starts at len-1 and decrements.
981    cursor: usize,
982    /// Number of elements remaining (avoids underflow on backward iteration).
983    remaining: usize,
984    direction: TraversalDirection,
985}
986
987impl<'a> ModifierChainIter<'a> {
988    fn forward(chain: &'a ModifierNodeChain) -> Self {
989        Self {
990            chain,
991            cursor: 0,
992            remaining: chain.ordered_nodes.len(),
993            direction: TraversalDirection::Forward,
994        }
995    }
996
997    fn backward(chain: &'a ModifierNodeChain) -> Self {
998        let len = chain.ordered_nodes.len();
999        Self {
1000            chain,
1001            cursor: len.wrapping_sub(1),
1002            remaining: len,
1003            direction: TraversalDirection::Backward,
1004        }
1005    }
1006}
1007
1008impl<'a> Iterator for ModifierChainIter<'a> {
1009    type Item = ModifierChainNodeRef<'a>;
1010
1011    #[inline]
1012    fn next(&mut self) -> Option<Self::Item> {
1013        if self.remaining == 0 {
1014            return None;
1015        }
1016        let (link, caps, agg) = self.chain.ordered_nodes[self.cursor];
1017        let node_ref = self.chain.make_node_ref_with_caps(link, caps, agg);
1018        self.remaining -= 1;
1019        match self.direction {
1020            TraversalDirection::Forward => self.cursor += 1,
1021            TraversalDirection::Backward => self.cursor = self.cursor.wrapping_sub(1),
1022        }
1023        Some(node_ref)
1024    }
1025
1026    #[inline]
1027    fn size_hint(&self) -> (usize, Option<usize>) {
1028        (self.remaining, Some(self.remaining))
1029    }
1030}
1031
1032impl<'a> ExactSizeIterator for ModifierChainIter<'a> {}
1033impl<'a> std::iter::FusedIterator for ModifierChainIter<'a> {}
1034
1035#[derive(Debug)]
1036struct ModifierNodeEntry {
1037    element_type: TypeId,
1038    node_type: TypeId,
1039    key: Option<u64>,
1040    hash_code: u64,
1041    element: DynModifierElement,
1042    node: Rc<RefCell<Box<dyn ModifierNode>>>,
1043    capabilities: NodeCapabilities,
1044}
1045
1046impl ModifierNodeEntry {
1047    fn new(
1048        element_type: TypeId,
1049        node_type: TypeId,
1050        key: Option<u64>,
1051        element: DynModifierElement,
1052        node: Box<dyn ModifierNode>,
1053        hash_code: u64,
1054        capabilities: NodeCapabilities,
1055    ) -> Self {
1056        // Wrap the boxed node in Rc<RefCell<>> for shared ownership
1057        let node_rc = Rc::new(RefCell::new(node));
1058        let entry = Self {
1059            element_type,
1060            node_type,
1061            key,
1062            hash_code,
1063            element,
1064            node: Rc::clone(&node_rc),
1065            capabilities,
1066        };
1067        entry
1068            .node
1069            .borrow()
1070            .node_state()
1071            .set_capabilities(entry.capabilities);
1072        entry
1073    }
1074}
1075
1076fn visit_node_tree_mut(
1077    node: &mut dyn ModifierNode,
1078    visitor: &mut dyn FnMut(&mut dyn ModifierNode),
1079) {
1080    visitor(node);
1081    node.for_each_delegate_mut(&mut |child| visit_node_tree_mut(child, visitor));
1082}
1083
1084fn nth_delegate(node: &dyn ModifierNode, target: usize) -> Option<&dyn ModifierNode> {
1085    let mut current = 0usize;
1086    let mut result: Option<&dyn ModifierNode> = None;
1087    node.for_each_delegate(&mut |child| {
1088        if result.is_none() && current == target {
1089            result = Some(child);
1090        }
1091        current += 1;
1092    });
1093    result
1094}
1095
1096fn nth_delegate_mut(node: &mut dyn ModifierNode, target: usize) -> Option<&mut dyn ModifierNode> {
1097    let mut current = 0usize;
1098    let mut result: Option<&mut dyn ModifierNode> = None;
1099    node.for_each_delegate_mut(&mut |child| {
1100        if result.is_none() && current == target {
1101            result = Some(child);
1102        }
1103        current += 1;
1104    });
1105    result
1106}
1107
1108fn with_node_context<F, R>(
1109    node: &mut dyn ModifierNode,
1110    context: &mut dyn ModifierNodeContext,
1111    f: F,
1112) -> R
1113where
1114    F: FnOnce(&mut dyn ModifierNode, &mut dyn ModifierNodeContext) -> R,
1115{
1116    context.push_active_capabilities(node.node_state().capabilities());
1117    let result = f(node, context);
1118    context.pop_active_capabilities();
1119    result
1120}
1121
1122fn request_auto_invalidations(
1123    context: &mut dyn ModifierNodeContext,
1124    capabilities: NodeCapabilities,
1125) {
1126    if capabilities.is_empty() {
1127        return;
1128    }
1129
1130    context.push_active_capabilities(capabilities);
1131
1132    if capabilities.contains(NodeCapabilities::LAYOUT) {
1133        context.invalidate(InvalidationKind::Layout);
1134    }
1135    if capabilities.contains(NodeCapabilities::DRAW) {
1136        context.invalidate(InvalidationKind::Draw);
1137    }
1138    if capabilities.contains(NodeCapabilities::POINTER_INPUT) {
1139        context.invalidate(InvalidationKind::PointerInput);
1140    }
1141    if capabilities.contains(NodeCapabilities::SEMANTICS) {
1142        context.invalidate(InvalidationKind::Semantics);
1143    }
1144    if capabilities.contains(NodeCapabilities::FOCUS) {
1145        context.invalidate(InvalidationKind::Focus);
1146    }
1147
1148    context.pop_active_capabilities();
1149}
1150
1151/// Attaches a node tree by calling on_attach for all unattached nodes.
1152///
1153/// # Safety
1154/// Callers must ensure no immutable RefCell borrows are held on the node
1155/// when calling this function. The on_attach callback may trigger mutations
1156/// (invalidations, state updates, etc.) that require mutable access, which
1157/// would panic if an immutable borrow is held across the call.
1158fn attach_node_tree(node: &mut dyn ModifierNode, context: &mut dyn ModifierNodeContext) {
1159    visit_node_tree_mut(node, &mut |n| {
1160        if !n.node_state().is_attached() {
1161            n.node_state().set_attached(true);
1162            with_node_context(n, context, |node, ctx| node.on_attach(ctx));
1163        }
1164    });
1165}
1166
1167fn reset_node_tree(node: &mut dyn ModifierNode) {
1168    visit_node_tree_mut(node, &mut |n| n.on_reset());
1169}
1170
1171fn detach_node_tree(node: &mut dyn ModifierNode) {
1172    visit_node_tree_mut(node, &mut |n| {
1173        if n.node_state().is_attached() {
1174            n.on_detach();
1175            n.node_state().set_attached(false);
1176        }
1177        n.node_state().set_parent_link(None);
1178        n.node_state().set_child_link(None);
1179        n.node_state()
1180            .set_aggregate_child_capabilities(NodeCapabilities::empty());
1181    });
1182}
1183
1184/// Chain of modifier nodes attached to a layout node.
1185///
1186/// The chain tracks ownership of modifier nodes and reuses them across
1187/// updates when the incoming element list still contains a node of the
1188/// same type. Removed nodes detach automatically so callers do not need
1189/// to manually manage their lifetimes.
1190pub struct ModifierNodeChain {
1191    entries: Vec<ModifierNodeEntry>,
1192    aggregated_capabilities: NodeCapabilities,
1193    head_aggregate_child_capabilities: NodeCapabilities,
1194    head_sentinel: Box<SentinelNode>,
1195    tail_sentinel: Box<SentinelNode>,
1196    /// (link, own_capabilities, aggregate_child_capabilities)
1197    ordered_nodes: Vec<(NodeLink, NodeCapabilities, NodeCapabilities)>,
1198    // Scratch buffers reused during update to avoid repeated allocations
1199    scratch_old_used: Vec<bool>,
1200    scratch_match_order: Vec<Option<usize>>,
1201    scratch_final_slots: Vec<Option<ModifierNodeEntry>>,
1202    scratch_elements: Vec<DynModifierElement>,
1203}
1204
1205struct SentinelNode {
1206    state: NodeState,
1207}
1208
1209impl SentinelNode {
1210    fn new() -> Self {
1211        Self {
1212            state: NodeState::sentinel(),
1213        }
1214    }
1215}
1216
1217impl DelegatableNode for SentinelNode {
1218    fn node_state(&self) -> &NodeState {
1219        &self.state
1220    }
1221}
1222
1223impl ModifierNode for SentinelNode {}
1224
1225#[derive(Clone)]
1226pub struct ModifierChainNodeRef<'a> {
1227    chain: &'a ModifierNodeChain,
1228    link: NodeLink,
1229    /// Capabilities cached from `ordered_nodes` build time — avoids RefCell borrow in kind_set().
1230    cached_capabilities: Option<NodeCapabilities>,
1231    /// Aggregate child capabilities cached from `ordered_nodes` — avoids RefCell borrow.
1232    cached_aggregate_child: Option<NodeCapabilities>,
1233}
1234
1235impl Default for ModifierNodeChain {
1236    fn default() -> Self {
1237        Self::new()
1238    }
1239}
1240
1241/// Index structure for O(1) modifier entry lookups during update.
1242///
1243/// This avoids O(n²) complexity by pre-building hash maps that allow constant-time
1244/// lookups for matching entries by key, hash, or type.
1245struct EntryIndex {
1246    /// Map (element type, node type, key) to keyed entries.
1247    keyed: HashMap<(TypeId, TypeId, u64), Vec<usize>>,
1248    /// Map (element type, node type, hash) to unkeyed entries with specific hash.
1249    hashed: HashMap<(TypeId, TypeId, u64), Vec<usize>>,
1250    /// Map (element type, node type) to unkeyed entries.
1251    typed: HashMap<(TypeId, TypeId), Vec<usize>>,
1252}
1253
1254struct EntryMatchQuery<'a> {
1255    element_type: TypeId,
1256    node_type: TypeId,
1257    key: Option<u64>,
1258    hash_code: u64,
1259    element: &'a DynModifierElement,
1260}
1261
1262impl EntryIndex {
1263    fn build(entries: &[ModifierNodeEntry]) -> Self {
1264        let mut keyed = HashMap::default();
1265        let mut hashed = HashMap::default();
1266        let mut typed = HashMap::default();
1267
1268        for (i, entry) in entries.iter().enumerate() {
1269            if let Some(key_value) = entry.key {
1270                // Keyed entry
1271                keyed
1272                    .entry((entry.element_type, entry.node_type, key_value))
1273                    .or_insert_with(Vec::new)
1274                    .push(i);
1275            } else {
1276                // Unkeyed entry - add to both hash and type indices
1277                hashed
1278                    .entry((entry.element_type, entry.node_type, entry.hash_code))
1279                    .or_insert_with(Vec::new)
1280                    .push(i);
1281                typed
1282                    .entry((entry.element_type, entry.node_type))
1283                    .or_insert_with(Vec::new)
1284                    .push(i);
1285            }
1286        }
1287
1288        Self {
1289            keyed,
1290            hashed,
1291            typed,
1292        }
1293    }
1294
1295    /// Find the best matching entry for reuse.
1296    ///
1297    /// Matching priority (from highest to lowest):
1298    /// 1. Keyed match: same element type, node type, and key.
1299    /// 2. Exact match: same retained identity, no key, same hash, and equal element.
1300    /// 3. Retained identity match without equality, which requires update.
1301    fn find_match(
1302        &self,
1303        entries: &[ModifierNodeEntry],
1304        used: &[bool],
1305        query: EntryMatchQuery<'_>,
1306    ) -> Option<usize> {
1307        if let Some(key_value) = query.key {
1308            // Priority 1: Keyed lookup - O(1)
1309            if let Some(candidates) =
1310                self.keyed
1311                    .get(&(query.element_type, query.node_type, key_value))
1312            {
1313                for &i in candidates {
1314                    if !used[i] {
1315                        return Some(i);
1316                    }
1317                }
1318            }
1319        } else {
1320            // Priority 2: Exact match (hash + equality) - O(1) lookup + O(k) equality checks
1321            if let Some(candidates) =
1322                self.hashed
1323                    .get(&(query.element_type, query.node_type, query.hash_code))
1324            {
1325                for &i in candidates {
1326                    if !used[i]
1327                        && entries[i]
1328                            .element
1329                            .as_ref()
1330                            .equals_element(query.element.as_ref())
1331                    {
1332                        return Some(i);
1333                    }
1334                }
1335            }
1336
1337            // Priority 3: Type match only - O(1) lookup + O(k) scan
1338            if let Some(candidates) = self.typed.get(&(query.element_type, query.node_type)) {
1339                for &i in candidates {
1340                    if !used[i] {
1341                        return Some(i);
1342                    }
1343                }
1344            }
1345        }
1346
1347        None
1348    }
1349}
1350
1351impl ModifierNodeChain {
1352    pub fn new() -> Self {
1353        let mut chain = Self {
1354            entries: Vec::new(),
1355            aggregated_capabilities: NodeCapabilities::empty(),
1356            head_aggregate_child_capabilities: NodeCapabilities::empty(),
1357            head_sentinel: Box::new(SentinelNode::new()),
1358            tail_sentinel: Box::new(SentinelNode::new()),
1359            ordered_nodes: Vec::new(),
1360            scratch_old_used: Vec::new(),
1361            scratch_match_order: Vec::new(),
1362            scratch_final_slots: Vec::new(),
1363            scratch_elements: Vec::new(),
1364        };
1365        chain.sync_chain_links();
1366        chain
1367    }
1368
1369    /// Detaches all nodes in the chain.
1370    pub fn detach_nodes(&mut self) {
1371        for entry in &self.entries {
1372            detach_node_tree(&mut **entry.node.borrow_mut());
1373        }
1374    }
1375
1376    /// Attaches all nodes in the chain.
1377    pub fn attach_nodes(&mut self, context: &mut dyn ModifierNodeContext) {
1378        for entry in &self.entries {
1379            attach_node_tree(&mut **entry.node.borrow_mut(), context);
1380        }
1381    }
1382
1383    /// Rebuilds the internal chain links (parent/child relationships).
1384    /// This should be called if nodes have been detached but are intended to be reused.
1385    pub fn repair_chain(&mut self) {
1386        self.sync_chain_links();
1387    }
1388
1389    /// Reconcile the chain against the provided elements, attaching newly
1390    /// created nodes and detaching nodes that are no longer required.
1391    ///
1392    /// This method delegates to `update_from_ref_iter` which handles the
1393    /// actual reconciliation logic.
1394    pub fn update_from_slice(
1395        &mut self,
1396        elements: &[DynModifierElement],
1397        context: &mut dyn ModifierNodeContext,
1398    ) {
1399        self.update_from_ref_iter(elements.iter(), context);
1400    }
1401
1402    /// Reconcile the chain against the provided iterator of element references.
1403    ///
1404    /// This is the preferred method as it avoids requiring a collected slice,
1405    /// enabling zero-allocation traversal of modifier trees.
1406    pub fn update_from_ref_iter<'a, I>(
1407        &mut self,
1408        elements: I,
1409        context: &mut dyn ModifierNodeContext,
1410    ) where
1411        I: Iterator<Item = &'a DynModifierElement>,
1412    {
1413        // Fast path: try to match elements sequentially without building index.
1414        // If all elements match in order (same type and key at same position),
1415        // we skip the expensive EntryIndex building. This is O(n) instead of O(n + m).
1416        let old_len = self.entries.len();
1417        let mut fast_path_failed_at: Option<usize> = None;
1418        let mut elements_count = 0;
1419
1420        // Collect elements we need to process in slow path
1421        self.scratch_elements.clear();
1422
1423        for (idx, element) in elements.enumerate() {
1424            elements_count = idx + 1;
1425
1426            if fast_path_failed_at.is_none() && idx < old_len {
1427                let entry = &mut self.entries[idx];
1428                let same_type = entry.element_type == element.element_type();
1429                let same_node_type = entry.node_type == element.node_type();
1430                let same_key = entry.key == element.key();
1431                let same_hash = entry.hash_code == element.hash_code();
1432
1433                // Fast path requires same type, key, AND hash to ensure we're not
1434                // breaking reordering semantics (where elements can move positions)
1435                let positional_update = element.requires_update();
1436                if same_type && same_node_type && same_key && (same_hash || positional_update) {
1437                    let can_update_node = {
1438                        let node_borrow = entry.node.borrow();
1439                        element.can_update_node(&**node_borrow)
1440                    };
1441                    if !can_update_node {
1442                        fast_path_failed_at = Some(idx);
1443                        self.scratch_elements.push(element.clone());
1444                        continue;
1445                    }
1446
1447                    // Fast path: element matches at same position
1448                    let same_element = entry.element.as_ref().equals_element(element.as_ref());
1449                    let capabilities = element.capabilities();
1450
1451                    // Re-attach node if it was detached during a previous update
1452                    {
1453                        let node_borrow = entry.node.borrow();
1454                        if !node_borrow.node_state().is_attached() {
1455                            drop(node_borrow);
1456                            attach_node_tree(&mut **entry.node.borrow_mut(), context);
1457                        }
1458                    }
1459
1460                    // Optimize updates: only call update_node if element changed
1461                    let needs_update = !same_element || element.requires_update();
1462                    if needs_update {
1463                        element.update_node(&mut **entry.node.borrow_mut());
1464                        entry.element = element.clone();
1465                        entry.hash_code = element.hash_code();
1466                        request_auto_invalidations(context, capabilities);
1467                    }
1468
1469                    // Always update metadata
1470                    entry.capabilities = capabilities;
1471                    entry
1472                        .node
1473                        .borrow()
1474                        .node_state()
1475                        .set_capabilities(capabilities);
1476                    continue;
1477                }
1478                // Fast path failed - mark position and fall through to collect
1479                fast_path_failed_at = Some(idx);
1480            }
1481
1482            // Collect element for slow path processing
1483            self.scratch_elements.push(element.clone());
1484        }
1485
1486        // Fast path succeeded if:
1487        // 1. No mismatch was found (fast_path_failed_at is None)
1488        // 2. All elements were processed via fast path (scratch_elements is empty)
1489        // Note: If old_len=0 and we have new elements, scratch_elements won't be empty
1490        if fast_path_failed_at.is_none() && self.scratch_elements.is_empty() {
1491            // Detach any removed entries (elements_count <= old_len guaranteed here)
1492            if elements_count < self.entries.len() {
1493                for entry in self.entries.drain(elements_count..) {
1494                    request_auto_invalidations(context, entry.capabilities);
1495                    detach_node_tree(&mut **entry.node.borrow_mut());
1496                }
1497            }
1498            self.sync_chain_links();
1499            return;
1500        }
1501
1502        // Slow path: need full reconciliation starting from failure point
1503        // If no mismatch but we have extra elements, fail_idx is the old length
1504        let fail_idx = fast_path_failed_at.unwrap_or(old_len);
1505
1506        // Move entries that were already processed to a safe place
1507        let mut old_entries: Vec<ModifierNodeEntry> = self.entries.drain(fail_idx..).collect();
1508        let processed_entries_len = self.entries.len();
1509        let old_len = old_entries.len();
1510
1511        // Reuse scratch buffers for the remaining entries only
1512        self.scratch_old_used.clear();
1513        self.scratch_old_used.resize(old_len, false);
1514
1515        self.scratch_match_order.clear();
1516        self.scratch_match_order.resize(old_len, None);
1517
1518        // Build index only for unprocessed entries
1519        let index = EntryIndex::build(&old_entries);
1520
1521        let new_elements_count = self.scratch_elements.len();
1522        self.scratch_final_slots.clear();
1523        self.scratch_final_slots.reserve(new_elements_count);
1524
1525        // Process each remaining element
1526        for (new_pos, element) in self.scratch_elements.drain(..).enumerate() {
1527            self.scratch_final_slots.push(None);
1528            let element_type = element.element_type();
1529            let node_type = element.node_type();
1530            let key = element.key();
1531            let hash_code = element.hash_code();
1532            let capabilities = element.capabilities();
1533
1534            // Find best matching old entry via index
1535            let matched_idx = index.find_match(
1536                &old_entries,
1537                &self.scratch_old_used,
1538                EntryMatchQuery {
1539                    element_type,
1540                    node_type,
1541                    key,
1542                    hash_code,
1543                    element: &element,
1544                },
1545            );
1546
1547            if let Some(idx) = matched_idx {
1548                // Reuse existing entry
1549                let entry = &mut old_entries[idx];
1550                let can_update_node = {
1551                    let node_borrow = entry.node.borrow();
1552                    element.can_update_node(&**node_borrow)
1553                };
1554                if !can_update_node {
1555                    let replacement = ModifierNodeEntry::new(
1556                        element_type,
1557                        node_type,
1558                        key,
1559                        element.clone(),
1560                        element.create_node(),
1561                        hash_code,
1562                        capabilities,
1563                    );
1564                    attach_node_tree(&mut **replacement.node.borrow_mut(), context);
1565                    element.update_node(&mut **replacement.node.borrow_mut());
1566                    request_auto_invalidations(context, capabilities);
1567                    self.scratch_final_slots[new_pos] = Some(replacement);
1568                    continue;
1569                }
1570
1571                self.scratch_old_used[idx] = true;
1572                self.scratch_match_order[idx] = Some(new_pos);
1573                let moved = idx != new_pos;
1574
1575                // Check if element actually changed
1576                let same_element = entry.element.as_ref().equals_element(element.as_ref());
1577
1578                // Re-attach node if it was detached
1579                {
1580                    let node_borrow = entry.node.borrow();
1581                    if !node_borrow.node_state().is_attached() {
1582                        drop(node_borrow);
1583                        attach_node_tree(&mut **entry.node.borrow_mut(), context);
1584                    }
1585                }
1586
1587                // Optimize updates: only call update_node if element changed
1588                let needs_update = !same_element || element.requires_update();
1589                if needs_update {
1590                    element.update_node(&mut **entry.node.borrow_mut());
1591                    entry.element = element;
1592                    entry.hash_code = hash_code;
1593                    request_auto_invalidations(context, capabilities);
1594                }
1595                if moved {
1596                    request_auto_invalidations(context, capabilities);
1597                }
1598
1599                // Always update metadata
1600                entry.key = key;
1601                entry.element_type = element_type;
1602                entry.node_type = node_type;
1603                entry.capabilities = capabilities;
1604                entry
1605                    .node
1606                    .borrow()
1607                    .node_state()
1608                    .set_capabilities(capabilities);
1609            } else {
1610                // Create new entry
1611                let entry = ModifierNodeEntry::new(
1612                    element_type,
1613                    node_type,
1614                    key,
1615                    element.clone(),
1616                    element.create_node(),
1617                    hash_code,
1618                    capabilities,
1619                );
1620                attach_node_tree(&mut **entry.node.borrow_mut(), context);
1621                element.update_node(&mut **entry.node.borrow_mut());
1622                request_auto_invalidations(context, capabilities);
1623                self.scratch_final_slots[new_pos] = Some(entry);
1624            }
1625        }
1626
1627        // Place matched entries in their new positions
1628        for (i, entry) in old_entries.into_iter().enumerate() {
1629            if self.scratch_old_used[i] {
1630                if let Some(pos) = self.scratch_match_order[i] {
1631                    self.scratch_final_slots[pos] = Some(entry);
1632                } else {
1633                    request_auto_invalidations(context, entry.capabilities);
1634                    detach_node_tree(&mut **entry.node.borrow_mut());
1635                }
1636            } else {
1637                request_auto_invalidations(context, entry.capabilities);
1638                detach_node_tree(&mut **entry.node.borrow_mut());
1639            }
1640        }
1641
1642        // Append processed entries to self.entries
1643        self.entries.reserve(self.scratch_final_slots.len());
1644        for slot in self.scratch_final_slots.drain(..) {
1645            if let Some(entry) = slot {
1646                self.entries.push(entry);
1647            } else {
1648                log::error!("modifier reconciliation produced an empty final slot");
1649            }
1650        }
1651
1652        debug_assert_eq!(
1653            self.entries.len(),
1654            processed_entries_len + new_elements_count
1655        );
1656        self.sync_chain_links();
1657    }
1658
1659    /// Convenience wrapper that accepts any iterator of type-erased
1660    /// modifier elements. Elements are collected into a temporary vector
1661    /// before reconciliation.
1662    pub fn update<I>(&mut self, elements: I, context: &mut dyn ModifierNodeContext)
1663    where
1664        I: IntoIterator<Item = DynModifierElement>,
1665    {
1666        let collected: Vec<DynModifierElement> = elements.into_iter().collect();
1667        self.update_from_slice(&collected, context);
1668    }
1669
1670    /// Resets all nodes in the chain. This mirrors the behaviour of
1671    /// Jetpack Compose's `onReset` callback.
1672    pub fn reset(&mut self) {
1673        for entry in &mut self.entries {
1674            reset_node_tree(&mut **entry.node.borrow_mut());
1675        }
1676    }
1677
1678    /// Detaches every node in the chain and clears internal storage.
1679    pub fn detach_all(&mut self) {
1680        for entry in std::mem::take(&mut self.entries) {
1681            detach_node_tree(&mut **entry.node.borrow_mut());
1682            {
1683                let node_borrow = entry.node.borrow();
1684                let state = node_borrow.node_state();
1685                state.set_capabilities(NodeCapabilities::empty());
1686            }
1687        }
1688        self.aggregated_capabilities = NodeCapabilities::empty();
1689        self.head_aggregate_child_capabilities = NodeCapabilities::empty();
1690        self.ordered_nodes.clear();
1691        self.sync_chain_links();
1692    }
1693
1694    pub fn len(&self) -> usize {
1695        self.entries.len()
1696    }
1697
1698    pub fn is_empty(&self) -> bool {
1699        self.entries.is_empty()
1700    }
1701
1702    /// Returns the aggregated capability mask for the entire chain.
1703    pub fn capabilities(&self) -> NodeCapabilities {
1704        self.aggregated_capabilities
1705    }
1706
1707    /// Returns true if the chain contains at least one node with the requested capability.
1708    pub fn has_capability(&self, capability: NodeCapabilities) -> bool {
1709        self.aggregated_capabilities.contains(capability)
1710    }
1711
1712    /// Returns the sentinel head reference for traversal.
1713    pub fn head(&self) -> ModifierChainNodeRef<'_> {
1714        self.make_node_ref(NodeLink::Head)
1715    }
1716
1717    /// Returns the sentinel tail reference for traversal.
1718    pub fn tail(&self) -> ModifierChainNodeRef<'_> {
1719        self.make_node_ref(NodeLink::Tail)
1720    }
1721
1722    /// Iterates over the chain from head to tail, skipping sentinels.
1723    pub fn head_to_tail(&self) -> ModifierChainIter<'_> {
1724        ModifierChainIter::forward(self)
1725    }
1726
1727    /// Iterates over the chain from tail to head, skipping sentinels.
1728    pub fn tail_to_head(&self) -> ModifierChainIter<'_> {
1729        ModifierChainIter::backward(self)
1730    }
1731
1732    /// Calls `f` for every node in insertion order.
1733    pub fn for_each_forward<F>(&self, mut f: F)
1734    where
1735        F: FnMut(ModifierChainNodeRef<'_>),
1736    {
1737        for node in self.head_to_tail() {
1738            f(node);
1739        }
1740    }
1741
1742    /// Calls `f` for every node containing any capability from `mask`.
1743    pub fn for_each_forward_matching<F>(&self, mask: NodeCapabilities, mut f: F)
1744    where
1745        F: FnMut(ModifierChainNodeRef<'_>),
1746    {
1747        if mask.is_empty() {
1748            self.for_each_forward(f);
1749            return;
1750        }
1751
1752        if !self.head().aggregate_child_capabilities().intersects(mask) {
1753            return;
1754        }
1755
1756        for node in self.head_to_tail() {
1757            if node.kind_set().intersects(mask) {
1758                f(node);
1759            }
1760        }
1761    }
1762
1763    /// Calls `f` for every node containing any capability from `mask`, providing the node ref.
1764    pub fn for_each_node_with_capability<F>(&self, mask: NodeCapabilities, mut f: F)
1765    where
1766        F: FnMut(ModifierChainNodeRef<'_>, &dyn ModifierNode),
1767    {
1768        self.for_each_forward_matching(mask, |node_ref| {
1769            node_ref.with_node(|node| f(node_ref.clone(), node));
1770        });
1771    }
1772
1773    /// Calls `f` for every node in reverse insertion order.
1774    pub fn for_each_backward<F>(&self, mut f: F)
1775    where
1776        F: FnMut(ModifierChainNodeRef<'_>),
1777    {
1778        for node in self.tail_to_head() {
1779            f(node);
1780        }
1781    }
1782
1783    /// Calls `f` for every node in reverse order that matches `mask`.
1784    pub fn for_each_backward_matching<F>(&self, mask: NodeCapabilities, mut f: F)
1785    where
1786        F: FnMut(ModifierChainNodeRef<'_>),
1787    {
1788        if mask.is_empty() {
1789            self.for_each_backward(f);
1790            return;
1791        }
1792
1793        if !self.head().aggregate_child_capabilities().intersects(mask) {
1794            return;
1795        }
1796
1797        for node in self.tail_to_head() {
1798            if node.kind_set().intersects(mask) {
1799                f(node);
1800            }
1801        }
1802    }
1803
1804    /// Returns a node reference for the entry at `index`.
1805    pub fn node_ref_at(&self, index: usize) -> Option<ModifierChainNodeRef<'_>> {
1806        if index >= self.entries.len() {
1807            None
1808        } else {
1809            Some(self.make_node_ref(NodeLink::Entry(NodePath::root(index))))
1810        }
1811    }
1812
1813    /// Returns the node reference that owns `node`.
1814    pub fn find_node_ref(&self, node: &dyn ModifierNode) -> Option<ModifierChainNodeRef<'_>> {
1815        fn node_data_ptr(node: &dyn ModifierNode) -> *const () {
1816            node as *const dyn ModifierNode as *const ()
1817        }
1818
1819        let target = node_data_ptr(node);
1820        for (index, entry) in self.entries.iter().enumerate() {
1821            if node_data_ptr(&**entry.node.borrow()) == target {
1822                return Some(self.make_node_ref(NodeLink::Entry(NodePath::root(index))));
1823            }
1824        }
1825
1826        self.ordered_nodes.iter().find_map(|(link, _caps, _agg)| {
1827            if matches!(link, NodeLink::Entry(path) if path.delegates().is_empty()) {
1828                return None;
1829            }
1830            let matches_target = match link {
1831                NodeLink::Head => node_data_ptr(self.head_sentinel.as_ref()) == target,
1832                NodeLink::Tail => node_data_ptr(self.tail_sentinel.as_ref()) == target,
1833                NodeLink::Entry(path) => {
1834                    let node_borrow = self.entries[path.entry()].node.borrow();
1835                    node_data_ptr(&**node_borrow) == target
1836                }
1837            };
1838            if matches_target {
1839                Some(self.make_node_ref(*link))
1840            } else {
1841                None
1842            }
1843        })
1844    }
1845
1846    /// Downcasts the node at `index` to the requested type.
1847    /// Returns a `Ref` guard that dereferences to the node type.
1848    pub fn node<N: ModifierNode + 'static>(&self, index: usize) -> Option<std::cell::Ref<'_, N>> {
1849        self.entries.get(index).and_then(|entry| {
1850            std::cell::Ref::filter_map(entry.node.borrow(), |boxed_node| {
1851                boxed_node.as_any().downcast_ref::<N>()
1852            })
1853            .ok()
1854        })
1855    }
1856
1857    /// Downcasts the node at `index` to the requested mutable type.
1858    /// Returns a `RefMut` guard that dereferences to the node type.
1859    pub fn node_mut<N: ModifierNode + 'static>(
1860        &self,
1861        index: usize,
1862    ) -> Option<std::cell::RefMut<'_, N>> {
1863        self.entries.get(index).and_then(|entry| {
1864            std::cell::RefMut::filter_map(entry.node.borrow_mut(), |boxed_node| {
1865                boxed_node.as_any_mut().downcast_mut::<N>()
1866            })
1867            .ok()
1868        })
1869    }
1870
1871    /// Returns an Rc clone of the node at the given index for shared ownership.
1872    /// This is used by coordinators to hold direct references to nodes.
1873    pub fn get_node_rc(&self, index: usize) -> Option<Rc<RefCell<Box<dyn ModifierNode>>>> {
1874        self.entries.get(index).map(|entry| Rc::clone(&entry.node))
1875    }
1876
1877    /// Returns true if the chain contains any nodes matching the given invalidation kind.
1878    pub fn has_nodes_for_invalidation(&self, kind: InvalidationKind) -> bool {
1879        self.aggregated_capabilities
1880            .contains(NodeCapabilities::for_invalidation(kind))
1881    }
1882
1883    /// Visits every node in insertion order together with its capability mask.
1884    pub fn visit_nodes<F>(&self, mut f: F)
1885    where
1886        F: FnMut(&dyn ModifierNode, NodeCapabilities),
1887    {
1888        for (link, cached_caps, _agg) in &self.ordered_nodes {
1889            match link {
1890                NodeLink::Head => {
1891                    f(self.head_sentinel.as_ref(), *cached_caps);
1892                }
1893                NodeLink::Tail => {
1894                    f(self.tail_sentinel.as_ref(), *cached_caps);
1895                }
1896                NodeLink::Entry(path) => {
1897                    let node_borrow = self.entries[path.entry()].node.borrow();
1898                    if path.delegates().is_empty() {
1899                        f(&**node_borrow, *cached_caps);
1900                    } else {
1901                        let mut current: &dyn ModifierNode = &**node_borrow;
1902                        for &delegate_index in path.delegates() {
1903                            if let Some(delegate) = nth_delegate(current, delegate_index as usize) {
1904                                current = delegate;
1905                            } else {
1906                                return; // Invalid delegate path
1907                            }
1908                        }
1909                        f(current, *cached_caps);
1910                    }
1911                }
1912            }
1913        }
1914    }
1915
1916    /// Visits every node mutably in insertion order together with its capability mask.
1917    pub fn visit_nodes_mut<F>(&mut self, mut f: F)
1918    where
1919        F: FnMut(&mut dyn ModifierNode, NodeCapabilities),
1920    {
1921        for index in 0..self.ordered_nodes.len() {
1922            let (link, cached_caps, _agg) = self.ordered_nodes[index];
1923            match link {
1924                NodeLink::Head => {
1925                    f(self.head_sentinel.as_mut(), cached_caps);
1926                }
1927                NodeLink::Tail => {
1928                    f(self.tail_sentinel.as_mut(), cached_caps);
1929                }
1930                NodeLink::Entry(path) => {
1931                    let mut node_borrow = self.entries[path.entry()].node.borrow_mut();
1932                    if path.delegates().is_empty() {
1933                        f(&mut **node_borrow, cached_caps);
1934                    } else {
1935                        let mut current: &mut dyn ModifierNode = &mut **node_borrow;
1936                        for &delegate_index in path.delegates() {
1937                            if let Some(delegate) =
1938                                nth_delegate_mut(current, delegate_index as usize)
1939                            {
1940                                current = delegate;
1941                            } else {
1942                                return; // Invalid delegate path
1943                            }
1944                        }
1945                        f(current, cached_caps);
1946                    }
1947                }
1948            }
1949        }
1950    }
1951
1952    fn make_node_ref(&self, link: NodeLink) -> ModifierChainNodeRef<'_> {
1953        ModifierChainNodeRef {
1954            chain: self,
1955            link,
1956            cached_capabilities: None,
1957            cached_aggregate_child: None,
1958        }
1959    }
1960
1961    fn make_node_ref_with_caps(
1962        &self,
1963        link: NodeLink,
1964        caps: NodeCapabilities,
1965        aggregate_child: NodeCapabilities,
1966    ) -> ModifierChainNodeRef<'_> {
1967        ModifierChainNodeRef {
1968            chain: self,
1969            link,
1970            cached_capabilities: Some(caps),
1971            cached_aggregate_child: Some(aggregate_child),
1972        }
1973    }
1974
1975    fn sync_chain_links(&mut self) {
1976        self.rebuild_ordered_nodes();
1977
1978        self.head_sentinel.node_state().set_parent_link(None);
1979        self.tail_sentinel.node_state().set_child_link(None);
1980
1981        if self.ordered_nodes.is_empty() {
1982            self.head_sentinel
1983                .node_state()
1984                .set_child_link(Some(NodeLink::Tail));
1985            self.tail_sentinel
1986                .node_state()
1987                .set_parent_link(Some(NodeLink::Head));
1988            self.aggregated_capabilities = NodeCapabilities::empty();
1989            self.head_aggregate_child_capabilities = NodeCapabilities::empty();
1990            self.head_sentinel
1991                .node_state()
1992                .set_aggregate_child_capabilities(NodeCapabilities::empty());
1993            self.tail_sentinel
1994                .node_state()
1995                .set_aggregate_child_capabilities(NodeCapabilities::empty());
1996            return;
1997        }
1998
1999        let mut previous = NodeLink::Head;
2000        for (link, _caps, _agg) in self.ordered_nodes.iter().copied() {
2001            // Set child link on previous
2002            match &previous {
2003                NodeLink::Head => self.head_sentinel.node_state().set_child_link(Some(link)),
2004                NodeLink::Tail => self.tail_sentinel.node_state().set_child_link(Some(link)),
2005                NodeLink::Entry(path) => {
2006                    let node_borrow = self.entries[path.entry()].node.borrow();
2007                    // Navigate to delegate if needed
2008                    if path.delegates().is_empty() {
2009                        node_borrow.node_state().set_child_link(Some(link));
2010                    } else {
2011                        let mut current: &dyn ModifierNode = &**node_borrow;
2012                        for &delegate_index in path.delegates() {
2013                            if let Some(delegate) = nth_delegate(current, delegate_index as usize) {
2014                                current = delegate;
2015                            }
2016                        }
2017                        current.node_state().set_child_link(Some(link));
2018                    }
2019                }
2020            }
2021            // Set parent link on current
2022            match &link {
2023                NodeLink::Head => self
2024                    .head_sentinel
2025                    .node_state()
2026                    .set_parent_link(Some(previous)),
2027                NodeLink::Tail => self
2028                    .tail_sentinel
2029                    .node_state()
2030                    .set_parent_link(Some(previous)),
2031                NodeLink::Entry(path) => {
2032                    let node_borrow = self.entries[path.entry()].node.borrow();
2033                    // Navigate to delegate if needed
2034                    if path.delegates().is_empty() {
2035                        node_borrow.node_state().set_parent_link(Some(previous));
2036                    } else {
2037                        let mut current: &dyn ModifierNode = &**node_borrow;
2038                        for &delegate_index in path.delegates() {
2039                            if let Some(delegate) = nth_delegate(current, delegate_index as usize) {
2040                                current = delegate;
2041                            }
2042                        }
2043                        current.node_state().set_parent_link(Some(previous));
2044                    }
2045                }
2046            }
2047            previous = link;
2048        }
2049
2050        // Set child link on last node to Tail
2051        match &previous {
2052            NodeLink::Head => self
2053                .head_sentinel
2054                .node_state()
2055                .set_child_link(Some(NodeLink::Tail)),
2056            NodeLink::Tail => self
2057                .tail_sentinel
2058                .node_state()
2059                .set_child_link(Some(NodeLink::Tail)),
2060            NodeLink::Entry(path) => {
2061                let node_borrow = self.entries[path.entry()].node.borrow();
2062                // Navigate to delegate if needed
2063                if path.delegates().is_empty() {
2064                    node_borrow
2065                        .node_state()
2066                        .set_child_link(Some(NodeLink::Tail));
2067                } else {
2068                    let mut current: &dyn ModifierNode = &**node_borrow;
2069                    for &delegate_index in path.delegates() {
2070                        if let Some(delegate) = nth_delegate(current, delegate_index as usize) {
2071                            current = delegate;
2072                        }
2073                    }
2074                    current.node_state().set_child_link(Some(NodeLink::Tail));
2075                }
2076            }
2077        }
2078        self.tail_sentinel
2079            .node_state()
2080            .set_parent_link(Some(previous));
2081        self.tail_sentinel.node_state().set_child_link(None);
2082
2083        let mut aggregate = NodeCapabilities::empty();
2084        for (link, cached_caps, cached_aggregate) in self.ordered_nodes.iter_mut().rev() {
2085            aggregate |= *cached_caps;
2086            *cached_aggregate = aggregate;
2087            // Also update NodeState for code that reads through DelegatableNode
2088            match link {
2089                NodeLink::Head => {
2090                    self.head_sentinel
2091                        .node_state()
2092                        .set_aggregate_child_capabilities(aggregate);
2093                }
2094                NodeLink::Tail => {
2095                    self.tail_sentinel
2096                        .node_state()
2097                        .set_aggregate_child_capabilities(aggregate);
2098                }
2099                NodeLink::Entry(path) => {
2100                    let node_borrow = self.entries[path.entry()].node.borrow();
2101                    let state = if path.delegates().is_empty() {
2102                        node_borrow.node_state()
2103                    } else {
2104                        let mut current: &dyn ModifierNode = &**node_borrow;
2105                        for &delegate_index in path.delegates() {
2106                            if let Some(delegate) = nth_delegate(current, delegate_index as usize) {
2107                                current = delegate;
2108                            }
2109                        }
2110                        current.node_state()
2111                    };
2112                    state.set_aggregate_child_capabilities(aggregate);
2113                }
2114            }
2115        }
2116
2117        self.aggregated_capabilities = aggregate;
2118        self.head_aggregate_child_capabilities = aggregate;
2119        self.head_sentinel
2120            .node_state()
2121            .set_aggregate_child_capabilities(aggregate);
2122        self.tail_sentinel
2123            .node_state()
2124            .set_aggregate_child_capabilities(NodeCapabilities::empty());
2125    }
2126
2127    fn rebuild_ordered_nodes(&mut self) {
2128        self.ordered_nodes.clear();
2129        let mut path_buf = [0usize; MAX_DELEGATE_DEPTH];
2130        for (index, entry) in self.entries.iter().enumerate() {
2131            let node_borrow = entry.node.borrow();
2132            Self::enumerate_link_order(
2133                &**node_borrow,
2134                index,
2135                &mut path_buf,
2136                0,
2137                &mut self.ordered_nodes,
2138            );
2139        }
2140    }
2141
2142    fn enumerate_link_order(
2143        node: &dyn ModifierNode,
2144        entry: usize,
2145        path_buf: &mut [usize; MAX_DELEGATE_DEPTH],
2146        path_len: usize,
2147        out: &mut Vec<(NodeLink, NodeCapabilities, NodeCapabilities)>,
2148    ) {
2149        let caps = node.node_state().capabilities();
2150        out.push((
2151            NodeLink::Entry(NodePath::from_slice(entry, &path_buf[..path_len])),
2152            caps,
2153            NodeCapabilities::empty(),
2154        ));
2155        let mut delegate_index = 0usize;
2156        node.for_each_delegate(&mut |child| {
2157            if path_len < MAX_DELEGATE_DEPTH {
2158                path_buf[path_len] = delegate_index;
2159                Self::enumerate_link_order(child, entry, path_buf, path_len + 1, out);
2160            }
2161            delegate_index += 1;
2162        });
2163    }
2164}
2165
2166impl<'a> ModifierChainNodeRef<'a> {
2167    /// Helper to get NodeState, properly handling RefCell for entries.
2168    /// Returns NodeState values by calling a closure with the state.
2169    fn with_state<R>(&self, f: impl FnOnce(&NodeState) -> R) -> R {
2170        match &self.link {
2171            NodeLink::Head => f(self.chain.head_sentinel.node_state()),
2172            NodeLink::Tail => f(self.chain.tail_sentinel.node_state()),
2173            NodeLink::Entry(path) => {
2174                let node_borrow = self.chain.entries[path.entry()].node.borrow();
2175                // Navigate through delegates if path has them
2176                if path.delegates().is_empty() {
2177                    f(node_borrow.node_state())
2178                } else {
2179                    // Navigate to the delegate node
2180                    let mut current: &dyn ModifierNode = &**node_borrow;
2181                    for &delegate_index in path.delegates() {
2182                        if let Some(delegate) = nth_delegate(current, delegate_index as usize) {
2183                            current = delegate;
2184                        } else {
2185                            // Fallback to root node state if delegate path is invalid
2186                            return f(node_borrow.node_state());
2187                        }
2188                    }
2189                    f(current.node_state())
2190                }
2191            }
2192        }
2193    }
2194
2195    /// Provides access to the node via a closure, properly handling RefCell borrows.
2196    /// Returns None for sentinel nodes.
2197    pub fn with_node<R>(&self, f: impl FnOnce(&dyn ModifierNode) -> R) -> Option<R> {
2198        match &self.link {
2199            NodeLink::Head => None, // Head sentinel
2200            NodeLink::Tail => None, // Tail sentinel
2201            NodeLink::Entry(path) => {
2202                let node_borrow = self.chain.entries[path.entry()].node.borrow();
2203                // Navigate through delegates if path has them
2204                if path.delegates().is_empty() {
2205                    Some(f(&**node_borrow))
2206                } else {
2207                    // Navigate to the delegate node
2208                    let mut current: &dyn ModifierNode = &**node_borrow;
2209                    for &delegate_index in path.delegates() {
2210                        if let Some(delegate) = nth_delegate(current, delegate_index as usize) {
2211                            current = delegate;
2212                        } else {
2213                            // Return None if delegate path is invalid
2214                            return None;
2215                        }
2216                    }
2217                    Some(f(current))
2218                }
2219            }
2220        }
2221    }
2222
2223    /// Returns the parent reference, including sentinel head when applicable.
2224    #[inline]
2225    pub fn parent(&self) -> Option<Self> {
2226        self.with_state(|state| state.parent_link())
2227            .map(|link| self.chain.make_node_ref(link))
2228    }
2229
2230    /// Returns the child reference, including sentinel tail for the last entry.
2231    #[inline]
2232    pub fn child(&self) -> Option<Self> {
2233        self.with_state(|state| state.child_link())
2234            .map(|link| self.chain.make_node_ref(link))
2235    }
2236
2237    /// Returns the capability mask for this specific node.
2238    #[inline]
2239    pub fn kind_set(&self) -> NodeCapabilities {
2240        if let Some(caps) = self.cached_capabilities {
2241            return caps;
2242        }
2243        match &self.link {
2244            NodeLink::Head | NodeLink::Tail => NodeCapabilities::empty(),
2245            NodeLink::Entry(_) => self.with_state(|state| state.capabilities()),
2246        }
2247    }
2248
2249    /// Returns the entry index backing this node when it is part of the chain.
2250    pub fn entry_index(&self) -> Option<usize> {
2251        match &self.link {
2252            NodeLink::Entry(path) => Some(path.entry()),
2253            _ => None,
2254        }
2255    }
2256
2257    /// Returns how many delegate hops separate this node from its root element.
2258    pub fn delegate_depth(&self) -> usize {
2259        match &self.link {
2260            NodeLink::Entry(path) => path.delegates().len(),
2261            _ => 0,
2262        }
2263    }
2264
2265    /// Returns the aggregated capability mask for the subtree rooted at this node.
2266    #[inline]
2267    pub fn aggregate_child_capabilities(&self) -> NodeCapabilities {
2268        if let Some(agg) = self.cached_aggregate_child {
2269            return agg;
2270        }
2271        if self.is_tail() {
2272            NodeCapabilities::empty()
2273        } else {
2274            self.with_state(|state| state.aggregate_child_capabilities())
2275        }
2276    }
2277
2278    /// Returns true if this reference targets the sentinel head.
2279    pub fn is_head(&self) -> bool {
2280        matches!(self.link, NodeLink::Head)
2281    }
2282
2283    /// Returns true if this reference targets the sentinel tail.
2284    pub fn is_tail(&self) -> bool {
2285        matches!(self.link, NodeLink::Tail)
2286    }
2287
2288    /// Returns true if this reference targets either sentinel.
2289    pub fn is_sentinel(&self) -> bool {
2290        matches!(self.link, NodeLink::Head | NodeLink::Tail)
2291    }
2292
2293    /// Returns true if this node has any capability bits present in `mask`.
2294    pub fn has_capability(&self, mask: NodeCapabilities) -> bool {
2295        !mask.is_empty() && self.kind_set().intersects(mask)
2296    }
2297
2298    /// Visits descendant nodes, optionally including `self`, in insertion order.
2299    pub fn visit_descendants<F>(self, include_self: bool, mut f: F)
2300    where
2301        F: FnMut(ModifierChainNodeRef<'a>),
2302    {
2303        let mut current = if include_self {
2304            Some(self)
2305        } else {
2306            self.child()
2307        };
2308        while let Some(node) = current {
2309            if node.is_tail() {
2310                break;
2311            }
2312            if !node.is_sentinel() {
2313                f(node.clone());
2314            }
2315            current = node.child();
2316        }
2317    }
2318
2319    /// Visits descendant nodes that match `mask`, short-circuiting when possible.
2320    pub fn visit_descendants_matching<F>(self, include_self: bool, mask: NodeCapabilities, mut f: F)
2321    where
2322        F: FnMut(ModifierChainNodeRef<'a>),
2323    {
2324        if mask.is_empty() {
2325            self.visit_descendants(include_self, f);
2326            return;
2327        }
2328
2329        if !self.aggregate_child_capabilities().intersects(mask) {
2330            return;
2331        }
2332
2333        self.visit_descendants(include_self, |node| {
2334            if node.kind_set().intersects(mask) {
2335                f(node);
2336            }
2337        });
2338    }
2339
2340    /// Visits ancestor nodes up to (but excluding) the sentinel head.
2341    pub fn visit_ancestors<F>(self, include_self: bool, mut f: F)
2342    where
2343        F: FnMut(ModifierChainNodeRef<'a>),
2344    {
2345        let mut current = if include_self {
2346            Some(self)
2347        } else {
2348            self.parent()
2349        };
2350        while let Some(node) = current {
2351            if node.is_head() {
2352                break;
2353            }
2354            f(node.clone());
2355            current = node.parent();
2356        }
2357    }
2358
2359    /// Visits ancestor nodes that match `mask`.
2360    pub fn visit_ancestors_matching<F>(self, include_self: bool, mask: NodeCapabilities, mut f: F)
2361    where
2362        F: FnMut(ModifierChainNodeRef<'a>),
2363    {
2364        if mask.is_empty() {
2365            self.visit_ancestors(include_self, f);
2366            return;
2367        }
2368
2369        self.visit_ancestors(include_self, |node| {
2370            if node.kind_set().intersects(mask) {
2371                f(node);
2372            }
2373        });
2374    }
2375
2376    /// Finds the nearest ancestor focus target node.
2377    ///
2378    /// This is useful for focus navigation to find the parent focusable
2379    /// component in the tree.
2380    pub fn find_parent_focus_target(&self) -> Option<ModifierChainNodeRef<'a>> {
2381        let mut result = None;
2382        self.clone()
2383            .visit_ancestors_matching(false, NodeCapabilities::FOCUS, |node| {
2384                if result.is_none() {
2385                    result = Some(node);
2386                }
2387            });
2388        result
2389    }
2390
2391    /// Finds the first descendant focus target node.
2392    ///
2393    /// This is useful for focus navigation to find the first focusable
2394    /// child component in the tree.
2395    pub fn find_first_focus_target(&self) -> Option<ModifierChainNodeRef<'a>> {
2396        let mut result = None;
2397        self.clone()
2398            .visit_descendants_matching(false, NodeCapabilities::FOCUS, |node| {
2399                if result.is_none() {
2400                    result = Some(node);
2401                }
2402            });
2403        result
2404    }
2405
2406    /// Returns true if this node or any ancestor has focus capability.
2407    pub fn has_focus_capability_in_ancestors(&self) -> bool {
2408        let mut found = false;
2409        self.clone()
2410            .visit_ancestors_matching(true, NodeCapabilities::FOCUS, |_| {
2411                found = true;
2412            });
2413        found
2414    }
2415}
2416
2417#[cfg(test)]
2418#[path = "tests/modifier_tests.rs"]
2419mod tests;