Skip to main content

cranpose_foundation/modifier/
chain.rs

1//! The chain of modifier nodes a layout node holds, and its reconciliation
2//! with the node's modifier.
3
4use std::{any::TypeId, cell::RefCell, rc::Rc};
5
6use cranpose_core::{PackedU64, collections::map::HashMap};
7
8use super::{
9    AnyModifierElement, DynModifierElement, InvalidationKind, MAX_DELEGATE_DEPTH,
10    ModifierChainIter, ModifierChainNodeRef, ModifierNode, ModifierNodeContext, NodeCapabilities,
11    NodePath, chain_node_ref::ChainPosition,
12};
13
14/// One node of a chain and the element it last took. The element's hash,
15/// which matches entries when a chain rebuilds, is worked out then: an
16/// element updated in place on every frame is not hashed for it.
17#[derive(Debug)]
18struct ModifierNodeEntry {
19    key: Option<PackedU64>,
20    element: DynModifierElement,
21    node: Rc<RefCell<dyn ModifierNode>>,
22    capabilities: NodeCapabilities,
23    // The union of the node's capabilities and those of every node after it,
24    // while no node of the chain delegates.
25    aggregate: NodeCapabilities,
26}
27
28impl ModifierNodeEntry {
29    fn new(
30        key: Option<PackedU64>,
31        element: DynModifierElement,
32        node: Rc<RefCell<dyn ModifierNode>>,
33        capabilities: NodeCapabilities,
34    ) -> Self {
35        let entry = Self {
36            key,
37            element,
38            node,
39            capabilities,
40            aggregate: NodeCapabilities::empty(),
41        };
42        entry
43            .node
44            .borrow()
45            .node_state()
46            .set_capabilities(entry.capabilities);
47        entry
48    }
49}
50
51fn visit_node_tree_mut(
52    node: &mut dyn ModifierNode,
53    visitor: &mut dyn FnMut(&mut dyn ModifierNode),
54) {
55    visitor(node);
56    node.for_each_delegate_mut(&mut |child| visit_node_tree_mut(child, visitor));
57}
58
59fn nth_delegate(node: &dyn ModifierNode, target: usize) -> Option<&dyn ModifierNode> {
60    let mut current = 0usize;
61    let mut result: Option<&dyn ModifierNode> = None;
62    node.for_each_delegate(&mut |child| {
63        if result.is_none() && current == target {
64            result = Some(child);
65        }
66        current += 1;
67    });
68    result
69}
70
71fn nth_delegate_mut(node: &mut dyn ModifierNode, target: usize) -> Option<&mut dyn ModifierNode> {
72    let mut current = 0usize;
73    let mut result: Option<&mut dyn ModifierNode> = None;
74    node.for_each_delegate_mut(&mut |child| {
75        if result.is_none() && current == target {
76            result = Some(child);
77        }
78        current += 1;
79    });
80    result
81}
82
83fn with_node_context<F, R>(
84    node: &mut dyn ModifierNode,
85    context: &mut dyn ModifierNodeContext,
86    f: F,
87) -> R
88where
89    F: FnOnce(&mut dyn ModifierNode, &mut dyn ModifierNodeContext) -> R,
90{
91    context.push_active_capabilities(node.node_state().capabilities());
92    let result = f(node, context);
93    context.pop_active_capabilities();
94    result
95}
96
97fn request_update_auto_invalidations(
98    element: &dyn AnyModifierElement,
99    context: &mut dyn ModifierNodeContext,
100    capabilities: NodeCapabilities,
101) {
102    if let Some(kind) = element.update_invalidation_kind() {
103        let capabilities = NodeCapabilities::for_invalidation(kind);
104        context.push_active_capabilities(capabilities);
105        context.invalidate(kind);
106        context.pop_active_capabilities();
107    } else if element.auto_invalidates_on_update() {
108        request_auto_invalidations(context, capabilities);
109    }
110}
111
112fn request_auto_invalidations(
113    context: &mut dyn ModifierNodeContext,
114    capabilities: NodeCapabilities,
115) {
116    if capabilities.is_empty() {
117        return;
118    }
119
120    context.push_active_capabilities(capabilities);
121
122    if capabilities.contains(NodeCapabilities::LAYOUT) {
123        context.invalidate(InvalidationKind::Layout);
124    }
125    if capabilities.contains(NodeCapabilities::DRAW) {
126        context.invalidate(InvalidationKind::Draw);
127    }
128    if capabilities.contains(NodeCapabilities::POINTER_INPUT) {
129        context.invalidate(InvalidationKind::PointerInput);
130    }
131    if capabilities.contains(NodeCapabilities::SEMANTICS) {
132        context.invalidate(InvalidationKind::Semantics);
133    }
134    if capabilities.contains(NodeCapabilities::FOCUS) {
135        context.invalidate(InvalidationKind::Focus);
136    }
137
138    context.pop_active_capabilities();
139}
140
141fn attach_node_tree(node: &mut dyn ModifierNode, context: &mut dyn ModifierNodeContext) {
142    visit_node_tree_mut(node, &mut |n| {
143        if !n.node_state().is_attached() {
144            n.node_state().set_attached(true);
145            with_node_context(n, context, |node, ctx| node.on_attach(ctx));
146        }
147    });
148}
149
150fn reset_node_tree(node: &mut dyn ModifierNode) {
151    visit_node_tree_mut(node, &mut |n| n.on_reset());
152}
153
154fn detach_node_tree(node: &mut dyn ModifierNode) {
155    visit_node_tree_mut(node, &mut |n| {
156        if n.node_state().is_attached() {
157            n.on_detach();
158            n.node_state().set_attached(false);
159        }
160    });
161}
162
163/// Chain of modifier nodes attached to a layout node.
164///
165/// The chain tracks ownership of modifier nodes and reuses them across
166/// updates when the incoming element list still contains a node of the
167/// same type. Removed nodes detach automatically so callers do not need
168/// to manually manage their lifetimes.
169pub struct ModifierNodeChain {
170    entries: Vec<ModifierNodeEntry>,
171    pub(super) aggregated_capabilities: NodeCapabilities,
172    // While a node of the chain delegates: the chain's nodes in order,
173    // delegates after the node that delegates to them, each with its
174    // capabilities and the union of its own and those of every node after
175    // it. Empty otherwise, when the entries are the order and keep the
176    // unions: most chains delegate nowhere and allocate none.
177    delegated_order: Vec<(NodePath, NodeCapabilities, NodeCapabilities)>,
178    /// Whether the chain's nodes are attached. A node that joins an attached
179    /// chain attaches as it joins; one that joins a detached chain waits for
180    /// [`Self::attach_nodes`].
181    attached: bool,
182}
183
184/// Buffers the reconciliation of a chain reuses, held per thread rather than
185/// per chain: a chain kept its own after its first reconciliation, a few
186/// hundred bytes on every node of a tree.
187#[derive(Default)]
188struct ReconcileScratch {
189    old_used: Vec<bool>,
190    match_order: Vec<Option<usize>>,
191    final_slots: Vec<Option<ModifierNodeEntry>>,
192    elements: Vec<DynModifierElement>,
193}
194
195thread_local! {
196    static RECONCILE_SCRATCH: RefCell<ReconcileScratch> =
197        RefCell::default();
198}
199
200impl Default for ModifierNodeChain {
201    fn default() -> Self {
202        Self::new()
203    }
204}
205
206struct EntryIndex {
207    keyed: HashMap<(TypeId, TypeId, u64), Vec<usize>>,
208    hashed: HashMap<(TypeId, TypeId, u64), Vec<usize>>,
209    typed: HashMap<(TypeId, TypeId), Vec<usize>>,
210}
211
212struct EntryMatchQuery<'a> {
213    element_type: TypeId,
214    node_type: TypeId,
215    key: Option<u64>,
216    hash_code: u64,
217    element: &'a DynModifierElement,
218}
219
220impl EntryIndex {
221    fn build(entries: &[ModifierNodeEntry]) -> Self {
222        let mut keyed = HashMap::default();
223        let mut hashed = HashMap::default();
224        let mut typed = HashMap::default();
225
226        for (i, entry) in entries.iter().enumerate() {
227            let (element_type, node_type) =
228                (entry.element.element_type(), entry.element.node_type());
229            if let Some(key_value) = entry.key {
230                keyed
231                    .entry((element_type, node_type, key_value.get()))
232                    .or_insert_with(Vec::new)
233                    .push(i);
234            } else {
235                hashed
236                    .entry((element_type, node_type, entry.element.hash_code()))
237                    .or_insert_with(Vec::new)
238                    .push(i);
239                typed
240                    .entry((element_type, node_type))
241                    .or_insert_with(Vec::new)
242                    .push(i);
243            }
244        }
245
246        Self {
247            keyed,
248            hashed,
249            typed,
250        }
251    }
252
253    fn find_match(
254        &self,
255        entries: &[ModifierNodeEntry],
256        used: &[bool],
257        query: EntryMatchQuery<'_>,
258    ) -> Option<usize> {
259        if let Some(key_value) = query.key {
260            if let Some(candidates) =
261                self.keyed
262                    .get(&(query.element_type, query.node_type, key_value))
263            {
264                for &i in candidates {
265                    if !used[i] {
266                        return Some(i);
267                    }
268                }
269            }
270        } else {
271            if let Some(candidates) =
272                self.hashed
273                    .get(&(query.element_type, query.node_type, query.hash_code))
274            {
275                for &i in candidates {
276                    if !used[i]
277                        && entries[i]
278                            .element
279                            .as_ref()
280                            .equals_element(query.element.as_ref())
281                    {
282                        return Some(i);
283                    }
284                }
285            }
286
287            if let Some(candidates) = self.typed.get(&(query.element_type, query.node_type)) {
288                for &i in candidates {
289                    if !used[i] {
290                        return Some(i);
291                    }
292                }
293            }
294        }
295
296        None
297    }
298}
299
300/// What updating an entry in place did to the chain's links.
301#[derive(Clone, Copy, PartialEq, Eq)]
302enum InPlace {
303    /// The links and capability aggregates stand as they were.
304    LinksHold,
305    /// The entry's capabilities changed, or its updated node delegates and
306    /// may have changed its delegates: the chain links again.
307    Relink,
308}
309
310/// Updates `entry` for `element` where it is, when the element is of the
311/// entry's type and key and its node can take it: an element of a node's
312/// type and key updates the node whatever its content, as Compose does.
313/// `None` leaves the entry as it was.
314fn update_entry_in_place(
315    entry: &mut ModifierNodeEntry,
316    element: &DynModifierElement,
317    context: &mut dyn ModifierNodeContext,
318) -> Option<InPlace> {
319    if entry.element.element_type() != element.element_type()
320        || entry.element.node_type() != element.node_type()
321        || entry.key.map(PackedU64::get) != element.key()
322        || !element.can_update_node(&*entry.node.borrow())
323    {
324        return None;
325    }
326    let same_element = entry.element.as_ref().equals_element(element.as_ref());
327    let capabilities = element.capabilities();
328    let mut outcome = if capabilities == entry.capabilities {
329        InPlace::LinksHold
330    } else {
331        InPlace::Relink
332    };
333    if !same_element || element.requires_update() {
334        element.update_node(&mut *entry.node.borrow_mut());
335        entry.element = Rc::clone(element);
336        request_update_auto_invalidations(element.as_ref(), context, capabilities);
337        entry
338            .node
339            .borrow()
340            .for_each_delegate(&mut |_| outcome = InPlace::Relink);
341    }
342    entry.capabilities = capabilities;
343    entry
344        .node
345        .borrow()
346        .node_state()
347        .set_capabilities(capabilities);
348    Some(outcome)
349}
350
351/// A new entry for `element` and its node, updated, and attached when
352/// `attach`, as it joins an attached chain.
353fn fresh_entry(
354    element: DynModifierElement,
355    context: &mut dyn ModifierNodeContext,
356    attach: bool,
357) -> ModifierNodeEntry {
358    let capabilities = element.capabilities();
359    let entry = ModifierNodeEntry::new(
360        element.key().map(PackedU64::new),
361        Rc::clone(&element),
362        element.create_node(),
363        capabilities,
364    );
365    if attach {
366        attach_node_tree(&mut *entry.node.borrow_mut(), context);
367    }
368    element.update_node(&mut *entry.node.borrow_mut());
369    request_auto_invalidations(context, capabilities);
370    entry
371}
372
373/// Matches `element`, at `new_pos` of the rebuilt tail, against the old
374/// entries: one of its type and key whose node can take it is updated and
375/// marked for `new_pos`, and `None` is returned; otherwise the element's
376/// new entry is, attached when `attach`.
377fn reconcile_element(
378    element: DynModifierElement,
379    new_pos: usize,
380    (old_entries, index): (&mut [ModifierNodeEntry], &EntryIndex),
381    (used, match_order): (&mut [bool], &mut [Option<usize>]),
382    context: &mut dyn ModifierNodeContext,
383    attach: bool,
384) -> Option<ModifierNodeEntry> {
385    let element_type = element.element_type();
386    let node_type = element.node_type();
387    let key = element.key();
388    // Only an unkeyed element is matched by its hash.
389    let hash_code = if key.is_none() {
390        element.hash_code()
391    } else {
392        0
393    };
394    let capabilities = element.capabilities();
395    let Some(idx) = index.find_match(
396        old_entries,
397        used,
398        EntryMatchQuery {
399            element_type,
400            node_type,
401            key,
402            hash_code,
403            element: &element,
404        },
405    ) else {
406        return Some(fresh_entry(element, context, attach));
407    };
408    let entry = &mut old_entries[idx];
409    if !element.can_update_node(&*entry.node.borrow()) {
410        return Some(fresh_entry(element, context, attach));
411    }
412
413    used[idx] = true;
414    match_order[idx] = Some(new_pos);
415    let same_element = entry.element.as_ref().equals_element(element.as_ref());
416    if !same_element || element.requires_update() {
417        element.update_node(&mut *entry.node.borrow_mut());
418        entry.element = element;
419        request_update_auto_invalidations(entry.element.as_ref(), context, capabilities);
420    }
421    if idx != new_pos {
422        request_auto_invalidations(context, capabilities);
423    }
424    entry.key = key.map(PackedU64::new);
425    entry.capabilities = capabilities;
426    entry
427        .node
428        .borrow()
429        .node_state()
430        .set_capabilities(capabilities);
431    None
432}
433
434impl ModifierNodeChain {
435    /// An attached chain: its nodes attach as they join it.
436    pub fn new() -> Self {
437        let mut chain = Self::detached();
438        chain.attached = true;
439        chain
440    }
441
442    /// A detached chain: its nodes attach at [`Self::attach_nodes`], as a
443    /// layout node's do once the node has its id.
444    pub fn detached() -> Self {
445        Self {
446            entries: Vec::new(),
447            aggregated_capabilities: NodeCapabilities::empty(),
448            delegated_order: Vec::new(),
449            attached: false,
450        }
451    }
452
453    /// Detaches all nodes in the chain.
454    pub fn detach_nodes(&mut self) {
455        if !self.attached {
456            return;
457        }
458        self.attached = false;
459        for entry in &self.entries {
460            detach_node_tree(&mut *entry.node.borrow_mut());
461        }
462    }
463
464    /// Attaches all nodes in the chain.
465    pub fn attach_nodes(&mut self, context: &mut dyn ModifierNodeContext) {
466        if self.attached {
467            return;
468        }
469        self.attached = true;
470        for entry in &self.entries {
471            attach_node_tree(&mut *entry.node.borrow_mut(), context);
472        }
473    }
474
475    /// Reconcile the chain against the provided elements, attaching newly
476    /// created nodes and detaching nodes that are no longer required.
477    ///
478    /// This method delegates to `update_from_ref_iter` which handles the
479    /// actual reconciliation logic.
480    pub fn update_from_slice(
481        &mut self,
482        elements: &[DynModifierElement],
483        context: &mut dyn ModifierNodeContext,
484    ) {
485        self.update_from_ref_iter(elements.iter(), context);
486    }
487
488    /// Updates in place the entries `changed` names, one bit an index, for
489    /// `elements` that differ from the chain's only in those: entries and
490    /// elements line up one to one, and every other entry stays as it is.
491    /// `false` when they do not line up or an entry cannot take its element;
492    /// a full update then reconciles the chain.
493    pub fn update_entries_in_place<'a, I>(
494        &mut self,
495        elements: I,
496        element_count: usize,
497        changed: u64,
498        context: &mut dyn ModifierNodeContext,
499    ) -> bool
500    where
501        I: Iterator<Item = &'a DynModifierElement>,
502    {
503        if element_count != self.entries.len() {
504            return false;
505        }
506        let mut relink = false;
507        let updated = self
508            .entries
509            .iter_mut()
510            .zip(elements)
511            .enumerate()
512            .filter(|&(index, _)| {
513                u32::try_from(index)
514                    .ok()
515                    .and_then(|bit| changed.checked_shr(bit))
516                    .is_some_and(|rest| rest & 1 == 1)
517            })
518            .map(|(_, pair)| pair)
519            .all(
520                |(entry, element)| match update_entry_in_place(entry, element, context) {
521                    Some(outcome) => {
522                        relink |= outcome == InPlace::Relink;
523                        true
524                    }
525                    None => false,
526                },
527            );
528        if relink {
529            self.sync_chain_links();
530        }
531        updated
532    }
533
534    /// Reconciles the chain against the elements that `elements` yields, without collecting them
535    /// first. See `update_from_slice`.
536    pub fn update_from_ref_iter<'a, I>(
537        &mut self,
538        elements: I,
539        context: &mut dyn ModifierNodeContext,
540    ) where
541        I: Iterator<Item = &'a DynModifierElement>,
542    {
543        // Taken out for the reconciliation, so one that reconciles another
544        // chain inside it works on buffers of its own.
545        let mut scratch = RECONCILE_SCRATCH
546            .try_with(|scratch| std::mem::take(&mut *scratch.borrow_mut()))
547            .unwrap_or_default();
548        self.reconcile(elements, context, &mut scratch);
549        scratch.elements.clear();
550        scratch.final_slots.clear();
551        let _ = RECONCILE_SCRATCH.try_with(|slot| *slot.borrow_mut() = scratch);
552    }
553
554    fn reconcile<'a, I>(
555        &mut self,
556        elements: I,
557        context: &mut dyn ModifierNodeContext,
558        scratch: &mut ReconcileScratch,
559    ) where
560        I: Iterator<Item = &'a DynModifierElement>,
561    {
562        let old_len = self.entries.len();
563        let mut fast_path_failed_at: Option<usize> = None;
564        let mut elements_count = 0;
565        // Entries updated where they are keep the links between them, unless
566        // their capabilities or delegates change.
567        let mut relink = false;
568
569        scratch.elements.clear();
570
571        for (idx, element) in elements.enumerate() {
572            elements_count = idx + 1;
573            if fast_path_failed_at.is_none() && idx < old_len {
574                if let Some(outcome) =
575                    update_entry_in_place(&mut self.entries[idx], element, context)
576                {
577                    relink |= outcome == InPlace::Relink;
578                    continue;
579                }
580                fast_path_failed_at = Some(idx);
581            }
582            scratch.elements.push(Rc::clone(element));
583        }
584
585        if fast_path_failed_at.is_none() && scratch.elements.is_empty() {
586            if elements_count < self.entries.len() {
587                for entry in self.entries.drain(elements_count..) {
588                    request_auto_invalidations(context, entry.capabilities);
589                    detach_node_tree(&mut *entry.node.borrow_mut());
590                }
591                relink = true;
592            }
593            if relink {
594                self.sync_chain_links();
595            }
596            return;
597        }
598
599        self.rebuild_tail(fast_path_failed_at.unwrap_or(old_len), context, scratch);
600    }
601
602    /// Rebuilds the chain from `fail_idx` for the elements in `scratch`:
603    /// each takes over an old entry of its type and key, wherever it was,
604    /// or gets a node of its own; old entries nothing took over detach.
605    fn rebuild_tail(
606        &mut self,
607        fail_idx: usize,
608        context: &mut dyn ModifierNodeContext,
609        scratch: &mut ReconcileScratch,
610    ) {
611        let mut old_entries: Vec<ModifierNodeEntry> = self.entries.drain(fail_idx..).collect();
612        let processed_entries_len = self.entries.len();
613        let old_len = old_entries.len();
614
615        scratch.old_used.clear();
616        scratch.old_used.resize(old_len, false);
617
618        scratch.match_order.clear();
619        scratch.match_order.resize(old_len, None);
620
621        let index = EntryIndex::build(&old_entries);
622
623        let new_elements_count = scratch.elements.len();
624        scratch.final_slots.clear();
625        scratch.final_slots.reserve(new_elements_count);
626
627        for (new_pos, element) in scratch.elements.drain(..).enumerate() {
628            let fresh = reconcile_element(
629                element,
630                new_pos,
631                (&mut old_entries, &index),
632                (&mut scratch.old_used, &mut scratch.match_order),
633                context,
634                self.attached,
635            );
636            scratch.final_slots.push(fresh);
637        }
638
639        for (i, entry) in old_entries.into_iter().enumerate() {
640            match scratch.match_order[i] {
641                Some(pos) if scratch.old_used[i] => scratch.final_slots[pos] = Some(entry),
642                _ => {
643                    request_auto_invalidations(context, entry.capabilities);
644                    detach_node_tree(&mut *entry.node.borrow_mut());
645                }
646            }
647        }
648
649        // Exactly: a chain is rebuilt only when its modifiers change, and
650        // most hold one to three entries, where growth would make room for
651        // four.
652        self.entries.reserve_exact(scratch.final_slots.len());
653        for slot in scratch.final_slots.drain(..) {
654            if let Some(entry) = slot {
655                self.entries.push(entry);
656            } else {
657                log::error!("modifier reconciliation produced an empty final slot");
658            }
659        }
660
661        debug_assert_eq!(
662            self.entries.len(),
663            processed_entries_len + new_elements_count
664        );
665        self.sync_chain_links();
666    }
667
668    /// Convenience wrapper that accepts any iterator of type-erased
669    /// modifier elements. Elements are collected into a temporary vector
670    /// before reconciliation.
671    pub fn update<I>(&mut self, elements: I, context: &mut dyn ModifierNodeContext)
672    where
673        I: IntoIterator<Item = DynModifierElement>,
674    {
675        let collected: Vec<DynModifierElement> = elements.into_iter().collect();
676        self.update_from_slice(&collected, context);
677    }
678
679    /// Resets all nodes in the chain. This mirrors the behaviour of
680    /// Jetpack Compose's `onReset` callback.
681    pub fn reset(&mut self) {
682        for entry in &mut self.entries {
683            reset_node_tree(&mut *entry.node.borrow_mut());
684        }
685    }
686
687    /// Detaches every node in the chain and clears internal storage.
688    pub fn detach_all(&mut self) {
689        for entry in std::mem::take(&mut self.entries) {
690            detach_node_tree(&mut *entry.node.borrow_mut());
691            {
692                let node_borrow = entry.node.borrow();
693                let state = node_borrow.node_state();
694                state.set_capabilities(NodeCapabilities::empty());
695            }
696        }
697        self.sync_chain_links();
698    }
699
700    /// The number of nodes in the chain.
701    pub fn len(&self) -> usize {
702        self.entries.len()
703    }
704
705    /// Whether the chain holds no nodes.
706    pub fn is_empty(&self) -> bool {
707        self.entries.is_empty()
708    }
709
710    /// Returns the aggregated capability mask for the entire chain.
711    pub fn capabilities(&self) -> NodeCapabilities {
712        self.aggregated_capabilities
713    }
714
715    /// Returns true if the chain contains at least one node with the requested capability.
716    pub fn has_capability(&self, capability: NodeCapabilities) -> bool {
717        self.aggregated_capabilities.contains(capability)
718    }
719
720    /// Returns the sentinel head reference for traversal.
721    pub fn head(&self) -> ModifierChainNodeRef<'_> {
722        self.node_ref(ChainPosition::Head)
723    }
724
725    /// Returns the sentinel tail reference for traversal.
726    pub fn tail(&self) -> ModifierChainNodeRef<'_> {
727        self.node_ref(ChainPosition::Tail)
728    }
729
730    /// Iterates over the chain from head to tail, skipping sentinels.
731    pub fn head_to_tail(&self) -> ModifierChainIter<'_> {
732        ModifierChainIter::forward(self)
733    }
734
735    /// Iterates over the chain from tail to head, skipping sentinels.
736    pub fn tail_to_head(&self) -> ModifierChainIter<'_> {
737        ModifierChainIter::backward(self)
738    }
739
740    /// Calls `f` for every node in insertion order.
741    pub fn for_each_forward<F>(&self, mut f: F)
742    where
743        F: FnMut(ModifierChainNodeRef<'_>),
744    {
745        for node in self.head_to_tail() {
746            f(node);
747        }
748    }
749
750    /// Calls `f` for every node containing any capability from `mask`.
751    pub fn for_each_forward_matching<F>(&self, mask: NodeCapabilities, mut f: F)
752    where
753        F: FnMut(ModifierChainNodeRef<'_>),
754    {
755        if mask.is_empty() {
756            self.for_each_forward(f);
757            return;
758        }
759
760        if !self.head().aggregate_child_capabilities().intersects(mask) {
761            return;
762        }
763
764        for node in self.head_to_tail() {
765            if node.kind_set().intersects(mask) {
766                f(node);
767            }
768        }
769    }
770
771    /// Calls `f` for every node containing any capability from `mask`, providing the node ref.
772    pub fn for_each_node_with_capability<F>(&self, mask: NodeCapabilities, mut f: F)
773    where
774        F: FnMut(ModifierChainNodeRef<'_>, &dyn ModifierNode),
775    {
776        self.for_each_forward_matching(mask, |node_ref| {
777            node_ref.with_node(|node| f(node_ref.clone(), node));
778        });
779    }
780
781    /// Calls `f` for every node in reverse insertion order.
782    pub fn for_each_backward<F>(&self, mut f: F)
783    where
784        F: FnMut(ModifierChainNodeRef<'_>),
785    {
786        for node in self.tail_to_head() {
787            f(node);
788        }
789    }
790
791    /// Returns the node reference that owns `node`.
792    pub fn find_node_ref(&self, node: &dyn ModifierNode) -> Option<ModifierChainNodeRef<'_>> {
793        fn node_data_ptr(node: &dyn ModifierNode) -> *const () {
794            node as *const dyn ModifierNode as *const ()
795        }
796
797        let target = node_data_ptr(node);
798        // A node comes before its delegates, so a delegate that starts its
799        // node's memory finds the node.
800        (0..self.order_len())
801            .find(|&index| {
802                self.with_path(self.order_at(index).0, |node| node_data_ptr(node) == target)
803                    .unwrap_or(false)
804            })
805            .map(|index| self.node_ref(ChainPosition::Node(index)))
806    }
807
808    /// Downcasts the node at `index` to the requested type.
809    /// Returns a `Ref` guard that dereferences to the node type.
810    pub fn node<N: ModifierNode + 'static>(&self, index: usize) -> Option<std::cell::Ref<'_, N>> {
811        self.entries.get(index).and_then(|entry| {
812            std::cell::Ref::filter_map(entry.node.borrow(), |boxed_node| {
813                boxed_node.as_any().downcast_ref::<N>()
814            })
815            .ok()
816        })
817    }
818
819    /// Downcasts the node at `index` to the requested mutable type.
820    /// Returns a `RefMut` guard that dereferences to the node type.
821    pub fn node_mut<N: ModifierNode + 'static>(
822        &self,
823        index: usize,
824    ) -> Option<std::cell::RefMut<'_, N>> {
825        self.entries.get(index).and_then(|entry| {
826            std::cell::RefMut::filter_map(entry.node.borrow_mut(), |boxed_node| {
827                boxed_node.as_any_mut().downcast_mut::<N>()
828            })
829            .ok()
830        })
831    }
832
833    /// Returns the shared node at the given index. Coordinators compare it
834    /// with the node they hold and clone it only to hold a new one.
835    pub fn get_node_rc(&self, index: usize) -> Option<&Rc<RefCell<dyn ModifierNode>>> {
836        self.entries.get(index).map(|entry| &entry.node)
837    }
838
839    /// Returns true if the chain contains any nodes matching the given invalidation kind.
840    pub fn has_nodes_for_invalidation(&self, kind: InvalidationKind) -> bool {
841        self.aggregated_capabilities
842            .contains(NodeCapabilities::for_invalidation(kind))
843    }
844
845    /// Visits every node mutably in insertion order together with its capability mask.
846    pub fn visit_nodes_mut<F>(&mut self, mut f: F)
847    where
848        F: FnMut(&mut dyn ModifierNode, NodeCapabilities),
849    {
850        for index in 0..self.order_len() {
851            let (path, cached_caps, _agg) = self.order_at(index);
852            let mut node_borrow = self.entries[path.entry()].node.borrow_mut();
853            let mut current: &mut dyn ModifierNode = &mut *node_borrow;
854            for &delegate_index in path.delegates() {
855                match nth_delegate_mut(current, delegate_index as usize) {
856                    Some(delegate) => current = delegate,
857                    None => return,
858                }
859            }
860            f(current, cached_caps);
861        }
862    }
863
864    pub(super) fn node_ref(&self, position: ChainPosition) -> ModifierChainNodeRef<'_> {
865        ModifierChainNodeRef {
866            chain: self,
867            position,
868        }
869    }
870
871    // Runs `f` on the node at `path`; `None` when a delegate of it is gone.
872    pub(super) fn with_path<R>(
873        &self,
874        path: NodePath,
875        f: impl FnOnce(&dyn ModifierNode) -> R,
876    ) -> Option<R> {
877        let node_borrow = self.entries[path.entry()].node.borrow();
878        let mut current: &dyn ModifierNode = &*node_borrow;
879        for &delegate_index in path.delegates() {
880            current = nth_delegate(current, delegate_index as usize)?;
881        }
882        Some(f(current))
883    }
884
885    // How many nodes the chain's order holds, delegates included.
886    pub(super) fn order_len(&self) -> usize {
887        if self.delegated_order.is_empty() {
888            self.entries.len()
889        } else {
890            self.delegated_order.len()
891        }
892    }
893
894    // The node at `index` of the chain's order: its path, its capabilities
895    // and the union of capabilities from it to the tail.
896    pub(super) fn order_at(&self, index: usize) -> (NodePath, NodeCapabilities, NodeCapabilities) {
897        if self.delegated_order.is_empty() {
898            let entry = &self.entries[index];
899            (NodePath::root(index), entry.capabilities, entry.aggregate)
900        } else {
901            self.delegated_order[index]
902        }
903    }
904
905    // Orders the nodes again and works out the union of capabilities from
906    // each node to the tail.
907    fn sync_chain_links(&mut self) {
908        self.rebuild_delegated_order();
909        let mut aggregate = NodeCapabilities::empty();
910        if self.delegated_order.is_empty() {
911            for entry in self.entries.iter_mut().rev() {
912                aggregate |= entry.capabilities;
913                entry.aggregate = aggregate;
914            }
915        } else {
916            for (_, caps, aggregate_child) in self.delegated_order.iter_mut().rev() {
917                aggregate |= *caps;
918                *aggregate_child = aggregate;
919            }
920        }
921        self.aggregated_capabilities = aggregate;
922    }
923
924    fn rebuild_delegated_order(&mut self) {
925        let delegates = self.entries.iter().any(|entry| {
926            let mut delegates = false;
927            entry
928                .node
929                .borrow()
930                .for_each_delegate(&mut |_| delegates = true);
931            delegates
932        });
933        if !delegates {
934            self.delegated_order = Vec::new();
935            return;
936        }
937        self.delegated_order.clear();
938        let mut path_buf = [0usize; MAX_DELEGATE_DEPTH];
939        for (index, entry) in self.entries.iter().enumerate() {
940            let node_borrow = entry.node.borrow();
941            Self::enumerate_link_order(
942                &*node_borrow,
943                index,
944                &mut path_buf,
945                0,
946                &mut self.delegated_order,
947            );
948        }
949    }
950
951    fn enumerate_link_order(
952        node: &dyn ModifierNode,
953        entry: usize,
954        path_buf: &mut [usize; MAX_DELEGATE_DEPTH],
955        path_len: usize,
956        out: &mut Vec<(NodePath, NodeCapabilities, NodeCapabilities)>,
957    ) {
958        let caps = node.node_state().capabilities();
959        out.push((
960            NodePath::from_slice(entry, &path_buf[..path_len]),
961            caps,
962            NodeCapabilities::empty(),
963        ));
964        let mut delegate_index = 0usize;
965        node.for_each_delegate(&mut |child| {
966            if path_len < MAX_DELEGATE_DEPTH {
967                path_buf[path_len] = delegate_index;
968                Self::enumerate_link_order(child, entry, path_buf, path_len + 1, out);
969            }
970            delegate_index += 1;
971        });
972    }
973}