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