Skip to main content

cranpose_foundation/
modifier.rs

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