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