Skip to main content

cranpose_foundation/
modifier.rs

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