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    /// Like [`create_draw_closure`](Self::create_draw_closure), but the
544    /// primitives render BEHIND the node's content — e.g. a text field's
545    /// selection highlight, which must sit under the glyphs (a highlight
546    /// drawn over them tints the text with its translucent fill).
547    fn create_behind_draw_closure(
548        &self,
549    ) -> Option<Rc<dyn Fn(Size) -> Vec<cranpose_ui_graphics::DrawPrimitive>>> {
550        None
551    }
552}
553
554/// Marker trait for pointer input modifier nodes.
555///
556/// Pointer input nodes participate in hit-testing and pointer event
557/// dispatch. They can intercept pointer events and handle them before
558/// they reach the wrapped content.
559pub trait PointerInputNode: ModifierNode {
560    /// Called when a pointer event occurs within the bounds of this node.
561    /// Returns true if the event was consumed and should not propagate further.
562    fn on_pointer_event(
563        &mut self,
564        _context: &mut dyn ModifierNodeContext,
565        _event: &PointerEvent,
566    ) -> bool {
567        false
568    }
569
570    /// Returns true if this node should participate in hit-testing for the
571    /// given pointer position.
572    fn hit_test(&self, _x: f32, _y: f32) -> bool {
573        true
574    }
575
576    /// Returns an event handler closure if the node wants to participate in pointer dispatch.
577    fn pointer_input_handler(&self) -> Option<Rc<dyn Fn(PointerEvent)>> {
578        None
579    }
580}
581
582/// Marker trait for semantics modifier nodes.
583///
584/// Semantics nodes participate in the semantics tree construction. They can
585/// add or modify semantic properties of their wrapped content for
586/// accessibility and testing purposes.
587pub trait SemanticsNode: ModifierNode {
588    /// Merges semantic properties into the provided configuration.
589    fn merge_semantics(&self, _config: &mut SemanticsConfiguration) {
590        // Default: no semantics added
591    }
592}
593
594/// Focus state of a focus target node.
595///
596/// This mirrors Jetpack Compose's FocusState enum which tracks whether
597/// a node is focused, has a focused child, or is inactive.
598#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Default)]
599pub enum FocusState {
600    /// The focusable component is currently active (i.e. it receives key events).
601    Active,
602    /// One of the descendants of the focusable component is Active.
603    ActiveParent,
604    /// The focusable component is currently active (has focus), and is in a state
605    /// where it does not want to give up focus. (Eg. a text field with an invalid
606    /// phone number).
607    Captured,
608    /// The focusable component does not receive any key events. (ie it is not active,
609    /// nor are any of its descendants active).
610    #[default]
611    Inactive,
612}
613
614impl FocusState {
615    /// Returns whether the component is focused (Active or Captured).
616    pub fn is_focused(self) -> bool {
617        matches!(self, FocusState::Active | FocusState::Captured)
618    }
619
620    /// Returns whether this node or any descendant has focus.
621    pub fn has_focus(self) -> bool {
622        matches!(
623            self,
624            FocusState::Active | FocusState::ActiveParent | FocusState::Captured
625        )
626    }
627
628    /// Returns whether focus is captured.
629    pub fn is_captured(self) -> bool {
630        matches!(self, FocusState::Captured)
631    }
632}
633
634/// Marker trait for focus modifier nodes.
635///
636/// Focus nodes participate in focus management. They can request focus,
637/// track focus state, and participate in focus traversal.
638pub trait FocusNode: ModifierNode {
639    /// Returns the current focus state of this node.
640    fn focus_state(&self) -> FocusState;
641
642    /// Called when focus state changes for this node.
643    fn on_focus_changed(&mut self, _context: &mut dyn ModifierNodeContext, _state: FocusState) {
644        // Default: no action on focus change
645    }
646}
647
648/// Semantics configuration for accessibility.
649#[derive(Clone, Debug, Default, PartialEq)]
650pub struct SemanticsConfiguration {
651    pub content_description: Option<String>,
652    pub is_button: bool,
653    pub is_clickable: bool,
654    pub is_editable_text: bool,
655    pub text_selection: Option<crate::text::TextRange>,
656}
657
658impl SemanticsConfiguration {
659    pub fn merge(&mut self, other: &SemanticsConfiguration) {
660        if let Some(description) = &other.content_description {
661            self.content_description = Some(description.clone());
662        }
663        self.is_button |= other.is_button;
664        self.is_clickable |= other.is_clickable;
665        self.is_editable_text |= other.is_editable_text;
666        if let Some(selection) = other.text_selection {
667            self.text_selection = Some(selection);
668        }
669    }
670}
671
672impl fmt::Debug for dyn ModifierNode {
673    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
674        f.debug_struct("ModifierNode").finish_non_exhaustive()
675    }
676}
677
678impl dyn ModifierNode {
679    pub fn as_any(&self) -> &dyn Any {
680        self
681    }
682
683    pub fn as_any_mut(&mut self) -> &mut dyn Any {
684        self
685    }
686}
687
688/// Strongly typed modifier elements that can create and update nodes while
689/// exposing equality/hash/inspector contracts that mirror Jetpack Compose.
690pub trait ModifierNodeElement: fmt::Debug + Hash + PartialEq + 'static {
691    type Node: ModifierNode;
692
693    /// Creates a new modifier node instance for this element.
694    fn create(&self) -> Self::Node;
695
696    /// Brings an existing modifier node up to date with the element's data.
697    fn update(&self, node: &mut Self::Node);
698
699    /// Optional key used to disambiguate multiple instances of the same element type.
700    fn key(&self) -> Option<u64> {
701        None
702    }
703
704    /// Human readable name surfaced to inspector tooling.
705    fn inspector_name(&self) -> &'static str {
706        type_name::<Self>()
707    }
708
709    /// Records inspector properties for tooling.
710    fn inspector_properties(&self, _inspector: &mut dyn FnMut(&'static str, String)) {}
711
712    /// Returns the capabilities of nodes created by this element.
713    /// Override this to indicate which specialized traits the node implements.
714    fn capabilities(&self) -> NodeCapabilities {
715        NodeCapabilities::default()
716    }
717
718    /// Whether this element requires `update` to be called even if `eq` returns true.
719    ///
720    /// This is useful for elements that ignore certain fields in `eq` (e.g. closures)
721    /// to allow node reuse, but still need those fields updated in the existing node.
722    /// Defaults to `false`.
723    fn always_update(&self) -> bool {
724        false
725    }
726
727    /// Whether modifier reconciliation should request capability-wide invalidations
728    /// after updating an existing node.
729    fn auto_invalidate_on_update(&self) -> bool {
730        true
731    }
732
733    /// Optional targeted invalidation requested after updating an existing node.
734    ///
735    /// This is for nodes whose attach/remove capability is broader than the
736    /// work needed for a value-only update. For example, an offset node
737    /// participates in layout on attach but an x/y change only needs placement
738    /// data and draw output refreshed.
739    fn update_invalidation_kind(&self) -> Option<InvalidationKind> {
740        None
741    }
742}
743
744/// Capability flags indicating which specialized traits a modifier node implements.
745#[derive(Clone, Copy, PartialEq, Eq, Hash)]
746pub struct NodeCapabilities(u32);
747
748impl NodeCapabilities {
749    /// No capabilities.
750    pub const NONE: Self = Self(0);
751    /// Modifier participates in measure/layout.
752    pub const LAYOUT: Self = Self(1 << 0);
753    /// Modifier participates in draw.
754    pub const DRAW: Self = Self(1 << 1);
755    /// Modifier participates in pointer input.
756    pub const POINTER_INPUT: Self = Self(1 << 2);
757    /// Modifier participates in semantics tree construction.
758    pub const SEMANTICS: Self = Self(1 << 3);
759    /// Modifier participates in modifier locals.
760    pub const MODIFIER_LOCALS: Self = Self(1 << 4);
761    /// Modifier participates in focus management.
762    pub const FOCUS: Self = Self(1 << 5);
763
764    /// Returns an empty capability set.
765    pub const fn empty() -> Self {
766        Self::NONE
767    }
768
769    /// Returns whether all bits in `other` are present in `self`.
770    pub const fn contains(self, other: Self) -> bool {
771        (self.0 & other.0) == other.0
772    }
773
774    /// Returns whether any bit in `other` is present in `self`.
775    pub const fn intersects(self, other: Self) -> bool {
776        (self.0 & other.0) != 0
777    }
778
779    /// Inserts the requested capability bits.
780    pub fn insert(&mut self, other: Self) {
781        self.0 |= other.0;
782    }
783
784    /// Returns the raw bit representation.
785    pub const fn bits(self) -> u32 {
786        self.0
787    }
788
789    /// Returns true when no capabilities are set.
790    pub const fn is_empty(self) -> bool {
791        self.0 == 0
792    }
793
794    /// Returns the capability bit mask required for the given invalidation.
795    pub const fn for_invalidation(kind: InvalidationKind) -> Self {
796        match kind {
797            InvalidationKind::Layout => Self::LAYOUT,
798            InvalidationKind::Draw => Self::DRAW,
799            InvalidationKind::PointerInput => Self::POINTER_INPUT,
800            InvalidationKind::Semantics => Self::SEMANTICS,
801            InvalidationKind::Focus => Self::FOCUS,
802        }
803    }
804}
805
806impl Default for NodeCapabilities {
807    fn default() -> Self {
808        Self::NONE
809    }
810}
811
812impl fmt::Debug for NodeCapabilities {
813    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
814        f.debug_struct("NodeCapabilities")
815            .field("layout", &self.contains(Self::LAYOUT))
816            .field("draw", &self.contains(Self::DRAW))
817            .field("pointer_input", &self.contains(Self::POINTER_INPUT))
818            .field("semantics", &self.contains(Self::SEMANTICS))
819            .field("modifier_locals", &self.contains(Self::MODIFIER_LOCALS))
820            .field("focus", &self.contains(Self::FOCUS))
821            .finish()
822    }
823}
824
825impl BitOr for NodeCapabilities {
826    type Output = Self;
827
828    fn bitor(self, rhs: Self) -> Self::Output {
829        Self(self.0 | rhs.0)
830    }
831}
832
833impl BitOrAssign for NodeCapabilities {
834    fn bitor_assign(&mut self, rhs: Self) {
835        self.0 |= rhs.0;
836    }
837}
838
839/// Records an invalidation request together with the capability mask that triggered it.
840#[derive(Clone, Copy, Debug, PartialEq, Eq)]
841pub struct ModifierInvalidation {
842    kind: InvalidationKind,
843    capabilities: NodeCapabilities,
844}
845
846impl ModifierInvalidation {
847    /// Creates a new modifier invalidation entry.
848    pub const fn new(kind: InvalidationKind, capabilities: NodeCapabilities) -> Self {
849        Self { kind, capabilities }
850    }
851
852    /// Returns the invalidated pipeline kind.
853    pub const fn kind(self) -> InvalidationKind {
854        self.kind
855    }
856
857    /// Returns the capability mask associated with the invalidation.
858    pub const fn capabilities(self) -> NodeCapabilities {
859        self.capabilities
860    }
861}
862
863/// Type-erased modifier element used by the runtime to reconcile chains.
864pub trait AnyModifierElement: fmt::Debug {
865    fn node_type(&self) -> TypeId;
866
867    fn element_type(&self) -> TypeId;
868
869    fn create_node(&self) -> Box<dyn ModifierNode>;
870
871    fn can_update_node(&self, node: &dyn ModifierNode) -> bool;
872
873    fn update_node(&self, node: &mut dyn ModifierNode);
874
875    fn key(&self) -> Option<u64>;
876
877    fn capabilities(&self) -> NodeCapabilities {
878        NodeCapabilities::default()
879    }
880
881    fn hash_code(&self) -> u64;
882
883    fn equals_element(&self, other: &dyn AnyModifierElement) -> bool;
884
885    fn inspector_name(&self) -> &'static str;
886
887    fn record_inspector_properties(&self, visitor: &mut dyn FnMut(&'static str, String));
888
889    fn requires_update(&self) -> bool;
890
891    fn auto_invalidates_on_update(&self) -> bool;
892
893    fn update_invalidation_kind(&self) -> Option<InvalidationKind>;
894
895    fn as_any(&self) -> &dyn Any;
896}
897
898struct TypedModifierElement<E: ModifierNodeElement> {
899    element: E,
900    cached_hash: u64,
901}
902
903impl<E: ModifierNodeElement> TypedModifierElement<E> {
904    fn new(element: E) -> Self {
905        let mut hasher = default::new();
906        element.hash(&mut hasher);
907        Self {
908            element,
909            cached_hash: hasher.finish(),
910        }
911    }
912}
913
914impl<E> fmt::Debug for TypedModifierElement<E>
915where
916    E: ModifierNodeElement,
917{
918    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
919        f.debug_struct("TypedModifierElement")
920            .field("type", &type_name::<E>())
921            .finish()
922    }
923}
924
925impl<E> AnyModifierElement for TypedModifierElement<E>
926where
927    E: ModifierNodeElement,
928{
929    fn node_type(&self) -> TypeId {
930        TypeId::of::<E::Node>()
931    }
932
933    fn element_type(&self) -> TypeId {
934        TypeId::of::<E>()
935    }
936
937    fn create_node(&self) -> Box<dyn ModifierNode> {
938        Box::new(self.element.create())
939    }
940
941    fn can_update_node(&self, node: &dyn ModifierNode) -> bool {
942        node.as_any().is::<E::Node>()
943    }
944
945    fn update_node(&self, node: &mut dyn ModifierNode) {
946        if let Some(typed) = node.as_any_mut().downcast_mut::<E::Node>() {
947            self.element.update(typed);
948        }
949    }
950
951    fn key(&self) -> Option<u64> {
952        self.element.key()
953    }
954
955    fn capabilities(&self) -> NodeCapabilities {
956        self.element.capabilities()
957    }
958
959    fn hash_code(&self) -> u64 {
960        self.cached_hash
961    }
962
963    fn equals_element(&self, other: &dyn AnyModifierElement) -> bool {
964        other
965            .as_any()
966            .downcast_ref::<Self>()
967            .map(|typed| typed.element == self.element)
968            .unwrap_or(false)
969    }
970
971    fn inspector_name(&self) -> &'static str {
972        self.element.inspector_name()
973    }
974
975    fn record_inspector_properties(&self, visitor: &mut dyn FnMut(&'static str, String)) {
976        self.element.inspector_properties(visitor);
977    }
978
979    fn requires_update(&self) -> bool {
980        self.element.always_update()
981    }
982
983    fn auto_invalidates_on_update(&self) -> bool {
984        self.element.auto_invalidate_on_update()
985    }
986
987    fn update_invalidation_kind(&self) -> Option<InvalidationKind> {
988        self.element.update_invalidation_kind()
989    }
990
991    fn as_any(&self) -> &dyn Any {
992        self
993    }
994}
995
996fn request_update_auto_invalidations(
997    element: &dyn AnyModifierElement,
998    context: &mut dyn ModifierNodeContext,
999    capabilities: NodeCapabilities,
1000) {
1001    if let Some(kind) = element.update_invalidation_kind() {
1002        let capabilities = NodeCapabilities::for_invalidation(kind);
1003        context.push_active_capabilities(capabilities);
1004        context.invalidate(kind);
1005        context.pop_active_capabilities();
1006    } else if element.auto_invalidates_on_update() {
1007        request_auto_invalidations(context, capabilities);
1008    }
1009}
1010
1011/// Convenience helper for callers to construct a type-erased modifier
1012/// element without having to mention the internal wrapper type.
1013pub fn modifier_element<E: ModifierNodeElement>(element: E) -> DynModifierElement {
1014    Rc::new(TypedModifierElement::new(element))
1015}
1016
1017/// Boxed type-erased modifier element.
1018pub type DynModifierElement = Rc<dyn AnyModifierElement>;
1019
1020#[derive(Clone, Copy, Debug, PartialEq, Eq)]
1021enum TraversalDirection {
1022    Forward,
1023    Backward,
1024}
1025
1026/// Iterator walking a modifier chain by indexing into `ordered_nodes`.
1027///
1028/// This avoids the per-step `RefCell::borrow()` + `NodeLink::clone()` cost
1029/// of following the linked-list through `NodeState::child`/`parent`.
1030pub struct ModifierChainIter<'a> {
1031    chain: &'a ModifierNodeChain,
1032    /// Current position in `ordered_nodes`. For forward iteration, starts at 0
1033    /// and increments; for backward, starts at len-1 and decrements.
1034    cursor: usize,
1035    /// Number of elements remaining (avoids underflow on backward iteration).
1036    remaining: usize,
1037    direction: TraversalDirection,
1038}
1039
1040impl<'a> ModifierChainIter<'a> {
1041    fn forward(chain: &'a ModifierNodeChain) -> Self {
1042        Self {
1043            chain,
1044            cursor: 0,
1045            remaining: chain.ordered_nodes.len(),
1046            direction: TraversalDirection::Forward,
1047        }
1048    }
1049
1050    fn backward(chain: &'a ModifierNodeChain) -> Self {
1051        let len = chain.ordered_nodes.len();
1052        Self {
1053            chain,
1054            cursor: len.wrapping_sub(1),
1055            remaining: len,
1056            direction: TraversalDirection::Backward,
1057        }
1058    }
1059}
1060
1061impl<'a> Iterator for ModifierChainIter<'a> {
1062    type Item = ModifierChainNodeRef<'a>;
1063
1064    #[inline]
1065    fn next(&mut self) -> Option<Self::Item> {
1066        if self.remaining == 0 {
1067            return None;
1068        }
1069        let (link, caps, agg) = self.chain.ordered_nodes[self.cursor];
1070        let node_ref = self.chain.make_node_ref_with_caps(link, caps, agg);
1071        self.remaining -= 1;
1072        match self.direction {
1073            TraversalDirection::Forward => self.cursor += 1,
1074            TraversalDirection::Backward => self.cursor = self.cursor.wrapping_sub(1),
1075        }
1076        Some(node_ref)
1077    }
1078
1079    #[inline]
1080    fn size_hint(&self) -> (usize, Option<usize>) {
1081        (self.remaining, Some(self.remaining))
1082    }
1083}
1084
1085impl<'a> ExactSizeIterator for ModifierChainIter<'a> {}
1086impl<'a> std::iter::FusedIterator for ModifierChainIter<'a> {}
1087
1088#[derive(Debug)]
1089struct ModifierNodeEntry {
1090    element_type: TypeId,
1091    node_type: TypeId,
1092    key: Option<u64>,
1093    hash_code: u64,
1094    element: DynModifierElement,
1095    node: Rc<RefCell<Box<dyn ModifierNode>>>,
1096    capabilities: NodeCapabilities,
1097}
1098
1099impl ModifierNodeEntry {
1100    fn new(
1101        element_type: TypeId,
1102        node_type: TypeId,
1103        key: Option<u64>,
1104        element: DynModifierElement,
1105        node: Box<dyn ModifierNode>,
1106        hash_code: u64,
1107        capabilities: NodeCapabilities,
1108    ) -> Self {
1109        // Wrap the boxed node in Rc<RefCell<>> for shared ownership
1110        let node_rc = Rc::new(RefCell::new(node));
1111        let entry = Self {
1112            element_type,
1113            node_type,
1114            key,
1115            hash_code,
1116            element,
1117            node: Rc::clone(&node_rc),
1118            capabilities,
1119        };
1120        entry
1121            .node
1122            .borrow()
1123            .node_state()
1124            .set_capabilities(entry.capabilities);
1125        entry
1126    }
1127}
1128
1129fn visit_node_tree_mut(
1130    node: &mut dyn ModifierNode,
1131    visitor: &mut dyn FnMut(&mut dyn ModifierNode),
1132) {
1133    visitor(node);
1134    node.for_each_delegate_mut(&mut |child| visit_node_tree_mut(child, visitor));
1135}
1136
1137fn nth_delegate(node: &dyn ModifierNode, target: usize) -> Option<&dyn ModifierNode> {
1138    let mut current = 0usize;
1139    let mut result: Option<&dyn ModifierNode> = None;
1140    node.for_each_delegate(&mut |child| {
1141        if result.is_none() && current == target {
1142            result = Some(child);
1143        }
1144        current += 1;
1145    });
1146    result
1147}
1148
1149fn nth_delegate_mut(node: &mut dyn ModifierNode, target: usize) -> Option<&mut dyn ModifierNode> {
1150    let mut current = 0usize;
1151    let mut result: Option<&mut dyn ModifierNode> = None;
1152    node.for_each_delegate_mut(&mut |child| {
1153        if result.is_none() && current == target {
1154            result = Some(child);
1155        }
1156        current += 1;
1157    });
1158    result
1159}
1160
1161fn with_node_context<F, R>(
1162    node: &mut dyn ModifierNode,
1163    context: &mut dyn ModifierNodeContext,
1164    f: F,
1165) -> R
1166where
1167    F: FnOnce(&mut dyn ModifierNode, &mut dyn ModifierNodeContext) -> R,
1168{
1169    context.push_active_capabilities(node.node_state().capabilities());
1170    let result = f(node, context);
1171    context.pop_active_capabilities();
1172    result
1173}
1174
1175fn request_auto_invalidations(
1176    context: &mut dyn ModifierNodeContext,
1177    capabilities: NodeCapabilities,
1178) {
1179    if capabilities.is_empty() {
1180        return;
1181    }
1182
1183    context.push_active_capabilities(capabilities);
1184
1185    if capabilities.contains(NodeCapabilities::LAYOUT) {
1186        context.invalidate(InvalidationKind::Layout);
1187    }
1188    if capabilities.contains(NodeCapabilities::DRAW) {
1189        context.invalidate(InvalidationKind::Draw);
1190    }
1191    if capabilities.contains(NodeCapabilities::POINTER_INPUT) {
1192        context.invalidate(InvalidationKind::PointerInput);
1193    }
1194    if capabilities.contains(NodeCapabilities::SEMANTICS) {
1195        context.invalidate(InvalidationKind::Semantics);
1196    }
1197    if capabilities.contains(NodeCapabilities::FOCUS) {
1198        context.invalidate(InvalidationKind::Focus);
1199    }
1200
1201    context.pop_active_capabilities();
1202}
1203
1204/// Attaches a node tree by calling on_attach for all unattached nodes.
1205///
1206/// # Safety
1207/// Callers must ensure no immutable RefCell borrows are held on the node
1208/// when calling this function. The on_attach callback may trigger mutations
1209/// (invalidations, state updates, etc.) that require mutable access, which
1210/// would panic if an immutable borrow is held across the call.
1211fn attach_node_tree(node: &mut dyn ModifierNode, context: &mut dyn ModifierNodeContext) {
1212    visit_node_tree_mut(node, &mut |n| {
1213        if !n.node_state().is_attached() {
1214            n.node_state().set_attached(true);
1215            with_node_context(n, context, |node, ctx| node.on_attach(ctx));
1216        }
1217    });
1218}
1219
1220fn reset_node_tree(node: &mut dyn ModifierNode) {
1221    visit_node_tree_mut(node, &mut |n| n.on_reset());
1222}
1223
1224fn detach_node_tree(node: &mut dyn ModifierNode) {
1225    visit_node_tree_mut(node, &mut |n| {
1226        if n.node_state().is_attached() {
1227            n.on_detach();
1228            n.node_state().set_attached(false);
1229        }
1230        n.node_state().set_parent_link(None);
1231        n.node_state().set_child_link(None);
1232        n.node_state()
1233            .set_aggregate_child_capabilities(NodeCapabilities::empty());
1234    });
1235}
1236
1237/// Chain of modifier nodes attached to a layout node.
1238///
1239/// The chain tracks ownership of modifier nodes and reuses them across
1240/// updates when the incoming element list still contains a node of the
1241/// same type. Removed nodes detach automatically so callers do not need
1242/// to manually manage their lifetimes.
1243pub struct ModifierNodeChain {
1244    entries: Vec<ModifierNodeEntry>,
1245    aggregated_capabilities: NodeCapabilities,
1246    head_aggregate_child_capabilities: NodeCapabilities,
1247    head_sentinel: Box<SentinelNode>,
1248    tail_sentinel: Box<SentinelNode>,
1249    /// (link, own_capabilities, aggregate_child_capabilities)
1250    ordered_nodes: Vec<(NodeLink, NodeCapabilities, NodeCapabilities)>,
1251    // Scratch buffers reused during update to avoid repeated allocations
1252    scratch_old_used: Vec<bool>,
1253    scratch_match_order: Vec<Option<usize>>,
1254    scratch_final_slots: Vec<Option<ModifierNodeEntry>>,
1255    scratch_elements: Vec<DynModifierElement>,
1256}
1257
1258struct SentinelNode {
1259    state: NodeState,
1260}
1261
1262impl SentinelNode {
1263    fn new() -> Self {
1264        Self {
1265            state: NodeState::sentinel(),
1266        }
1267    }
1268}
1269
1270impl DelegatableNode for SentinelNode {
1271    fn node_state(&self) -> &NodeState {
1272        &self.state
1273    }
1274}
1275
1276impl ModifierNode for SentinelNode {}
1277
1278#[derive(Clone)]
1279pub struct ModifierChainNodeRef<'a> {
1280    chain: &'a ModifierNodeChain,
1281    link: NodeLink,
1282    /// Capabilities cached from `ordered_nodes` build time — avoids RefCell borrow in kind_set().
1283    cached_capabilities: Option<NodeCapabilities>,
1284    /// Aggregate child capabilities cached from `ordered_nodes` — avoids RefCell borrow.
1285    cached_aggregate_child: Option<NodeCapabilities>,
1286}
1287
1288impl Default for ModifierNodeChain {
1289    fn default() -> Self {
1290        Self::new()
1291    }
1292}
1293
1294/// Index structure for O(1) modifier entry lookups during update.
1295///
1296/// This avoids O(n²) complexity by pre-building hash maps that allow constant-time
1297/// lookups for matching entries by key, hash, or type.
1298struct EntryIndex {
1299    /// Map (element type, node type, key) to keyed entries.
1300    keyed: HashMap<(TypeId, TypeId, u64), Vec<usize>>,
1301    /// Map (element type, node type, hash) to unkeyed entries with specific hash.
1302    hashed: HashMap<(TypeId, TypeId, u64), Vec<usize>>,
1303    /// Map (element type, node type) to unkeyed entries.
1304    typed: HashMap<(TypeId, TypeId), Vec<usize>>,
1305}
1306
1307struct EntryMatchQuery<'a> {
1308    element_type: TypeId,
1309    node_type: TypeId,
1310    key: Option<u64>,
1311    hash_code: u64,
1312    element: &'a DynModifierElement,
1313}
1314
1315impl EntryIndex {
1316    fn build(entries: &[ModifierNodeEntry]) -> Self {
1317        let mut keyed = HashMap::default();
1318        let mut hashed = HashMap::default();
1319        let mut typed = HashMap::default();
1320
1321        for (i, entry) in entries.iter().enumerate() {
1322            if let Some(key_value) = entry.key {
1323                // Keyed entry
1324                keyed
1325                    .entry((entry.element_type, entry.node_type, key_value))
1326                    .or_insert_with(Vec::new)
1327                    .push(i);
1328            } else {
1329                // Unkeyed entry - add to both hash and type indices
1330                hashed
1331                    .entry((entry.element_type, entry.node_type, entry.hash_code))
1332                    .or_insert_with(Vec::new)
1333                    .push(i);
1334                typed
1335                    .entry((entry.element_type, entry.node_type))
1336                    .or_insert_with(Vec::new)
1337                    .push(i);
1338            }
1339        }
1340
1341        Self {
1342            keyed,
1343            hashed,
1344            typed,
1345        }
1346    }
1347
1348    /// Find the best matching entry for reuse.
1349    ///
1350    /// Matching priority (from highest to lowest):
1351    /// 1. Keyed match: same element type, node type, and key.
1352    /// 2. Exact match: same retained identity, no key, same hash, and equal element.
1353    /// 3. Retained identity match without equality, which requires update.
1354    fn find_match(
1355        &self,
1356        entries: &[ModifierNodeEntry],
1357        used: &[bool],
1358        query: EntryMatchQuery<'_>,
1359    ) -> Option<usize> {
1360        if let Some(key_value) = query.key {
1361            // Priority 1: Keyed lookup - O(1)
1362            if let Some(candidates) =
1363                self.keyed
1364                    .get(&(query.element_type, query.node_type, key_value))
1365            {
1366                for &i in candidates {
1367                    if !used[i] {
1368                        return Some(i);
1369                    }
1370                }
1371            }
1372        } else {
1373            // Priority 2: Exact match (hash + equality) - O(1) lookup + O(k) equality checks
1374            if let Some(candidates) =
1375                self.hashed
1376                    .get(&(query.element_type, query.node_type, query.hash_code))
1377            {
1378                for &i in candidates {
1379                    if !used[i]
1380                        && entries[i]
1381                            .element
1382                            .as_ref()
1383                            .equals_element(query.element.as_ref())
1384                    {
1385                        return Some(i);
1386                    }
1387                }
1388            }
1389
1390            // Priority 3: Type match only - O(1) lookup + O(k) scan
1391            if let Some(candidates) = self.typed.get(&(query.element_type, query.node_type)) {
1392                for &i in candidates {
1393                    if !used[i] {
1394                        return Some(i);
1395                    }
1396                }
1397            }
1398        }
1399
1400        None
1401    }
1402}
1403
1404impl ModifierNodeChain {
1405    pub fn new() -> Self {
1406        let mut chain = Self {
1407            entries: Vec::new(),
1408            aggregated_capabilities: NodeCapabilities::empty(),
1409            head_aggregate_child_capabilities: NodeCapabilities::empty(),
1410            head_sentinel: Box::new(SentinelNode::new()),
1411            tail_sentinel: Box::new(SentinelNode::new()),
1412            ordered_nodes: Vec::new(),
1413            scratch_old_used: Vec::new(),
1414            scratch_match_order: Vec::new(),
1415            scratch_final_slots: Vec::new(),
1416            scratch_elements: Vec::new(),
1417        };
1418        chain.sync_chain_links();
1419        chain
1420    }
1421
1422    /// Detaches all nodes in the chain.
1423    pub fn detach_nodes(&mut self) {
1424        for entry in &self.entries {
1425            detach_node_tree(&mut **entry.node.borrow_mut());
1426        }
1427    }
1428
1429    /// Attaches all nodes in the chain.
1430    pub fn attach_nodes(&mut self, context: &mut dyn ModifierNodeContext) {
1431        for entry in &self.entries {
1432            attach_node_tree(&mut **entry.node.borrow_mut(), context);
1433        }
1434    }
1435
1436    /// Rebuilds the internal chain links (parent/child relationships).
1437    /// This should be called if nodes have been detached but are intended to be reused.
1438    pub fn repair_chain(&mut self) {
1439        self.sync_chain_links();
1440    }
1441
1442    /// Reconcile the chain against the provided elements, attaching newly
1443    /// created nodes and detaching nodes that are no longer required.
1444    ///
1445    /// This method delegates to `update_from_ref_iter` which handles the
1446    /// actual reconciliation logic.
1447    pub fn update_from_slice(
1448        &mut self,
1449        elements: &[DynModifierElement],
1450        context: &mut dyn ModifierNodeContext,
1451    ) {
1452        self.update_from_ref_iter(elements.iter(), context);
1453    }
1454
1455    /// Reconcile the chain against the provided iterator of element references.
1456    ///
1457    /// This is the preferred method as it avoids requiring a collected slice,
1458    /// enabling zero-allocation traversal of modifier trees.
1459    pub fn update_from_ref_iter<'a, I>(
1460        &mut self,
1461        elements: I,
1462        context: &mut dyn ModifierNodeContext,
1463    ) where
1464        I: Iterator<Item = &'a DynModifierElement>,
1465    {
1466        // Fast path: try to match elements sequentially without building index.
1467        // If all elements match in order (same type and key at same position),
1468        // we skip the expensive EntryIndex building. This is O(n) instead of O(n + m).
1469        let old_len = self.entries.len();
1470        let mut fast_path_failed_at: Option<usize> = None;
1471        let mut elements_count = 0;
1472
1473        // Collect elements we need to process in slow path
1474        self.scratch_elements.clear();
1475
1476        for (idx, element) in elements.enumerate() {
1477            elements_count = idx + 1;
1478
1479            if fast_path_failed_at.is_none() && idx < old_len {
1480                let entry = &mut self.entries[idx];
1481                let same_type = entry.element_type == element.element_type();
1482                let same_node_type = entry.node_type == element.node_type();
1483                let same_key = entry.key == element.key();
1484                let same_hash = entry.hash_code == element.hash_code();
1485
1486                // Fast path requires same type, key, AND hash to ensure we're not
1487                // breaking reordering semantics (where elements can move positions)
1488                let positional_update = element.requires_update();
1489                if same_type && same_node_type && same_key && (same_hash || positional_update) {
1490                    let can_update_node = {
1491                        let node_borrow = entry.node.borrow();
1492                        element.can_update_node(&**node_borrow)
1493                    };
1494                    if !can_update_node {
1495                        fast_path_failed_at = Some(idx);
1496                        self.scratch_elements.push(element.clone());
1497                        continue;
1498                    }
1499
1500                    // Fast path: element matches at same position
1501                    let same_element = entry.element.as_ref().equals_element(element.as_ref());
1502                    let capabilities = element.capabilities();
1503
1504                    // Re-attach node if it was detached during a previous update
1505                    {
1506                        let node_borrow = entry.node.borrow();
1507                        if !node_borrow.node_state().is_attached() {
1508                            drop(node_borrow);
1509                            attach_node_tree(&mut **entry.node.borrow_mut(), context);
1510                        }
1511                    }
1512
1513                    // Optimize updates: only call update_node if element changed
1514                    let needs_update = !same_element || element.requires_update();
1515                    if needs_update {
1516                        element.update_node(&mut **entry.node.borrow_mut());
1517                        entry.element = element.clone();
1518                        entry.hash_code = element.hash_code();
1519                        request_update_auto_invalidations(element.as_ref(), context, capabilities);
1520                    }
1521
1522                    // Always update metadata
1523                    entry.capabilities = capabilities;
1524                    entry
1525                        .node
1526                        .borrow()
1527                        .node_state()
1528                        .set_capabilities(capabilities);
1529                    continue;
1530                }
1531                // Fast path failed - mark position and fall through to collect
1532                fast_path_failed_at = Some(idx);
1533            }
1534
1535            // Collect element for slow path processing
1536            self.scratch_elements.push(element.clone());
1537        }
1538
1539        // Fast path succeeded if:
1540        // 1. No mismatch was found (fast_path_failed_at is None)
1541        // 2. All elements were processed via fast path (scratch_elements is empty)
1542        // Note: If old_len=0 and we have new elements, scratch_elements won't be empty
1543        if fast_path_failed_at.is_none() && self.scratch_elements.is_empty() {
1544            // Detach any removed entries (elements_count <= old_len guaranteed here)
1545            if elements_count < self.entries.len() {
1546                for entry in self.entries.drain(elements_count..) {
1547                    request_auto_invalidations(context, entry.capabilities);
1548                    detach_node_tree(&mut **entry.node.borrow_mut());
1549                }
1550            }
1551            self.sync_chain_links();
1552            return;
1553        }
1554
1555        // Slow path: need full reconciliation starting from failure point
1556        // If no mismatch but we have extra elements, fail_idx is the old length
1557        let fail_idx = fast_path_failed_at.unwrap_or(old_len);
1558
1559        // Move entries that were already processed to a safe place
1560        let mut old_entries: Vec<ModifierNodeEntry> = self.entries.drain(fail_idx..).collect();
1561        let processed_entries_len = self.entries.len();
1562        let old_len = old_entries.len();
1563
1564        // Reuse scratch buffers for the remaining entries only
1565        self.scratch_old_used.clear();
1566        self.scratch_old_used.resize(old_len, false);
1567
1568        self.scratch_match_order.clear();
1569        self.scratch_match_order.resize(old_len, None);
1570
1571        // Build index only for unprocessed entries
1572        let index = EntryIndex::build(&old_entries);
1573
1574        let new_elements_count = self.scratch_elements.len();
1575        self.scratch_final_slots.clear();
1576        self.scratch_final_slots.reserve(new_elements_count);
1577
1578        // Process each remaining element
1579        for (new_pos, element) in self.scratch_elements.drain(..).enumerate() {
1580            self.scratch_final_slots.push(None);
1581            let element_type = element.element_type();
1582            let node_type = element.node_type();
1583            let key = element.key();
1584            let hash_code = element.hash_code();
1585            let capabilities = element.capabilities();
1586
1587            // Find best matching old entry via index
1588            let matched_idx = index.find_match(
1589                &old_entries,
1590                &self.scratch_old_used,
1591                EntryMatchQuery {
1592                    element_type,
1593                    node_type,
1594                    key,
1595                    hash_code,
1596                    element: &element,
1597                },
1598            );
1599
1600            if let Some(idx) = matched_idx {
1601                // Reuse existing entry
1602                let entry = &mut old_entries[idx];
1603                let can_update_node = {
1604                    let node_borrow = entry.node.borrow();
1605                    element.can_update_node(&**node_borrow)
1606                };
1607                if !can_update_node {
1608                    let replacement = ModifierNodeEntry::new(
1609                        element_type,
1610                        node_type,
1611                        key,
1612                        element.clone(),
1613                        element.create_node(),
1614                        hash_code,
1615                        capabilities,
1616                    );
1617                    attach_node_tree(&mut **replacement.node.borrow_mut(), context);
1618                    element.update_node(&mut **replacement.node.borrow_mut());
1619                    request_auto_invalidations(context, capabilities);
1620                    self.scratch_final_slots[new_pos] = Some(replacement);
1621                    continue;
1622                }
1623
1624                self.scratch_old_used[idx] = true;
1625                self.scratch_match_order[idx] = Some(new_pos);
1626                let moved = idx != new_pos;
1627
1628                // Check if element actually changed
1629                let same_element = entry.element.as_ref().equals_element(element.as_ref());
1630
1631                // Re-attach node if it was detached
1632                {
1633                    let node_borrow = entry.node.borrow();
1634                    if !node_borrow.node_state().is_attached() {
1635                        drop(node_borrow);
1636                        attach_node_tree(&mut **entry.node.borrow_mut(), context);
1637                    }
1638                }
1639
1640                // Optimize updates: only call update_node if element changed
1641                let needs_update = !same_element || element.requires_update();
1642                if needs_update {
1643                    element.update_node(&mut **entry.node.borrow_mut());
1644                    entry.element = element;
1645                    entry.hash_code = hash_code;
1646                    request_update_auto_invalidations(
1647                        entry.element.as_ref(),
1648                        context,
1649                        capabilities,
1650                    );
1651                }
1652                if moved {
1653                    request_auto_invalidations(context, capabilities);
1654                }
1655
1656                // Always update metadata
1657                entry.key = key;
1658                entry.element_type = element_type;
1659                entry.node_type = node_type;
1660                entry.capabilities = capabilities;
1661                entry
1662                    .node
1663                    .borrow()
1664                    .node_state()
1665                    .set_capabilities(capabilities);
1666            } else {
1667                // Create new entry
1668                let entry = ModifierNodeEntry::new(
1669                    element_type,
1670                    node_type,
1671                    key,
1672                    element.clone(),
1673                    element.create_node(),
1674                    hash_code,
1675                    capabilities,
1676                );
1677                attach_node_tree(&mut **entry.node.borrow_mut(), context);
1678                element.update_node(&mut **entry.node.borrow_mut());
1679                request_auto_invalidations(context, capabilities);
1680                self.scratch_final_slots[new_pos] = Some(entry);
1681            }
1682        }
1683
1684        // Place matched entries in their new positions
1685        for (i, entry) in old_entries.into_iter().enumerate() {
1686            if self.scratch_old_used[i] {
1687                if let Some(pos) = self.scratch_match_order[i] {
1688                    self.scratch_final_slots[pos] = Some(entry);
1689                } else {
1690                    request_auto_invalidations(context, entry.capabilities);
1691                    detach_node_tree(&mut **entry.node.borrow_mut());
1692                }
1693            } else {
1694                request_auto_invalidations(context, entry.capabilities);
1695                detach_node_tree(&mut **entry.node.borrow_mut());
1696            }
1697        }
1698
1699        // Append processed entries to self.entries
1700        self.entries.reserve(self.scratch_final_slots.len());
1701        for slot in self.scratch_final_slots.drain(..) {
1702            if let Some(entry) = slot {
1703                self.entries.push(entry);
1704            } else {
1705                log::error!("modifier reconciliation produced an empty final slot");
1706            }
1707        }
1708
1709        debug_assert_eq!(
1710            self.entries.len(),
1711            processed_entries_len + new_elements_count
1712        );
1713        self.sync_chain_links();
1714    }
1715
1716    /// Convenience wrapper that accepts any iterator of type-erased
1717    /// modifier elements. Elements are collected into a temporary vector
1718    /// before reconciliation.
1719    pub fn update<I>(&mut self, elements: I, context: &mut dyn ModifierNodeContext)
1720    where
1721        I: IntoIterator<Item = DynModifierElement>,
1722    {
1723        let collected: Vec<DynModifierElement> = elements.into_iter().collect();
1724        self.update_from_slice(&collected, context);
1725    }
1726
1727    /// Resets all nodes in the chain. This mirrors the behaviour of
1728    /// Jetpack Compose's `onReset` callback.
1729    pub fn reset(&mut self) {
1730        for entry in &mut self.entries {
1731            reset_node_tree(&mut **entry.node.borrow_mut());
1732        }
1733    }
1734
1735    /// Detaches every node in the chain and clears internal storage.
1736    pub fn detach_all(&mut self) {
1737        for entry in std::mem::take(&mut self.entries) {
1738            detach_node_tree(&mut **entry.node.borrow_mut());
1739            {
1740                let node_borrow = entry.node.borrow();
1741                let state = node_borrow.node_state();
1742                state.set_capabilities(NodeCapabilities::empty());
1743            }
1744        }
1745        self.aggregated_capabilities = NodeCapabilities::empty();
1746        self.head_aggregate_child_capabilities = NodeCapabilities::empty();
1747        self.ordered_nodes.clear();
1748        self.sync_chain_links();
1749    }
1750
1751    pub fn len(&self) -> usize {
1752        self.entries.len()
1753    }
1754
1755    pub fn is_empty(&self) -> bool {
1756        self.entries.is_empty()
1757    }
1758
1759    /// Returns the aggregated capability mask for the entire chain.
1760    pub fn capabilities(&self) -> NodeCapabilities {
1761        self.aggregated_capabilities
1762    }
1763
1764    /// Returns true if the chain contains at least one node with the requested capability.
1765    pub fn has_capability(&self, capability: NodeCapabilities) -> bool {
1766        self.aggregated_capabilities.contains(capability)
1767    }
1768
1769    /// Returns the sentinel head reference for traversal.
1770    pub fn head(&self) -> ModifierChainNodeRef<'_> {
1771        self.make_node_ref(NodeLink::Head)
1772    }
1773
1774    /// Returns the sentinel tail reference for traversal.
1775    pub fn tail(&self) -> ModifierChainNodeRef<'_> {
1776        self.make_node_ref(NodeLink::Tail)
1777    }
1778
1779    /// Iterates over the chain from head to tail, skipping sentinels.
1780    pub fn head_to_tail(&self) -> ModifierChainIter<'_> {
1781        ModifierChainIter::forward(self)
1782    }
1783
1784    /// Iterates over the chain from tail to head, skipping sentinels.
1785    pub fn tail_to_head(&self) -> ModifierChainIter<'_> {
1786        ModifierChainIter::backward(self)
1787    }
1788
1789    /// Calls `f` for every node in insertion order.
1790    pub fn for_each_forward<F>(&self, mut f: F)
1791    where
1792        F: FnMut(ModifierChainNodeRef<'_>),
1793    {
1794        for node in self.head_to_tail() {
1795            f(node);
1796        }
1797    }
1798
1799    /// Calls `f` for every node containing any capability from `mask`.
1800    pub fn for_each_forward_matching<F>(&self, mask: NodeCapabilities, mut f: F)
1801    where
1802        F: FnMut(ModifierChainNodeRef<'_>),
1803    {
1804        if mask.is_empty() {
1805            self.for_each_forward(f);
1806            return;
1807        }
1808
1809        if !self.head().aggregate_child_capabilities().intersects(mask) {
1810            return;
1811        }
1812
1813        for node in self.head_to_tail() {
1814            if node.kind_set().intersects(mask) {
1815                f(node);
1816            }
1817        }
1818    }
1819
1820    /// Calls `f` for every node containing any capability from `mask`, providing the node ref.
1821    pub fn for_each_node_with_capability<F>(&self, mask: NodeCapabilities, mut f: F)
1822    where
1823        F: FnMut(ModifierChainNodeRef<'_>, &dyn ModifierNode),
1824    {
1825        self.for_each_forward_matching(mask, |node_ref| {
1826            node_ref.with_node(|node| f(node_ref.clone(), node));
1827        });
1828    }
1829
1830    /// Calls `f` for every node in reverse insertion order.
1831    pub fn for_each_backward<F>(&self, mut f: F)
1832    where
1833        F: FnMut(ModifierChainNodeRef<'_>),
1834    {
1835        for node in self.tail_to_head() {
1836            f(node);
1837        }
1838    }
1839
1840    /// Calls `f` for every node in reverse order that matches `mask`.
1841    pub fn for_each_backward_matching<F>(&self, mask: NodeCapabilities, mut f: F)
1842    where
1843        F: FnMut(ModifierChainNodeRef<'_>),
1844    {
1845        if mask.is_empty() {
1846            self.for_each_backward(f);
1847            return;
1848        }
1849
1850        if !self.head().aggregate_child_capabilities().intersects(mask) {
1851            return;
1852        }
1853
1854        for node in self.tail_to_head() {
1855            if node.kind_set().intersects(mask) {
1856                f(node);
1857            }
1858        }
1859    }
1860
1861    /// Returns a node reference for the entry at `index`.
1862    pub fn node_ref_at(&self, index: usize) -> Option<ModifierChainNodeRef<'_>> {
1863        if index >= self.entries.len() {
1864            None
1865        } else {
1866            Some(self.make_node_ref(NodeLink::Entry(NodePath::root(index))))
1867        }
1868    }
1869
1870    /// Returns the node reference that owns `node`.
1871    pub fn find_node_ref(&self, node: &dyn ModifierNode) -> Option<ModifierChainNodeRef<'_>> {
1872        fn node_data_ptr(node: &dyn ModifierNode) -> *const () {
1873            node as *const dyn ModifierNode as *const ()
1874        }
1875
1876        let target = node_data_ptr(node);
1877        for (index, entry) in self.entries.iter().enumerate() {
1878            if node_data_ptr(&**entry.node.borrow()) == target {
1879                return Some(self.make_node_ref(NodeLink::Entry(NodePath::root(index))));
1880            }
1881        }
1882
1883        self.ordered_nodes.iter().find_map(|(link, _caps, _agg)| {
1884            if matches!(link, NodeLink::Entry(path) if path.delegates().is_empty()) {
1885                return None;
1886            }
1887            let matches_target = match link {
1888                NodeLink::Head => node_data_ptr(self.head_sentinel.as_ref()) == target,
1889                NodeLink::Tail => node_data_ptr(self.tail_sentinel.as_ref()) == target,
1890                NodeLink::Entry(path) => {
1891                    let node_borrow = self.entries[path.entry()].node.borrow();
1892                    node_data_ptr(&**node_borrow) == target
1893                }
1894            };
1895            if matches_target {
1896                Some(self.make_node_ref(*link))
1897            } else {
1898                None
1899            }
1900        })
1901    }
1902
1903    /// Downcasts the node at `index` to the requested type.
1904    /// Returns a `Ref` guard that dereferences to the node type.
1905    pub fn node<N: ModifierNode + 'static>(&self, index: usize) -> Option<std::cell::Ref<'_, N>> {
1906        self.entries.get(index).and_then(|entry| {
1907            std::cell::Ref::filter_map(entry.node.borrow(), |boxed_node| {
1908                boxed_node.as_any().downcast_ref::<N>()
1909            })
1910            .ok()
1911        })
1912    }
1913
1914    /// Downcasts the node at `index` to the requested mutable type.
1915    /// Returns a `RefMut` guard that dereferences to the node type.
1916    pub fn node_mut<N: ModifierNode + 'static>(
1917        &self,
1918        index: usize,
1919    ) -> Option<std::cell::RefMut<'_, N>> {
1920        self.entries.get(index).and_then(|entry| {
1921            std::cell::RefMut::filter_map(entry.node.borrow_mut(), |boxed_node| {
1922                boxed_node.as_any_mut().downcast_mut::<N>()
1923            })
1924            .ok()
1925        })
1926    }
1927
1928    /// Returns an Rc clone of the node at the given index for shared ownership.
1929    /// This is used by coordinators to hold direct references to nodes.
1930    pub fn get_node_rc(&self, index: usize) -> Option<Rc<RefCell<Box<dyn ModifierNode>>>> {
1931        self.entries.get(index).map(|entry| Rc::clone(&entry.node))
1932    }
1933
1934    /// Returns true if the chain contains any nodes matching the given invalidation kind.
1935    pub fn has_nodes_for_invalidation(&self, kind: InvalidationKind) -> bool {
1936        self.aggregated_capabilities
1937            .contains(NodeCapabilities::for_invalidation(kind))
1938    }
1939
1940    /// Visits every node in insertion order together with its capability mask.
1941    pub fn visit_nodes<F>(&self, mut f: F)
1942    where
1943        F: FnMut(&dyn ModifierNode, NodeCapabilities),
1944    {
1945        for (link, cached_caps, _agg) in &self.ordered_nodes {
1946            match link {
1947                NodeLink::Head => {
1948                    f(self.head_sentinel.as_ref(), *cached_caps);
1949                }
1950                NodeLink::Tail => {
1951                    f(self.tail_sentinel.as_ref(), *cached_caps);
1952                }
1953                NodeLink::Entry(path) => {
1954                    let node_borrow = self.entries[path.entry()].node.borrow();
1955                    if path.delegates().is_empty() {
1956                        f(&**node_borrow, *cached_caps);
1957                    } else {
1958                        let mut current: &dyn ModifierNode = &**node_borrow;
1959                        for &delegate_index in path.delegates() {
1960                            if let Some(delegate) = nth_delegate(current, delegate_index as usize) {
1961                                current = delegate;
1962                            } else {
1963                                return; // Invalid delegate path
1964                            }
1965                        }
1966                        f(current, *cached_caps);
1967                    }
1968                }
1969            }
1970        }
1971    }
1972
1973    /// Visits every node mutably in insertion order together with its capability mask.
1974    pub fn visit_nodes_mut<F>(&mut self, mut f: F)
1975    where
1976        F: FnMut(&mut dyn ModifierNode, NodeCapabilities),
1977    {
1978        for index in 0..self.ordered_nodes.len() {
1979            let (link, cached_caps, _agg) = self.ordered_nodes[index];
1980            match link {
1981                NodeLink::Head => {
1982                    f(self.head_sentinel.as_mut(), cached_caps);
1983                }
1984                NodeLink::Tail => {
1985                    f(self.tail_sentinel.as_mut(), cached_caps);
1986                }
1987                NodeLink::Entry(path) => {
1988                    let mut node_borrow = self.entries[path.entry()].node.borrow_mut();
1989                    if path.delegates().is_empty() {
1990                        f(&mut **node_borrow, cached_caps);
1991                    } else {
1992                        let mut current: &mut dyn ModifierNode = &mut **node_borrow;
1993                        for &delegate_index in path.delegates() {
1994                            if let Some(delegate) =
1995                                nth_delegate_mut(current, delegate_index as usize)
1996                            {
1997                                current = delegate;
1998                            } else {
1999                                return; // Invalid delegate path
2000                            }
2001                        }
2002                        f(current, cached_caps);
2003                    }
2004                }
2005            }
2006        }
2007    }
2008
2009    fn make_node_ref(&self, link: NodeLink) -> ModifierChainNodeRef<'_> {
2010        ModifierChainNodeRef {
2011            chain: self,
2012            link,
2013            cached_capabilities: None,
2014            cached_aggregate_child: None,
2015        }
2016    }
2017
2018    fn make_node_ref_with_caps(
2019        &self,
2020        link: NodeLink,
2021        caps: NodeCapabilities,
2022        aggregate_child: NodeCapabilities,
2023    ) -> ModifierChainNodeRef<'_> {
2024        ModifierChainNodeRef {
2025            chain: self,
2026            link,
2027            cached_capabilities: Some(caps),
2028            cached_aggregate_child: Some(aggregate_child),
2029        }
2030    }
2031
2032    fn sync_chain_links(&mut self) {
2033        self.rebuild_ordered_nodes();
2034
2035        self.head_sentinel.node_state().set_parent_link(None);
2036        self.tail_sentinel.node_state().set_child_link(None);
2037
2038        if self.ordered_nodes.is_empty() {
2039            self.head_sentinel
2040                .node_state()
2041                .set_child_link(Some(NodeLink::Tail));
2042            self.tail_sentinel
2043                .node_state()
2044                .set_parent_link(Some(NodeLink::Head));
2045            self.aggregated_capabilities = NodeCapabilities::empty();
2046            self.head_aggregate_child_capabilities = NodeCapabilities::empty();
2047            self.head_sentinel
2048                .node_state()
2049                .set_aggregate_child_capabilities(NodeCapabilities::empty());
2050            self.tail_sentinel
2051                .node_state()
2052                .set_aggregate_child_capabilities(NodeCapabilities::empty());
2053            return;
2054        }
2055
2056        let mut previous = NodeLink::Head;
2057        for (link, _caps, _agg) in self.ordered_nodes.iter().copied() {
2058            // Set child link on previous
2059            match &previous {
2060                NodeLink::Head => self.head_sentinel.node_state().set_child_link(Some(link)),
2061                NodeLink::Tail => self.tail_sentinel.node_state().set_child_link(Some(link)),
2062                NodeLink::Entry(path) => {
2063                    let node_borrow = self.entries[path.entry()].node.borrow();
2064                    // Navigate to delegate if needed
2065                    if path.delegates().is_empty() {
2066                        node_borrow.node_state().set_child_link(Some(link));
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(link));
2075                    }
2076                }
2077            }
2078            // Set parent link on current
2079            match &link {
2080                NodeLink::Head => self
2081                    .head_sentinel
2082                    .node_state()
2083                    .set_parent_link(Some(previous)),
2084                NodeLink::Tail => self
2085                    .tail_sentinel
2086                    .node_state()
2087                    .set_parent_link(Some(previous)),
2088                NodeLink::Entry(path) => {
2089                    let node_borrow = self.entries[path.entry()].node.borrow();
2090                    // Navigate to delegate if needed
2091                    if path.delegates().is_empty() {
2092                        node_borrow.node_state().set_parent_link(Some(previous));
2093                    } else {
2094                        let mut current: &dyn ModifierNode = &**node_borrow;
2095                        for &delegate_index in path.delegates() {
2096                            if let Some(delegate) = nth_delegate(current, delegate_index as usize) {
2097                                current = delegate;
2098                            }
2099                        }
2100                        current.node_state().set_parent_link(Some(previous));
2101                    }
2102                }
2103            }
2104            previous = link;
2105        }
2106
2107        // Set child link on last node to Tail
2108        match &previous {
2109            NodeLink::Head => self
2110                .head_sentinel
2111                .node_state()
2112                .set_child_link(Some(NodeLink::Tail)),
2113            NodeLink::Tail => self
2114                .tail_sentinel
2115                .node_state()
2116                .set_child_link(Some(NodeLink::Tail)),
2117            NodeLink::Entry(path) => {
2118                let node_borrow = self.entries[path.entry()].node.borrow();
2119                // Navigate to delegate if needed
2120                if path.delegates().is_empty() {
2121                    node_borrow
2122                        .node_state()
2123                        .set_child_link(Some(NodeLink::Tail));
2124                } else {
2125                    let mut current: &dyn ModifierNode = &**node_borrow;
2126                    for &delegate_index in path.delegates() {
2127                        if let Some(delegate) = nth_delegate(current, delegate_index as usize) {
2128                            current = delegate;
2129                        }
2130                    }
2131                    current.node_state().set_child_link(Some(NodeLink::Tail));
2132                }
2133            }
2134        }
2135        self.tail_sentinel
2136            .node_state()
2137            .set_parent_link(Some(previous));
2138        self.tail_sentinel.node_state().set_child_link(None);
2139
2140        let mut aggregate = NodeCapabilities::empty();
2141        for (link, cached_caps, cached_aggregate) in self.ordered_nodes.iter_mut().rev() {
2142            aggregate |= *cached_caps;
2143            *cached_aggregate = aggregate;
2144            // Also update NodeState for code that reads through DelegatableNode
2145            match link {
2146                NodeLink::Head => {
2147                    self.head_sentinel
2148                        .node_state()
2149                        .set_aggregate_child_capabilities(aggregate);
2150                }
2151                NodeLink::Tail => {
2152                    self.tail_sentinel
2153                        .node_state()
2154                        .set_aggregate_child_capabilities(aggregate);
2155                }
2156                NodeLink::Entry(path) => {
2157                    let node_borrow = self.entries[path.entry()].node.borrow();
2158                    let state = if path.delegates().is_empty() {
2159                        node_borrow.node_state()
2160                    } else {
2161                        let mut current: &dyn ModifierNode = &**node_borrow;
2162                        for &delegate_index in path.delegates() {
2163                            if let Some(delegate) = nth_delegate(current, delegate_index as usize) {
2164                                current = delegate;
2165                            }
2166                        }
2167                        current.node_state()
2168                    };
2169                    state.set_aggregate_child_capabilities(aggregate);
2170                }
2171            }
2172        }
2173
2174        self.aggregated_capabilities = aggregate;
2175        self.head_aggregate_child_capabilities = aggregate;
2176        self.head_sentinel
2177            .node_state()
2178            .set_aggregate_child_capabilities(aggregate);
2179        self.tail_sentinel
2180            .node_state()
2181            .set_aggregate_child_capabilities(NodeCapabilities::empty());
2182    }
2183
2184    fn rebuild_ordered_nodes(&mut self) {
2185        self.ordered_nodes.clear();
2186        let mut path_buf = [0usize; MAX_DELEGATE_DEPTH];
2187        for (index, entry) in self.entries.iter().enumerate() {
2188            let node_borrow = entry.node.borrow();
2189            Self::enumerate_link_order(
2190                &**node_borrow,
2191                index,
2192                &mut path_buf,
2193                0,
2194                &mut self.ordered_nodes,
2195            );
2196        }
2197    }
2198
2199    fn enumerate_link_order(
2200        node: &dyn ModifierNode,
2201        entry: usize,
2202        path_buf: &mut [usize; MAX_DELEGATE_DEPTH],
2203        path_len: usize,
2204        out: &mut Vec<(NodeLink, NodeCapabilities, NodeCapabilities)>,
2205    ) {
2206        let caps = node.node_state().capabilities();
2207        out.push((
2208            NodeLink::Entry(NodePath::from_slice(entry, &path_buf[..path_len])),
2209            caps,
2210            NodeCapabilities::empty(),
2211        ));
2212        let mut delegate_index = 0usize;
2213        node.for_each_delegate(&mut |child| {
2214            if path_len < MAX_DELEGATE_DEPTH {
2215                path_buf[path_len] = delegate_index;
2216                Self::enumerate_link_order(child, entry, path_buf, path_len + 1, out);
2217            }
2218            delegate_index += 1;
2219        });
2220    }
2221}
2222
2223impl<'a> ModifierChainNodeRef<'a> {
2224    /// Helper to get NodeState, properly handling RefCell for entries.
2225    /// Returns NodeState values by calling a closure with the state.
2226    fn with_state<R>(&self, f: impl FnOnce(&NodeState) -> R) -> R {
2227        match &self.link {
2228            NodeLink::Head => f(self.chain.head_sentinel.node_state()),
2229            NodeLink::Tail => f(self.chain.tail_sentinel.node_state()),
2230            NodeLink::Entry(path) => {
2231                let node_borrow = self.chain.entries[path.entry()].node.borrow();
2232                // Navigate through delegates if path has them
2233                if path.delegates().is_empty() {
2234                    f(node_borrow.node_state())
2235                } else {
2236                    // Navigate to the delegate node
2237                    let mut current: &dyn ModifierNode = &**node_borrow;
2238                    for &delegate_index in path.delegates() {
2239                        if let Some(delegate) = nth_delegate(current, delegate_index as usize) {
2240                            current = delegate;
2241                        } else {
2242                            // Fallback to root node state if delegate path is invalid
2243                            return f(node_borrow.node_state());
2244                        }
2245                    }
2246                    f(current.node_state())
2247                }
2248            }
2249        }
2250    }
2251
2252    /// Provides access to the node via a closure, properly handling RefCell borrows.
2253    /// Returns None for sentinel nodes.
2254    pub fn with_node<R>(&self, f: impl FnOnce(&dyn ModifierNode) -> R) -> Option<R> {
2255        match &self.link {
2256            NodeLink::Head => None, // Head sentinel
2257            NodeLink::Tail => None, // Tail sentinel
2258            NodeLink::Entry(path) => {
2259                let node_borrow = self.chain.entries[path.entry()].node.borrow();
2260                // Navigate through delegates if path has them
2261                if path.delegates().is_empty() {
2262                    Some(f(&**node_borrow))
2263                } else {
2264                    // Navigate to the delegate node
2265                    let mut current: &dyn ModifierNode = &**node_borrow;
2266                    for &delegate_index in path.delegates() {
2267                        // `?`: bail out with None if the delegate path is invalid.
2268                        current = nth_delegate(current, delegate_index as usize)?;
2269                    }
2270                    Some(f(current))
2271                }
2272            }
2273        }
2274    }
2275
2276    /// Returns the parent reference, including sentinel head when applicable.
2277    #[inline]
2278    pub fn parent(&self) -> Option<Self> {
2279        self.with_state(|state| state.parent_link())
2280            .map(|link| self.chain.make_node_ref(link))
2281    }
2282
2283    /// Returns the child reference, including sentinel tail for the last entry.
2284    #[inline]
2285    pub fn child(&self) -> Option<Self> {
2286        self.with_state(|state| state.child_link())
2287            .map(|link| self.chain.make_node_ref(link))
2288    }
2289
2290    /// Returns the capability mask for this specific node.
2291    #[inline]
2292    pub fn kind_set(&self) -> NodeCapabilities {
2293        if let Some(caps) = self.cached_capabilities {
2294            return caps;
2295        }
2296        match &self.link {
2297            NodeLink::Head | NodeLink::Tail => NodeCapabilities::empty(),
2298            NodeLink::Entry(_) => self.with_state(|state| state.capabilities()),
2299        }
2300    }
2301
2302    /// Returns the entry index backing this node when it is part of the chain.
2303    pub fn entry_index(&self) -> Option<usize> {
2304        match &self.link {
2305            NodeLink::Entry(path) => Some(path.entry()),
2306            _ => None,
2307        }
2308    }
2309
2310    /// Returns how many delegate hops separate this node from its root element.
2311    pub fn delegate_depth(&self) -> usize {
2312        match &self.link {
2313            NodeLink::Entry(path) => path.delegates().len(),
2314            _ => 0,
2315        }
2316    }
2317
2318    /// Returns the aggregated capability mask for the subtree rooted at this node.
2319    #[inline]
2320    pub fn aggregate_child_capabilities(&self) -> NodeCapabilities {
2321        if let Some(agg) = self.cached_aggregate_child {
2322            return agg;
2323        }
2324        if self.is_tail() {
2325            NodeCapabilities::empty()
2326        } else {
2327            self.with_state(|state| state.aggregate_child_capabilities())
2328        }
2329    }
2330
2331    /// Returns true if this reference targets the sentinel head.
2332    pub fn is_head(&self) -> bool {
2333        matches!(self.link, NodeLink::Head)
2334    }
2335
2336    /// Returns true if this reference targets the sentinel tail.
2337    pub fn is_tail(&self) -> bool {
2338        matches!(self.link, NodeLink::Tail)
2339    }
2340
2341    /// Returns true if this reference targets either sentinel.
2342    pub fn is_sentinel(&self) -> bool {
2343        matches!(self.link, NodeLink::Head | NodeLink::Tail)
2344    }
2345
2346    /// Returns true if this node has any capability bits present in `mask`.
2347    pub fn has_capability(&self, mask: NodeCapabilities) -> bool {
2348        !mask.is_empty() && self.kind_set().intersects(mask)
2349    }
2350
2351    /// Visits descendant nodes, optionally including `self`, in insertion order.
2352    pub fn visit_descendants<F>(self, include_self: bool, mut f: F)
2353    where
2354        F: FnMut(ModifierChainNodeRef<'a>),
2355    {
2356        let mut current = if include_self {
2357            Some(self)
2358        } else {
2359            self.child()
2360        };
2361        while let Some(node) = current {
2362            if node.is_tail() {
2363                break;
2364            }
2365            if !node.is_sentinel() {
2366                f(node.clone());
2367            }
2368            current = node.child();
2369        }
2370    }
2371
2372    /// Visits descendant nodes that match `mask`, short-circuiting when possible.
2373    pub fn visit_descendants_matching<F>(self, include_self: bool, mask: NodeCapabilities, mut f: F)
2374    where
2375        F: FnMut(ModifierChainNodeRef<'a>),
2376    {
2377        if mask.is_empty() {
2378            self.visit_descendants(include_self, f);
2379            return;
2380        }
2381
2382        if !self.aggregate_child_capabilities().intersects(mask) {
2383            return;
2384        }
2385
2386        self.visit_descendants(include_self, |node| {
2387            if node.kind_set().intersects(mask) {
2388                f(node);
2389            }
2390        });
2391    }
2392
2393    /// Visits ancestor nodes up to (but excluding) the sentinel head.
2394    pub fn visit_ancestors<F>(self, include_self: bool, mut f: F)
2395    where
2396        F: FnMut(ModifierChainNodeRef<'a>),
2397    {
2398        let mut current = if include_self {
2399            Some(self)
2400        } else {
2401            self.parent()
2402        };
2403        while let Some(node) = current {
2404            if node.is_head() {
2405                break;
2406            }
2407            f(node.clone());
2408            current = node.parent();
2409        }
2410    }
2411
2412    /// Visits ancestor nodes that match `mask`.
2413    pub fn visit_ancestors_matching<F>(self, include_self: bool, mask: NodeCapabilities, mut f: F)
2414    where
2415        F: FnMut(ModifierChainNodeRef<'a>),
2416    {
2417        if mask.is_empty() {
2418            self.visit_ancestors(include_self, f);
2419            return;
2420        }
2421
2422        self.visit_ancestors(include_self, |node| {
2423            if node.kind_set().intersects(mask) {
2424                f(node);
2425            }
2426        });
2427    }
2428
2429    /// Finds the nearest ancestor focus target node.
2430    ///
2431    /// This is useful for focus navigation to find the parent focusable
2432    /// component in the tree.
2433    pub fn find_parent_focus_target(&self) -> Option<ModifierChainNodeRef<'a>> {
2434        let mut result = None;
2435        self.clone()
2436            .visit_ancestors_matching(false, NodeCapabilities::FOCUS, |node| {
2437                if result.is_none() {
2438                    result = Some(node);
2439                }
2440            });
2441        result
2442    }
2443
2444    /// Finds the first descendant focus target node.
2445    ///
2446    /// This is useful for focus navigation to find the first focusable
2447    /// child component in the tree.
2448    pub fn find_first_focus_target(&self) -> Option<ModifierChainNodeRef<'a>> {
2449        let mut result = None;
2450        self.clone()
2451            .visit_descendants_matching(false, NodeCapabilities::FOCUS, |node| {
2452                if result.is_none() {
2453                    result = Some(node);
2454                }
2455            });
2456        result
2457    }
2458
2459    /// Returns true if this node or any ancestor has focus capability.
2460    pub fn has_focus_capability_in_ancestors(&self) -> bool {
2461        let mut found = false;
2462        self.clone()
2463            .visit_ancestors_matching(true, NodeCapabilities::FOCUS, |_| {
2464                found = true;
2465            });
2466        found
2467    }
2468}
2469
2470#[cfg(test)]
2471#[path = "tests/modifier_tests.rs"]
2472mod tests;