Skip to main content

universal_weave/independent/
mod.rs

1//! [`IndependentWeave`] is a DAG-based [`Weave`] where each [`Node`] does *not* depend on the contents of the previous Node.
2
3use alloc::vec::Vec;
4use core::{
5    cmp::Ordering,
6    hash::{BuildHasher, Hash},
7    mem,
8};
9
10use hashbrown::{HashMap, HashSet};
11use indexmap::IndexSet;
12use scratchpads::{Scratchpad, ScratchpadMap};
13
14#[cfg(debug_assertions)]
15use contracts::contract;
16
17#[cfg(feature = "rkyv")]
18use rkyv::{
19    Archive, Deserialize, Serialize,
20    bytecheck::Verify,
21    collections::swiss_table::{ArchivedHashMap, ArchivedHashSet, ArchivedIndexSet},
22    rancor::{Fallible, Source, fail},
23    with::Skip,
24};
25
26#[cfg(feature = "serde")]
27use serde::{
28    Deserialize as SerdeDeserialize, Deserializer as SerdeDeserializer,
29    Serialize as SerdeSerialize, de::Error as _,
30};
31
32use crate::{
33    ActivePathWeave, BookmarkableWeave, DiscreteContentResult, DiscreteContents, DiscreteWeave,
34    IndependentContents, MetadataWeave, Node, SemiIndependentWeave, SortableBookmarkableWeave,
35    SortableWeave, Weave, ancestor_subgraph, ancestor_subgraph_reaches,
36    contract::valid_topology,
37    dependent::{DependentNode, DependentWeave},
38    descendant_subgraph, descendant_subgraph_reaches, longest_candidate_path_to_root,
39    shortest_path_to_ancestor, topological_sort, topological_sort_subgraph,
40};
41
42#[cfg(debug_assertions)]
43use crate::contract::{lacks_duplicates, valid_path, valid_topological_sort};
44
45#[cfg(feature = "rkyv")]
46use crate::{
47    ImmutableActivePathWeave, ImmutableBookmarkableWeave, ImmutableMetadataWeave, ImmutableWeave,
48    archived_ancestor_subgraph, archived_descendant_subgraph,
49    archived_longest_candidate_path_to_root, archived_shortest_path_to_ancestor,
50    archived_topological_sort, archived_topological_sort_subgraph,
51    contract::archived_valid_topology,
52};
53
54#[cfg(any(feature = "serde", feature = "rkyv"))]
55use crate::contract::ValidationError;
56
57#[derive(Default, Debug, Clone)]
58#[cfg_attr(feature = "rkyv", derive(Archive, Deserialize, Serialize))]
59#[cfg_attr(feature = "serde", derive(SerdeSerialize, SerdeDeserialize))]
60/// A [`Node`] in a [`IndependentWeave`] document.
61#[must_use]
62pub struct IndependentNode<K, T, S>
63where
64    K: Hash + Copy + Eq + Ord,
65    T: IndependentContents,
66    S: BuildHasher + Default + Clone,
67{
68    /// The node's unique identifier.
69    pub id: K,
70    /// The identifiers corresponding to the node's parents.
71    #[cfg_attr(
72        feature = "serde",
73        serde(bound(
74            serialize = "IndexSet<K, S>: SerdeSerialize",
75            deserialize = "IndexSet<K, S>: SerdeDeserialize<'de>"
76        ))
77    )]
78    pub from: IndexSet<K, S>,
79    /// The identifiers corresponding to the node's children.
80    #[cfg_attr(
81        feature = "serde",
82        serde(bound(
83            serialize = "IndexSet<K, S>: SerdeSerialize",
84            deserialize = "IndexSet<K, S>: SerdeDeserialize<'de>"
85        ))
86    )]
87    pub to: IndexSet<K, S>,
88    /// If the node should be considered active.
89    ///
90    /// Unlike [`DependentWeave`], [`IndependentWeave`] considers all nodes within an active path to be active.
91    pub active: bool,
92    /// If the node is bookmarked.
93    pub bookmarked: bool,
94    /// The node's contents.
95    pub contents: T,
96}
97
98#[allow(clippy::missing_trait_methods, reason = "Conflicting lint")]
99impl<K, T, S> PartialEq for IndependentNode<K, T, S>
100where
101    K: Hash + Copy + Eq + Ord,
102    T: IndependentContents + PartialEq,
103    S: BuildHasher + Default + Clone,
104{
105    #[inline]
106    fn eq(&self, other: &Self) -> bool {
107        self.id == other.id
108            && self.from.len() == other.from.len()
109            && self.to.len() == other.to.len()
110            && self.active == other.active
111            && self.bookmarked == other.bookmarked
112            && self.from.iter().zip(other.from.iter()).all(|(a, b)| a == b)
113            && self.to.iter().zip(other.to.iter()).all(|(a, b)| a == b)
114            && self.contents == other.contents
115    }
116}
117
118#[allow(clippy::missing_trait_methods, reason = "Conflicting lint")]
119impl<K, T, S> Eq for IndependentNode<K, T, S>
120where
121    K: Hash + Copy + Eq + Ord,
122    T: IndependentContents + Eq,
123    S: BuildHasher + Default + Clone,
124{
125}
126
127impl<K, T, S> IndependentNode<K, T, S>
128where
129    K: Hash + Copy + Eq + Ord,
130    T: IndependentContents,
131    S: BuildHasher + Default + Clone,
132{
133    fn validate(&self) -> bool {
134        self.from.is_disjoint(&self.to)
135            && !self.from.contains(&self.id)
136            && !self.to.contains(&self.id)
137    }
138}
139
140impl<K, T, S> Node<K, T> for IndependentNode<K, T, S>
141where
142    K: Hash + Copy + Eq + Ord,
143    T: IndependentContents,
144    S: BuildHasher + Default + Clone,
145{
146    type From = IndexSet<K, S>;
147    type To = IndexSet<K, S>;
148
149    #[inline]
150    fn id(&self) -> K {
151        self.id
152    }
153    #[inline]
154    fn from(&self) -> &Self::From {
155        &self.from
156    }
157    #[inline]
158    fn to(&self) -> &Self::To {
159        &self.to
160    }
161    #[inline]
162    fn is_active(&self) -> bool {
163        self.active
164    }
165    #[inline]
166    fn contents(&self) -> &T {
167        &self.contents
168    }
169}
170
171impl<K, T, S> From<DependentNode<K, T, S>> for IndependentNode<K, T, S>
172where
173    K: Hash + Copy + Eq + Ord,
174    T: IndependentContents,
175    S: BuildHasher + Default + Clone,
176{
177    #[inline]
178    fn from(value: DependentNode<K, T, S>) -> Self {
179        Self {
180            id: value.id,
181            from: IndexSet::from_iter(value.from),
182            to: value.to,
183            active: value.active,
184            bookmarked: value.bookmarked,
185            contents: value.contents,
186        }
187    }
188}
189
190impl<K, T, S> TryFrom<IndependentNode<K, T, S>> for DependentNode<K, T, S>
191where
192    K: Hash + Copy + Eq + Ord,
193    T: IndependentContents,
194    S: BuildHasher + Default + Clone,
195{
196    type Error = IndependentNode<K, T, S>;
197
198    #[inline]
199    fn try_from(value: IndependentNode<K, T, S>) -> Result<Self, Self::Error> {
200        if value.from.len() < 2 {
201            Ok(Self {
202                id: value.id,
203                from: value.from.into_iter().next(),
204                to: value.to,
205                active: value.active,
206                bookmarked: value.bookmarked,
207                contents: value.contents,
208            })
209        } else {
210            Err(value)
211        }
212    }
213}
214
215/// A DAG-based [`Weave`] where each [`Node`] does *not* depend on the contents of the previous Node.
216///
217/// However, this additional flexibility results in worse performance and memory usage characteristics:
218/// - Memory overhead is approximately doubled.
219/// - Updating node activation has a worst-case time complexity of O(V + E) rather than [`DependentWeave`]'s O(1), so bulk operations must be done carefully to prevent accidentally quadratic behavior.
220///
221/// For best performance, it is recommended that you use random node identifiers and the [`Hasher`](core::hash::Hasher) implementation from the [nohash-hasher](https://crates.io/crates/nohash-hasher) crate. If your node identifiers end with random data (such as ULIDs in their raw representation), use the [hash_hasher](https://crates.io/crates/hash_hasher) crate instead.
222#[derive(Debug, Clone)]
223#[cfg_attr(feature = "rkyv", derive(Archive, Deserialize, Serialize))]
224#[cfg_attr(feature = "serde", derive(SerdeSerialize))]
225#[cfg_attr(feature = "rkyv", rkyv(bytecheck(verify)))]
226#[must_use]
227pub struct IndependentWeave<K, T, M, S>
228where
229    K: Hash + Copy + Eq + Ord,
230    T: IndependentContents,
231    S: BuildHasher + Default + Clone,
232{
233    #[cfg_attr(
234        feature = "serde",
235        serde(bound(
236            serialize = "HashMap<K, IndependentNode<K, T, S>, S>: SerdeSerialize",
237            deserialize = "HashMap<K, IndependentNode<K, T, S>, S>: SerdeDeserialize<'de>"
238        ))
239    )]
240    pub(super) nodes: HashMap<K, IndependentNode<K, T, S>, S>,
241    #[cfg_attr(
242        feature = "serde",
243        serde(bound(
244            serialize = "IndexSet<K, S>: SerdeSerialize",
245            deserialize = "IndexSet<K, S>: SerdeDeserialize<'de>"
246        ))
247    )]
248    pub(super) roots: IndexSet<K, S>,
249    #[cfg_attr(
250        feature = "serde",
251        serde(bound(
252            serialize = "HashSet<K, S>: SerdeSerialize",
253            deserialize = "HashSet<K, S>: SerdeDeserialize<'de>"
254        ))
255    )]
256    pub(super) active: HashSet<K, S>,
257    #[cfg_attr(
258        feature = "serde",
259        serde(bound(
260            serialize = "IndexSet<K, S>: SerdeSerialize",
261            deserialize = "IndexSet<K, S>: SerdeDeserialize<'de>"
262        ))
263    )]
264    pub(super) bookmarked: IndexSet<K, S>,
265
266    #[cfg_attr(feature = "rkyv", rkyv(with = Skip))]
267    #[cfg_attr(feature = "serde", serde(skip))]
268    pub(super) scratchpad: Scratchpad,
269
270    /// The metadata associated with the weave.
271    pub metadata: M,
272}
273
274impl<K, T, M, S> Default for IndependentWeave<K, T, M, S>
275where
276    K: Hash + Copy + Eq + Ord,
277    T: IndependentContents,
278    S: BuildHasher + Default + Clone,
279    M: Default,
280{
281    fn default() -> Self {
282        Self::new(M::default())
283    }
284}
285
286#[cfg(feature = "serde")]
287#[derive(SerdeDeserialize)]
288#[serde(rename = "IndependentWeave")]
289struct ProxyIndependentWeave<K, T, M, S>
290where
291    K: Hash + Copy + Eq + Ord,
292    T: IndependentContents,
293    S: BuildHasher + Default + Clone,
294{
295    #[serde(bound(
296        serialize = "HashMap<K, IndependentNode<K, T, S>, S>: SerdeSerialize",
297        deserialize = "HashMap<K, IndependentNode<K, T, S>, S>: SerdeDeserialize<'de>"
298    ))]
299    nodes: HashMap<K, IndependentNode<K, T, S>, S>,
300    #[serde(bound(
301        serialize = "IndexSet<K, S>: SerdeSerialize",
302        deserialize = "IndexSet<K, S>: SerdeDeserialize<'de>"
303    ))]
304    roots: IndexSet<K, S>,
305    #[serde(bound(
306        serialize = "HashSet<K, S>: SerdeSerialize",
307        deserialize = "HashSet<K, S>: SerdeDeserialize<'de>"
308    ))]
309    active: HashSet<K, S>,
310    #[serde(bound(
311        serialize = "IndexSet<K, S>: SerdeSerialize",
312        deserialize = "IndexSet<K, S>: SerdeDeserialize<'de>"
313    ))]
314    bookmarked: IndexSet<K, S>,
315    metadata: M,
316}
317
318#[cfg(feature = "serde")]
319#[allow(clippy::missing_trait_methods, reason = "Conflicting lint")]
320impl<'de, K, T, M, S> SerdeDeserialize<'de> for IndependentWeave<K, T, M, S>
321where
322    K: Hash + Copy + Eq + Ord + SerdeDeserialize<'de>,
323    T: IndependentContents + SerdeDeserialize<'de>,
324    M: SerdeDeserialize<'de>,
325    S: BuildHasher + Default + Clone,
326{
327    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
328    where
329        D: SerdeDeserializer<'de>,
330    {
331        let proxy = ProxyIndependentWeave::deserialize(deserializer)?;
332        let weave = Self {
333            nodes: proxy.nodes,
334            roots: proxy.roots,
335            active: proxy.active,
336            bookmarked: proxy.bookmarked,
337            scratchpad: Scratchpad::new(),
338            metadata: proxy.metadata,
339        };
340
341        if weave.validate() {
342            Ok(weave)
343        } else {
344            Err(D::Error::custom(ValidationError))
345        }
346    }
347}
348
349#[allow(clippy::missing_trait_methods, reason = "Conflicting lint")]
350impl<K, T, M, S> PartialEq for IndependentWeave<K, T, M, S>
351where
352    K: Hash + Copy + Eq + Ord,
353    T: IndependentContents + PartialEq,
354    M: PartialEq,
355    S: BuildHasher + Default + Clone,
356{
357    #[inline]
358    fn eq(&self, other: &Self) -> bool {
359        self.roots.len() == other.roots.len()
360            && self.bookmarked.len() == other.bookmarked.len()
361            && self.nodes.len() == other.nodes.len()
362            && self.active == other.active
363            && self
364                .roots
365                .iter()
366                .zip(other.roots.iter())
367                .all(|(a, b)| a == b)
368            && self
369                .bookmarked
370                .iter()
371                .zip(other.bookmarked.iter())
372                .all(|(a, b)| a == b)
373            && self.nodes == other.nodes
374            && self.metadata == other.metadata
375    }
376}
377
378#[allow(clippy::missing_trait_methods, reason = "Conflicting lint")]
379impl<K, T, M, S> Eq for IndependentWeave<K, T, M, S>
380where
381    K: Hash + Copy + Eq + Ord,
382    T: IndependentContents + Eq,
383    M: Eq,
384    S: BuildHasher + Default + Clone,
385{
386}
387
388impl<K, T, M, S> IndependentWeave<K, T, M, S>
389where
390    K: Hash + Copy + Eq + Ord,
391    T: IndependentContents,
392    S: BuildHasher + Default + Clone,
393{
394    /// Creates a new, empty [`IndependentWeave`].
395    #[cfg_attr(debug_assertions, contract(
396        ensures(ret.nodes.is_empty()),
397        ensures(ret.validate())
398    ))]
399    pub fn new(metadata: M) -> Self {
400        Self {
401            nodes: HashMap::with_hasher(S::default()),
402            roots: IndexSet::with_hasher(S::default()),
403            active: HashSet::with_hasher(S::default()),
404            bookmarked: IndexSet::with_hasher(S::default()),
405            scratchpad: Scratchpad::new(),
406            metadata,
407        }
408    }
409    /// Creates a new, empty [`IndependentWeave`] with at least the specified capacity.
410    ///
411    /// This function over-allocates for worst-case memory usage rather than average-case.
412    #[cfg_attr(debug_assertions, contract(
413        ensures(ret.nodes.is_empty()),
414        ensures(ret.validate())
415    ))]
416    pub fn with_capacity(capacity: usize, metadata: M) -> Self {
417        let nodes = HashMap::with_capacity_and_hasher(capacity, S::default());
418        let capacity = nodes.capacity();
419
420        Self {
421            nodes,
422            roots: IndexSet::with_capacity_and_hasher(capacity, S::default()),
423            active: HashSet::with_capacity_and_hasher(capacity, S::default()),
424            bookmarked: IndexSet::with_capacity_and_hasher(capacity, S::default()),
425            scratchpad: Scratchpad::new(),
426            metadata,
427        }
428    }
429    /// Returns the worst-case number of nodes that the weave can hold without reallocating.
430    ///
431    /// May be lower than `self.len()`.
432    #[inline]
433    pub fn capacity(&self) -> usize {
434        self.nodes
435            .capacity()
436            .min(self.roots.capacity())
437            .min(self.active.capacity())
438            .min(self.bookmarked.capacity())
439    }
440    /// Reserves capacity for at least `additional` more nodes.
441    pub fn reserve(&mut self, additional: usize) {
442        self.nodes.reserve(additional);
443        self.roots
444            .reserve(self.nodes.capacity().saturating_sub(self.roots.len()));
445        self.active
446            .reserve(self.nodes.capacity().saturating_sub(self.active.len()));
447        self.bookmarked
448            .reserve(self.nodes.capacity().saturating_sub(self.bookmarked.len()));
449    }
450    /// Shrinks the capacity of the weave as much as possible.
451    pub fn shrink_to_fit(&mut self) {
452        self.nodes.shrink_to_fit();
453        self.roots.shrink_to_fit();
454        self.active.shrink_to_fit();
455        self.bookmarked.shrink_to_fit();
456        self.scratchpad = Scratchpad::new();
457    }
458    #[cfg_attr(debug_assertions, contract(
459        ensures(ret == self.nodes.contains_key(id)),
460        ensures(!ret || value == self.active.contains(id)),
461        ensures(self.validate())
462    ))]
463    fn update_node_activity_in_place(&mut self, id: &K, value: bool) -> bool {
464        let at_end = if let Some(node) = self.nodes.get(id) {
465            if node.active == value {
466                return true;
467            }
468
469            if value {
470                (node.from.is_empty() && self.active.is_empty())
471                    || node.from.iter().any(|parent| {
472                        self.active.contains(parent)
473                            && self.nodes[parent]
474                                .to
475                                .iter()
476                                .all(|child| !self.active.contains(child))
477                    })
478            } else {
479                node.to.iter().all(|child| !self.active.contains(child))
480            }
481        } else {
482            return false;
483        };
484
485        let node = self.nodes.get_mut(id).unwrap();
486        node.active = value;
487        if value {
488            self.active.insert(node.id);
489        } else {
490            self.active.remove(id);
491        }
492
493        if at_end {
494            return true;
495        }
496
497        if value {
498            let has_descendants = !node.to.is_empty();
499
500            let guard = self.scratchpad.guard();
501
502            let mut stack = guard.vec();
503            let mut closure = guard.set(S::default());
504            let mut closure_roots = guard.vec();
505
506            ancestor_subgraph(&self.nodes, *id, &mut stack, &mut closure, |id| {
507                closure_roots.push(id);
508            });
509
510            let mut topological = guard.vec_with_capacity(closure.len());
511            let mut scratchpad_map = guard.map_with_capacity(closure.len(), S::default());
512            let mut scratchpad_map_2: ScratchpadMap<'_, K, ((usize, usize), Option<K>), S> =
513                guard.map_with_capacity(closure.len(), S::default());
514            let mut scratchpad_set = guard.set(S::default());
515
516            for root in closure_roots.drain(..) {
517                topological_sort_subgraph(
518                    &self.nodes,
519                    |id| closure.contains(id),
520                    root,
521                    &mut stack,
522                    |id| topological.push(id),
523                    &mut scratchpad_map,
524                );
525            }
526
527            for id in topological.iter().copied() {
528                let node = &self.nodes[&id];
529
530                let best_parent = node
531                    .from
532                    .iter()
533                    .map(|id| (id, scratchpad_map_2[id].0)) // score: (connectors, active)
534                    .min_by(|(_, a), (_, b)| b.1.cmp(&a.1).then(a.0.cmp(&b.0)));
535
536                let (parent, score) = if let Some((parent, mut score)) = best_parent {
537                    #[allow(clippy::arithmetic_side_effects, reason = "Can never overflow")]
538                    if node.active {
539                        score.1 += 1;
540                    } else {
541                        score.0 += 1;
542                    }
543
544                    (Some(parent), score)
545                } else {
546                    (None, if node.active { (0, 1) } else { (1, 0) })
547                };
548
549                scratchpad_map_2.insert(id, (score, parent.copied()));
550            }
551
552            let mut current = Some(id);
553
554            while let Some(id) = current {
555                scratchpad_set.insert(*id);
556                current = scratchpad_map_2
557                    .get(id)
558                    .and_then(|(_, parent)| parent.as_ref());
559            }
560
561            closure.clear();
562            topological.clear();
563            scratchpad_map.clear();
564            scratchpad_map_2.clear();
565
566            if self.active.len() != 1 && has_descendants {
567                descendant_subgraph(&self.nodes, *id, &mut stack, &mut closure);
568
569                let has_active_descendant = if closure.len() >= self.active.len() {
570                    self.active.iter().any(|a| a != id && closure.contains(a))
571                } else {
572                    closure.iter().any(|d| d != id && self.active.contains(d))
573                };
574
575                if has_active_descendant {
576                    topological_sort_subgraph(
577                        &self.nodes,
578                        |id| closure.contains(id),
579                        *id,
580                        &mut stack,
581                        |id| topological.push(id),
582                        &mut scratchpad_map,
583                    );
584
585                    for id in topological.drain(..).rev() {
586                        let node = &self.nodes[&id];
587
588                        let best_child = node
589                            .to
590                            .iter()
591                            .map(|id| (id, scratchpad_map_2[id].0)) // score: (connectors, active)
592                            .min_by(|(_, a), (_, b)| b.1.cmp(&a.1).then(a.0.cmp(&b.0)));
593
594                        let (child, score) = if let Some((child, mut score)) = best_child {
595                            #[allow(clippy::arithmetic_side_effects, reason = "Can never overflow")]
596                            if node.active {
597                                score.1 += 1;
598                            } else {
599                                score.0 += 1;
600                            }
601
602                            (Some(child), score)
603                        } else {
604                            (None, if node.active { (0, 1) } else { (1, 0) })
605                        };
606
607                        scratchpad_map_2.insert(id, (score, child.copied()));
608                    }
609
610                    let mut current = Some(id);
611
612                    while let Some(id) = current {
613                        scratchpad_set.insert(*id);
614
615                        let (score, successor) = &scratchpad_map_2[id];
616                        current = if score.1 > usize::from(self.nodes[id].active) {
617                            successor.as_ref()
618                        } else {
619                            None
620                        };
621                    }
622                }
623            }
624
625            let mut disjoint = topological;
626
627            disjoint.extend(
628                self.active
629                    .iter()
630                    .filter(|id| !scratchpad_set.contains(*id))
631                    .copied(),
632            );
633
634            for id in disjoint.drain(..) {
635                self.nodes.get_mut(&id).unwrap().active = false;
636                self.active.remove(&id);
637            }
638
639            disjoint.extend(
640                scratchpad_set
641                    .iter()
642                    .filter(|id| !self.active.contains(*id))
643                    .copied(),
644            );
645
646            for id in disjoint.drain(..) {
647                self.nodes.get_mut(&id).unwrap().active = true;
648                self.active.insert(id);
649            }
650        } else {
651            self.fix_orphaned_activations();
652        }
653
654        true
655    }
656    #[cfg_attr(debug_assertions, contract(
657        ensures(self.validate())
658    ))]
659    fn fix_orphaned_activations(&mut self) {
660        if self.active.is_empty() {
661            return;
662        }
663
664        let guard = self.scratchpad.guard();
665
666        let mut stack = guard.vec();
667        let mut closure = guard.set_with_capacity(self.active.len(), S::default());
668
669        for id in self.active.iter().copied() {
670            ancestor_subgraph(&self.nodes, id, &mut stack, &mut closure, |_| {});
671        }
672
673        let mut topological = guard.vec_with_capacity(closure.len());
674        let mut scratchpad_map = guard.map_with_capacity(closure.len(), S::default());
675
676        for root in self
677            .roots
678            .iter()
679            .filter(|id| closure.contains(*id))
680            .copied()
681        {
682            topological_sort_subgraph(
683                &self.nodes,
684                |id| closure.contains(id),
685                root,
686                &mut stack,
687                |id| topological.push(id),
688                &mut scratchpad_map,
689            );
690        }
691
692        let mut candidate_path = guard.vec_with_capacity(self.active.len());
693
694        longest_candidate_path_to_root(
695            &self.nodes,
696            &topological,
697            |id| self.active.contains(id),
698            &mut guard.map_with_capacity(self.active.len(), S::default()),
699            |id| candidate_path.push(id),
700        );
701
702        topological.clear();
703        let mut disjoint = topological;
704
705        closure.clear();
706        let mut candidate_path_set = closure;
707
708        candidate_path_set.extend(candidate_path.drain(..));
709
710        disjoint.extend(
711            self.active
712                .iter()
713                .filter(|id| !candidate_path_set.contains(*id))
714                .copied(),
715        );
716
717        for orphan in disjoint.drain(..) {
718            self.active.remove(&orphan);
719            if let Some(node) = self.nodes.get_mut(&orphan) {
720                node.active = false;
721            }
722        }
723    }
724    #[cfg_attr(debug_assertions, contract(
725        ensures(!ret || value || !self.active.contains(id) || (old(self.active.clone()) == self.active && self.nodes[id].to.iter().any(|id| self.contains_active(id)))),
726        ensures(!ret || !value || self.contains_active(id) && !self.nodes[id].to.iter().any(|id| self.active.contains(id))),
727        ensures(ret || old(self.active.clone()) == self.active),
728        ensures(ret == self.nodes.contains_key(id)),
729        ensures(old(self.nodes.keys().copied().collect::<HashSet<_>>()) == self.nodes.keys().copied().collect::<HashSet<_>>()),
730        ensures(old(self.roots.clone()) == self.roots),
731        ensures(old(self.bookmarked.clone()) == self.bookmarked),
732        invariant(self.validate())
733    ))]
734    #[allow(clippy::missing_panics_doc, reason = "Should never panic")]
735    /// Sets the active status of a node with the specified identifier, using identical activation behavior to [`DependentWeave`].
736    pub fn set_active_dependent_semantics(&mut self, id: &K, value: bool) -> bool {
737        if value {
738            if let Some(node) = self.nodes.get(id) {
739                if node.active && !node.to.iter().any(|id| self.active.contains(id)) {
740                    return true;
741                }
742
743                if !node.active
744                    && ((node.from.is_empty() && self.active.is_empty())
745                        || node.from.iter().any(|parent| {
746                            self.active.contains(parent)
747                                && self.nodes[parent]
748                                    .to
749                                    .iter()
750                                    .all(|child| !self.active.contains(child))
751                        }))
752                {
753                    self.nodes.get_mut(id).unwrap().active = true;
754                    self.active.insert(*id);
755                    return true;
756                }
757            } else {
758                return false;
759            }
760
761            let guard = self.scratchpad.guard();
762
763            let mut stack = guard.vec();
764            let mut closure = guard.set(S::default());
765            let mut closure_roots = guard.vec();
766
767            ancestor_subgraph(&self.nodes, *id, &mut stack, &mut closure, |id| {
768                closure_roots.push(id);
769            });
770
771            let mut topological = guard.vec_with_capacity(closure.len());
772            let mut scratchpad_map = guard.map_with_capacity(closure.len(), S::default());
773            let mut scratchpad_map_2: ScratchpadMap<'_, K, ((usize, usize), Option<K>), S> =
774                guard.map_with_capacity(closure.len(), S::default());
775
776            for root in closure_roots.drain(..) {
777                topological_sort_subgraph(
778                    &self.nodes,
779                    |id| closure.contains(id),
780                    root,
781                    &mut stack,
782                    |id| topological.push(id), // topological order
783                    &mut scratchpad_map,
784                );
785            }
786
787            for id in topological.drain(..) {
788                let node = &self.nodes[&id];
789
790                let best_parent = node
791                    .from
792                    .iter()
793                    .map(|id| (id, scratchpad_map_2[id].0)) // score: (connectors, active)
794                    .min_by(|(_, a), (_, b)| b.1.cmp(&a.1).then(a.0.cmp(&b.0)));
795
796                let (parent, score) = if let Some((parent, mut score)) = best_parent {
797                    #[allow(clippy::arithmetic_side_effects, reason = "Can never overflow")]
798                    if node.active {
799                        score.1 += 1;
800                    } else {
801                        score.0 += 1;
802                    }
803
804                    (Some(parent), score)
805                } else {
806                    (None, if node.active { (0, 1) } else { (1, 0) })
807                };
808
809                scratchpad_map_2.insert(id, (score, parent.copied()));
810            }
811
812            closure.clear();
813            let mut scratchpad_set = closure;
814
815            let mut disjoint = topological;
816
817            let mut current = Some(id);
818
819            while let Some(id) = current {
820                scratchpad_set.insert(*id);
821                current = scratchpad_map_2
822                    .get(id)
823                    .and_then(|(_, parent)| parent.as_ref());
824            }
825
826            disjoint.extend(
827                self.active
828                    .iter()
829                    .filter(|id| !scratchpad_set.contains(*id))
830                    .copied(),
831            );
832
833            for id in disjoint.drain(..) {
834                self.nodes.get_mut(&id).unwrap().active = false;
835                self.active.remove(&id);
836            }
837
838            disjoint.extend(
839                scratchpad_set
840                    .iter()
841                    .filter(|id| !self.active.contains(*id))
842                    .copied(),
843            );
844
845            for id in disjoint.drain(..) {
846                self.nodes.get_mut(&id).unwrap().active = true;
847                self.active.insert(id);
848            }
849        } else if let Some(node) = self.nodes.get_mut(id) {
850            if !node.active || node.to.iter().any(|id| self.active.contains(id)) {
851                return true;
852            }
853
854            node.active = false;
855            self.active.remove(&node.id);
856        } else {
857            return false;
858        }
859
860        true
861    }
862}
863
864impl<K, T, M, S> From<DependentWeave<K, T, M, S>> for IndependentWeave<K, T, M, S>
865where
866    K: Hash + Copy + Eq + Ord,
867    T: IndependentContents,
868    S: BuildHasher + Default + Clone,
869{
870    fn from(value: DependentWeave<K, T, M, S>) -> Self {
871        let mut output = Self {
872            active: HashSet::with_capacity_and_hasher(value.nodes.capacity(), S::default()),
873            nodes: {
874                let mut map =
875                    HashMap::with_capacity_and_hasher(value.nodes.capacity(), S::default());
876                map.extend(value.nodes.into_iter().map(|(id, mut node)| {
877                    node.active = false;
878                    (id, node.into())
879                }));
880
881                map
882            },
883            roots: value.roots,
884            bookmarked: value.bookmarked,
885            scratchpad: value.scratchpad,
886            metadata: value.metadata,
887        };
888
889        if let Some(active) = value.active {
890            output.set_active(&active, true);
891        }
892
893        debug_assert!(output.validate(), "Converted weave is malformed");
894
895        output
896    }
897}
898
899#[allow(clippy::panic_in_result_fn, reason = "Should never panic")]
900#[allow(clippy::unreachable, reason = "Should never panic")]
901impl<K, T, M, S> TryFrom<IndependentWeave<K, T, M, S>> for DependentWeave<K, T, M, S>
902where
903    K: Hash + Copy + Eq + Ord,
904    T: IndependentContents,
905    S: BuildHasher + Default + Clone,
906{
907    type Error = IndependentWeave<K, T, M, S>;
908
909    fn try_from(value: IndependentWeave<K, T, M, S>) -> Result<Self, Self::Error> {
910        if value.nodes.iter().all(|(_, node)| node.from.len() < 2) {
911            let mut active = None;
912
913            let output = Self {
914                nodes: {
915                    let mut map =
916                        HashMap::with_capacity_and_hasher(value.nodes.capacity(), S::default());
917                    map.extend(value.nodes.into_iter().map(|(id, mut node)| {
918                        node.active =
919                            node.active && !node.to.iter().any(|id| value.active.contains(id));
920                        if node.active {
921                            active = Some(id);
922                        }
923
924                        node.try_into()
925                            .map_or_else(|_| unreachable!(), |node| (id, node))
926                    }));
927
928                    map
929                },
930                roots: value.roots,
931                active,
932                bookmarked: value.bookmarked,
933                scratchpad: value.scratchpad,
934                metadata: value.metadata,
935            };
936
937            debug_assert!(output.validate(), "Converted weave is malformed");
938
939            Ok(output)
940        } else {
941            Err(value)
942        }
943    }
944}
945
946impl<K, T, M, S> Weave<K, IndependentNode<K, T, S>, T> for IndependentWeave<K, T, M, S>
947where
948    K: Hash + Copy + Eq + Ord,
949    T: IndependentContents,
950    S: BuildHasher + Default + Clone,
951{
952    type Nodes = HashMap<K, IndependentNode<K, T, S>, S>;
953    type Roots = IndexSet<K, S>;
954
955    #[inline]
956    fn len(&self) -> usize {
957        self.nodes.len()
958    }
959    #[inline]
960    fn is_empty(&self) -> bool {
961        self.nodes.is_empty()
962    }
963    #[inline]
964    fn nodes(&self) -> &Self::Nodes {
965        &self.nodes
966    }
967    #[inline]
968    fn roots(&self) -> &Self::Roots {
969        &self.roots
970    }
971    #[inline]
972    fn contains(&self, id: &K) -> bool {
973        self.nodes.contains_key(id)
974    }
975    #[inline]
976    fn contains_active(&self, id: &K) -> bool {
977        self.active.contains(id)
978    }
979    #[inline]
980    fn get(&self, id: &K) -> Option<&IndependentNode<K, T, S>> {
981        self.nodes.get(id)
982    }
983    #[inline]
984    fn get_parents(&self, id: &K) -> Option<&IndexSet<K, S>> {
985        self.nodes.get(id).map(|node| &node.from)
986    }
987    #[inline]
988    fn get_children(&self, id: &K) -> Option<&IndexSet<K, S>> {
989        self.nodes.get(id).map(|node| &node.to)
990    }
991    #[inline]
992    fn get_contents(&self, id: &K) -> Option<&T> {
993        self.nodes.get(id).map(|node| &node.contents)
994    }
995    #[cfg_attr(debug_assertions, contract(
996        ensures(output.len() == self.nodes.len()),
997        ensures(valid_topological_sort(&self.nodes, output)),
998        ensures(old(self.nodes.keys().copied().collect::<HashSet<_>>()) == self.nodes.keys().copied().collect::<HashSet<_>>()),
999        ensures(old(self.roots.clone()) == self.roots),
1000        ensures(old(self.active.clone()) == self.active),
1001        ensures(old(self.bookmarked.clone()) == self.bookmarked),
1002        invariant(self.validate())
1003    ))]
1004    fn get_ordered_identifiers(&mut self, output: &mut Vec<K>) {
1005        output.clear();
1006        output.reserve(self.nodes.len());
1007
1008        let guard = self.scratchpad.guard();
1009
1010        topological_sort(
1011            &self.nodes,
1012            self.roots.iter().copied(),
1013            &mut guard.vec_with_capacity(self.roots.len()),
1014            |id| output.push(id),
1015            &mut guard.map_with_capacity(self.nodes.len(), S::default()),
1016        );
1017    }
1018    #[cfg_attr(debug_assertions, contract(
1019        ensures(lacks_duplicates(output)),
1020        ensures(!self.nodes.contains_key(id) || output.first() == Some(id)),
1021        ensures(self.nodes.contains_key(id) || output.is_empty()),
1022        ensures(old(self.nodes.keys().copied().collect::<HashSet<_>>()) == self.nodes.keys().copied().collect::<HashSet<_>>()),
1023        ensures(old(self.roots.clone()) == self.roots),
1024        ensures(old(self.active.clone()) == self.active),
1025        ensures(old(self.bookmarked.clone()) == self.bookmarked),
1026        invariant(self.validate())
1027    ))]
1028    fn get_ordered_identifiers_from(&mut self, id: &K, output: &mut Vec<K>) {
1029        output.clear();
1030
1031        if self.nodes.contains_key(id) {
1032            let guard = self.scratchpad.guard();
1033
1034            let mut stack = guard.vec();
1035            let mut descendants = guard.set(S::default());
1036
1037            descendant_subgraph(&self.nodes, *id, &mut stack, &mut descendants);
1038
1039            output.reserve(descendants.len());
1040
1041            topological_sort_subgraph(
1042                &self.nodes,
1043                |id| descendants.contains(id),
1044                *id,
1045                &mut stack,
1046                |id| output.push(id),
1047                &mut guard.map_with_capacity(descendants.len(), S::default()),
1048            );
1049        }
1050    }
1051    #[cfg_attr(debug_assertions, contract(
1052        ensures(output.len() == self.active.len()),
1053        ensures(output.iter().all(|i| self.active.contains(i))),
1054        ensures(lacks_duplicates(output)),
1055        ensures(valid_path(&self.nodes, output)),
1056        ensures(old(self.nodes.keys().copied().collect::<HashSet<_>>()) == self.nodes.keys().copied().collect::<HashSet<_>>()),
1057        ensures(old(self.roots.clone()) == self.roots),
1058        ensures(old(self.active.clone()) == self.active),
1059        ensures(old(self.bookmarked.clone()) == self.bookmarked),
1060        invariant(self.validate())
1061    ))]
1062    fn get_active_path(&mut self, output: &mut Vec<K>) {
1063        output.clear();
1064
1065        if self.active.is_empty() {
1066            return;
1067        }
1068
1069        output.reserve(self.active.len());
1070
1071        let guard = self.scratchpad.guard();
1072
1073        let mut stack = guard.vec();
1074        let mut topological_subgraph = guard.vec_with_capacity(self.active.len());
1075        let mut scratchpad_map = guard.map_with_capacity(self.active.len(), S::default());
1076
1077        for root in self
1078            .roots
1079            .iter()
1080            .filter(|id| self.active.contains(*id))
1081            .copied()
1082        {
1083            topological_sort_subgraph(
1084                &self.nodes,
1085                |id| self.active.contains(id),
1086                root,
1087                &mut stack,
1088                |id| topological_subgraph.push(id),
1089                &mut scratchpad_map,
1090            );
1091        }
1092
1093        longest_candidate_path_to_root(
1094            &self.nodes,
1095            &topological_subgraph,
1096            |id| self.active.contains(id),
1097            &mut guard.map_with_capacity(self.active.len(), S::default()),
1098            |id| output.push(id),
1099        );
1100    }
1101    #[cfg_attr(debug_assertions, contract(
1102        ensures(!self.nodes.contains_key(id) || output.first() == Some(id)),
1103        ensures(self.nodes.contains_key(id) || output.is_empty()),
1104        ensures(lacks_duplicates(output)),
1105        ensures(valid_path(&self.nodes, output)),
1106        ensures(old(self.nodes.keys().copied().collect::<HashSet<_>>()) == self.nodes.keys().copied().collect::<HashSet<_>>()),
1107        ensures(old(self.roots.clone()) == self.roots),
1108        ensures(old(self.active.clone()) == self.active),
1109        ensures(old(self.bookmarked.clone()) == self.bookmarked),
1110        invariant(self.validate())
1111    ))]
1112    fn get_path_from(&mut self, id: &K, output: &mut Vec<K>) {
1113        output.clear();
1114        if !self.nodes.contains_key(id) {
1115            return;
1116        }
1117
1118        let guard = self.scratchpad.guard();
1119        let mut stack = guard.vec();
1120        let mut ancestors = guard.set(S::default());
1121        let mut root_ancestors = guard.vec();
1122
1123        ancestor_subgraph(&self.nodes, *id, &mut stack, &mut ancestors, |id| {
1124            root_ancestors.push(id);
1125        });
1126
1127        let mut active_topological_subgraph =
1128            guard.vec_with_capacity(self.active.len().min(ancestors.len()));
1129        let mut scratchpad_map =
1130            guard.map_with_capacity(self.active.len().min(ancestors.len()), S::default());
1131
1132        for root in root_ancestors
1133            .drain(..)
1134            .filter(|id| self.active.contains(id))
1135        {
1136            topological_sort_subgraph(
1137                &self.nodes,
1138                |id| self.active.contains(id) && ancestors.contains(id),
1139                root,
1140                &mut stack,
1141                |id| active_topological_subgraph.push(id),
1142                &mut scratchpad_map,
1143            );
1144        }
1145
1146        let mut reversed_path = guard.vec();
1147
1148        longest_candidate_path_to_root(
1149            &self.nodes,
1150            &active_topological_subgraph,
1151            |id| self.active.contains(id) && ancestors.contains(id),
1152            &mut guard.map_with_capacity(self.active.len().min(ancestors.len()), S::default()),
1153            |id| reversed_path.push(id),
1154        );
1155
1156        let mut scratchpad_map_2 = guard.map_with_capacity(ancestors.len(), S::default());
1157
1158        if let Some(target) = reversed_path.first().copied() {
1159            shortest_path_to_ancestor(
1160                &self.nodes,
1161                id,
1162                |node| node.id == target,
1163                &mut stack,
1164                &mut scratchpad_map_2,
1165                output,
1166            );
1167
1168            output.reverse();
1169            output.pop();
1170            output.extend_from_slice(&reversed_path);
1171        } else {
1172            shortest_path_to_ancestor(
1173                &self.nodes,
1174                id,
1175                |node| node.from.is_empty(),
1176                &mut stack,
1177                &mut scratchpad_map_2,
1178                output,
1179            );
1180
1181            output.reverse();
1182        }
1183    }
1184    #[cfg_attr(debug_assertions, contract(
1185        ensures(!ret || old(self.nodes.len()) + 1 == self.nodes.len()),
1186        ensures(!ret || old(!self.nodes.contains_key(&node.id))),
1187        ensures(!ret || self.nodes.contains_key(&old(node.id))),
1188        ensures(!ret || old(node.active) == self.active.contains(&old(node.id)) || (!old(node.active) && self.active.contains(&old(node.id)) && old(node.to.iter().any(|c| self.active.contains(c))))),
1189        ensures(!ret || old(node.bookmarked) == self.bookmarked.contains(&old(node.id))),
1190        ensures(!ret || old(!node.from.is_empty()) || self.roots.contains(&old(node.id))),
1191        ensures(ret || old(self.nodes.keys().copied().collect::<HashSet<_>>()) == self.nodes.keys().copied().collect::<HashSet<_>>()),
1192        ensures(ret || old(self.roots.clone()) == self.roots),
1193        ensures(ret || old(self.active.clone()) == self.active),
1194        ensures(ret || old(self.bookmarked.clone()) == self.bookmarked),
1195        invariant(self.validate())
1196    ))]
1197    fn insert(&mut self, mut node: IndependentNode<K, T, S>) -> bool {
1198        if self.nodes.contains_key(&node.id)
1199            || !node.validate()
1200            || !node.from.iter().all(|id| self.nodes.contains_key(id))
1201            || !node.to.iter().all(|id| self.nodes.contains_key(id))
1202        {
1203            return false;
1204        }
1205
1206        if !node.to.is_empty() && !node.from.is_empty() {
1207            let guard = self.scratchpad.guard();
1208
1209            if ancestor_subgraph_reaches(
1210                &self.nodes,
1211                node.from.iter().copied(),
1212                |id| node.to.contains(id),
1213                &mut guard.vec_with_capacity(node.from.len()),
1214                &mut guard.set_with_capacity(node.from.len(), S::default()),
1215            ) {
1216                return false;
1217            }
1218        }
1219
1220        let root_index = if node.from.is_empty() {
1221            node.to
1222                .iter()
1223                .filter_map(|child| self.roots.get_index_of(child))
1224                .min()
1225        } else {
1226            None
1227        };
1228
1229        let mut detached_root = false;
1230
1231        for child in &node.to {
1232            let child = self.nodes.get_mut(child).unwrap();
1233
1234            if child.from.is_empty() {
1235                node.active |= child.active;
1236                detached_root = true;
1237            }
1238
1239            child.from.insert(node.id);
1240        }
1241
1242        if detached_root {
1243            self.roots.retain(|id| !node.to.contains(id));
1244        }
1245
1246        let extends_active = node.active
1247            && node.to.is_empty()
1248            && node.from.iter().map(|id| &self.nodes[id]).any(|parent| {
1249                parent.active && parent.to.iter().all(|child| !self.active.contains(child))
1250            });
1251
1252        if node.from.is_empty() {
1253            if let Some(index) = root_index {
1254                self.roots.shift_insert(index, node.id);
1255            } else {
1256                self.roots.insert(node.id);
1257            }
1258        } else {
1259            for parent in &node.from {
1260                let parent = self.nodes.get_mut(parent).unwrap();
1261                parent.to.insert(node.id);
1262            }
1263        }
1264
1265        if node.bookmarked {
1266            self.bookmarked.insert(node.id);
1267        }
1268
1269        let id = node.id;
1270        let active = node.active;
1271
1272        if !extends_active {
1273            node.active = false;
1274        }
1275
1276        self.nodes.insert(node.id, node);
1277
1278        if extends_active {
1279            self.active.insert(id);
1280        } else if active {
1281            self.update_node_activity_in_place(&id, true);
1282        }
1283
1284        true
1285    }
1286    #[cfg_attr(debug_assertions, contract(
1287        ensures(!ret || value == self.contains_active(id)),
1288        ensures(ret || old(self.active.clone()) == self.active),
1289        ensures(ret == self.nodes.contains_key(id)),
1290        ensures(old(self.nodes.keys().copied().collect::<HashSet<_>>()) == self.nodes.keys().copied().collect::<HashSet<_>>()),
1291        ensures(old(self.roots.clone()) == self.roots),
1292        ensures(old(self.bookmarked.clone()) == self.bookmarked),
1293        invariant(self.validate())
1294    ))]
1295    fn set_active(&mut self, id: &K, value: bool) -> bool {
1296        self.update_node_activity_in_place(id, value)
1297    }
1298    #[cfg_attr(debug_assertions, contract(
1299        ensures(!self.nodes.contains_key(id)),
1300        ensures(ret.is_some() == old(self.nodes.contains_key(id))),
1301        ensures(ret.as_ref().is_none_or(|node| &node.id == id)),
1302        ensures(ret.is_none() || old(self.nodes.len()) > self.nodes.len()),
1303        ensures(ret.is_none() || old(self.active.len()) >= self.active.len()),
1304        ensures(ret.is_none() || old(self.bookmarked.len()) >= self.bookmarked.len()),
1305        ensures(ret.is_some() || old(self.nodes.keys().copied().collect::<HashSet<_>>()) == self.nodes.keys().copied().collect::<HashSet<_>>()),
1306        ensures(ret.is_some() || old(self.roots.clone()) == self.roots),
1307        ensures(ret.is_some() || old(self.active.clone()) == self.active),
1308        ensures(ret.is_some() || old(self.bookmarked.clone()) == self.bookmarked),
1309        invariant(self.validate())
1310    ))]
1311    fn remove(&mut self, id: &K) -> Option<IndependentNode<K, T, S>> {
1312        let node = self.nodes.remove(id)?;
1313
1314        if node.from.is_empty() {
1315            self.roots.shift_remove(id);
1316        } else {
1317            for parent in &node.from {
1318                if let Some(parent) = self.nodes.get_mut(parent) {
1319                    parent.to.shift_remove(id);
1320                }
1321            }
1322        }
1323
1324        let mut removed_active = node.active;
1325        let mut removed_bookmark = node.bookmarked;
1326
1327        if removed_active {
1328            self.active.remove(id);
1329        }
1330
1331        if node.to.is_empty() {
1332            if removed_bookmark {
1333                self.bookmarked.shift_remove(id);
1334            }
1335            return Some(node);
1336        }
1337
1338        {
1339            let guard = self.scratchpad.guard();
1340            let mut stack = guard.vec();
1341            let mut removed = guard.vec_with_capacity(node.to.len().strict_add(1));
1342            let mut remaining_parents = guard.map_with_capacity(node.to.len(), S::default());
1343
1344            removed.push(*id);
1345
1346            for child in node.to.iter().rev().copied() {
1347                let remaining = remaining_parents
1348                    .entry(child)
1349                    .or_insert_with(|| self.nodes[&child].from.len());
1350                #[allow(clippy::arithmetic_side_effects, reason = "Can never underflow")]
1351                {
1352                    *remaining -= 1;
1353                }
1354
1355                if *remaining == 0 {
1356                    stack.push(child);
1357                }
1358            }
1359
1360            while let Some(id) = stack.pop() {
1361                let node = self.nodes.remove(&id).unwrap();
1362                removed.push(id);
1363
1364                removed_bookmark |= node.bookmarked;
1365                if node.active {
1366                    self.active.remove(&id);
1367                    removed_active = true;
1368                }
1369
1370                for child in node.to.iter().rev().copied() {
1371                    let remaining = remaining_parents
1372                        .entry(child)
1373                        .or_insert_with(|| self.nodes[&child].from.len());
1374                    #[allow(clippy::arithmetic_side_effects, reason = "Can never underflow")]
1375                    {
1376                        *remaining -= 1;
1377                    }
1378
1379                    if *remaining == 0 {
1380                        stack.push(child);
1381                    }
1382                }
1383            }
1384
1385            if removed_active
1386                && !remaining_parents
1387                    .iter()
1388                    .any(|(child, remaining)| *remaining > 0 && self.active.contains(child))
1389            {
1390                removed_active = false;
1391            }
1392
1393            if removed.len() == 1 {
1394                for (child, _) in remaining_parents {
1395                    if let Some(child) = self.nodes.get_mut(&child) {
1396                        child.from.shift_remove(id);
1397                    }
1398                }
1399                if removed_bookmark {
1400                    self.bookmarked.shift_remove(id);
1401                }
1402            } else {
1403                let mut removed_set = guard.set_with_capacity(removed.len(), S::default());
1404                removed_set.extend(removed);
1405
1406                for (child, remaining) in remaining_parents {
1407                    if remaining > 0
1408                        && let Some(child) = self.nodes.get_mut(&child)
1409                    {
1410                        child.from.retain(|parent| !removed_set.contains(parent));
1411                    }
1412                }
1413
1414                if removed_bookmark {
1415                    self.bookmarked.retain(|id| !removed_set.contains(id));
1416                }
1417            }
1418        }
1419
1420        if removed_active {
1421            self.fix_orphaned_activations();
1422        }
1423
1424        Some(node)
1425    }
1426    #[cfg_attr(debug_assertions, contract(
1427        ensures(!self.nodes.contains_key(id)),
1428        ensures(ret == old(self.nodes.contains_key(id))),
1429        ensures(!ret || old(self.nodes.len()) > self.nodes.len()),
1430        ensures(!ret || old(self.active.len()) >= self.active.len()),
1431        ensures(!ret || old(self.bookmarked.len()) >= self.bookmarked.len()),
1432        ensures(ret || old(self.nodes.keys().copied().collect::<HashSet<_>>()) == self.nodes.keys().copied().collect::<HashSet<_>>()),
1433        ensures(ret || old(self.roots.clone()) == self.roots),
1434        ensures(ret || old(self.active.clone()) == self.active),
1435        ensures(ret || old(self.bookmarked.clone()) == self.bookmarked),
1436        invariant(self.validate())
1437    ))]
1438    fn remove_tracked(
1439        &mut self,
1440        id: &K,
1441        mut on_removal: impl FnMut(IndependentNode<K, T, S>),
1442    ) -> bool {
1443        let Some(node) = self.nodes.remove(id) else {
1444            return false;
1445        };
1446
1447        if node.from.is_empty() {
1448            self.roots.shift_remove(id);
1449        } else {
1450            for parent in &node.from {
1451                if let Some(parent) = self.nodes.get_mut(parent) {
1452                    parent.to.shift_remove(id);
1453                }
1454            }
1455        }
1456
1457        let mut removed_active = node.active;
1458        let mut removed_bookmark = node.bookmarked;
1459
1460        if removed_active {
1461            self.active.remove(id);
1462        }
1463
1464        if node.to.is_empty() {
1465            if removed_bookmark {
1466                self.bookmarked.shift_remove(id);
1467            }
1468            on_removal(node);
1469            return true;
1470        }
1471
1472        {
1473            let guard = self.scratchpad.guard();
1474            let mut stack = guard.vec();
1475            let mut removed = guard.vec_with_capacity(node.to.len().strict_add(1));
1476            let mut remaining_parents = guard.map_with_capacity(node.to.len(), S::default());
1477
1478            removed.push(*id);
1479
1480            for child in node.to.iter().rev().copied() {
1481                let remaining = remaining_parents
1482                    .entry(child)
1483                    .or_insert_with(|| self.nodes[&child].from.len());
1484                #[allow(clippy::arithmetic_side_effects, reason = "Can never underflow")]
1485                {
1486                    *remaining -= 1;
1487                }
1488
1489                if *remaining == 0 {
1490                    stack.push(child);
1491                }
1492            }
1493
1494            on_removal(node);
1495
1496            while let Some(id) = stack.pop() {
1497                let node = self.nodes.remove(&id).unwrap();
1498                removed.push(id);
1499
1500                removed_bookmark |= node.bookmarked;
1501                if node.active {
1502                    self.active.remove(&id);
1503                    removed_active = true;
1504                }
1505
1506                for child in node.to.iter().rev().copied() {
1507                    let remaining = remaining_parents
1508                        .entry(child)
1509                        .or_insert_with(|| self.nodes[&child].from.len());
1510                    #[allow(clippy::arithmetic_side_effects, reason = "Can never underflow")]
1511                    {
1512                        *remaining -= 1;
1513                    }
1514
1515                    if *remaining == 0 {
1516                        stack.push(child);
1517                    }
1518                }
1519
1520                on_removal(node);
1521            }
1522
1523            if removed_active
1524                && !remaining_parents
1525                    .iter()
1526                    .any(|(child, remaining)| *remaining > 0 && self.active.contains(child))
1527            {
1528                removed_active = false;
1529            }
1530
1531            if removed.len() == 1 {
1532                for (child, _) in remaining_parents {
1533                    if let Some(child) = self.nodes.get_mut(&child) {
1534                        child.from.shift_remove(id);
1535                    }
1536                }
1537                if removed_bookmark {
1538                    self.bookmarked.shift_remove(id);
1539                }
1540            } else {
1541                let mut removed_set = guard.set_with_capacity(removed.len(), S::default());
1542                removed_set.extend(removed);
1543
1544                for (child, remaining) in remaining_parents {
1545                    if remaining > 0
1546                        && let Some(child) = self.nodes.get_mut(&child)
1547                    {
1548                        child.from.retain(|parent| !removed_set.contains(parent));
1549                    }
1550                }
1551
1552                if removed_bookmark {
1553                    self.bookmarked.retain(|id| !removed_set.contains(id));
1554                }
1555            }
1556        }
1557
1558        if removed_active {
1559            self.fix_orphaned_activations();
1560        }
1561
1562        true
1563    }
1564    #[cfg_attr(debug_assertions, contract(
1565        ensures(self.nodes.is_empty()),
1566        ensures(self.validate())
1567    ))]
1568    fn clear(&mut self) {
1569        self.nodes.clear();
1570        self.roots.clear();
1571        self.active.clear();
1572        self.bookmarked.clear();
1573    }
1574}
1575
1576impl<K, T, M, S> IndependentWeave<K, T, M, S>
1577where
1578    K: Hash + Copy + Eq + Ord,
1579    T: IndependentContents,
1580    S: BuildHasher + Default + Clone,
1581{
1582    /// Validates that the weave is internally consistent.
1583    pub fn validate(&self) -> bool {
1584        self.roots
1585            .iter()
1586            .all(move |value| self.nodes.contains_key(value))
1587            && self
1588                .active
1589                .iter()
1590                .all(move |value| self.nodes.contains_key(value))
1591            && self
1592                .bookmarked
1593                .iter()
1594                .all(move |value| self.nodes.contains_key(value))
1595            && self.nodes.iter().all(|(key, value)| {
1596                value.validate()
1597                    && value.id == *key
1598                    && value
1599                        .from
1600                        .iter()
1601                        .all(|v| self.nodes.get(v).is_some_and(|p| p.to.contains(key)))
1602                    && value
1603                        .to
1604                        .iter()
1605                        .all(|v| self.nodes.get(v).is_some_and(|p| p.from.contains(key)))
1606                    && value.from.is_empty() == self.roots.contains(key)
1607                    && value.active == self.active.contains(key)
1608                    && value.bookmarked == self.bookmarked.contains(key)
1609            })
1610            && valid_topology(&self.nodes, &self.roots, &self.active)
1611    }
1612}
1613
1614impl<K, T, M, S> MetadataWeave<K, IndependentNode<K, T, S>, T, M> for IndependentWeave<K, T, M, S>
1615where
1616    K: Hash + Copy + Eq + Ord,
1617    T: IndependentContents,
1618    S: BuildHasher + Default + Clone,
1619{
1620    #[inline]
1621    fn metadata(&self) -> &M {
1622        &self.metadata
1623    }
1624    #[cfg_attr(debug_assertions, contract(
1625        ensures(old(self.nodes.keys().copied().collect::<HashSet<_>>()) == self.nodes.keys().copied().collect::<HashSet<_>>()),
1626        ensures(old(self.roots.clone()) == self.roots),
1627        ensures(old(self.active.clone()) == self.active),
1628        ensures(old(self.bookmarked.clone()) == self.bookmarked),
1629        invariant(self.validate())
1630    ))]
1631    #[inline]
1632    fn metadata_mut<O>(&mut self, callback: impl FnOnce(&mut M) -> O) -> O {
1633        callback(&mut self.metadata)
1634    }
1635}
1636
1637impl<K, T, M, S> BookmarkableWeave<K, IndependentNode<K, T, S>, T> for IndependentWeave<K, T, M, S>
1638where
1639    K: Hash + Copy + Eq + Ord,
1640    T: IndependentContents,
1641    S: BuildHasher + Default + Clone,
1642{
1643    type Bookmarks = IndexSet<K, S>;
1644
1645    #[inline]
1646    fn bookmarks(&self) -> &Self::Bookmarks {
1647        &self.bookmarked
1648    }
1649    #[inline]
1650    fn contains_bookmark(&self, id: &K) -> bool {
1651        self.bookmarked.contains(id)
1652    }
1653    #[cfg_attr(debug_assertions, contract(
1654        ensures(!ret || value == self.bookmarked.contains(id)),
1655        ensures(ret || old(self.bookmarked.clone()) == self.bookmarked),
1656        ensures(ret == self.nodes.contains_key(id)),
1657        ensures(old(self.nodes.keys().copied().collect::<HashSet<_>>()) == self.nodes.keys().copied().collect::<HashSet<_>>()),
1658        ensures(old(self.roots.clone()) == self.roots),
1659        ensures(old(self.active.clone()) == self.active),
1660        invariant(self.validate())
1661    ))]
1662    fn set_bookmarked(&mut self, id: &K, value: bool) -> bool {
1663        match self.nodes.get_mut(id) {
1664            Some(node) => {
1665                node.bookmarked = value;
1666                if value {
1667                    self.bookmarked.insert(node.id);
1668                } else {
1669                    self.bookmarked.shift_remove(id);
1670                }
1671
1672                true
1673            }
1674            None => false,
1675        }
1676    }
1677}
1678
1679impl<K, T, M, S> SortableWeave<K, IndependentNode<K, T, S>, T> for IndependentWeave<K, T, M, S>
1680where
1681    K: Hash + Copy + Eq + Ord,
1682    T: IndependentContents,
1683    S: BuildHasher + Default + Clone,
1684{
1685    #[cfg_attr(debug_assertions, contract(
1686        ensures(ret == self.nodes.contains_key(id)),
1687        ensures(old(self.nodes.get(id).map(|n| n.to.clone())) == self.nodes.get(id).map(|n| n.to.clone())),
1688        ensures(old(self.nodes.keys().copied().collect::<HashSet<_>>()) == self.nodes.keys().copied().collect::<HashSet<_>>()),
1689        ensures(old(self.roots.clone()) == self.roots),
1690        ensures(old(self.active.clone()) == self.active),
1691        ensures(old(self.bookmarked.clone()) == self.bookmarked),
1692        invariant(self.validate())
1693    ))]
1694    fn sort_children_by(
1695        &mut self,
1696        id: &K,
1697        mut cmp: impl FnMut(&IndependentNode<K, T, S>, &IndependentNode<K, T, S>) -> Ordering,
1698    ) -> bool {
1699        if let Some(node) = self.nodes.get_mut(id) {
1700            let mut set = mem::take(&mut node.to);
1701
1702            if set.len() > 20 {
1703                let guard = self.scratchpad.guard();
1704                let mut nodes = guard
1705                    .arena()
1706                    .alloc_iter_exact(set.drain(..).map(|id| &self.nodes[&id]));
1707                nodes.sort_by(|a, b| cmp(*a, *b));
1708
1709                set.extend(nodes.into_iter().map(|node| node.id));
1710            } else {
1711                set.sort_by(|a, b| cmp(&self.nodes[a], &self.nodes[b]));
1712            }
1713
1714            self.nodes.get_mut(id).unwrap().to = set;
1715
1716            true
1717        } else {
1718            false
1719        }
1720    }
1721    #[cfg_attr(debug_assertions, contract(
1722        ensures(ret == self.nodes.contains_key(id)),
1723        ensures(old(self.nodes.get(id).map(|n| n.to.clone())) == self.nodes.get(id).map(|n| n.to.clone())),
1724        ensures(old(self.nodes.keys().copied().collect::<HashSet<_>>()) == self.nodes.keys().copied().collect::<HashSet<_>>()),
1725        ensures(old(self.roots.clone()) == self.roots),
1726        ensures(old(self.active.clone()) == self.active),
1727        ensures(old(self.bookmarked.clone()) == self.bookmarked),
1728        invariant(self.validate())
1729    ))]
1730    fn sort_children_by_id(&mut self, id: &K, cmp: impl FnMut(&K, &K) -> Ordering) -> bool {
1731        if let Some(node) = self.nodes.get_mut(id) {
1732            node.to.sort_by(cmp);
1733
1734            true
1735        } else {
1736            false
1737        }
1738    }
1739    #[cfg_attr(debug_assertions, contract(
1740        ensures(old(self.nodes.keys().copied().collect::<HashSet<_>>()) == self.nodes.keys().copied().collect::<HashSet<_>>()),
1741        ensures(old(self.roots.clone()) == self.roots),
1742        ensures(old(self.active.clone()) == self.active),
1743        ensures(old(self.bookmarked.clone()) == self.bookmarked),
1744        invariant(self.validate())
1745    ))]
1746    fn sort_roots_by(
1747        &mut self,
1748        mut cmp: impl FnMut(&IndependentNode<K, T, S>, &IndependentNode<K, T, S>) -> Ordering,
1749    ) {
1750        if self.roots.len() > 20 {
1751            let guard = self.scratchpad.guard();
1752
1753            let mut nodes = guard
1754                .arena()
1755                .alloc_iter_exact(self.roots.iter().map(|id| &self.nodes[id]));
1756            nodes.sort_by(|a, b| cmp(*a, *b));
1757
1758            self.roots.clear();
1759            self.roots.extend(nodes.into_iter().map(|node| node.id));
1760        } else {
1761            self.roots
1762                .sort_by(|a, b| cmp(&self.nodes[a], &self.nodes[b]));
1763        }
1764    }
1765    #[cfg_attr(debug_assertions, contract(
1766        ensures(old(self.nodes.keys().copied().collect::<HashSet<_>>()) == self.nodes.keys().copied().collect::<HashSet<_>>()),
1767        ensures(old(self.roots.clone()) == self.roots),
1768        ensures(old(self.active.clone()) == self.active),
1769        ensures(old(self.bookmarked.clone()) == self.bookmarked),
1770        invariant(self.validate())
1771    ))]
1772    fn sort_roots_by_id(&mut self, cmp: impl FnMut(&K, &K) -> Ordering) {
1773        self.roots.sort_by(cmp);
1774    }
1775}
1776
1777impl<K, T, M, S> SortableBookmarkableWeave<K, IndependentNode<K, T, S>, T>
1778    for IndependentWeave<K, T, M, S>
1779where
1780    K: Hash + Copy + Eq + Ord,
1781    T: IndependentContents,
1782    S: BuildHasher + Default + Clone,
1783{
1784    #[cfg_attr(debug_assertions, contract(
1785        ensures(old(self.nodes.keys().copied().collect::<HashSet<_>>()) == self.nodes.keys().copied().collect::<HashSet<_>>()),
1786        ensures(old(self.roots.clone()) == self.roots),
1787        ensures(old(self.active.clone()) == self.active),
1788        ensures(old(self.bookmarked.clone()) == self.bookmarked),
1789        invariant(self.validate())
1790    ))]
1791    fn sort_bookmarks_by(
1792        &mut self,
1793        mut cmp: impl FnMut(&IndependentNode<K, T, S>, &IndependentNode<K, T, S>) -> Ordering,
1794    ) {
1795        if self.bookmarked.len() > 20 {
1796            let guard = self.scratchpad.guard();
1797
1798            let mut nodes = guard
1799                .arena()
1800                .alloc_iter_exact(self.bookmarked.iter().map(|id| &self.nodes[id]));
1801            nodes.sort_by(|a, b| cmp(*a, *b));
1802
1803            self.bookmarked.clear();
1804            self.bookmarked
1805                .extend(nodes.into_iter().map(|node| node.id));
1806        } else {
1807            self.bookmarked
1808                .sort_by(|a, b| cmp(&self.nodes[a], &self.nodes[b]));
1809        }
1810    }
1811    #[cfg_attr(debug_assertions, contract(
1812        ensures(old(self.nodes.keys().copied().collect::<HashSet<_>>()) == self.nodes.keys().copied().collect::<HashSet<_>>()),
1813        ensures(old(self.roots.clone()) == self.roots),
1814        ensures(old(self.active.clone()) == self.active),
1815        ensures(old(self.bookmarked.clone()) == self.bookmarked),
1816        invariant(self.validate())
1817    ))]
1818    fn sort_bookmarks_by_id(&mut self, cmp: impl FnMut(&K, &K) -> Ordering) {
1819        self.bookmarked.sort_by(cmp);
1820    }
1821}
1822
1823impl<K, T, M, S> ActivePathWeave<K, IndependentNode<K, T, S>, T> for IndependentWeave<K, T, M, S>
1824where
1825    K: Hash + Copy + Eq + Ord,
1826    T: IndependentContents,
1827    S: BuildHasher + Default + Clone,
1828{
1829    type Active = HashSet<K, S>;
1830
1831    #[inline]
1832    fn active(&self) -> &Self::Active {
1833        &self.active
1834    }
1835    #[cfg_attr(debug_assertions, contract(
1836        ensures(old(self.nodes.keys().copied().collect::<HashSet<_>>()) == self.nodes.keys().copied().collect::<HashSet<_>>()),
1837        ensures(old(self.roots.clone()) == self.roots),
1838        ensures(old(self.bookmarked.clone()) == self.bookmarked),
1839        invariant(self.validate())
1840    ))]
1841    fn set_active_path(&mut self, active: impl Iterator<Item = K>) {
1842        self.active.drain().for_each(|active| {
1843            self.nodes.get_mut(&active).unwrap().active = false;
1844        });
1845        self.active
1846            .extend(active.filter(|id| self.nodes.contains_key(id)));
1847        self.active.iter().for_each(|active| {
1848            self.nodes.get_mut(active).unwrap().active = true;
1849        });
1850        self.fix_orphaned_activations();
1851    }
1852}
1853
1854impl<K, T, M, S> DiscreteWeave<K, IndependentNode<K, T, S>, T> for IndependentWeave<K, T, M, S>
1855where
1856    K: Hash + Copy + Eq + Ord,
1857    T: IndependentContents + DiscreteContents,
1858    S: BuildHasher + Default + Clone,
1859{
1860    #[cfg_attr(debug_assertions, contract(
1861        ensures(!ret || old(self.nodes.len()) + 1 == self.nodes.len()),
1862        ensures(!ret || self.nodes.contains_key(id)),
1863        ensures(!ret || self.nodes.contains_key(&new_id)),
1864        ensures(!ret || old(!self.nodes.contains_key(&new_id))),
1865        ensures(!ret || self.nodes[id].to.contains(&new_id) && self.nodes[id].to.len() == 1),
1866        ensures(!ret || self.nodes[&new_id].from.contains(id) && self.nodes[&new_id].from.len() == 1),
1867        ensures(!ret || old(self.nodes.get(id).map(|n| n.to.clone())).unwrap() == self.nodes[&new_id].to),
1868        ensures(ret || old(self.nodes.keys().copied().collect::<HashSet<_>>()) == self.nodes.keys().copied().collect::<HashSet<_>>()),
1869        ensures(ret || old(self.active.clone()) == self.active),
1870        ensures(old(self.roots.clone()) == self.roots),
1871        ensures(old(self.bookmarked.clone()) == self.bookmarked),
1872        invariant(self.validate())
1873    ))]
1874    fn split(&mut self, id: &K, at: usize, new_id: K) -> bool {
1875        if self.nodes.contains_key(&new_id) || *id == new_id {
1876            return false;
1877        }
1878
1879        if let Some(mut node) = self.nodes.remove(id) {
1880            match node.contents.split(at) {
1881                DiscreteContentResult::Two(left, right) => {
1882                    let left_node = IndependentNode {
1883                        id: node.id,
1884                        from: node.from,
1885                        to: IndexSet::from_iter([new_id]),
1886                        active: node.active,
1887                        bookmarked: node.bookmarked,
1888                        contents: left,
1889                    };
1890
1891                    node.from = IndexSet::from_iter([node.id]);
1892                    node.id = new_id;
1893                    node.contents = right;
1894                    node.active = false;
1895                    node.bookmarked = false;
1896
1897                    let mut child_active = false;
1898
1899                    for child in &node.to {
1900                        let child = self.nodes.get_mut(child).unwrap();
1901                        let index = child.from.get_index_of(&left_node.id).unwrap();
1902
1903                        assert!(
1904                            child.from.replace_index(index, node.id).is_ok(),
1905                            "Should be unreachable"
1906                        );
1907
1908                        child_active |= child.active;
1909                    }
1910
1911                    if left_node.active && child_active {
1912                        node.active = true;
1913                        self.active.insert(node.id);
1914                    }
1915
1916                    self.nodes.insert(left_node.id, left_node);
1917                    self.nodes.insert(node.id, node);
1918
1919                    true
1920                }
1921                DiscreteContentResult::One(content) => {
1922                    node.contents = content;
1923                    self.nodes.insert(node.id, node);
1924                    false
1925                }
1926            }
1927        } else {
1928            false
1929        }
1930    }
1931    #[cfg_attr(debug_assertions, contract(
1932        ensures(ret.is_none() || old(self.nodes.len()) - 1 == self.nodes.len()),
1933        ensures(ret.is_none() || !self.nodes.contains_key(id)),
1934        ensures(ret.is_none() || old(self.nodes.contains_key(id))),
1935        ensures(ret.is_none() || !old(self.contains_active(id)) || old(self.contains_active(id)) && self.contains_active(&ret.unwrap())),
1936        ensures(ret.is_none() || old(self.nodes.get(id).and_then(|n| n.from.first()).and_then(|p| self.nodes.get(p)).map(|p| p.active)).unwrap() == self.nodes[&ret.unwrap()].active),
1937        ensures(ret.is_none() || old(self.nodes.get(id).and_then(|n| n.from.first()).and_then(|p| self.nodes.get(p)).map(|p| p.from.clone())).unwrap() == self.nodes[&ret.unwrap()].from),
1938        ensures(ret.is_none() || old(self.nodes.get(id).map(|node| node.to.clone())).unwrap() == self.nodes[&ret.unwrap()].to),
1939        ensures(ret.is_none() || old(self.nodes.get(id).map(|node| node.from.len() == 1)).unwrap()),
1940        ensures(ret.is_none() || ret.unwrap() == old(self.nodes.get(id).and_then(|node| node.from.first().copied())).unwrap()),
1941        ensures(ret.is_some() || old(self.nodes.keys().copied().collect::<HashSet<_>>()) == self.nodes.keys().copied().collect::<HashSet<_>>()),
1942        ensures(ret.is_some() || old(self.active.clone()) == self.active),
1943        ensures(ret.is_some() || old(self.bookmarked.clone()) == self.bookmarked),
1944        ensures(old(self.roots.clone()) == self.roots),
1945        invariant(self.validate())
1946    ))]
1947    fn merge_with_parent(&mut self, id: &K) -> Option<K> {
1948        if let Some(mut node) = self.nodes.remove(id) {
1949            if node.from.len() != 1 {
1950                self.nodes.insert(node.id, node);
1951                return None;
1952            }
1953
1954            if let Some(mut parent) = node.from.first().and_then(|id| self.nodes.remove(id)) {
1955                if parent.to.len() > 1 {
1956                    self.nodes.insert(parent.id, parent);
1957                    self.nodes.insert(node.id, node);
1958                    return None;
1959                }
1960
1961                match parent.contents.merge(node.contents) {
1962                    DiscreteContentResult::Two(left, right) => {
1963                        parent.contents = left;
1964                        node.contents = right;
1965                        self.nodes.insert(parent.id, parent);
1966                        self.nodes.insert(node.id, node);
1967                        None
1968                    }
1969                    DiscreteContentResult::One(content) => {
1970                        parent.contents = content;
1971                        parent.to = node.to;
1972
1973                        for child in &parent.to {
1974                            let child = self.nodes.get_mut(child).unwrap();
1975                            let index = child.from.get_index_of(&node.id).unwrap();
1976
1977                            assert!(
1978                                child.from.replace_index(index, parent.id).is_ok(),
1979                                "Should be unreachable"
1980                            );
1981                        }
1982
1983                        let parent_id = parent.id;
1984
1985                        if node.bookmarked && !parent.bookmarked {
1986                            parent.bookmarked = true;
1987                            assert!(
1988                                self.bookmarked
1989                                    .replace_index(
1990                                        self.bookmarked.get_index_of(&node.id).unwrap(),
1991                                        parent.id,
1992                                    )
1993                                    .is_ok(),
1994                                "Should be unreachable"
1995                            );
1996                        } else if node.bookmarked {
1997                            self.bookmarked.shift_remove(&node.id);
1998                        }
1999
2000                        self.nodes.insert(parent.id, parent);
2001                        self.active.remove(&node.id);
2002
2003                        Some(parent_id)
2004                    }
2005                }
2006            } else {
2007                self.nodes.insert(node.id, node);
2008                None
2009            }
2010        } else {
2011            None
2012        }
2013    }
2014}
2015
2016impl<K, T, M, S> SemiIndependentWeave<K, IndependentNode<K, T, S>, T>
2017    for IndependentWeave<K, T, M, S>
2018where
2019    K: Hash + Copy + Eq + Ord,
2020    T: IndependentContents,
2021    S: BuildHasher + Default + Clone,
2022{
2023    #[cfg_attr(debug_assertions, contract(
2024        ensures(ret.is_some() == old(self.nodes.contains_key(id))),
2025        ensures(old(self.nodes.keys().copied().collect::<HashSet<_>>()) == self.nodes.keys().copied().collect::<HashSet<_>>()),
2026        ensures(old(self.roots.clone()) == self.roots),
2027        ensures(old(self.active.clone()) == self.active),
2028        ensures(old(self.bookmarked.clone()) == self.bookmarked),
2029        invariant(self.validate())
2030    ))]
2031    #[inline]
2032    fn get_contents_mut<O>(&mut self, id: &K, callback: impl FnOnce(&mut T) -> O) -> Option<O> {
2033        self.nodes
2034            .get_mut(id)
2035            .map(|node| callback(&mut node.contents))
2036    }
2037}
2038
2039impl<K, T, M, S> crate::IndependentWeave<K, IndependentNode<K, T, S>, T>
2040    for IndependentWeave<K, T, M, S>
2041where
2042    K: Hash + Copy + Eq + Ord,
2043    T: IndependentContents,
2044    S: BuildHasher + Default + Clone,
2045{
2046    #[cfg_attr(debug_assertions, contract(
2047        ensures(!ret || self.nodes[id].from.iter().copied().collect::<HashSet<_>>() == new_parents.iter().copied().collect::<HashSet<_>>()),
2048        ensures(ret || old(self.nodes.get(id).map(|node| node.from.clone())).as_ref() == self.nodes.get(id).map(|node| &node.from)),
2049        ensures(ret || old(self.roots.clone()) == self.roots),
2050        ensures(ret || old(self.active.clone()) == self.active),
2051        ensures(old(self.nodes.get(id).map(|node| node.to.clone())).as_ref() == self.nodes.get(id).map(|node| &node.to)),
2052        ensures(old(self.nodes.keys().copied().collect::<HashSet<_>>()) == self.nodes.keys().copied().collect::<HashSet<_>>()),
2053        ensures(old(self.bookmarked.clone()) == self.bookmarked),
2054        ensures(old(self.active.contains(id)) == self.active.contains(id)),
2055        invariant(self.validate())
2056    ))]
2057    fn move_to(&mut self, id: &K, new_parents: &[K]) -> bool {
2058        if new_parents
2059            .iter()
2060            .any(|new_parent| !self.nodes.contains_key(new_parent))
2061        {
2062            return false;
2063        }
2064
2065        let Some(node) = self.nodes.get(id) else {
2066            return false;
2067        };
2068
2069        if node.from.iter().eq(new_parents) {
2070            return true;
2071        }
2072
2073        let new_parents: IndexSet<K, S> = new_parents.iter().copied().collect();
2074
2075        if new_parents.contains(id) {
2076            return false;
2077        }
2078
2079        if !node.to.is_empty() && !new_parents.is_empty() {
2080            let guard = self.scratchpad.guard();
2081
2082            if descendant_subgraph_reaches(
2083                &self.nodes,
2084                node.to.iter().copied(),
2085                |id| new_parents.contains(id),
2086                &mut guard.vec_with_capacity(node.to.len()),
2087                &mut guard.set_with_capacity(node.to.len(), S::default()),
2088            ) {
2089                return false;
2090            }
2091        }
2092
2093        if let Some(node) = self.nodes.get_mut(id) {
2094            let old_parents = mem::take(&mut node.from);
2095
2096            for old_parent in &old_parents {
2097                if !new_parents.contains(old_parent)
2098                    && let Some(old_parent) = self.nodes.get_mut(old_parent)
2099                {
2100                    old_parent.to.shift_remove(id);
2101                }
2102            }
2103
2104            for new_parent in &new_parents {
2105                if !old_parents.contains(new_parent)
2106                    && let Some(new_parent) = self.nodes.get_mut(new_parent)
2107                {
2108                    new_parent.to.insert(*id);
2109                }
2110            }
2111        }
2112
2113        let node = self.nodes.get_mut(id).unwrap();
2114        node.from = new_parents;
2115
2116        if node.from.is_empty() {
2117            self.roots.insert(node.id);
2118        } else {
2119            self.roots.shift_remove(&node.id);
2120        }
2121
2122        if node.active {
2123            node.active = false;
2124            self.active.remove(id);
2125            self.update_node_activity_in_place(id, true);
2126        }
2127
2128        true
2129    }
2130}
2131
2132#[cfg(feature = "rkyv")]
2133impl<K, T, S> ArchivedIndependentNode<K, T, S>
2134where
2135    K: Archive + Hash + Copy + Eq + Ord,
2136    <K as Archive>::Archived: Hash + Copy + Eq + Ord + 'static,
2137    T: Archive + IndependentContents,
2138    S: BuildHasher + Default + Clone,
2139{
2140    #[inline]
2141    fn validate(&self) -> bool {
2142        (if self.from.len() <= self.to.len() {
2143            self.from.iter().all(|v| !self.to.contains(v))
2144        } else {
2145            self.to.iter().all(|v| !self.from.contains(v))
2146        }) && !self.from.contains(&self.id)
2147            && !self.to.contains(&self.id)
2148    }
2149}
2150
2151#[cfg(feature = "rkyv")]
2152impl<K, T, S> Node<K::Archived, T::Archived> for ArchivedIndependentNode<K, T, S>
2153where
2154    K: Archive + Hash + Copy + Eq + Ord,
2155    <K as Archive>::Archived: Hash + Copy + Eq + Ord + 'static,
2156    T: Archive + IndependentContents,
2157    S: BuildHasher + Default + Clone,
2158{
2159    type From = ArchivedIndexSet<K::Archived>;
2160    type To = ArchivedIndexSet<K::Archived>;
2161
2162    #[inline]
2163    fn id(&self) -> K::Archived {
2164        self.id
2165    }
2166    #[inline]
2167    fn from(&self) -> &Self::From {
2168        &self.from
2169    }
2170    #[inline]
2171    fn to(&self) -> &Self::To {
2172        &self.to
2173    }
2174    #[inline]
2175    fn is_active(&self) -> bool {
2176        self.active
2177    }
2178    #[inline]
2179    fn contents(&self) -> &T::Archived {
2180        &self.contents
2181    }
2182}
2183
2184#[cfg(feature = "rkyv")]
2185impl<K, T, M, S> ArchivedIndependentWeave<K, T, M, S>
2186where
2187    K: Archive + Hash + Copy + Eq + Ord,
2188    <K as Archive>::Archived: Hash + Copy + Eq + Ord + 'static,
2189    T: Archive + IndependentContents,
2190    M: Archive,
2191    S: BuildHasher + Default + Clone,
2192{
2193    fn validate(&self) -> bool {
2194        self.roots
2195            .iter()
2196            .all(move |value| self.nodes.contains_key(value))
2197            && self
2198                .active
2199                .iter()
2200                .all(move |value| self.nodes.contains_key(value))
2201            && self
2202                .bookmarked
2203                .iter()
2204                .all(move |value| self.nodes.contains_key(value))
2205            && self.nodes.iter().all(|(key, value)| {
2206                value.validate()
2207                    && value.id == *key
2208                    && value
2209                        .from
2210                        .iter()
2211                        .all(|v| self.nodes.get(v).is_some_and(|p| p.to.contains(key)))
2212                    && value
2213                        .to
2214                        .iter()
2215                        .all(|v| self.nodes.get(v).is_some_and(|p| p.from.contains(key)))
2216                    && value.from.is_empty() == self.roots.contains(key)
2217                    && value.active == self.active.contains(key)
2218                    && value.bookmarked == self.bookmarked.contains(key)
2219            })
2220            && archived_valid_topology(&self.nodes, &self.roots, &self.active)
2221    }
2222}
2223
2224#[cfg(feature = "rkyv")]
2225#[allow(unsafe_code, reason = "rkyv limitation")]
2226// SAFETY:
2227// All fields are safe to access and no unsafe functions are called
2228unsafe impl<K, T, M, S, C> Verify<C> for ArchivedIndependentWeave<K, T, M, S>
2229where
2230    K: Archive + Hash + Copy + Eq + Ord,
2231    <K as Archive>::Archived: Hash + Copy + Eq + Ord + 'static,
2232    T: Archive + IndependentContents,
2233    M: Archive,
2234    S: BuildHasher + Default + Clone,
2235    C: Fallible + ?Sized,
2236    C::Error: Source,
2237{
2238    fn verify(&self, _context: &mut C) -> Result<(), C::Error> {
2239        if !self.validate() {
2240            fail!(ValidationError)
2241        }
2242
2243        Ok(())
2244    }
2245}
2246
2247#[cfg(feature = "rkyv")]
2248impl<K, T, M, S> ImmutableWeave<K::Archived, ArchivedIndependentNode<K, T, S>, T::Archived>
2249    for ArchivedIndependentWeave<K, T, M, S>
2250where
2251    K: Archive + Hash + Copy + Eq + Ord,
2252    <K as Archive>::Archived: Hash + Copy + Eq + Ord + 'static,
2253    T: Archive + IndependentContents,
2254    M: Archive,
2255    S: BuildHasher + Default + Clone,
2256{
2257    type Nodes = ArchivedHashMap<K::Archived, ArchivedIndependentNode<K, T, S>>;
2258    type Roots = ArchivedIndexSet<K::Archived>;
2259
2260    #[inline]
2261    fn len(&self) -> usize {
2262        self.nodes.len()
2263    }
2264    #[inline]
2265    fn is_empty(&self) -> bool {
2266        self.nodes.is_empty()
2267    }
2268    #[inline]
2269    fn nodes(&self) -> &Self::Nodes {
2270        &self.nodes
2271    }
2272    #[inline]
2273    fn roots(&self) -> &Self::Roots {
2274        &self.roots
2275    }
2276    #[inline]
2277    fn contains(&self, id: &K::Archived) -> bool {
2278        self.nodes.contains_key(id)
2279    }
2280    #[inline]
2281    fn contains_active(&self, id: &K::Archived) -> bool {
2282        self.active.contains(id)
2283    }
2284    #[inline]
2285    fn get(&self, id: &K::Archived) -> Option<&ArchivedIndependentNode<K, T, S>> {
2286        self.nodes.get(id)
2287    }
2288    #[inline]
2289    fn get_parents(&self, id: &K::Archived) -> Option<&ArchivedIndexSet<K::Archived>> {
2290        self.nodes.get(id).map(|node| &node.from)
2291    }
2292    #[inline]
2293    fn get_children(&self, id: &K::Archived) -> Option<&ArchivedIndexSet<K::Archived>> {
2294        self.nodes.get(id).map(|node| &node.to)
2295    }
2296    #[inline]
2297    fn get_contents(&self, id: &K::Archived) -> Option<&T::Archived> {
2298        self.nodes.get(id).map(|node| &node.contents)
2299    }
2300    fn get_ordered_identifiers(&self, output: &mut Vec<K::Archived>) {
2301        output.clear();
2302        output.reserve(self.nodes.len());
2303
2304        let mut scratchpad = Scratchpad::new();
2305        let guard = scratchpad.guard();
2306
2307        archived_topological_sort(
2308            &self.nodes,
2309            &self.roots,
2310            &mut guard.vec_with_capacity(self.roots.len()),
2311            |id| output.push(id),
2312            &mut guard.map_with_capacity(self.nodes.len(), S::default()),
2313        );
2314    }
2315    fn get_ordered_identifiers_from(&self, id: &K::Archived, output: &mut Vec<K::Archived>) {
2316        output.clear();
2317
2318        if self.nodes.contains_key(id) {
2319            let mut scratchpad = Scratchpad::new();
2320            let guard = scratchpad.guard();
2321
2322            let mut stack = guard.vec();
2323            let mut descendants = guard.set(S::default());
2324
2325            archived_descendant_subgraph(&self.nodes, *id, &mut stack, &mut descendants);
2326
2327            output.reserve(descendants.len());
2328
2329            archived_topological_sort_subgraph(
2330                &self.nodes,
2331                |id| descendants.contains(id),
2332                *id,
2333                &mut stack,
2334                |id| output.push(id),
2335                &mut guard.map_with_capacity(descendants.len(), S::default()),
2336            );
2337        }
2338    }
2339    fn get_active_path(&self, output: &mut Vec<K::Archived>) {
2340        output.clear();
2341
2342        if self.active.is_empty() {
2343            return;
2344        }
2345
2346        output.reserve(self.active.len());
2347
2348        let mut scratchpad = Scratchpad::new();
2349        let guard = scratchpad.guard();
2350
2351        let mut stack = guard.vec();
2352        let mut topological_subgraph = guard.vec_with_capacity(self.active.len());
2353        let mut scratchpad_map = guard.map_with_capacity(self.active.len(), S::default());
2354
2355        for root in self
2356            .roots
2357            .iter()
2358            .filter(|id| self.active.contains(*id))
2359            .copied()
2360        {
2361            archived_topological_sort_subgraph(
2362                &self.nodes,
2363                |id| self.active.contains(id),
2364                root,
2365                &mut stack,
2366                |id| topological_subgraph.push(id),
2367                &mut scratchpad_map,
2368            );
2369        }
2370
2371        archived_longest_candidate_path_to_root(
2372            &self.nodes,
2373            &topological_subgraph,
2374            |id| self.active.contains(id),
2375            &mut guard.map_with_capacity(self.active.len(), S::default()),
2376            |id| output.push(id),
2377        );
2378    }
2379    fn get_path_from(&self, id: &K::Archived, output: &mut Vec<K::Archived>) {
2380        output.clear();
2381        if !self.nodes.contains_key(id) {
2382            return;
2383        }
2384
2385        let mut scratchpad = Scratchpad::new();
2386        let guard = scratchpad.guard();
2387        let mut stack = guard.vec();
2388        let mut ancestors = guard.set(S::default());
2389        let mut root_ancestors = guard.vec();
2390
2391        archived_ancestor_subgraph(&self.nodes, *id, &mut stack, &mut ancestors, |id| {
2392            root_ancestors.push(id);
2393        });
2394
2395        let mut active_topological_subgraph =
2396            guard.vec_with_capacity(self.active.len().min(ancestors.len()));
2397        let mut scratchpad_map =
2398            guard.map_with_capacity(self.active.len().min(ancestors.len()), S::default());
2399
2400        for root in root_ancestors
2401            .drain(..)
2402            .filter(|id| self.active.contains(id))
2403        {
2404            archived_topological_sort_subgraph(
2405                &self.nodes,
2406                |id| self.active.contains(id) && ancestors.contains(id),
2407                root,
2408                &mut stack,
2409                |id| active_topological_subgraph.push(id),
2410                &mut scratchpad_map,
2411            );
2412        }
2413
2414        let mut reversed_path = guard.vec();
2415
2416        archived_longest_candidate_path_to_root(
2417            &self.nodes,
2418            &active_topological_subgraph,
2419            |id| self.active.contains(id) && ancestors.contains(id),
2420            &mut guard.map_with_capacity(self.active.len().min(ancestors.len()), S::default()),
2421            |id| reversed_path.push(id),
2422        );
2423
2424        let mut scratchpad_map_2 = guard.map_with_capacity(ancestors.len(), S::default());
2425
2426        if let Some(target) = reversed_path.first().copied() {
2427            archived_shortest_path_to_ancestor(
2428                &self.nodes,
2429                id,
2430                |node| node.id == target,
2431                &mut stack,
2432                &mut scratchpad_map_2,
2433                output,
2434            );
2435
2436            output.reverse();
2437            output.pop();
2438            output.extend_from_slice(&reversed_path);
2439        } else {
2440            archived_shortest_path_to_ancestor(
2441                &self.nodes,
2442                id,
2443                |node| node.from.is_empty(),
2444                &mut stack,
2445                &mut scratchpad_map_2,
2446                output,
2447            );
2448
2449            output.reverse();
2450        }
2451    }
2452}
2453
2454#[cfg(feature = "rkyv")]
2455impl<K, T, M, S>
2456    ImmutableMetadataWeave<K::Archived, ArchivedIndependentNode<K, T, S>, T::Archived, M::Archived>
2457    for ArchivedIndependentWeave<K, T, M, S>
2458where
2459    K: Archive + Hash + Copy + Eq + Ord,
2460    <K as Archive>::Archived: Hash + Copy + Eq + Ord + 'static,
2461    T: Archive + IndependentContents,
2462    M: Archive,
2463    S: BuildHasher + Default + Clone,
2464{
2465    #[inline]
2466    fn metadata(&self) -> &M::Archived {
2467        &self.metadata
2468    }
2469}
2470
2471#[cfg(feature = "rkyv")]
2472impl<K, T, M, S>
2473    ImmutableBookmarkableWeave<K::Archived, ArchivedIndependentNode<K, T, S>, T::Archived>
2474    for ArchivedIndependentWeave<K, T, M, S>
2475where
2476    K: Archive + Hash + Copy + Eq + Ord,
2477    <K as Archive>::Archived: Hash + Copy + Eq + Ord + 'static,
2478    T: Archive + IndependentContents,
2479    M: Archive,
2480    S: BuildHasher + Default + Clone,
2481{
2482    type Bookmarks = ArchivedIndexSet<K::Archived>;
2483
2484    #[inline]
2485    fn bookmarks(&self) -> &Self::Bookmarks {
2486        &self.bookmarked
2487    }
2488    #[inline]
2489    fn contains_bookmark(&self, id: &K::Archived) -> bool {
2490        self.bookmarked.contains(id)
2491    }
2492}
2493
2494#[cfg(feature = "rkyv")]
2495impl<K, T, M, S>
2496    ImmutableActivePathWeave<K::Archived, ArchivedIndependentNode<K, T, S>, T::Archived>
2497    for ArchivedIndependentWeave<K, T, M, S>
2498where
2499    K: Archive + Hash + Copy + Eq + Ord,
2500    <K as Archive>::Archived: Hash + Copy + Eq + Ord + 'static,
2501    T: Archive + IndependentContents,
2502    M: Archive,
2503    S: BuildHasher + Default + Clone,
2504{
2505    type Active = ArchivedHashSet<K::Archived>;
2506
2507    #[inline]
2508    fn active(&self) -> &Self::Active {
2509        &self.active
2510    }
2511}