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                let positional_update = element.requires_update();
1444                if same_type && same_key && (same_hash || positional_update) {
1445                    // Fast path: element matches at same position
1446                    let same_element = entry.element.as_ref().equals_element(element.as_ref());
1447                    let capabilities = element.capabilities();
1448
1449                    // Re-attach node if it was detached during a previous update
1450                    {
1451                        let node_borrow = entry.node.borrow();
1452                        if !node_borrow.node_state().is_attached() {
1453                            drop(node_borrow);
1454                            attach_node_tree(&mut **entry.node.borrow_mut(), context);
1455                        }
1456                    }
1457
1458                    // Optimize updates: only call update_node if element changed
1459                    let needs_update = !same_element || element.requires_update();
1460                    if needs_update {
1461                        element.update_node(&mut **entry.node.borrow_mut());
1462                        entry.element = element.clone();
1463                        entry.hash_code = element.hash_code();
1464                        request_auto_invalidations(context, capabilities);
1465                    }
1466
1467                    // Always update metadata
1468                    entry.capabilities = capabilities;
1469                    entry
1470                        .node
1471                        .borrow()
1472                        .node_state()
1473                        .set_capabilities(capabilities);
1474                    continue;
1475                }
1476                // Fast path failed - mark position and fall through to collect
1477                fast_path_failed_at = Some(idx);
1478            }
1479
1480            // Collect element for slow path processing
1481            self.scratch_elements.push(element.clone());
1482        }
1483
1484        // Fast path succeeded if:
1485        // 1. No mismatch was found (fast_path_failed_at is None)
1486        // 2. All elements were processed via fast path (scratch_elements is empty)
1487        // Note: If old_len=0 and we have new elements, scratch_elements won't be empty
1488        if fast_path_failed_at.is_none() && self.scratch_elements.is_empty() {
1489            // Detach any removed entries (elements_count <= old_len guaranteed here)
1490            if elements_count < self.entries.len() {
1491                for entry in self.entries.drain(elements_count..) {
1492                    request_auto_invalidations(context, entry.capabilities);
1493                    detach_node_tree(&mut **entry.node.borrow_mut());
1494                }
1495            }
1496            self.sync_chain_links();
1497            return;
1498        }
1499
1500        // Slow path: need full reconciliation starting from failure point
1501        // If no mismatch but we have extra elements, fail_idx is the old length
1502        let fail_idx = fast_path_failed_at.unwrap_or(old_len);
1503
1504        // Move entries that were already processed to a safe place
1505        let mut old_entries: Vec<ModifierNodeEntry> = self.entries.drain(fail_idx..).collect();
1506        let processed_entries_len = self.entries.len();
1507        let old_len = old_entries.len();
1508
1509        // Reuse scratch buffers for the remaining entries only
1510        self.scratch_old_used.clear();
1511        self.scratch_old_used.resize(old_len, false);
1512
1513        self.scratch_match_order.clear();
1514        self.scratch_match_order.resize(old_len, None);
1515
1516        // Build index only for unprocessed entries
1517        let index = EntryIndex::build(&old_entries);
1518
1519        let new_elements_count = self.scratch_elements.len();
1520        self.scratch_final_slots.clear();
1521        self.scratch_final_slots.reserve(new_elements_count);
1522
1523        // Process each remaining element
1524        for (new_pos, element) in self.scratch_elements.drain(..).enumerate() {
1525            self.scratch_final_slots.push(None);
1526            let element_type = element.element_type();
1527            let key = element.key();
1528            let hash_code = element.hash_code();
1529            let capabilities = element.capabilities();
1530
1531            // Find best matching old entry via index
1532            let matched_idx = index.find_match(
1533                &old_entries,
1534                &self.scratch_old_used,
1535                element_type,
1536                key,
1537                hash_code,
1538                &element,
1539            );
1540
1541            if let Some(idx) = matched_idx {
1542                // Reuse existing entry
1543                self.scratch_old_used[idx] = true;
1544                self.scratch_match_order[idx] = Some(new_pos);
1545                let entry = &mut old_entries[idx];
1546                let moved = idx != new_pos;
1547
1548                // Check if element actually changed
1549                let same_element = entry.element.as_ref().equals_element(element.as_ref());
1550
1551                // Re-attach node if it was detached
1552                {
1553                    let node_borrow = entry.node.borrow();
1554                    if !node_borrow.node_state().is_attached() {
1555                        drop(node_borrow);
1556                        attach_node_tree(&mut **entry.node.borrow_mut(), context);
1557                    }
1558                }
1559
1560                // Optimize updates: only call update_node if element changed
1561                let needs_update = !same_element || element.requires_update();
1562                if needs_update {
1563                    element.update_node(&mut **entry.node.borrow_mut());
1564                    entry.element = element;
1565                    entry.hash_code = hash_code;
1566                    request_auto_invalidations(context, capabilities);
1567                }
1568                if moved {
1569                    request_auto_invalidations(context, capabilities);
1570                }
1571
1572                // Always update metadata
1573                entry.key = key;
1574                entry.element_type = element_type;
1575                entry.capabilities = capabilities;
1576                entry
1577                    .node
1578                    .borrow()
1579                    .node_state()
1580                    .set_capabilities(capabilities);
1581            } else {
1582                // Create new entry
1583                let entry = ModifierNodeEntry::new(
1584                    element_type,
1585                    key,
1586                    element.clone(),
1587                    element.create_node(),
1588                    hash_code,
1589                    capabilities,
1590                );
1591                attach_node_tree(&mut **entry.node.borrow_mut(), context);
1592                element.update_node(&mut **entry.node.borrow_mut());
1593                request_auto_invalidations(context, capabilities);
1594                self.scratch_final_slots[new_pos] = Some(entry);
1595            }
1596        }
1597
1598        // Place matched entries in their new positions
1599        for (i, entry) in old_entries.into_iter().enumerate() {
1600            if self.scratch_old_used[i] {
1601                let pos = self.scratch_match_order[i]
1602                    .expect("Missing match order for used modifier entry");
1603                self.scratch_final_slots[pos] = Some(entry);
1604            } else {
1605                request_auto_invalidations(context, entry.capabilities);
1606                detach_node_tree(&mut **entry.node.borrow_mut());
1607            }
1608        }
1609
1610        // Append processed entries to self.entries
1611        self.entries.reserve(self.scratch_final_slots.len());
1612        for slot in self.scratch_final_slots.drain(..) {
1613            let entry = slot.expect("Missing modifier entry for reconciled position");
1614            self.entries.push(entry);
1615        }
1616
1617        debug_assert_eq!(
1618            self.entries.len(),
1619            processed_entries_len + new_elements_count
1620        );
1621        self.sync_chain_links();
1622    }
1623
1624    /// Convenience wrapper that accepts any iterator of type-erased
1625    /// modifier elements. Elements are collected into a temporary vector
1626    /// before reconciliation.
1627    pub fn update<I>(&mut self, elements: I, context: &mut dyn ModifierNodeContext)
1628    where
1629        I: IntoIterator<Item = DynModifierElement>,
1630    {
1631        let collected: Vec<DynModifierElement> = elements.into_iter().collect();
1632        self.update_from_slice(&collected, context);
1633    }
1634
1635    /// Resets all nodes in the chain. This mirrors the behaviour of
1636    /// Jetpack Compose's `onReset` callback.
1637    pub fn reset(&mut self) {
1638        for entry in &mut self.entries {
1639            reset_node_tree(&mut **entry.node.borrow_mut());
1640        }
1641    }
1642
1643    /// Detaches every node in the chain and clears internal storage.
1644    pub fn detach_all(&mut self) {
1645        for entry in std::mem::take(&mut self.entries) {
1646            detach_node_tree(&mut **entry.node.borrow_mut());
1647            {
1648                let node_borrow = entry.node.borrow();
1649                let state = node_borrow.node_state();
1650                state.set_capabilities(NodeCapabilities::empty());
1651            }
1652        }
1653        self.aggregated_capabilities = NodeCapabilities::empty();
1654        self.head_aggregate_child_capabilities = NodeCapabilities::empty();
1655        self.ordered_nodes.clear();
1656        self.sync_chain_links();
1657    }
1658
1659    pub fn len(&self) -> usize {
1660        self.entries.len()
1661    }
1662
1663    pub fn is_empty(&self) -> bool {
1664        self.entries.is_empty()
1665    }
1666
1667    /// Returns the aggregated capability mask for the entire chain.
1668    pub fn capabilities(&self) -> NodeCapabilities {
1669        self.aggregated_capabilities
1670    }
1671
1672    /// Returns true if the chain contains at least one node with the requested capability.
1673    pub fn has_capability(&self, capability: NodeCapabilities) -> bool {
1674        self.aggregated_capabilities.contains(capability)
1675    }
1676
1677    /// Returns the sentinel head reference for traversal.
1678    pub fn head(&self) -> ModifierChainNodeRef<'_> {
1679        self.make_node_ref(NodeLink::Head)
1680    }
1681
1682    /// Returns the sentinel tail reference for traversal.
1683    pub fn tail(&self) -> ModifierChainNodeRef<'_> {
1684        self.make_node_ref(NodeLink::Tail)
1685    }
1686
1687    /// Iterates over the chain from head to tail, skipping sentinels.
1688    pub fn head_to_tail(&self) -> ModifierChainIter<'_> {
1689        ModifierChainIter::forward(self)
1690    }
1691
1692    /// Iterates over the chain from tail to head, skipping sentinels.
1693    pub fn tail_to_head(&self) -> ModifierChainIter<'_> {
1694        ModifierChainIter::backward(self)
1695    }
1696
1697    /// Calls `f` for every node in insertion order.
1698    pub fn for_each_forward<F>(&self, mut f: F)
1699    where
1700        F: FnMut(ModifierChainNodeRef<'_>),
1701    {
1702        for node in self.head_to_tail() {
1703            f(node);
1704        }
1705    }
1706
1707    /// Calls `f` for every node containing any capability from `mask`.
1708    pub fn for_each_forward_matching<F>(&self, mask: NodeCapabilities, mut f: F)
1709    where
1710        F: FnMut(ModifierChainNodeRef<'_>),
1711    {
1712        if mask.is_empty() {
1713            self.for_each_forward(f);
1714            return;
1715        }
1716
1717        if !self.head().aggregate_child_capabilities().intersects(mask) {
1718            return;
1719        }
1720
1721        for node in self.head_to_tail() {
1722            if node.kind_set().intersects(mask) {
1723                f(node);
1724            }
1725        }
1726    }
1727
1728    /// Calls `f` for every node containing any capability from `mask`, providing the node ref.
1729    pub fn for_each_node_with_capability<F>(&self, mask: NodeCapabilities, mut f: F)
1730    where
1731        F: FnMut(ModifierChainNodeRef<'_>, &dyn ModifierNode),
1732    {
1733        self.for_each_forward_matching(mask, |node_ref| {
1734            node_ref.with_node(|node| f(node_ref.clone(), node));
1735        });
1736    }
1737
1738    /// Calls `f` for every node in reverse insertion order.
1739    pub fn for_each_backward<F>(&self, mut f: F)
1740    where
1741        F: FnMut(ModifierChainNodeRef<'_>),
1742    {
1743        for node in self.tail_to_head() {
1744            f(node);
1745        }
1746    }
1747
1748    /// Calls `f` for every node in reverse order that matches `mask`.
1749    pub fn for_each_backward_matching<F>(&self, mask: NodeCapabilities, mut f: F)
1750    where
1751        F: FnMut(ModifierChainNodeRef<'_>),
1752    {
1753        if mask.is_empty() {
1754            self.for_each_backward(f);
1755            return;
1756        }
1757
1758        if !self.head().aggregate_child_capabilities().intersects(mask) {
1759            return;
1760        }
1761
1762        for node in self.tail_to_head() {
1763            if node.kind_set().intersects(mask) {
1764                f(node);
1765            }
1766        }
1767    }
1768
1769    /// Returns a node reference for the entry at `index`.
1770    pub fn node_ref_at(&self, index: usize) -> Option<ModifierChainNodeRef<'_>> {
1771        if index >= self.entries.len() {
1772            None
1773        } else {
1774            Some(self.make_node_ref(NodeLink::Entry(NodePath::root(index))))
1775        }
1776    }
1777
1778    /// Returns the node reference that owns `node`.
1779    pub fn find_node_ref(&self, node: &dyn ModifierNode) -> Option<ModifierChainNodeRef<'_>> {
1780        fn node_data_ptr(node: &dyn ModifierNode) -> *const () {
1781            node as *const dyn ModifierNode as *const ()
1782        }
1783
1784        let target = node_data_ptr(node);
1785        for (index, entry) in self.entries.iter().enumerate() {
1786            if node_data_ptr(&**entry.node.borrow()) == target {
1787                return Some(self.make_node_ref(NodeLink::Entry(NodePath::root(index))));
1788            }
1789        }
1790
1791        self.ordered_nodes.iter().find_map(|(link, _caps, _agg)| {
1792            if matches!(link, NodeLink::Entry(path) if path.delegates().is_empty()) {
1793                return None;
1794            }
1795            let matches_target = match link {
1796                NodeLink::Head => node_data_ptr(self.head_sentinel.as_ref()) == target,
1797                NodeLink::Tail => node_data_ptr(self.tail_sentinel.as_ref()) == target,
1798                NodeLink::Entry(path) => {
1799                    let node_borrow = self.entries[path.entry()].node.borrow();
1800                    node_data_ptr(&**node_borrow) == target
1801                }
1802            };
1803            if matches_target {
1804                Some(self.make_node_ref(*link))
1805            } else {
1806                None
1807            }
1808        })
1809    }
1810
1811    /// Downcasts the node at `index` to the requested type.
1812    /// Returns a `Ref` guard that dereferences to the node type.
1813    pub fn node<N: ModifierNode + 'static>(&self, index: usize) -> Option<std::cell::Ref<'_, N>> {
1814        self.entries.get(index).and_then(|entry| {
1815            std::cell::Ref::filter_map(entry.node.borrow(), |boxed_node| {
1816                boxed_node.as_any().downcast_ref::<N>()
1817            })
1818            .ok()
1819        })
1820    }
1821
1822    /// Downcasts the node at `index` to the requested mutable type.
1823    /// Returns a `RefMut` guard that dereferences to the node type.
1824    pub fn node_mut<N: ModifierNode + 'static>(
1825        &self,
1826        index: usize,
1827    ) -> Option<std::cell::RefMut<'_, N>> {
1828        self.entries.get(index).and_then(|entry| {
1829            std::cell::RefMut::filter_map(entry.node.borrow_mut(), |boxed_node| {
1830                boxed_node.as_any_mut().downcast_mut::<N>()
1831            })
1832            .ok()
1833        })
1834    }
1835
1836    /// Returns an Rc clone of the node at the given index for shared ownership.
1837    /// This is used by coordinators to hold direct references to nodes.
1838    pub fn get_node_rc(&self, index: usize) -> Option<Rc<RefCell<Box<dyn ModifierNode>>>> {
1839        self.entries.get(index).map(|entry| Rc::clone(&entry.node))
1840    }
1841
1842    /// Returns true if the chain contains any nodes matching the given invalidation kind.
1843    pub fn has_nodes_for_invalidation(&self, kind: InvalidationKind) -> bool {
1844        self.aggregated_capabilities
1845            .contains(NodeCapabilities::for_invalidation(kind))
1846    }
1847
1848    /// Visits every node in insertion order together with its capability mask.
1849    pub fn visit_nodes<F>(&self, mut f: F)
1850    where
1851        F: FnMut(&dyn ModifierNode, NodeCapabilities),
1852    {
1853        for (link, cached_caps, _agg) in &self.ordered_nodes {
1854            match link {
1855                NodeLink::Head => {
1856                    f(self.head_sentinel.as_ref(), *cached_caps);
1857                }
1858                NodeLink::Tail => {
1859                    f(self.tail_sentinel.as_ref(), *cached_caps);
1860                }
1861                NodeLink::Entry(path) => {
1862                    let node_borrow = self.entries[path.entry()].node.borrow();
1863                    if path.delegates().is_empty() {
1864                        f(&**node_borrow, *cached_caps);
1865                    } else {
1866                        let mut current: &dyn ModifierNode = &**node_borrow;
1867                        for &delegate_index in path.delegates() {
1868                            if let Some(delegate) = nth_delegate(current, delegate_index as usize) {
1869                                current = delegate;
1870                            } else {
1871                                return; // Invalid delegate path
1872                            }
1873                        }
1874                        f(current, *cached_caps);
1875                    }
1876                }
1877            }
1878        }
1879    }
1880
1881    /// Visits every node mutably in insertion order together with its capability mask.
1882    pub fn visit_nodes_mut<F>(&mut self, mut f: F)
1883    where
1884        F: FnMut(&mut dyn ModifierNode, NodeCapabilities),
1885    {
1886        for index in 0..self.ordered_nodes.len() {
1887            let (link, cached_caps, _agg) = self.ordered_nodes[index];
1888            match link {
1889                NodeLink::Head => {
1890                    f(self.head_sentinel.as_mut(), cached_caps);
1891                }
1892                NodeLink::Tail => {
1893                    f(self.tail_sentinel.as_mut(), cached_caps);
1894                }
1895                NodeLink::Entry(path) => {
1896                    let mut node_borrow = self.entries[path.entry()].node.borrow_mut();
1897                    if path.delegates().is_empty() {
1898                        f(&mut **node_borrow, cached_caps);
1899                    } else {
1900                        let mut current: &mut dyn ModifierNode = &mut **node_borrow;
1901                        for &delegate_index in path.delegates() {
1902                            if let Some(delegate) =
1903                                nth_delegate_mut(current, delegate_index as usize)
1904                            {
1905                                current = delegate;
1906                            } else {
1907                                return; // Invalid delegate path
1908                            }
1909                        }
1910                        f(current, cached_caps);
1911                    }
1912                }
1913            }
1914        }
1915    }
1916
1917    fn make_node_ref(&self, link: NodeLink) -> ModifierChainNodeRef<'_> {
1918        ModifierChainNodeRef {
1919            chain: self,
1920            link,
1921            cached_capabilities: None,
1922            cached_aggregate_child: None,
1923        }
1924    }
1925
1926    fn make_node_ref_with_caps(
1927        &self,
1928        link: NodeLink,
1929        caps: NodeCapabilities,
1930        aggregate_child: NodeCapabilities,
1931    ) -> ModifierChainNodeRef<'_> {
1932        ModifierChainNodeRef {
1933            chain: self,
1934            link,
1935            cached_capabilities: Some(caps),
1936            cached_aggregate_child: Some(aggregate_child),
1937        }
1938    }
1939
1940    fn sync_chain_links(&mut self) {
1941        self.rebuild_ordered_nodes();
1942
1943        self.head_sentinel.node_state().set_parent_link(None);
1944        self.tail_sentinel.node_state().set_child_link(None);
1945
1946        if self.ordered_nodes.is_empty() {
1947            self.head_sentinel
1948                .node_state()
1949                .set_child_link(Some(NodeLink::Tail));
1950            self.tail_sentinel
1951                .node_state()
1952                .set_parent_link(Some(NodeLink::Head));
1953            self.aggregated_capabilities = NodeCapabilities::empty();
1954            self.head_aggregate_child_capabilities = NodeCapabilities::empty();
1955            self.head_sentinel
1956                .node_state()
1957                .set_aggregate_child_capabilities(NodeCapabilities::empty());
1958            self.tail_sentinel
1959                .node_state()
1960                .set_aggregate_child_capabilities(NodeCapabilities::empty());
1961            return;
1962        }
1963
1964        let mut previous = NodeLink::Head;
1965        for (link, _caps, _agg) in self.ordered_nodes.iter().copied() {
1966            // Set child link on previous
1967            match &previous {
1968                NodeLink::Head => self.head_sentinel.node_state().set_child_link(Some(link)),
1969                NodeLink::Tail => self.tail_sentinel.node_state().set_child_link(Some(link)),
1970                NodeLink::Entry(path) => {
1971                    let node_borrow = self.entries[path.entry()].node.borrow();
1972                    // Navigate to delegate if needed
1973                    if path.delegates().is_empty() {
1974                        node_borrow.node_state().set_child_link(Some(link));
1975                    } else {
1976                        let mut current: &dyn ModifierNode = &**node_borrow;
1977                        for &delegate_index in path.delegates() {
1978                            if let Some(delegate) = nth_delegate(current, delegate_index as usize) {
1979                                current = delegate;
1980                            }
1981                        }
1982                        current.node_state().set_child_link(Some(link));
1983                    }
1984                }
1985            }
1986            // Set parent link on current
1987            match &link {
1988                NodeLink::Head => self
1989                    .head_sentinel
1990                    .node_state()
1991                    .set_parent_link(Some(previous)),
1992                NodeLink::Tail => self
1993                    .tail_sentinel
1994                    .node_state()
1995                    .set_parent_link(Some(previous)),
1996                NodeLink::Entry(path) => {
1997                    let node_borrow = self.entries[path.entry()].node.borrow();
1998                    // Navigate to delegate if needed
1999                    if path.delegates().is_empty() {
2000                        node_borrow.node_state().set_parent_link(Some(previous));
2001                    } else {
2002                        let mut current: &dyn ModifierNode = &**node_borrow;
2003                        for &delegate_index in path.delegates() {
2004                            if let Some(delegate) = nth_delegate(current, delegate_index as usize) {
2005                                current = delegate;
2006                            }
2007                        }
2008                        current.node_state().set_parent_link(Some(previous));
2009                    }
2010                }
2011            }
2012            previous = link;
2013        }
2014
2015        // Set child link on last node to Tail
2016        match &previous {
2017            NodeLink::Head => self
2018                .head_sentinel
2019                .node_state()
2020                .set_child_link(Some(NodeLink::Tail)),
2021            NodeLink::Tail => self
2022                .tail_sentinel
2023                .node_state()
2024                .set_child_link(Some(NodeLink::Tail)),
2025            NodeLink::Entry(path) => {
2026                let node_borrow = self.entries[path.entry()].node.borrow();
2027                // Navigate to delegate if needed
2028                if path.delegates().is_empty() {
2029                    node_borrow
2030                        .node_state()
2031                        .set_child_link(Some(NodeLink::Tail));
2032                } else {
2033                    let mut current: &dyn ModifierNode = &**node_borrow;
2034                    for &delegate_index in path.delegates() {
2035                        if let Some(delegate) = nth_delegate(current, delegate_index as usize) {
2036                            current = delegate;
2037                        }
2038                    }
2039                    current.node_state().set_child_link(Some(NodeLink::Tail));
2040                }
2041            }
2042        }
2043        self.tail_sentinel
2044            .node_state()
2045            .set_parent_link(Some(previous));
2046        self.tail_sentinel.node_state().set_child_link(None);
2047
2048        let mut aggregate = NodeCapabilities::empty();
2049        for (link, cached_caps, cached_aggregate) in self.ordered_nodes.iter_mut().rev() {
2050            aggregate |= *cached_caps;
2051            *cached_aggregate = aggregate;
2052            // Also update NodeState for code that reads through DelegatableNode
2053            match link {
2054                NodeLink::Head => {
2055                    self.head_sentinel
2056                        .node_state()
2057                        .set_aggregate_child_capabilities(aggregate);
2058                }
2059                NodeLink::Tail => {
2060                    self.tail_sentinel
2061                        .node_state()
2062                        .set_aggregate_child_capabilities(aggregate);
2063                }
2064                NodeLink::Entry(path) => {
2065                    let node_borrow = self.entries[path.entry()].node.borrow();
2066                    let state = if path.delegates().is_empty() {
2067                        node_borrow.node_state()
2068                    } else {
2069                        let mut current: &dyn ModifierNode = &**node_borrow;
2070                        for &delegate_index in path.delegates() {
2071                            if let Some(delegate) = nth_delegate(current, delegate_index as usize) {
2072                                current = delegate;
2073                            }
2074                        }
2075                        current.node_state()
2076                    };
2077                    state.set_aggregate_child_capabilities(aggregate);
2078                }
2079            }
2080        }
2081
2082        self.aggregated_capabilities = aggregate;
2083        self.head_aggregate_child_capabilities = aggregate;
2084        self.head_sentinel
2085            .node_state()
2086            .set_aggregate_child_capabilities(aggregate);
2087        self.tail_sentinel
2088            .node_state()
2089            .set_aggregate_child_capabilities(NodeCapabilities::empty());
2090    }
2091
2092    fn rebuild_ordered_nodes(&mut self) {
2093        self.ordered_nodes.clear();
2094        let mut path_buf = [0usize; MAX_DELEGATE_DEPTH];
2095        for (index, entry) in self.entries.iter().enumerate() {
2096            let node_borrow = entry.node.borrow();
2097            Self::enumerate_link_order(
2098                &**node_borrow,
2099                index,
2100                &mut path_buf,
2101                0,
2102                &mut self.ordered_nodes,
2103            );
2104        }
2105    }
2106
2107    fn enumerate_link_order(
2108        node: &dyn ModifierNode,
2109        entry: usize,
2110        path_buf: &mut [usize; MAX_DELEGATE_DEPTH],
2111        path_len: usize,
2112        out: &mut Vec<(NodeLink, NodeCapabilities, NodeCapabilities)>,
2113    ) {
2114        let caps = node.node_state().capabilities();
2115        out.push((
2116            NodeLink::Entry(NodePath::from_slice(entry, &path_buf[..path_len])),
2117            caps,
2118            NodeCapabilities::empty(),
2119        ));
2120        let mut delegate_index = 0usize;
2121        node.for_each_delegate(&mut |child| {
2122            if path_len < MAX_DELEGATE_DEPTH {
2123                path_buf[path_len] = delegate_index;
2124                Self::enumerate_link_order(child, entry, path_buf, path_len + 1, out);
2125            }
2126            delegate_index += 1;
2127        });
2128    }
2129}
2130
2131impl<'a> ModifierChainNodeRef<'a> {
2132    /// Helper to get NodeState, properly handling RefCell for entries.
2133    /// Returns NodeState values by calling a closure with the state.
2134    fn with_state<R>(&self, f: impl FnOnce(&NodeState) -> R) -> R {
2135        match &self.link {
2136            NodeLink::Head => f(self.chain.head_sentinel.node_state()),
2137            NodeLink::Tail => f(self.chain.tail_sentinel.node_state()),
2138            NodeLink::Entry(path) => {
2139                let node_borrow = self.chain.entries[path.entry()].node.borrow();
2140                // Navigate through delegates if path has them
2141                if path.delegates().is_empty() {
2142                    f(node_borrow.node_state())
2143                } else {
2144                    // Navigate to the delegate node
2145                    let mut current: &dyn ModifierNode = &**node_borrow;
2146                    for &delegate_index in path.delegates() {
2147                        if let Some(delegate) = nth_delegate(current, delegate_index as usize) {
2148                            current = delegate;
2149                        } else {
2150                            // Fallback to root node state if delegate path is invalid
2151                            return f(node_borrow.node_state());
2152                        }
2153                    }
2154                    f(current.node_state())
2155                }
2156            }
2157        }
2158    }
2159
2160    /// Provides access to the node via a closure, properly handling RefCell borrows.
2161    /// Returns None for sentinel nodes.
2162    pub fn with_node<R>(&self, f: impl FnOnce(&dyn ModifierNode) -> R) -> Option<R> {
2163        match &self.link {
2164            NodeLink::Head => None, // Head sentinel
2165            NodeLink::Tail => None, // Tail sentinel
2166            NodeLink::Entry(path) => {
2167                let node_borrow = self.chain.entries[path.entry()].node.borrow();
2168                // Navigate through delegates if path has them
2169                if path.delegates().is_empty() {
2170                    Some(f(&**node_borrow))
2171                } else {
2172                    // Navigate to the delegate node
2173                    let mut current: &dyn ModifierNode = &**node_borrow;
2174                    for &delegate_index in path.delegates() {
2175                        if let Some(delegate) = nth_delegate(current, delegate_index as usize) {
2176                            current = delegate;
2177                        } else {
2178                            // Return None if delegate path is invalid
2179                            return None;
2180                        }
2181                    }
2182                    Some(f(current))
2183                }
2184            }
2185        }
2186    }
2187
2188    /// Returns the parent reference, including sentinel head when applicable.
2189    #[inline]
2190    pub fn parent(&self) -> Option<Self> {
2191        self.with_state(|state| state.parent_link())
2192            .map(|link| self.chain.make_node_ref(link))
2193    }
2194
2195    /// Returns the child reference, including sentinel tail for the last entry.
2196    #[inline]
2197    pub fn child(&self) -> Option<Self> {
2198        self.with_state(|state| state.child_link())
2199            .map(|link| self.chain.make_node_ref(link))
2200    }
2201
2202    /// Returns the capability mask for this specific node.
2203    #[inline]
2204    pub fn kind_set(&self) -> NodeCapabilities {
2205        if let Some(caps) = self.cached_capabilities {
2206            return caps;
2207        }
2208        match &self.link {
2209            NodeLink::Head | NodeLink::Tail => NodeCapabilities::empty(),
2210            NodeLink::Entry(_) => self.with_state(|state| state.capabilities()),
2211        }
2212    }
2213
2214    /// Returns the entry index backing this node when it is part of the chain.
2215    pub fn entry_index(&self) -> Option<usize> {
2216        match &self.link {
2217            NodeLink::Entry(path) => Some(path.entry()),
2218            _ => None,
2219        }
2220    }
2221
2222    /// Returns how many delegate hops separate this node from its root element.
2223    pub fn delegate_depth(&self) -> usize {
2224        match &self.link {
2225            NodeLink::Entry(path) => path.delegates().len(),
2226            _ => 0,
2227        }
2228    }
2229
2230    /// Returns the aggregated capability mask for the subtree rooted at this node.
2231    #[inline]
2232    pub fn aggregate_child_capabilities(&self) -> NodeCapabilities {
2233        if let Some(agg) = self.cached_aggregate_child {
2234            return agg;
2235        }
2236        if self.is_tail() {
2237            NodeCapabilities::empty()
2238        } else {
2239            self.with_state(|state| state.aggregate_child_capabilities())
2240        }
2241    }
2242
2243    /// Returns true if this reference targets the sentinel head.
2244    pub fn is_head(&self) -> bool {
2245        matches!(self.link, NodeLink::Head)
2246    }
2247
2248    /// Returns true if this reference targets the sentinel tail.
2249    pub fn is_tail(&self) -> bool {
2250        matches!(self.link, NodeLink::Tail)
2251    }
2252
2253    /// Returns true if this reference targets either sentinel.
2254    pub fn is_sentinel(&self) -> bool {
2255        matches!(self.link, NodeLink::Head | NodeLink::Tail)
2256    }
2257
2258    /// Returns true if this node has any capability bits present in `mask`.
2259    pub fn has_capability(&self, mask: NodeCapabilities) -> bool {
2260        !mask.is_empty() && self.kind_set().intersects(mask)
2261    }
2262
2263    /// Visits descendant nodes, optionally including `self`, in insertion order.
2264    pub fn visit_descendants<F>(self, include_self: bool, mut f: F)
2265    where
2266        F: FnMut(ModifierChainNodeRef<'a>),
2267    {
2268        let mut current = if include_self {
2269            Some(self)
2270        } else {
2271            self.child()
2272        };
2273        while let Some(node) = current {
2274            if node.is_tail() {
2275                break;
2276            }
2277            if !node.is_sentinel() {
2278                f(node.clone());
2279            }
2280            current = node.child();
2281        }
2282    }
2283
2284    /// Visits descendant nodes that match `mask`, short-circuiting when possible.
2285    pub fn visit_descendants_matching<F>(self, include_self: bool, mask: NodeCapabilities, mut f: F)
2286    where
2287        F: FnMut(ModifierChainNodeRef<'a>),
2288    {
2289        if mask.is_empty() {
2290            self.visit_descendants(include_self, f);
2291            return;
2292        }
2293
2294        if !self.aggregate_child_capabilities().intersects(mask) {
2295            return;
2296        }
2297
2298        self.visit_descendants(include_self, |node| {
2299            if node.kind_set().intersects(mask) {
2300                f(node);
2301            }
2302        });
2303    }
2304
2305    /// Visits ancestor nodes up to (but excluding) the sentinel head.
2306    pub fn visit_ancestors<F>(self, include_self: bool, mut f: F)
2307    where
2308        F: FnMut(ModifierChainNodeRef<'a>),
2309    {
2310        let mut current = if include_self {
2311            Some(self)
2312        } else {
2313            self.parent()
2314        };
2315        while let Some(node) = current {
2316            if node.is_head() {
2317                break;
2318            }
2319            f(node.clone());
2320            current = node.parent();
2321        }
2322    }
2323
2324    /// Visits ancestor nodes that match `mask`.
2325    pub fn visit_ancestors_matching<F>(self, include_self: bool, mask: NodeCapabilities, mut f: F)
2326    where
2327        F: FnMut(ModifierChainNodeRef<'a>),
2328    {
2329        if mask.is_empty() {
2330            self.visit_ancestors(include_self, f);
2331            return;
2332        }
2333
2334        self.visit_ancestors(include_self, |node| {
2335            if node.kind_set().intersects(mask) {
2336                f(node);
2337            }
2338        });
2339    }
2340
2341    /// Finds the nearest ancestor focus target node.
2342    ///
2343    /// This is useful for focus navigation to find the parent focusable
2344    /// component in the tree.
2345    pub fn find_parent_focus_target(&self) -> Option<ModifierChainNodeRef<'a>> {
2346        let mut result = None;
2347        self.clone()
2348            .visit_ancestors_matching(false, NodeCapabilities::FOCUS, |node| {
2349                if result.is_none() {
2350                    result = Some(node);
2351                }
2352            });
2353        result
2354    }
2355
2356    /// Finds the first descendant focus target node.
2357    ///
2358    /// This is useful for focus navigation to find the first focusable
2359    /// child component in the tree.
2360    pub fn find_first_focus_target(&self) -> Option<ModifierChainNodeRef<'a>> {
2361        let mut result = None;
2362        self.clone()
2363            .visit_descendants_matching(false, NodeCapabilities::FOCUS, |node| {
2364                if result.is_none() {
2365                    result = Some(node);
2366                }
2367            });
2368        result
2369    }
2370
2371    /// Returns true if this node or any ancestor has focus capability.
2372    pub fn has_focus_capability_in_ancestors(&self) -> bool {
2373        let mut found = false;
2374        self.clone()
2375            .visit_ancestors_matching(true, NodeCapabilities::FOCUS, |_| {
2376                found = true;
2377            });
2378        found
2379    }
2380}
2381
2382#[cfg(test)]
2383#[path = "tests/modifier_tests.rs"]
2384mod tests;