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