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        let at_end = if let Some(node) = self.nodes.get(id) {
544            if node.active == value {
545                return true;
546            }
547
548            if value {
549                (node.from.is_empty() && self.active.is_empty())
550                    || node.from.iter().any(|parent| {
551                        self.active.contains(parent)
552                            && self.nodes[parent]
553                                .to
554                                .iter()
555                                .all(|child| !self.active.contains(child))
556                    })
557            } else {
558                node.to.iter().all(|child| !self.active.contains(child))
559            }
560        } else {
561            return false;
562        };
563
564        let node = self.nodes.get_mut(id).unwrap();
565        node.active = value;
566        if value {
567            self.active.insert(node.id);
568        } else {
569            self.active.remove(id);
570        }
571
572        if at_end {
573            return true;
574        }
575
576        if value {
577            for root in &self.roots {
578                topological_sort(
579                    &self.nodes,
580                    root,
581                    &mut self.scratchpad_stack,
582                    &mut self.scratchpad_list, // topological order
583                    &mut self.scratchpad_set,
584                    &mut self.scratchpad_map,
585                );
586            }
587
588            self.scratchpad_set.clear();
589            self.scratchpad_map.clear();
590
591            for id in self.scratchpad_list.iter().copied() {
592                let node = &self.nodes[&id];
593
594                let best_parent = node
595                    .from
596                    .iter()
597                    .map(|id| (id, self.scratchpad_map_3[id])) // score: (connectors, active)
598                    .min_by(|(_, a), (_, b)| b.1.cmp(&a.1).then(a.0.cmp(&b.0)));
599
600                let (parent, score) = if let Some((parent, mut score)) = best_parent {
601                    if node.active {
602                        score.1 = score.1.strict_add(1);
603                    } else {
604                        score.0 = score.0.strict_add(1);
605                    }
606
607                    (Some(parent), score)
608                } else {
609                    (None, if node.active { (0, 1) } else { (1, 0) })
610                };
611
612                if let Some(parent) = parent {
613                    self.scratchpad_map_2.insert(id, *parent); // predecessors
614                }
615
616                self.scratchpad_map_3.insert(id, score);
617            }
618
619            let mut current = Some(id);
620
621            while let Some(id) = current {
622                self.scratchpad_set.insert(*id);
623                current = self.scratchpad_map_2.get(id);
624            }
625
626            self.scratchpad_map_2.clear();
627            self.scratchpad_map_3.clear();
628
629            for id in self.scratchpad_list.drain(..).rev() {
630                let node = &self.nodes[&id];
631
632                let best_child = node
633                    .to
634                    .iter()
635                    .map(|id| (id, self.scratchpad_map_3[id])) // score: (connectors, active)
636                    .min_by(|(_, a), (_, b)| b.1.cmp(&a.1).then(a.0.cmp(&b.0)));
637
638                let (child, score) = if let Some((child, mut score)) = best_child {
639                    if node.active {
640                        score.1 = score.1.strict_add(1);
641                    } else {
642                        score.0 = score.0.strict_add(1);
643                    }
644
645                    (Some(child), score)
646                } else {
647                    (None, if node.active { (0, 1) } else { (1, 0) })
648                };
649
650                if let Some(child) = child {
651                    self.scratchpad_map_2.insert(id, *child); // successors
652                }
653
654                self.scratchpad_map_3.insert(id, score);
655            }
656
657            let mut current = Some(id);
658
659            while let Some(id) = current {
660                self.scratchpad_set.insert(*id);
661
662                current = if self.scratchpad_map_3[id].1 > usize::from(self.nodes[id].active) {
663                    self.scratchpad_map_2.get(id)
664                } else {
665                    None
666                };
667            }
668
669            self.scratchpad_map_2.clear();
670            self.scratchpad_map_3.clear();
671
672            self.scratchpad_list
673                .extend(self.active.difference(&self.scratchpad_set).copied());
674
675            for id in self.scratchpad_list.drain(..) {
676                self.nodes.get_mut(&id).unwrap().active = false;
677                self.active.remove(&id);
678            }
679
680            self.scratchpad_list
681                .extend(self.scratchpad_set.difference(&self.active).copied());
682
683            self.scratchpad_set.clear();
684
685            for id in self.scratchpad_list.drain(..) {
686                self.nodes.get_mut(&id).unwrap().active = true;
687                self.active.insert(id);
688            }
689        } else {
690            self.fix_orphaned_activations();
691        }
692
693        true
694    }
695    #[cfg_attr(debug_assertions, contract(
696        requires(self.validate_scratchpads()),
697        ensures(self.validate())
698    ))]
699    fn fix_orphaned_activations(&mut self) {
700        for root in &self.roots {
701            topological_sort(
702                &self.nodes,
703                root,
704                &mut self.scratchpad_stack,
705                &mut self.scratchpad_list,
706                &mut self.scratchpad_set,
707                &mut self.scratchpad_map,
708            );
709        }
710
711        self.scratchpad_map.clear();
712
713        longest_candidate_path_to_root(
714            &self.nodes,
715            &self.scratchpad_list,
716            &|id| self.active.contains(id),
717            &mut self.scratchpad_map,
718            &mut self.scratchpad_list_2,
719        );
720
721        self.scratchpad_list.clear();
722        self.scratchpad_set.clear();
723        self.scratchpad_map.clear();
724
725        self.scratchpad_set.extend(self.scratchpad_list_2.drain(..));
726        self.scratchpad_list
727            .extend(self.active.difference(&self.scratchpad_set).copied());
728
729        self.scratchpad_set.clear();
730
731        for orphan in self.scratchpad_list.drain(..) {
732            self.active.remove(&orphan);
733            if let Some(node) = self.nodes.get_mut(&orphan) {
734                node.active = false;
735            }
736        }
737    }
738    #[cfg_attr(debug_assertions, contract(
739        ensures(!ret || value || !self.active.contains(id) || (old(self.active.clone()) == self.active && self.nodes[id].to.iter().any(|id| self.contains_active(id)))),
740        ensures(!ret || !value || self.contains_active(id) && !self.nodes[id].to.iter().any(|id| self.active.contains(id))),
741        ensures(ret || old(self.active.clone()) == self.active),
742        ensures(ret == self.nodes.contains_key(id)),
743        ensures(old(self.nodes.keys().copied().collect::<HashSet<_>>()) == self.nodes.keys().copied().collect::<HashSet<_>>()),
744        ensures(old(self.roots.clone()) == self.roots),
745        ensures(old(self.bookmarked.clone()) == self.bookmarked),
746        invariant(self.validate())
747    ))]
748    #[allow(clippy::missing_panics_doc, reason = "Should never panic")]
749    /// Sets the active status of a node with the specified identifier, using identical activation behavior to [`DependentWeave`].
750    pub fn set_active_dependent_semantics(&mut self, id: &K, value: bool) -> bool {
751        if value {
752            if let Some(node) = self.nodes.get(id) {
753                if node.active && !node.to.iter().any(|id| self.active.contains(id)) {
754                    return true;
755                }
756
757                if !node.active
758                    && ((node.from.is_empty() && self.active.is_empty())
759                        || node.from.iter().any(|parent| {
760                            self.active.contains(parent)
761                                && self.nodes[parent]
762                                    .to
763                                    .iter()
764                                    .all(|child| !self.active.contains(child))
765                        }))
766                {
767                    self.nodes.get_mut(id).unwrap().active = true;
768                    self.active.insert(*id);
769                    return true;
770                }
771            } else {
772                return false;
773            }
774
775            for root in &self.roots {
776                topological_sort(
777                    &self.nodes,
778                    root,
779                    &mut self.scratchpad_stack,
780                    &mut self.scratchpad_list, // topological order
781                    &mut self.scratchpad_set,
782                    &mut self.scratchpad_map,
783                );
784            }
785
786            self.scratchpad_set.clear();
787            self.scratchpad_map.clear();
788
789            for id in self.scratchpad_list.drain(..) {
790                let node = &self.nodes[&id];
791
792                let best_parent = node
793                    .from
794                    .iter()
795                    .map(|id| (id, self.scratchpad_map_3[id])) // score: (connectors, active)
796                    .min_by(|(_, a), (_, b)| b.1.cmp(&a.1).then(a.0.cmp(&b.0)));
797
798                let (parent, score) = if let Some((parent, mut score)) = best_parent {
799                    if node.active {
800                        score.1 = score.1.strict_add(1);
801                    } else {
802                        score.0 = score.0.strict_add(1);
803                    }
804
805                    (Some(parent), score)
806                } else {
807                    (None, if node.active { (0, 1) } else { (1, 0) })
808                };
809
810                if let Some(parent) = parent {
811                    self.scratchpad_map_2.insert(id, *parent); // predecessors
812                }
813
814                self.scratchpad_map_3.insert(id, score);
815            }
816
817            let mut current = Some(id);
818
819            while let Some(id) = current {
820                self.scratchpad_set.insert(*id);
821                current = self.scratchpad_map_2.get(id);
822            }
823
824            self.scratchpad_map_2.clear();
825            self.scratchpad_map_3.clear();
826
827            self.scratchpad_list
828                .extend(self.active.difference(&self.scratchpad_set).copied());
829
830            for id in self.scratchpad_list.drain(..) {
831                self.nodes.get_mut(&id).unwrap().active = false;
832                self.active.remove(&id);
833            }
834
835            self.scratchpad_list
836                .extend(self.scratchpad_set.difference(&self.active).copied());
837
838            self.scratchpad_set.clear();
839
840            for id in self.scratchpad_list.drain(..) {
841                self.nodes.get_mut(&id).unwrap().active = true;
842                self.active.insert(id);
843            }
844        } else if let Some(node) = self.nodes.get_mut(id) {
845            if !node.active || node.to.iter().any(|id| self.active.contains(id)) {
846                return true;
847            }
848
849            node.active = false;
850            self.active.remove(&node.id);
851        } else {
852            return false;
853        }
854
855        true
856    }
857}
858
859impl<K, T, M, S> From<DependentWeave<K, T, M, S>> for IndependentWeave<K, T, M, S>
860where
861    K: Hash + Copy + Eq + Ord,
862    T: IndependentContents,
863    S: BuildHasher + Default + Clone,
864{
865    fn from(value: DependentWeave<K, T, M, S>) -> Self {
866        let mut output = Self {
867            active: HashSet::with_capacity_and_hasher(value.nodes.capacity(), S::default()),
868            scratchpad_list: Vec::with_capacity(value.nodes.capacity()),
869            scratchpad_list_2: Vec::with_capacity(value.nodes.capacity()),
870            scratchpad_set: HashSet::with_capacity_and_hasher(value.nodes.capacity(), S::default()),
871            scratchpad_set_2: HashSet::with_capacity_and_hasher(
872                value.nodes.capacity(),
873                S::default(),
874            ),
875            scratchpad_map: HashMap::with_capacity_and_hasher(value.nodes.capacity(), S::default()),
876            scratchpad_map_2: HashMap::with_capacity_and_hasher(
877                value.nodes.capacity(),
878                S::default(),
879            ),
880            scratchpad_map_3: HashMap::with_capacity_and_hasher(
881                value.nodes.capacity(),
882                S::default(),
883            ),
884            scratchpad_stack: Vec::with_capacity(value.nodes.capacity()),
885            scratchpad_queue: VecDeque::with_capacity(value.nodes.capacity()),
886            nodes: {
887                let mut map =
888                    HashMap::with_capacity_and_hasher(value.nodes.capacity(), S::default());
889                map.extend(value.nodes.into_iter().map(|(id, mut node)| {
890                    node.active = false;
891                    (id, node.into())
892                }));
893
894                map
895            },
896            roots: value.roots,
897            bookmarked: value.bookmarked,
898            metadata: value.metadata,
899        };
900
901        if let Some(active) = value.active {
902            output.set_active(&active, true);
903        }
904
905        debug_assert!(output.validate(), "Converted weave is malformed");
906
907        output
908    }
909}
910
911#[allow(clippy::panic_in_result_fn, reason = "Should never panic")]
912#[allow(clippy::unreachable, reason = "Should never panic")]
913impl<K, T, M, S> TryFrom<IndependentWeave<K, T, M, S>> for DependentWeave<K, T, M, S>
914where
915    K: Hash + Copy + Eq + Ord,
916    T: IndependentContents,
917    S: BuildHasher + Default + Clone,
918{
919    type Error = IndependentWeave<K, T, M, S>;
920
921    fn try_from(value: IndependentWeave<K, T, M, S>) -> Result<Self, Self::Error> {
922        if value.nodes.iter().all(|(_, node)| node.from.len() < 2) {
923            let mut active = None;
924
925            let output = Self {
926                nodes: {
927                    let mut map =
928                        HashMap::with_capacity_and_hasher(value.nodes.capacity(), S::default());
929                    map.extend(value.nodes.into_iter().map(|(id, mut node)| {
930                        node.active =
931                            node.active && !node.to.iter().any(|id| value.active.contains(id));
932                        if node.active {
933                            active = Some(id);
934                        }
935
936                        node.try_into()
937                            .map_or_else(|_| unreachable!(), |node| (id, node))
938                    }));
939
940                    map
941                },
942                roots: value.roots,
943                active,
944                bookmarked: value.bookmarked,
945                scratchpad: value.scratchpad_stack,
946                metadata: value.metadata,
947            };
948
949            debug_assert!(output.validate(), "Converted weave is malformed");
950
951            Ok(output)
952        } else {
953            Err(value)
954        }
955    }
956}
957
958impl<K, T, M, S> Weave<K, IndependentNode<K, T, S>, T> for IndependentWeave<K, T, M, S>
959where
960    K: Hash + Copy + Eq + Ord,
961    T: IndependentContents,
962    S: BuildHasher + Default + Clone,
963{
964    type Nodes = HashMap<K, IndependentNode<K, T, S>, S>;
965    type Roots = IndexSet<K, S>;
966
967    #[inline]
968    fn len(&self) -> usize {
969        self.nodes.len()
970    }
971    #[inline]
972    fn is_empty(&self) -> bool {
973        self.nodes.is_empty()
974    }
975    #[inline]
976    fn nodes(&self) -> &Self::Nodes {
977        &self.nodes
978    }
979    #[inline]
980    fn roots(&self) -> &Self::Roots {
981        &self.roots
982    }
983    #[inline]
984    fn contains(&self, id: &K) -> bool {
985        self.nodes.contains_key(id)
986    }
987    #[inline]
988    fn contains_active(&self, id: &K) -> bool {
989        self.active.contains(id)
990    }
991    #[inline]
992    fn get(&self, id: &K) -> Option<&IndependentNode<K, T, S>> {
993        self.nodes.get(id)
994    }
995    #[inline]
996    fn get_parents(&self, id: &K) -> Option<&IndexSet<K, S>> {
997        self.nodes.get(id).map(|node| &node.from)
998    }
999    #[inline]
1000    fn get_children(&self, id: &K) -> Option<&IndexSet<K, S>> {
1001        self.nodes.get(id).map(|node| &node.to)
1002    }
1003    #[inline]
1004    fn get_contents(&self, id: &K) -> Option<&T> {
1005        self.nodes.get(id).map(|node| &node.contents)
1006    }
1007    #[cfg_attr(debug_assertions, contract(
1008        ensures(output.len() == self.nodes.len()),
1009        ensures(valid_topological_sort(&self.nodes, output)),
1010        ensures(old(self.nodes.keys().copied().collect::<HashSet<_>>()) == self.nodes.keys().copied().collect::<HashSet<_>>()),
1011        ensures(old(self.roots.clone()) == self.roots),
1012        ensures(old(self.active.clone()) == self.active),
1013        ensures(old(self.bookmarked.clone()) == self.bookmarked),
1014        invariant(self.validate())
1015    ))]
1016    fn get_ordered_identifiers(&mut self, output: &mut Vec<K>) {
1017        output.clear();
1018
1019        for root in &self.roots {
1020            topological_sort(
1021                &self.nodes,
1022                root,
1023                &mut self.scratchpad_stack,
1024                output,
1025                &mut self.scratchpad_set,
1026                &mut self.scratchpad_map,
1027            );
1028        }
1029
1030        self.scratchpad_set.clear();
1031        self.scratchpad_map.clear();
1032    }
1033    #[cfg_attr(debug_assertions, contract(
1034        ensures(lacks_duplicates(output)),
1035        ensures(!self.nodes.contains_key(id) || output.first() == Some(id)),
1036        ensures(self.nodes.contains_key(id) || output.is_empty()),
1037        ensures(old(self.nodes.keys().copied().collect::<HashSet<_>>()) == self.nodes.keys().copied().collect::<HashSet<_>>()),
1038        ensures(old(self.roots.clone()) == self.roots),
1039        ensures(old(self.active.clone()) == self.active),
1040        ensures(old(self.bookmarked.clone()) == self.bookmarked),
1041        invariant(self.validate())
1042    ))]
1043    fn get_ordered_identifiers_from(&mut self, id: &K, output: &mut Vec<K>) {
1044        output.clear();
1045
1046        if self.nodes.contains_key(id) {
1047            descendant_subgraph(
1048                &self.nodes,
1049                *id,
1050                &mut self.scratchpad_stack,
1051                &mut self.scratchpad_set,
1052            );
1053
1054            topological_sort_subgraph(
1055                &self.nodes,
1056                &|id| self.scratchpad_set.contains(id),
1057                id,
1058                &mut self.scratchpad_stack,
1059                output,
1060                &mut self.scratchpad_set_2,
1061                &mut self.scratchpad_map,
1062            );
1063
1064            self.scratchpad_set.clear();
1065            self.scratchpad_set_2.clear();
1066            self.scratchpad_map.clear();
1067        }
1068    }
1069    #[cfg_attr(debug_assertions, contract(
1070        ensures(output.len() == self.active.len()),
1071        ensures(output.iter().all(|i| self.active.contains(i))),
1072        ensures(lacks_duplicates(output)),
1073        ensures(valid_path(&self.nodes, output)),
1074        ensures(old(self.nodes.keys().copied().collect::<HashSet<_>>()) == self.nodes.keys().copied().collect::<HashSet<_>>()),
1075        ensures(old(self.roots.clone()) == self.roots),
1076        ensures(old(self.active.clone()) == self.active),
1077        ensures(old(self.bookmarked.clone()) == self.bookmarked),
1078        invariant(self.validate())
1079    ))]
1080    fn get_active_path(&mut self, output: &mut Vec<K>) {
1081        output.clear();
1082
1083        for root in &self.roots {
1084            topological_sort_subgraph(
1085                &self.nodes,
1086                &|id| self.active.contains(id),
1087                root,
1088                &mut self.scratchpad_stack,
1089                &mut self.scratchpad_list,
1090                &mut self.scratchpad_set,
1091                &mut self.scratchpad_map,
1092            );
1093        }
1094
1095        self.scratchpad_set.clear();
1096        self.scratchpad_map.clear();
1097
1098        longest_candidate_path_to_root(
1099            &self.nodes,
1100            &self.scratchpad_list,
1101            &|id| self.active.contains(id),
1102            &mut self.scratchpad_map,
1103            output,
1104        );
1105
1106        self.scratchpad_list.clear();
1107        self.scratchpad_map.clear();
1108    }
1109    #[cfg_attr(debug_assertions, contract(
1110        ensures(!self.nodes.contains_key(id) || output.first() == Some(id)),
1111        ensures(self.nodes.contains_key(id) || output.is_empty()),
1112        ensures(lacks_duplicates(output)),
1113        ensures(valid_path(&self.nodes, output)),
1114        ensures(old(self.nodes.keys().copied().collect::<HashSet<_>>()) == self.nodes.keys().copied().collect::<HashSet<_>>()),
1115        ensures(old(self.roots.clone()) == self.roots),
1116        ensures(old(self.active.clone()) == self.active),
1117        ensures(old(self.bookmarked.clone()) == self.bookmarked),
1118        invariant(self.validate())
1119    ))]
1120    fn get_path_from(&mut self, id: &K, output: &mut Vec<K>) {
1121        output.clear();
1122        if !self.nodes.contains_key(id) {
1123            return;
1124        }
1125
1126        ancestor_subgraph(
1127            &self.nodes,
1128            *id,
1129            &mut self.scratchpad_stack,
1130            &mut self.scratchpad_set,
1131        );
1132
1133        for root in &self.roots {
1134            topological_sort_subgraph(
1135                &self.nodes,
1136                &|id| self.active.contains(id),
1137                root,
1138                &mut self.scratchpad_stack,
1139                &mut self.scratchpad_list,
1140                &mut self.scratchpad_set_2,
1141                &mut self.scratchpad_map,
1142            );
1143        }
1144
1145        self.scratchpad_map.clear();
1146
1147        longest_candidate_path_to_root(
1148            &self.nodes,
1149            &self.scratchpad_list,
1150            &|id| self.active.contains(id) && self.scratchpad_set.contains(id),
1151            &mut self.scratchpad_map,
1152            &mut self.scratchpad_list_2,
1153        );
1154
1155        self.scratchpad_list.clear();
1156        self.scratchpad_set.clear();
1157        self.scratchpad_set_2.clear();
1158        self.scratchpad_map.clear();
1159
1160        if let Some(target) = self.scratchpad_list_2.first().copied() {
1161            shortest_path_to_ancestor(
1162                &self.nodes,
1163                id,
1164                &|node| node.id == target,
1165                &mut self.scratchpad_queue,
1166                &mut self.scratchpad_map_2,
1167                &mut self.scratchpad_set_2,
1168                output,
1169            );
1170
1171            output.reverse();
1172            output.pop();
1173            output.append(&mut self.scratchpad_list_2);
1174        } else {
1175            shortest_path_to_ancestor(
1176                &self.nodes,
1177                id,
1178                &|node| node.from.is_empty(),
1179                &mut self.scratchpad_queue,
1180                &mut self.scratchpad_map_2,
1181                &mut self.scratchpad_set_2,
1182                output,
1183            );
1184
1185            output.reverse();
1186        }
1187
1188        self.scratchpad_set_2.clear();
1189        self.scratchpad_map_2.clear();
1190    }
1191    #[cfg_attr(debug_assertions, contract(
1192        ensures(!ret || old(self.nodes.len()) + 1 == self.nodes.len()),
1193        ensures(!ret || old(!self.nodes.contains_key(&node.id))),
1194        ensures(!ret || self.nodes.contains_key(&old(node.id))),
1195        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))))),
1196        ensures(!ret || old(node.bookmarked) == self.bookmarked.contains(&old(node.id))),
1197        ensures(!ret || old(!node.from.is_empty()) || self.roots.contains(&old(node.id))),
1198        ensures(ret || old(self.nodes.keys().copied().collect::<HashSet<_>>()) == self.nodes.keys().copied().collect::<HashSet<_>>()),
1199        ensures(ret || old(self.roots.clone()) == self.roots),
1200        ensures(ret || old(self.active.clone()) == self.active),
1201        ensures(ret || old(self.bookmarked.clone()) == self.bookmarked),
1202        invariant(self.validate())
1203    ))]
1204    fn insert(&mut self, mut node: IndependentNode<K, T, S>) -> bool {
1205        if self.nodes.contains_key(&node.id)
1206            || !node.validate()
1207            || !node.from.iter().all(|id| self.nodes.contains_key(id))
1208            || !node.to.iter().all(|id| self.nodes.contains_key(id))
1209        {
1210            return false;
1211        }
1212
1213        if !node.to.is_empty() && !node.from.is_empty() {
1214            for parent in node.from.iter().copied() {
1215                ancestor_subgraph(
1216                    &self.nodes,
1217                    parent,
1218                    &mut self.scratchpad_stack,
1219                    &mut self.scratchpad_set,
1220                );
1221            }
1222
1223            if node
1224                .to
1225                .iter()
1226                .any(|child| self.scratchpad_set.contains(child))
1227            {
1228                self.scratchpad_set.clear();
1229                return false;
1230            }
1231
1232            self.scratchpad_set.clear();
1233        }
1234
1235        let root_index = if node.from.is_empty() {
1236            node.to
1237                .iter()
1238                .filter_map(|child| self.roots.get_index_of(child))
1239                .min()
1240        } else {
1241            None
1242        };
1243
1244        for child in &node.to {
1245            let child = &self.nodes[child];
1246            if child.from.is_empty() {
1247                if child.active {
1248                    node.active = true;
1249                }
1250                self.roots.shift_remove(&child.id);
1251            }
1252        }
1253
1254        let extends_active = node.active
1255            && node.to.is_empty()
1256            && node.from.iter().map(|id| &self.nodes[id]).any(|parent| {
1257                parent.active && parent.to.iter().all(|child| !self.active.contains(child))
1258            });
1259
1260        if node.from.is_empty() {
1261            if let Some(index) = root_index {
1262                self.roots.shift_insert(index, node.id);
1263            } else {
1264                self.roots.insert(node.id);
1265            }
1266        } else {
1267            for parent in &node.from {
1268                let parent = self.nodes.get_mut(parent).unwrap();
1269                parent.to.insert(node.id);
1270            }
1271        }
1272
1273        for child in &node.to {
1274            let child = self.nodes.get_mut(child).unwrap();
1275            child.from.insert(node.id);
1276        }
1277
1278        if node.bookmarked {
1279            self.bookmarked.insert(node.id);
1280        }
1281
1282        let id = node.id;
1283        let active = node.active;
1284
1285        if !extends_active {
1286            node.active = false;
1287        }
1288
1289        self.nodes.insert(node.id, node);
1290
1291        if extends_active {
1292            self.active.insert(id);
1293        } else if active {
1294            self.update_node_activity_in_place(&id, true);
1295        }
1296
1297        true
1298    }
1299    #[cfg_attr(debug_assertions, contract(
1300        ensures(!ret || value == self.contains_active(id)),
1301        ensures(ret || old(self.active.clone()) == self.active),
1302        ensures(ret == self.nodes.contains_key(id)),
1303        ensures(old(self.nodes.keys().copied().collect::<HashSet<_>>()) == self.nodes.keys().copied().collect::<HashSet<_>>()),
1304        ensures(old(self.roots.clone()) == self.roots),
1305        ensures(old(self.bookmarked.clone()) == self.bookmarked),
1306        invariant(self.validate())
1307    ))]
1308    fn set_active(&mut self, id: &K, value: bool) -> bool {
1309        self.update_node_activity_in_place(id, value)
1310    }
1311    #[cfg_attr(debug_assertions, contract(
1312        ensures(!self.nodes.contains_key(id)),
1313        ensures(ret.is_some() == old(self.nodes.contains_key(id))),
1314        ensures(ret.as_ref().is_none_or(|node| &node.id == id)),
1315        ensures(ret.is_none() || old(self.nodes.len()) > self.nodes.len()),
1316        ensures(ret.is_none() || old(self.active.len()) >= self.active.len()),
1317        ensures(ret.is_none() || old(self.bookmarked.len()) >= self.bookmarked.len()),
1318        ensures(ret.is_some() || old(self.nodes.keys().copied().collect::<HashSet<_>>()) == self.nodes.keys().copied().collect::<HashSet<_>>()),
1319        ensures(ret.is_some() || old(self.roots.clone()) == self.roots),
1320        ensures(ret.is_some() || old(self.active.clone()) == self.active),
1321        ensures(ret.is_some() || old(self.bookmarked.clone()) == self.bookmarked),
1322        invariant(self.validate())
1323    ))]
1324    fn remove(&mut self, id: &K) -> Option<IndependentNode<K, T, S>> {
1325        let mut removed_node = None;
1326        let mut removed_active = false;
1327
1328        self.scratchpad_stack.push(*id);
1329
1330        while let Some(id) = self.scratchpad_stack.pop() {
1331            if let Some(node) = self.nodes.remove(&id) {
1332                if removed_node.is_none() && node.from.is_empty() {
1333                    self.roots.shift_remove(&id);
1334                }
1335                if node.bookmarked {
1336                    self.bookmarked.shift_remove(&id);
1337                }
1338                if node.active {
1339                    self.active.remove(&id);
1340                    removed_active = true;
1341                }
1342
1343                for parent in &node.from {
1344                    if let Some(parent) = self.nodes.get_mut(parent) {
1345                        parent.to.shift_remove(&node.id);
1346                    }
1347                }
1348                for child in node.to.iter().rev() {
1349                    if let Some(child) = self.nodes.get_mut(child) {
1350                        child.from.shift_remove(&node.id);
1351
1352                        if child.from.is_empty() {
1353                            self.scratchpad_stack.push(child.id);
1354                        }
1355                    }
1356                }
1357
1358                if removed_node.is_none() {
1359                    removed_node = Some(node);
1360                }
1361            }
1362        }
1363
1364        if removed_node.is_some() {
1365            if removed_active {
1366                // matches set_active(id, false)
1367                self.fix_orphaned_activations();
1368            }
1369            removed_node
1370        } else {
1371            None
1372        }
1373    }
1374    #[cfg_attr(debug_assertions, contract(
1375        ensures(!self.nodes.contains_key(id)),
1376        ensures(ret == old(self.nodes.contains_key(id))),
1377        ensures(!ret || old(self.nodes.len()) > self.nodes.len()),
1378        ensures(!ret || old(self.active.len()) >= self.active.len()),
1379        ensures(!ret || old(self.bookmarked.len()) >= self.bookmarked.len()),
1380        ensures(ret || old(self.nodes.keys().copied().collect::<HashSet<_>>()) == self.nodes.keys().copied().collect::<HashSet<_>>()),
1381        ensures(ret || old(self.roots.clone()) == self.roots),
1382        ensures(ret || old(self.active.clone()) == self.active),
1383        ensures(ret || old(self.bookmarked.clone()) == self.bookmarked),
1384        invariant(self.validate())
1385    ))]
1386    fn remove_tracked(
1387        &mut self,
1388        id: &K,
1389        mut on_removal: impl FnMut(IndependentNode<K, T, S>),
1390    ) -> bool {
1391        let had_node = match self.nodes.get(id) {
1392            Some(node) => {
1393                if node.from.is_empty() {
1394                    self.roots.shift_remove(id);
1395                }
1396
1397                true
1398            }
1399            None => false,
1400        };
1401        let mut removed_active = false;
1402
1403        self.scratchpad_stack.push(*id);
1404
1405        while let Some(id) = self.scratchpad_stack.pop() {
1406            if let Some(node) = self.nodes.remove(&id) {
1407                if node.bookmarked {
1408                    self.bookmarked.shift_remove(&id);
1409                }
1410                if node.active {
1411                    self.active.remove(&id);
1412                    removed_active = true;
1413                }
1414
1415                for parent in &node.from {
1416                    if let Some(parent) = self.nodes.get_mut(parent) {
1417                        parent.to.shift_remove(&node.id);
1418                    }
1419                }
1420                for child in node.to.iter().rev() {
1421                    if let Some(child) = self.nodes.get_mut(child) {
1422                        child.from.shift_remove(&node.id);
1423
1424                        if child.from.is_empty() {
1425                            self.scratchpad_stack.push(child.id);
1426                        }
1427                    }
1428                }
1429
1430                on_removal(node);
1431            }
1432        }
1433
1434        if had_node {
1435            if removed_active {
1436                self.fix_orphaned_activations();
1437            }
1438            true
1439        } else {
1440            false
1441        }
1442    }
1443    #[cfg_attr(debug_assertions, contract(
1444        ensures(self.nodes.is_empty()),
1445        ensures(self.validate())
1446    ))]
1447    fn clear(&mut self) {
1448        self.nodes.clear();
1449        self.roots.clear();
1450        self.active.clear();
1451        self.bookmarked.clear();
1452    }
1453}
1454
1455impl<K, T, M, S> IndependentWeave<K, T, M, S>
1456where
1457    K: Hash + Copy + Eq + Ord,
1458    T: IndependentContents,
1459    S: BuildHasher + Default + Clone,
1460{
1461    /// Validates that the weave is internally consistent.
1462    pub fn validate(&self) -> bool {
1463        let mut scratchpad = Vec::with_capacity(self.nodes.len());
1464        let mut scratchpad_map = HashMap::with_capacity_and_hasher(self.nodes.len(), S::default());
1465
1466        self.validate_scratchpads()
1467            && self
1468                .roots
1469                .iter()
1470                .all(move |value| self.nodes.contains_key(value))
1471            && self
1472                .active
1473                .iter()
1474                .all(move |value| self.nodes.contains_key(value))
1475            && self
1476                .bookmarked
1477                .iter()
1478                .all(move |value| self.nodes.contains_key(value))
1479            && self.nodes.iter().all(|(key, value)| {
1480                value.validate()
1481                    && value.id == *key
1482                    && value
1483                        .from
1484                        .iter()
1485                        .all(|v| self.nodes.get(v).is_some_and(|p| p.to.contains(key)))
1486                    && value
1487                        .to
1488                        .iter()
1489                        .all(|v| self.nodes.get(v).is_some_and(|p| p.from.contains(key)))
1490                    && value.from.is_empty() == self.roots.contains(key)
1491                    && value.active == self.active.contains(key)
1492                    && value.bookmarked == self.bookmarked.contains(key)
1493            })
1494            && !detect_cycles(
1495                &self.nodes,
1496                self.roots.iter().copied(),
1497                &mut scratchpad,
1498                &mut scratchpad_map,
1499            )
1500            && active_path_is_valid(&self.nodes, self.roots.iter(), &self.active)
1501    }
1502    fn validate_scratchpads(&self) -> bool {
1503        self.scratchpad_list.is_empty()
1504            && self.scratchpad_list_2.is_empty()
1505            && self.scratchpad_set.is_empty()
1506            && self.scratchpad_set_2.is_empty()
1507            && self.scratchpad_map.is_empty()
1508            && self.scratchpad_map_2.is_empty()
1509            && self.scratchpad_map_3.is_empty()
1510            && self.scratchpad_stack.is_empty()
1511            && self.scratchpad_queue.is_empty()
1512    }
1513}
1514
1515impl<K, T, M, S> MetadataWeave<K, IndependentNode<K, T, S>, T, M> for IndependentWeave<K, T, M, S>
1516where
1517    K: Hash + Copy + Eq + Ord,
1518    T: IndependentContents,
1519    S: BuildHasher + Default + Clone,
1520{
1521    #[inline]
1522    fn metadata(&self) -> &M {
1523        &self.metadata
1524    }
1525    #[cfg_attr(debug_assertions, contract(
1526        ensures(old(self.nodes.keys().copied().collect::<HashSet<_>>()) == self.nodes.keys().copied().collect::<HashSet<_>>()),
1527        ensures(old(self.roots.clone()) == self.roots),
1528        ensures(old(self.active.clone()) == self.active),
1529        ensures(old(self.bookmarked.clone()) == self.bookmarked),
1530        invariant(self.validate())
1531    ))]
1532    #[inline]
1533    fn metadata_mut<O>(&mut self, callback: impl FnOnce(&mut M) -> O) -> O {
1534        callback(&mut self.metadata)
1535    }
1536}
1537
1538impl<K, T, M, S> BookmarkableWeave<K, IndependentNode<K, T, S>, T> for IndependentWeave<K, T, M, S>
1539where
1540    K: Hash + Copy + Eq + Ord,
1541    T: IndependentContents,
1542    S: BuildHasher + Default + Clone,
1543{
1544    type Bookmarks = IndexSet<K, S>;
1545
1546    #[inline]
1547    fn bookmarks(&self) -> &Self::Bookmarks {
1548        &self.bookmarked
1549    }
1550    #[inline]
1551    fn contains_bookmark(&self, id: &K) -> bool {
1552        self.bookmarked.contains(id)
1553    }
1554    #[cfg_attr(debug_assertions, contract(
1555        ensures(!ret || value == self.bookmarked.contains(id)),
1556        ensures(ret || old(self.bookmarked.clone()) == self.bookmarked),
1557        ensures(ret == self.nodes.contains_key(id)),
1558        ensures(old(self.nodes.keys().copied().collect::<HashSet<_>>()) == self.nodes.keys().copied().collect::<HashSet<_>>()),
1559        ensures(old(self.roots.clone()) == self.roots),
1560        ensures(old(self.active.clone()) == self.active),
1561        invariant(self.validate())
1562    ))]
1563    fn set_bookmarked(&mut self, id: &K, value: bool) -> bool {
1564        match self.nodes.get_mut(id) {
1565            Some(node) => {
1566                node.bookmarked = value;
1567                if value {
1568                    self.bookmarked.insert(node.id);
1569                } else {
1570                    self.bookmarked.shift_remove(id);
1571                }
1572
1573                true
1574            }
1575            None => false,
1576        }
1577    }
1578}
1579
1580impl<K, T, M, S> SortableWeave<K, IndependentNode<K, T, S>, T> for IndependentWeave<K, T, M, S>
1581where
1582    K: Hash + Copy + Eq + Ord,
1583    T: IndependentContents,
1584    S: BuildHasher + Default + Clone,
1585{
1586    #[cfg_attr(debug_assertions, contract(
1587        ensures(ret == self.nodes.contains_key(id)),
1588        ensures(old(self.nodes.get(id).map(|n| n.to.clone())) == self.nodes.get(id).map(|n| n.to.clone())),
1589        ensures(old(self.nodes.keys().copied().collect::<HashSet<_>>()) == self.nodes.keys().copied().collect::<HashSet<_>>()),
1590        ensures(old(self.roots.clone()) == self.roots),
1591        ensures(old(self.active.clone()) == self.active),
1592        ensures(old(self.bookmarked.clone()) == self.bookmarked),
1593        invariant(self.validate())
1594    ))]
1595    fn sort_children_by(
1596        &mut self,
1597        id: &K,
1598        mut cmp: impl FnMut(&IndependentNode<K, T, S>, &IndependentNode<K, T, S>) -> Ordering,
1599    ) -> bool {
1600        if let Some(mut node) = self.nodes.remove(id) {
1601            node.to.sort_by(|a, b| cmp(&self.nodes[a], &self.nodes[b]));
1602            self.nodes.insert(node.id, node);
1603
1604            true
1605        } else {
1606            false
1607        }
1608    }
1609    #[cfg_attr(debug_assertions, contract(
1610        ensures(ret == self.nodes.contains_key(id)),
1611        ensures(old(self.nodes.get(id).map(|n| n.to.clone())) == self.nodes.get(id).map(|n| n.to.clone())),
1612        ensures(old(self.nodes.keys().copied().collect::<HashSet<_>>()) == self.nodes.keys().copied().collect::<HashSet<_>>()),
1613        ensures(old(self.roots.clone()) == self.roots),
1614        ensures(old(self.active.clone()) == self.active),
1615        ensures(old(self.bookmarked.clone()) == self.bookmarked),
1616        invariant(self.validate())
1617    ))]
1618    fn sort_children_by_id(&mut self, id: &K, cmp: impl FnMut(&K, &K) -> Ordering) -> bool {
1619        if let Some(node) = self.nodes.get_mut(id) {
1620            node.to.sort_by(cmp);
1621
1622            true
1623        } else {
1624            false
1625        }
1626    }
1627    #[cfg_attr(debug_assertions, contract(
1628        ensures(old(self.nodes.keys().copied().collect::<HashSet<_>>()) == self.nodes.keys().copied().collect::<HashSet<_>>()),
1629        ensures(old(self.roots.clone()) == self.roots),
1630        ensures(old(self.active.clone()) == self.active),
1631        ensures(old(self.bookmarked.clone()) == self.bookmarked),
1632        invariant(self.validate())
1633    ))]
1634    fn sort_roots_by(
1635        &mut self,
1636        mut cmp: impl FnMut(&IndependentNode<K, T, S>, &IndependentNode<K, T, S>) -> Ordering,
1637    ) {
1638        self.roots
1639            .sort_by(|a, b| cmp(&self.nodes[a], &self.nodes[b]));
1640    }
1641    #[cfg_attr(debug_assertions, contract(
1642        ensures(old(self.nodes.keys().copied().collect::<HashSet<_>>()) == self.nodes.keys().copied().collect::<HashSet<_>>()),
1643        ensures(old(self.roots.clone()) == self.roots),
1644        ensures(old(self.active.clone()) == self.active),
1645        ensures(old(self.bookmarked.clone()) == self.bookmarked),
1646        invariant(self.validate())
1647    ))]
1648    fn sort_roots_by_id(&mut self, cmp: impl FnMut(&K, &K) -> Ordering) {
1649        self.roots.sort_by(cmp);
1650    }
1651}
1652
1653impl<K, T, M, S> SortableBookmarkableWeave<K, IndependentNode<K, T, S>, T>
1654    for IndependentWeave<K, T, M, S>
1655where
1656    K: Hash + Copy + Eq + Ord,
1657    T: IndependentContents,
1658    S: BuildHasher + Default + Clone,
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.active.clone()) == self.active),
1664        ensures(old(self.bookmarked.clone()) == self.bookmarked),
1665        invariant(self.validate())
1666    ))]
1667    fn sort_bookmarks_by(
1668        &mut self,
1669        mut cmp: impl FnMut(&IndependentNode<K, T, S>, &IndependentNode<K, T, S>) -> Ordering,
1670    ) {
1671        self.bookmarked
1672            .sort_by(|a, b| cmp(&self.nodes[a], &self.nodes[b]));
1673    }
1674    #[cfg_attr(debug_assertions, contract(
1675        ensures(old(self.nodes.keys().copied().collect::<HashSet<_>>()) == self.nodes.keys().copied().collect::<HashSet<_>>()),
1676        ensures(old(self.roots.clone()) == self.roots),
1677        ensures(old(self.active.clone()) == self.active),
1678        ensures(old(self.bookmarked.clone()) == self.bookmarked),
1679        invariant(self.validate())
1680    ))]
1681    fn sort_bookmarks_by_id(&mut self, cmp: impl FnMut(&K, &K) -> Ordering) {
1682        self.bookmarked.sort_by(cmp);
1683    }
1684}
1685
1686impl<K, T, M, S> ActivePathWeave<K, IndependentNode<K, T, S>, T> for IndependentWeave<K, T, M, S>
1687where
1688    K: Hash + Copy + Eq + Ord,
1689    T: IndependentContents,
1690    S: BuildHasher + Default + Clone,
1691{
1692    type Active = HashSet<K, S>;
1693
1694    #[inline]
1695    fn active(&self) -> &Self::Active {
1696        &self.active
1697    }
1698    #[cfg_attr(debug_assertions, contract(
1699        ensures(old(self.nodes.keys().copied().collect::<HashSet<_>>()) == self.nodes.keys().copied().collect::<HashSet<_>>()),
1700        ensures(old(self.roots.clone()) == self.roots),
1701        ensures(old(self.bookmarked.clone()) == self.bookmarked),
1702        invariant(self.validate())
1703    ))]
1704    fn set_active_path(&mut self, active: impl Iterator<Item = K>) {
1705        self.active.iter().for_each(|active| {
1706            self.nodes.get_mut(active).unwrap().active = false;
1707        });
1708        self.active.clear();
1709        self.active
1710            .extend(active.filter(|id| self.nodes.contains_key(id)));
1711        self.active.iter().for_each(|active| {
1712            self.nodes.get_mut(active).unwrap().active = true;
1713        });
1714        self.fix_orphaned_activations();
1715    }
1716}
1717
1718impl<K, T, M, S> DiscreteWeave<K, IndependentNode<K, T, S>, T> for IndependentWeave<K, T, M, S>
1719where
1720    K: Hash + Copy + Eq + Ord,
1721    T: IndependentContents + DiscreteContents,
1722    S: BuildHasher + Default + Clone,
1723{
1724    #[cfg_attr(debug_assertions, contract(
1725        ensures(!ret || old(self.nodes.len()) + 1 == self.nodes.len()),
1726        ensures(!ret || self.nodes.contains_key(id)),
1727        ensures(!ret || self.nodes.contains_key(&new_id)),
1728        ensures(!ret || old(!self.nodes.contains_key(&new_id))),
1729        ensures(!ret || self.nodes[id].to.contains(&new_id) && self.nodes[id].to.len() == 1),
1730        ensures(!ret || self.nodes[&new_id].from.contains(id) && self.nodes[&new_id].from.len() == 1),
1731        ensures(!ret || old(self.nodes.get(id).map(|n| n.to.clone())).unwrap() == self.nodes[&new_id].to),
1732        ensures(ret || old(self.nodes.keys().copied().collect::<HashSet<_>>()) == self.nodes.keys().copied().collect::<HashSet<_>>()),
1733        ensures(ret || old(self.active.clone()) == self.active),
1734        ensures(old(self.roots.clone()) == self.roots),
1735        ensures(old(self.bookmarked.clone()) == self.bookmarked),
1736        invariant(self.validate())
1737    ))]
1738    fn split(&mut self, id: &K, at: usize, new_id: K) -> bool {
1739        if self.nodes.contains_key(&new_id) || *id == new_id {
1740            return false;
1741        }
1742
1743        if let Some(mut node) = self.nodes.remove(id) {
1744            match node.contents.split(at) {
1745                DiscreteContentResult::Two(left, right) => {
1746                    let left_node = IndependentNode {
1747                        id: node.id,
1748                        from: node.from,
1749                        to: IndexSet::from_iter([new_id]),
1750                        active: node.active,
1751                        bookmarked: node.bookmarked,
1752                        contents: left,
1753                    };
1754
1755                    node.from = IndexSet::from_iter([node.id]);
1756                    node.id = new_id;
1757                    node.contents = right;
1758                    node.active = false;
1759                    node.bookmarked = false;
1760
1761                    for child in &node.to {
1762                        let child = self.nodes.get_mut(child).unwrap();
1763                        let index = child.from.get_index_of(&left_node.id).unwrap();
1764
1765                        assert!(
1766                            child.from.replace_index(index, node.id).is_ok(),
1767                            "Should be unreachable"
1768                        );
1769
1770                        if child.active && left_node.active {
1771                            node.active = true;
1772                            self.active.insert(node.id);
1773                        }
1774                    }
1775
1776                    self.nodes.insert(left_node.id, left_node);
1777                    self.nodes.insert(node.id, node);
1778
1779                    true
1780                }
1781                DiscreteContentResult::One(content) => {
1782                    node.contents = content;
1783                    self.nodes.insert(node.id, node);
1784                    false
1785                }
1786            }
1787        } else {
1788            false
1789        }
1790    }
1791    #[cfg_attr(debug_assertions, contract(
1792        ensures(ret.is_none() || old(self.nodes.len()) - 1 == self.nodes.len()),
1793        ensures(ret.is_none() || !self.nodes.contains_key(id)),
1794        ensures(ret.is_none() || old(self.nodes.contains_key(id))),
1795        ensures(ret.is_none() || !old(self.contains_active(id)) || old(self.contains_active(id)) && self.contains_active(&ret.unwrap())),
1796        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),
1797        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),
1798        ensures(ret.is_none() || old(self.nodes.get(id).map(|node| node.to.clone())).unwrap() == self.nodes[&ret.unwrap()].to),
1799        ensures(ret.is_none() || old(self.nodes.get(id).map(|node| node.from.len() == 1)).unwrap()),
1800        ensures(ret.is_none() || ret.unwrap() == old(self.nodes.get(id).and_then(|node| node.from.first().copied())).unwrap()),
1801        ensures(ret.is_some() || old(self.nodes.keys().copied().collect::<HashSet<_>>()) == self.nodes.keys().copied().collect::<HashSet<_>>()),
1802        ensures(ret.is_some() || old(self.active.clone()) == self.active),
1803        ensures(ret.is_some() || old(self.bookmarked.clone()) == self.bookmarked),
1804        ensures(old(self.roots.clone()) == self.roots),
1805        invariant(self.validate())
1806    ))]
1807    fn merge_with_parent(&mut self, id: &K) -> Option<K> {
1808        if let Some(mut node) = self.nodes.remove(id) {
1809            if node.from.len() != 1 {
1810                self.nodes.insert(node.id, node);
1811                return None;
1812            }
1813
1814            if let Some(mut parent) = node.from.first().and_then(|id| self.nodes.remove(id)) {
1815                if parent.to.len() > 1 {
1816                    self.nodes.insert(parent.id, parent);
1817                    self.nodes.insert(node.id, node);
1818                    return None;
1819                }
1820
1821                match parent.contents.merge(node.contents) {
1822                    DiscreteContentResult::Two(left, right) => {
1823                        parent.contents = left;
1824                        node.contents = right;
1825                        self.nodes.insert(parent.id, parent);
1826                        self.nodes.insert(node.id, node);
1827                        None
1828                    }
1829                    DiscreteContentResult::One(content) => {
1830                        parent.contents = content;
1831                        parent.to = node.to;
1832
1833                        for child in &parent.to {
1834                            let child = self.nodes.get_mut(child).unwrap();
1835                            let index = child.from.get_index_of(&node.id).unwrap();
1836
1837                            assert!(
1838                                child.from.replace_index(index, parent.id).is_ok(),
1839                                "Should be unreachable"
1840                            );
1841                        }
1842
1843                        let parent_id = parent.id;
1844
1845                        if node.bookmarked && !parent.bookmarked {
1846                            parent.bookmarked = true;
1847                            assert!(
1848                                self.bookmarked
1849                                    .replace_index(
1850                                        self.bookmarked.get_index_of(&node.id).unwrap(),
1851                                        parent.id,
1852                                    )
1853                                    .is_ok(),
1854                                "Should be unreachable"
1855                            );
1856                        } else {
1857                            self.bookmarked.shift_remove(&node.id);
1858                        }
1859
1860                        self.nodes.insert(parent.id, parent);
1861                        self.active.remove(&node.id);
1862
1863                        Some(parent_id)
1864                    }
1865                }
1866            } else {
1867                self.nodes.insert(node.id, node);
1868                None
1869            }
1870        } else {
1871            None
1872        }
1873    }
1874}
1875
1876impl<K, T, M, S> SemiIndependentWeave<K, IndependentNode<K, T, S>, T>
1877    for IndependentWeave<K, T, M, S>
1878where
1879    K: Hash + Copy + Eq + Ord,
1880    T: IndependentContents,
1881    S: BuildHasher + Default + Clone,
1882{
1883    #[cfg_attr(debug_assertions, contract(
1884        ensures(ret.is_some() == old(self.nodes.contains_key(id))),
1885        ensures(old(self.nodes.keys().copied().collect::<HashSet<_>>()) == self.nodes.keys().copied().collect::<HashSet<_>>()),
1886        ensures(old(self.roots.clone()) == self.roots),
1887        ensures(old(self.active.clone()) == self.active),
1888        ensures(old(self.bookmarked.clone()) == self.bookmarked),
1889        invariant(self.validate())
1890    ))]
1891    #[inline]
1892    fn get_contents_mut<O>(&mut self, id: &K, callback: impl FnOnce(&mut T) -> O) -> Option<O> {
1893        self.nodes
1894            .get_mut(id)
1895            .map(|node| callback(&mut node.contents))
1896    }
1897}
1898
1899impl<K, T, M, S> crate::IndependentWeave<K, IndependentNode<K, T, S>, T>
1900    for IndependentWeave<K, T, M, S>
1901where
1902    K: Hash + Copy + Eq + Ord,
1903    T: IndependentContents,
1904    S: BuildHasher + Default + Clone,
1905{
1906    #[cfg_attr(debug_assertions, contract(
1907        ensures(!ret || self.nodes[id].from.iter().copied().collect::<HashSet<_>>() == new_parents.iter().copied().collect::<HashSet<_>>()),
1908        ensures(ret || old(self.nodes.get(id).map(|node| node.from.clone())).as_ref() == self.nodes.get(id).map(|node| &node.from)),
1909        ensures(ret || old(self.roots.clone()) == self.roots),
1910        ensures(ret || old(self.active.clone()) == self.active),
1911        ensures(old(self.nodes.get(id).map(|node| node.to.clone())).as_ref() == self.nodes.get(id).map(|node| &node.to)),
1912        ensures(old(self.nodes.keys().copied().collect::<HashSet<_>>()) == self.nodes.keys().copied().collect::<HashSet<_>>()),
1913        ensures(old(self.bookmarked.clone()) == self.bookmarked),
1914        ensures(old(self.active.contains(id)) == self.active.contains(id)),
1915        invariant(self.validate())
1916    ))]
1917    fn move_to(&mut self, id: &K, new_parents: &[K]) -> bool {
1918        if new_parents
1919            .iter()
1920            .any(|new_parent| !self.nodes.contains_key(new_parent))
1921        {
1922            return false;
1923        }
1924
1925        if let Some(node) = self.nodes.get(id)
1926            && !node.to.is_empty()
1927            && !new_parents.is_empty()
1928        {
1929            for child in node.to.iter().copied() {
1930                descendant_subgraph(
1931                    &self.nodes,
1932                    child,
1933                    &mut self.scratchpad_stack,
1934                    &mut self.scratchpad_set,
1935                );
1936            }
1937
1938            if new_parents
1939                .iter()
1940                .any(|new_parent| self.scratchpad_set.contains(new_parent))
1941            {
1942                self.scratchpad_set.clear();
1943                return false;
1944            }
1945
1946            self.scratchpad_set.clear();
1947        }
1948
1949        let new_parents: IndexSet<K, S> = new_parents.iter().copied().collect();
1950
1951        if new_parents.contains(id) {
1952            return false;
1953        }
1954
1955        if let Some(node) = self.nodes.get_mut(id) {
1956            let old_parents = mem::take(&mut node.from);
1957
1958            for old_parent in &old_parents {
1959                if !new_parents.contains(old_parent)
1960                    && let Some(old_parent) = self.nodes.get_mut(old_parent)
1961                {
1962                    old_parent.to.shift_remove(id);
1963                }
1964            }
1965
1966            for new_parent in &new_parents {
1967                if !old_parents.contains(new_parent)
1968                    && let Some(new_parent) = self.nodes.get_mut(new_parent)
1969                {
1970                    new_parent.to.insert(*id);
1971                }
1972            }
1973        } else {
1974            return false;
1975        }
1976
1977        let node = self.nodes.get_mut(id).unwrap();
1978        node.from = new_parents;
1979
1980        if node.from.is_empty() {
1981            self.roots.insert(node.id);
1982        } else {
1983            self.roots.shift_remove(&node.id);
1984        }
1985
1986        if node.active {
1987            node.active = false; // hack
1988            self.update_node_activity_in_place(id, true);
1989        }
1990
1991        true
1992    }
1993}
1994
1995#[cfg(feature = "rkyv")]
1996impl<K, T, S> ArchivedIndependentNode<K, T, S>
1997where
1998    K: Archive + Hash + Copy + Eq + Ord,
1999    <K as Archive>::Archived: Hash + Copy + Eq + Ord + 'static,
2000    T: Archive + IndependentContents,
2001    S: BuildHasher + Default + Clone,
2002{
2003    #[inline]
2004    fn validate(&self) -> bool {
2005        (if self.from.len() <= self.to.len() {
2006            self.from.iter().all(|v| !self.to.contains(v))
2007        } else {
2008            self.to.iter().all(|v| !self.from.contains(v))
2009        }) && !self.from.contains(&self.id)
2010            && !self.to.contains(&self.id)
2011    }
2012}
2013
2014#[cfg(feature = "rkyv")]
2015impl<K, T, S> Node<K::Archived, T::Archived> for ArchivedIndependentNode<K, T, S>
2016where
2017    K: Archive + Hash + Copy + Eq + Ord,
2018    <K as Archive>::Archived: Hash + Copy + Eq + Ord + 'static,
2019    T: Archive + IndependentContents,
2020    S: BuildHasher + Default + Clone,
2021{
2022    type From = ArchivedIndexSet<K::Archived>;
2023    type To = ArchivedIndexSet<K::Archived>;
2024
2025    #[inline]
2026    fn id(&self) -> K::Archived {
2027        self.id
2028    }
2029    #[inline]
2030    fn from(&self) -> &Self::From {
2031        &self.from
2032    }
2033    #[inline]
2034    fn to(&self) -> &Self::To {
2035        &self.to
2036    }
2037    #[inline]
2038    fn is_active(&self) -> bool {
2039        self.active
2040    }
2041    #[inline]
2042    fn contents(&self) -> &T::Archived {
2043        &self.contents
2044    }
2045}
2046
2047#[cfg(feature = "rkyv")]
2048impl<K, T, M, S> ArchivedIndependentWeave<K, T, M, S>
2049where
2050    K: Archive + Hash + Copy + Eq + Ord,
2051    <K as Archive>::Archived: Hash + Copy + Eq + Ord + 'static,
2052    T: Archive + IndependentContents,
2053    M: Archive,
2054    S: BuildHasher + Default + Clone,
2055{
2056    fn validate(&self) -> bool {
2057        let mut scratchpad = Vec::with_capacity(self.nodes.len());
2058        let mut scratchpad_map = HashMap::with_capacity(self.nodes.len());
2059
2060        self.roots
2061            .iter()
2062            .all(move |value| self.nodes.contains_key(value))
2063            && self
2064                .active
2065                .iter()
2066                .all(move |value| self.nodes.contains_key(value))
2067            && self
2068                .bookmarked
2069                .iter()
2070                .all(move |value| self.nodes.contains_key(value))
2071            && self.nodes.iter().all(|(key, value)| {
2072                value.validate()
2073                    && value.id == *key
2074                    && value
2075                        .from
2076                        .iter()
2077                        .all(|v| self.nodes.get(v).is_some_and(|p| p.to.contains(key)))
2078                    && value
2079                        .to
2080                        .iter()
2081                        .all(|v| self.nodes.get(v).is_some_and(|p| p.from.contains(key)))
2082                    && value.from.is_empty() == self.roots.contains(key)
2083                    && value.active == self.active.contains(key)
2084                    && value.bookmarked == self.bookmarked.contains(key)
2085            })
2086            && !archived_detect_cycles(
2087                &self.nodes,
2088                self.roots.iter().copied(),
2089                &mut scratchpad,
2090                &mut scratchpad_map,
2091            )
2092            && archived_active_path_is_valid(&self.nodes, self.roots.iter(), &self.active)
2093    }
2094}
2095
2096#[cfg(feature = "rkyv")]
2097// SAFETY:
2098// All fields are safe to access and no unsafe functions are called
2099unsafe impl<K, T, M, S, C> Verify<C> for ArchivedIndependentWeave<K, T, M, S>
2100where
2101    K: Archive + Hash + Copy + Eq + Ord,
2102    <K as Archive>::Archived: Hash + Copy + Eq + Ord + 'static,
2103    T: Archive + IndependentContents,
2104    M: Archive,
2105    S: BuildHasher + Default + Clone,
2106    C: Fallible + ?Sized,
2107    C::Error: Source,
2108{
2109    fn verify(&self, _context: &mut C) -> Result<(), C::Error> {
2110        if !self.validate() {
2111            fail!(ValidationError)
2112        }
2113
2114        Ok(())
2115    }
2116}
2117
2118#[cfg(feature = "rkyv")]
2119impl<K, T, M, S> ImmutableWeave<K::Archived, ArchivedIndependentNode<K, T, S>, T::Archived>
2120    for ArchivedIndependentWeave<K, T, M, S>
2121where
2122    K: Archive + Hash + Copy + Eq + Ord,
2123    <K as Archive>::Archived: Hash + Copy + Eq + Ord + 'static,
2124    T: Archive + IndependentContents,
2125    M: Archive,
2126    S: BuildHasher + Default + Clone,
2127{
2128    type Nodes = ArchivedHashMap<K::Archived, ArchivedIndependentNode<K, T, S>>;
2129    type Roots = ArchivedIndexSet<K::Archived>;
2130
2131    #[inline]
2132    fn len(&self) -> usize {
2133        self.nodes.len()
2134    }
2135    #[inline]
2136    fn is_empty(&self) -> bool {
2137        self.nodes.is_empty()
2138    }
2139    #[inline]
2140    fn nodes(&self) -> &Self::Nodes {
2141        &self.nodes
2142    }
2143    #[inline]
2144    fn roots(&self) -> &Self::Roots {
2145        &self.roots
2146    }
2147    #[inline]
2148    fn contains(&self, id: &K::Archived) -> bool {
2149        self.nodes.contains_key(id)
2150    }
2151    #[inline]
2152    fn contains_active(&self, id: &K::Archived) -> bool {
2153        self.active.contains(id)
2154    }
2155    #[inline]
2156    fn get(&self, id: &K::Archived) -> Option<&ArchivedIndependentNode<K, T, S>> {
2157        self.nodes.get(id)
2158    }
2159    #[inline]
2160    fn get_parents(&self, id: &K::Archived) -> Option<&ArchivedIndexSet<K::Archived>> {
2161        self.nodes.get(id).map(|node| &node.from)
2162    }
2163    #[inline]
2164    fn get_children(&self, id: &K::Archived) -> Option<&ArchivedIndexSet<K::Archived>> {
2165        self.nodes.get(id).map(|node| &node.to)
2166    }
2167    #[inline]
2168    fn get_contents(&self, id: &K::Archived) -> Option<&T::Archived> {
2169        self.nodes.get(id).map(|node| &node.contents)
2170    }
2171    fn get_ordered_identifiers(&self, output: &mut Vec<K::Archived>) {
2172        output.clear();
2173        let mut scratchpad = Vec::with_capacity(self.len());
2174        let mut scratchpad_2 = Vec::with_capacity(self.len());
2175        let mut identifier_set = HashSet::with_capacity(self.len());
2176        let mut scratchpad_map = HashMap::with_capacity(self.len());
2177
2178        for root in self.roots.iter() {
2179            archived_topological_sort(
2180                &self.nodes,
2181                root,
2182                &mut scratchpad,
2183                &mut scratchpad_2,
2184                output,
2185                &mut identifier_set,
2186                &mut scratchpad_map,
2187            );
2188        }
2189    }
2190    fn get_ordered_identifiers_from(&self, id: &K::Archived, output: &mut Vec<K::Archived>) {
2191        output.clear();
2192
2193        if self.nodes.contains_key(id) {
2194            let mut scratchpad = Vec::with_capacity(self.len());
2195            let mut scratchpad_2 = Vec::with_capacity(self.len());
2196            let mut scratchpad_set = HashSet::with_capacity(self.len());
2197            let mut scratchpad_set_2 = HashSet::with_capacity(self.len());
2198            let mut scratchpad_map = HashMap::with_capacity(self.len());
2199
2200            archived_descendant_subgraph(&self.nodes, *id, &mut scratchpad, &mut scratchpad_set);
2201
2202            archived_topological_sort_subgraph(
2203                &self.nodes,
2204                &|id| scratchpad_set.contains(id),
2205                id,
2206                &mut scratchpad,
2207                &mut scratchpad_2,
2208                output,
2209                &mut scratchpad_set_2,
2210                &mut scratchpad_map,
2211            );
2212        }
2213    }
2214    fn get_active_path(&self, output: &mut Vec<K::Archived>) {
2215        output.clear();
2216        let mut scratchpad_list = Vec::with_capacity(self.len());
2217        let mut scratchpad_list_2 = Vec::with_capacity(self.len());
2218        let mut scratchpad_list_3 = Vec::with_capacity(self.len());
2219        let mut scratchpad_set = HashSet::with_capacity(self.len());
2220        let mut scratchpad_map = HashMap::with_capacity(self.len());
2221
2222        for root in self.roots.iter() {
2223            archived_topological_sort_subgraph(
2224                &self.nodes,
2225                &|id| self.active.contains(id),
2226                root,
2227                &mut scratchpad_list,
2228                &mut scratchpad_list_2,
2229                &mut scratchpad_list_3,
2230                &mut scratchpad_set,
2231                &mut scratchpad_map,
2232            );
2233        }
2234
2235        scratchpad_map.clear();
2236
2237        archived_longest_candidate_path_to_root(
2238            &self.nodes,
2239            &scratchpad_list_3,
2240            &|id| self.active.contains(id),
2241            &mut scratchpad_map,
2242            output,
2243        );
2244    }
2245    fn get_path_from(&self, id: &K::Archived, output: &mut Vec<K::Archived>) {
2246        output.clear();
2247
2248        if self.nodes.contains_key(id) {
2249            let mut scratchpad_list = Vec::with_capacity(self.len());
2250            let mut scratchpad_list_2 = Vec::with_capacity(self.len());
2251            let mut scratchpad_stack = Vec::with_capacity(self.len());
2252            let mut scratchpad_queue = VecDeque::with_capacity(self.len());
2253            let mut scratchpad_set = HashSet::with_capacity(self.len());
2254            let mut scratchpad_set_2 = HashSet::with_capacity(self.len());
2255            let mut scratchpad_map = HashMap::with_capacity(self.len());
2256            let mut scratchpad_map_2 = HashMap::with_capacity(self.len());
2257
2258            archived_ancestor_subgraph(
2259                &self.nodes,
2260                *id,
2261                &mut scratchpad_stack,
2262                &mut scratchpad_set,
2263            );
2264
2265            for root in self.roots.iter() {
2266                archived_topological_sort_subgraph(
2267                    &self.nodes,
2268                    &|id| self.active.contains(id),
2269                    root,
2270                    &mut scratchpad_stack,
2271                    &mut scratchpad_list_2,
2272                    &mut scratchpad_list,
2273                    &mut scratchpad_set_2,
2274                    &mut scratchpad_map,
2275                );
2276            }
2277
2278            scratchpad_map.clear();
2279
2280            archived_longest_candidate_path_to_root(
2281                &self.nodes,
2282                &scratchpad_list,
2283                &|id| self.active.contains(id) && scratchpad_set.contains(id),
2284                &mut scratchpad_map,
2285                &mut scratchpad_list_2,
2286            );
2287
2288            scratchpad_set_2.clear();
2289
2290            if let Some(target) = scratchpad_list_2.first().copied() {
2291                archived_shortest_path_to_ancestor(
2292                    &self.nodes,
2293                    id,
2294                    &|node| node.id == target,
2295                    &mut scratchpad_queue,
2296                    &mut scratchpad_map_2,
2297                    &mut scratchpad_set_2,
2298                    output,
2299                );
2300
2301                output.reverse();
2302                output.pop();
2303                output.append(&mut scratchpad_list_2);
2304            } else {
2305                archived_shortest_path_to_ancestor(
2306                    &self.nodes,
2307                    id,
2308                    &|node| node.from.is_empty(),
2309                    &mut scratchpad_queue,
2310                    &mut scratchpad_map_2,
2311                    &mut scratchpad_set_2,
2312                    output,
2313                );
2314
2315                output.reverse();
2316            }
2317        }
2318    }
2319}
2320
2321#[cfg(feature = "rkyv")]
2322impl<K, T, M, S>
2323    ImmutableMetadataWeave<K::Archived, ArchivedIndependentNode<K, T, S>, T::Archived, M::Archived>
2324    for ArchivedIndependentWeave<K, T, M, S>
2325where
2326    K: Archive + Hash + Copy + Eq + Ord,
2327    <K as Archive>::Archived: Hash + Copy + Eq + Ord + 'static,
2328    T: Archive + IndependentContents,
2329    M: Archive,
2330    S: BuildHasher + Default + Clone,
2331{
2332    #[inline]
2333    fn metadata(&self) -> &M::Archived {
2334        &self.metadata
2335    }
2336}
2337
2338#[cfg(feature = "rkyv")]
2339impl<K, T, M, S>
2340    ImmutableBookmarkableWeave<K::Archived, ArchivedIndependentNode<K, T, S>, T::Archived>
2341    for ArchivedIndependentWeave<K, T, M, S>
2342where
2343    K: Archive + Hash + Copy + Eq + Ord,
2344    <K as Archive>::Archived: Hash + Copy + Eq + Ord + 'static,
2345    T: Archive + IndependentContents,
2346    M: Archive,
2347    S: BuildHasher + Default + Clone,
2348{
2349    type Bookmarks = ArchivedIndexSet<K::Archived>;
2350
2351    #[inline]
2352    fn bookmarks(&self) -> &Self::Bookmarks {
2353        &self.bookmarked
2354    }
2355    #[inline]
2356    fn contains_bookmark(&self, id: &K::Archived) -> bool {
2357        self.bookmarked.contains(id)
2358    }
2359}
2360
2361#[cfg(feature = "rkyv")]
2362impl<K, T, M, S>
2363    ImmutableActivePathWeave<K::Archived, ArchivedIndependentNode<K, T, S>, T::Archived>
2364    for ArchivedIndependentWeave<K, T, M, S>
2365where
2366    K: Archive + Hash + Copy + Eq + Ord,
2367    <K as Archive>::Archived: Hash + Copy + Eq + Ord + 'static,
2368    T: Archive + IndependentContents,
2369    M: Archive,
2370    S: BuildHasher + Default + Clone,
2371{
2372    type Active = ArchivedHashSet<K::Archived>;
2373
2374    #[inline]
2375    fn active(&self) -> &Self::Active {
2376        &self.active
2377    }
2378}
2379
2380#[cfg(feature = "rkyv")]
2381fn archived_topological_sort<'a, K, N, T, S>(
2382    nodes: &'a ArchivedHashMap<K, N>,
2383    id: &'a K,
2384    scratchpad: &mut Vec<K>,
2385    scratchpad_2: &mut Vec<K>,
2386    identifiers: &mut Vec<K>,
2387    identifier_set: &mut HashSet<K, S>,
2388    identifier_map: &mut HashMap<K, usize, S>,
2389) where
2390    K: Hash + Copy + Eq + Ord + 'a,
2391    N: Node<K, T, From = ArchivedIndexSet<K>, To = ArchivedIndexSet<K>> + 'a,
2392    S: BuildHasher + Default + Clone,
2393{
2394    scratchpad.push(*id);
2395
2396    while let Some(id) = scratchpad.pop() {
2397        let node = &nodes[&id];
2398
2399        if identifier_set.contains(&id)
2400            || identifier_map
2401                .get(&id)
2402                .copied()
2403                .unwrap_or_else(|| node.from().len())
2404                != 0
2405        {
2406            continue;
2407        }
2408
2409        identifiers.push(id);
2410        identifier_set.insert(id);
2411
2412        for child in node.to().iter().copied() {
2413            let remaining = identifier_map
2414                .entry(child)
2415                .or_insert_with(|| nodes[&child].from().len());
2416            *remaining = remaining.strict_sub(1);
2417
2418            scratchpad_2.push(child);
2419        }
2420
2421        scratchpad_2.reverse();
2422        scratchpad.append(scratchpad_2);
2423    }
2424}
2425
2426#[cfg(feature = "rkyv")]
2427#[allow(clippy::too_many_arguments, reason = "Rkyv limitation")]
2428fn archived_topological_sort_subgraph<'a, K, N, T, S>(
2429    nodes: &'a ArchivedHashMap<K, N>,
2430    filter: &impl Fn(&K) -> bool,
2431    id: &'a K,
2432    scratchpad: &mut Vec<K>,
2433    scratchpad_2: &mut Vec<K>,
2434    identifiers: &mut Vec<K>,
2435    identifier_set: &mut HashSet<K, S>,
2436    identifier_map: &mut HashMap<K, usize, S>,
2437) where
2438    K: Hash + Copy + Eq + Ord + 'a,
2439    N: Node<K, T, From = ArchivedIndexSet<K>, To = ArchivedIndexSet<K>> + 'a,
2440    S: BuildHasher + Default + Clone,
2441{
2442    scratchpad.push(*id);
2443
2444    while let Some(id) = scratchpad.pop() {
2445        let node = &nodes[&id];
2446
2447        if !filter(&id)
2448            || identifier_set.contains(&id)
2449            || identifier_map
2450                .get(&id)
2451                .copied()
2452                .unwrap_or_else(|| node.from().iter().filter(|&parent| filter(parent)).count())
2453                != 0
2454        {
2455            continue;
2456        }
2457
2458        identifiers.push(id);
2459        identifier_set.insert(id);
2460
2461        for child in node.to().iter().copied() {
2462            let remaining = identifier_map.entry(child).or_insert_with(|| {
2463                nodes[&child]
2464                    .from()
2465                    .iter()
2466                    .filter(|&parent| filter(parent))
2467                    .count()
2468            });
2469            *remaining = remaining.strict_sub(1);
2470
2471            scratchpad_2.push(child);
2472        }
2473
2474        scratchpad_2.reverse();
2475        scratchpad.append(scratchpad_2);
2476    }
2477}
2478
2479#[cfg(feature = "rkyv")]
2480fn archived_detect_cycles<'a, K, N, T, S>(
2481    nodes: &'a ArchivedHashMap<K, N>,
2482    roots: impl Iterator<Item = K>,
2483    scratchpad: &mut Vec<Step<K, K>>,
2484    scratchpad_map: &mut HashMap<K, bool, S>,
2485) -> bool
2486where
2487    K: Hash + Copy + Eq + Ord + 'a,
2488    N: Node<K, T, From = ArchivedIndexSet<K>, To = ArchivedIndexSet<K>> + 'a,
2489    S: BuildHasher + Default + Clone,
2490{
2491    for root in roots {
2492        if scratchpad_map.contains_key(&root) {
2493            continue;
2494        }
2495
2496        scratchpad.push(Step::Enter(root));
2497
2498        while let Some(step) = scratchpad.pop() {
2499            match step {
2500                Step::Enter(id) => {
2501                    scratchpad.push(Step::Exit(id));
2502
2503                    match scratchpad_map.entry(id) {
2504                        Entry::Occupied(entry) => {
2505                            if !entry.get() {
2506                                return true;
2507                            }
2508                        }
2509                        Entry::Vacant(entry) => {
2510                            entry.insert_entry(false);
2511
2512                            scratchpad.extend(nodes[&id].to().iter().copied().map(Step::Enter));
2513                        }
2514                    }
2515                }
2516                Step::Exit(id) => {
2517                    scratchpad_map.insert(id, true);
2518                }
2519            }
2520        }
2521    }
2522
2523    scratchpad_map.len() != nodes.len()
2524}
2525
2526#[cfg(feature = "rkyv")]
2527#[allow(clippy::too_many_arguments, reason = "Rkyv limitation")]
2528fn archived_shortest_path_to_ancestor<'a, K, N, T, S>(
2529    nodes: &'a ArchivedHashMap<K, N>,
2530    id: &'a K,
2531    target: &impl Fn(&'a N) -> bool,
2532    scratchpad: &mut VecDeque<K>,
2533    scratchpad_map: &mut HashMap<K, K, S>,
2534    scratchpad_set: &mut HashSet<K, S>,
2535    path: &mut Vec<K>,
2536) where
2537    K: Hash + Copy + Eq + Ord + 'a,
2538    N: Node<K, T, From = ArchivedIndexSet<K>, To = ArchivedIndexSet<K>> + 'a,
2539    S: BuildHasher + Default + Clone,
2540{
2541    scratchpad.push_front(*id);
2542    scratchpad_set.insert(*id);
2543
2544    while let Some(id) = scratchpad.pop_back() {
2545        let node = &nodes[&id];
2546
2547        if target(node) {
2548            scratchpad.clear();
2549
2550            path.push(id);
2551
2552            while let Some(child) = scratchpad_map.remove(path.last().unwrap()) {
2553                path.push(child);
2554            }
2555
2556            return;
2557        }
2558
2559        for parent in node.from().iter().copied() {
2560            if scratchpad_set.insert(parent) {
2561                scratchpad.push_front(parent);
2562                scratchpad_map.insert(parent, id);
2563            }
2564        }
2565    }
2566}
2567
2568#[cfg(feature = "rkyv")]
2569fn archived_longest_candidate_path_to_root<'a, K, N, T, S>(
2570    nodes: &'a ArchivedHashMap<K, N>,
2571    topological_order: &'a [K],
2572    is_candidate: &impl Fn(&K) -> bool,
2573    scratchpad_map: &mut HashMap<K, usize, S>,
2574    reversed_path: &mut Vec<K>,
2575) where
2576    K: Hash + Copy + Eq + Ord + 'a,
2577    N: Node<K, T, From = ArchivedIndexSet<K>, To = ArchivedIndexSet<K>> + 'a,
2578    S: BuildHasher + Default + Clone,
2579{
2580    let mut longest_distance = None;
2581
2582    for id in topological_order {
2583        if !is_candidate(id) {
2584            continue;
2585        }
2586
2587        let node = &nodes[id];
2588        let distance = if node.from().is_empty() {
2589            Some(0)
2590        } else {
2591            node.from()
2592                .iter()
2593                .filter_map(|parent| scratchpad_map.get(parent).copied())
2594                .max()
2595                .map(|l| l.strict_add(1))
2596        };
2597
2598        if let Some(distance) = distance {
2599            scratchpad_map.insert(*id, distance);
2600
2601            if longest_distance.is_none_or(|(value, _)| distance > value) {
2602                longest_distance = Some((distance, id));
2603            }
2604        }
2605    }
2606
2607    let mut current = longest_distance.map(|(_, id)| id);
2608
2609    while let Some(id) = current {
2610        reversed_path.push(*id);
2611
2612        current = nodes[id]
2613            .from()
2614            .iter()
2615            .filter(|id| scratchpad_map.contains_key(*id))
2616            .min_by_key(|id| Reverse(scratchpad_map[*id]));
2617    }
2618}
2619
2620#[cfg(feature = "rkyv")]
2621fn archived_ancestor_subgraph<'a, K, N, T, S>(
2622    nodes: &'a ArchivedHashMap<K, N>,
2623    id: K,
2624    scratchpad: &mut Vec<K>,
2625    identifiers: &mut HashSet<K, S>,
2626) where
2627    K: Hash + Copy + Eq + Ord + 'a,
2628    N: Node<K, T, From = ArchivedIndexSet<K>, To = ArchivedIndexSet<K>> + 'a,
2629    S: BuildHasher + Default + Clone,
2630{
2631    scratchpad.push(id);
2632
2633    while let Some(id) = scratchpad.pop() {
2634        if identifiers.insert(id) {
2635            scratchpad.extend(nodes[&id].from().iter().copied());
2636        }
2637    }
2638}
2639
2640#[cfg(feature = "rkyv")]
2641fn archived_descendant_subgraph<'a, K, N, T, S>(
2642    nodes: &'a ArchivedHashMap<K, N>,
2643    id: K,
2644    scratchpad: &mut Vec<K>,
2645    identifiers: &mut HashSet<K, S>,
2646) where
2647    K: Hash + Copy + Eq + Ord + 'a,
2648    N: Node<K, T, From = ArchivedIndexSet<K>, To = ArchivedIndexSet<K>> + 'a,
2649    S: BuildHasher + Default + Clone,
2650{
2651    scratchpad.push(id);
2652
2653    while let Some(id) = scratchpad.pop() {
2654        if identifiers.insert(id) {
2655            scratchpad.extend(nodes[&id].to().iter().copied());
2656        }
2657    }
2658}
2659
2660#[cfg(feature = "rkyv")]
2661fn archived_active_path_is_valid<'a, K, N, T>(
2662    nodes: &'a ArchivedHashMap<K, N>,
2663    roots: impl Iterator<Item = &'a K>,
2664    active: &'a ArchivedHashSet<K>,
2665) -> bool
2666where
2667    K: Hash + Copy + Eq + Ord + 'a,
2668    N: Node<K, T, From = ArchivedIndexSet<K>, To = ArchivedIndexSet<K>> + 'a,
2669{
2670    let mut scratchpad = Vec::with_capacity(nodes.len());
2671    let mut scratchpad_list = Vec::with_capacity(nodes.len());
2672    let mut scratchpad_list_2 = Vec::with_capacity(nodes.len());
2673    let mut scratchpad_set = HashSet::with_capacity(nodes.len());
2674    let mut scratchpad_map = HashMap::with_capacity(nodes.len());
2675
2676    for root in roots {
2677        archived_topological_sort(
2678            nodes,
2679            root,
2680            &mut scratchpad,
2681            &mut scratchpad_list_2,
2682            &mut scratchpad_list,
2683            &mut scratchpad_set,
2684            &mut scratchpad_map,
2685        );
2686    }
2687
2688    scratchpad_list_2.clear();
2689    scratchpad_set.clear();
2690    scratchpad_map.clear();
2691
2692    archived_longest_candidate_path_to_root(
2693        nodes,
2694        &scratchpad_list,
2695        &|id| active.contains(id),
2696        &mut scratchpad_map,
2697        &mut scratchpad_list_2,
2698    );
2699
2700    scratchpad_set.extend(scratchpad_list_2);
2701
2702    scratchpad_set.len() == active.len()
2703        && scratchpad_set.into_iter().all(|id| active.contains(&id))
2704}