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