Skip to main content

universal_weave/independent/
mod.rs

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