1#![no_std]
12#![forbid(non_ascii_idents)]
13#![warn(missing_docs)]
14#![warn(let_underscore)]
15#![warn(clippy::pedantic)]
16#![warn(clippy::cargo)]
17#![allow(clippy::multiple_crate_versions, reason = "Unresolvable")]
18#![warn(clippy::nursery)]
19#![warn(clippy::restriction)]
20#![allow(clippy::blanket_clippy_restriction_lints, reason = "Conflicting lint")]
21#![allow(clippy::allow_attributes, reason = "Conflicting lint")]
22#![allow(clippy::pattern_type_mismatch, reason = "Conflicting lint")]
23#![allow(clippy::separated_literal_suffix, reason = "Conflicting lint")]
24#![allow(
25 clippy::field_scoped_visibility_modifiers,
26 reason = "Used by IndependentWeave::from()"
27)]
28#![allow(
29 clippy::missing_inline_in_public_items,
30 reason = "Reasonable candidates have already been inlined"
31)]
32#![allow(clippy::exhaustive_enums, reason = "API")]
33#![allow(clippy::exhaustive_structs, reason = "API")]
34#![allow(clippy::little_endian_bytes, reason = "API")]
35#![allow(clippy::partial_pub_fields, reason = "API")]
36#![allow(clippy::pub_use, reason = "API")]
37#![allow(clippy::arbitrary_source_item_ordering, reason = "Readability")]
38#![allow(clippy::question_mark_used, reason = "Readability")]
39#![allow(clippy::single_call_fn, reason = "Readability")]
40#![allow(clippy::single_char_lifetime_names, reason = "Readability")]
41#![allow(clippy::else_if_without_else, reason = "Style")]
42#![allow(clippy::if_then_some_else_none, reason = "Style")]
43#![allow(clippy::implicit_return, reason = "Style")]
44#![allow(clippy::min_ident_chars, reason = "Style")]
45#![allow(clippy::mod_module_files, reason = "Style")]
46#![allow(clippy::module_name_repetitions, reason = "Style")]
47#![allow(clippy::multiple_inherent_impl, reason = "Style")]
48#![allow(clippy::try_err, reason = "Style")]
49#![allow(clippy::allow_attributes_without_reason)] #![allow(clippy::indexing_slicing)] #![allow(clippy::unwrap_in_result)] #![allow(clippy::unwrap_used)] #![allow(clippy::missing_docs_in_private_items)] #![allow(clippy::shadow_unrelated)] #![allow(clippy::shadow_reuse)] mod contract;
58pub mod dependent;
59pub mod independent;
60pub mod wrappers;
61
62#[cfg(feature = "rkyv")]
63pub mod versioning;
64
65pub use contracts;
66pub use hashbrown;
67pub use indexmap;
68
69#[cfg(feature = "rkyv")]
70pub use rkyv;
71
72#[cfg(feature = "loro")]
73pub use loro;
74
75extern crate alloc;
76
77use alloc::{collections::vec_deque::VecDeque, vec::Vec};
78use core::{
79 cmp::{Ordering, Reverse},
80 hash::{BuildHasher, Hash},
81};
82
83use hashbrown::{HashMap, HashSet, hash_map::Entry};
84
85#[cfg(feature = "serde")]
86pub use serde;
87
88#[must_use]
90pub trait Node<K, T>
91where
92 K: Hash + Copy + Eq + Ord,
93{
94 type From;
96 type To;
98
99 #[must_use]
101 fn id(&self) -> K;
102 #[must_use]
104 fn from(&self) -> &Self::From;
105 #[must_use]
107 fn to(&self) -> &Self::To;
108 #[must_use]
112 fn is_active(&self) -> bool;
113 #[must_use]
115 fn contents(&self) -> &T;
116}
117
118pub trait DiscreteContents: Sized {
120 fn split(self, at: usize) -> DiscreteContentResult<Self>;
124 fn merge(self, value: Self) -> DiscreteContentResult<Self>;
128}
129
130#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
132#[allow(missing_docs, reason = "Enum items are self-explanatory")]
133#[must_use]
134pub enum DiscreteContentResult<T> {
135 One(T),
136 Two(T, T),
137}
138
139pub trait IndependentContents {}
141
142pub trait DeduplicatableContents {
146 #[must_use]
148 fn is_duplicate_of(&self, other: &Self) -> bool;
149}
150
151#[must_use]
161pub trait Weave<K, N, T>
162where
163 K: Hash + Copy + Eq + Ord,
164 N: Node<K, T>,
165{
166 type Nodes;
168 type Roots;
170
171 #[must_use]
173 fn len(&self) -> usize;
174 #[must_use]
176 fn is_empty(&self) -> bool;
177 #[must_use]
179 fn nodes(&self) -> &Self::Nodes;
180 #[must_use]
182 fn roots(&self) -> &Self::Roots;
183 #[must_use]
185 fn contains(&self, id: &K) -> bool;
186 #[must_use]
190 fn contains_active(&self, id: &K) -> bool;
191 #[must_use]
193 fn get_node(&self, id: &K) -> Option<&N>;
194 fn get_ordered_node_identifiers(&mut self, output: &mut Vec<K>);
196 fn get_ordered_node_identifiers_from(&mut self, id: &K, output: &mut Vec<K>);
198 fn get_active_path(&mut self, output: &mut Vec<K>);
200 fn get_path_from(&mut self, id: &K, output: &mut Vec<K>);
204 fn add_node(&mut self, node: N) -> bool;
208 fn set_node_active_status(&mut self, id: &K, value: bool) -> bool;
212 fn remove_node(&mut self, id: &K) -> Option<N>;
218 fn remove_node_tracked(&mut self, id: &K, on_removal: impl FnMut(N)) -> bool;
226 fn remove_all_nodes(&mut self);
228}
229
230pub trait MetadataWeave<K, N, T, M>: Weave<K, N, T>
232where
233 K: Hash + Copy + Eq + Ord,
234 N: Node<K, T>,
235{
236 #[must_use]
238 fn metadata(&self) -> &M;
239 fn metadata_mut<O>(&mut self, callback: impl FnOnce(&mut M) -> O) -> O;
245}
246
247pub trait BookmarkableWeave<K, N, T>: Weave<K, N, T>
249where
250 K: Hash + Copy + Eq + Ord,
251 N: Node<K, T>,
252{
253 type Bookmarks;
255
256 #[must_use]
258 fn bookmarks(&self) -> &Self::Bookmarks;
259 #[must_use]
261 fn contains_bookmark(&self, id: &K) -> bool;
262 fn set_node_bookmarked_status(&mut self, id: &K, value: bool) -> bool;
264}
265
266pub trait SortableWeave<K, N, T>: Weave<K, N, T>
268where
269 K: Hash + Copy + Eq + Ord,
270 N: Node<K, T>,
271{
272 fn get_ordered_node_identifiers_mirrored(&mut self, output: &mut Vec<K>);
276 fn get_ordered_node_identifiers_mirrored_from(&mut self, id: &K, output: &mut Vec<K>);
280 fn sort_node_children_by(&mut self, id: &K, cmp: impl FnMut(&N, &N) -> Ordering) -> bool;
286 fn sort_node_children_by_id(&mut self, id: &K, cmp: impl FnMut(&K, &K) -> Ordering) -> bool;
292 fn sort_roots_by(&mut self, cmp: impl FnMut(&N, &N) -> Ordering);
298 fn sort_roots_by_id(&mut self, cmp: impl FnMut(&K, &K) -> Ordering);
304}
305
306pub trait SortableBookmarkableWeave<K, N, T>:
308 BookmarkableWeave<K, N, T> + SortableWeave<K, N, T>
309where
310 K: Hash + Copy + Eq + Ord,
311 N: Node<K, T>,
312{
313 fn sort_bookmarks_by(&mut self, cmp: impl FnMut(&N, &N) -> Ordering);
319 fn sort_bookmarks_by_id(&mut self, cmp: impl FnMut(&K, &K) -> Ordering);
325}
326
327pub trait ActiveSingularWeave<K, N, T>: Weave<K, N, T>
329where
330 K: Hash + Copy + Eq + Ord,
331 N: Node<K, T>,
332{
333 #[must_use]
335 fn active(&self) -> Option<K>;
336}
337
338pub trait ActivePathWeave<K, N, T>: Weave<K, N, T>
340where
341 K: Hash + Copy + Eq + Ord,
342 N: Node<K, T>,
343{
344 type Active;
346
347 #[must_use]
349 fn active(&self) -> &Self::Active;
350 fn set_active_path(&mut self, active: impl Iterator<Item = K>);
354}
355
356pub trait IndependentWeave<K, N, T>: Weave<K, N, T> + SemiIndependentWeave<K, N, T>
358where
359 K: Hash + Copy + Eq + Ord,
360 N: Node<K, T>,
361 T: IndependentContents,
362{
363 fn move_node(&mut self, id: &K, new_parents: &[K]) -> bool;
367}
368
369pub trait SemiIndependentWeave<K, N, T>: Weave<K, N, T>
371where
372 K: Hash + Copy + Eq + Ord,
373 N: Node<K, T>,
374 T: IndependentContents,
375{
376 fn get_contents_mut<O>(&mut self, id: &K, callback: impl FnOnce(&mut T) -> O) -> Option<O>;
382}
383
384pub trait DiscreteWeave<K, N, T>: Weave<K, N, T>
386where
387 K: Hash + Copy + Eq + Ord,
388 N: Node<K, T>,
389 T: DiscreteContents,
390{
391 fn split_node(&mut self, id: &K, at: usize, new_id: K) -> bool;
395 fn merge_with_parent(&mut self, id: &K) -> Option<K>;
399}
400
401pub trait DeduplicatableWeave<K, N, T>: Weave<K, N, T>
403where
404 K: Hash + Copy + Eq + Ord,
405 N: Node<K, T>,
406 T: DeduplicatableContents,
407{
408 #[must_use]
410 fn find_duplicates(&self, id: &K) -> impl Iterator<Item = K>;
411}
412
413#[must_use]
415pub trait ImmutableWeave<K, N, T>
416where
417 K: Hash + Copy + Eq + Ord,
418 N: Node<K, T>,
419{
420 type Nodes;
422 type Roots;
424
425 #[must_use]
427 fn len(&self) -> usize;
428 #[must_use]
430 fn is_empty(&self) -> bool;
431 #[must_use]
433 fn nodes(&self) -> &Self::Nodes;
434 #[must_use]
436 fn roots(&self) -> &Self::Roots;
437 #[must_use]
439 fn contains(&self, id: &K) -> bool;
440 #[must_use]
444 fn contains_active(&self, id: &K) -> bool;
445 #[must_use]
447 fn get_node(&self, id: &K) -> Option<&N>;
448 fn get_ordered_node_identifiers(&self, output: &mut Vec<K>);
450 fn get_ordered_node_identifiers_from(&self, id: &K, output: &mut Vec<K>);
452 fn get_active_path(&self, output: &mut Vec<K>);
454 fn get_path_from(&self, id: &K, output: &mut Vec<K>);
458}
459
460pub trait ImmutableMetadataWeave<K, N, T, M>: ImmutableWeave<K, N, T>
462where
463 K: Hash + Copy + Eq + Ord,
464 N: Node<K, T>,
465{
466 #[must_use]
468 fn metadata(&self) -> &M;
469}
470
471pub trait ImmutableBookmarkableWeave<K, N, T>: ImmutableWeave<K, N, T>
473where
474 K: Hash + Copy + Eq + Ord,
475 N: Node<K, T>,
476{
477 type Bookmarks;
479
480 #[must_use]
482 fn bookmarks(&self) -> &Self::Bookmarks;
483 #[must_use]
485 fn contains_bookmark(&self, id: &K) -> bool;
486}
487
488pub trait ImmutableSortableWeave<K, N, T>: ImmutableWeave<K, N, T>
490where
491 K: Hash + Copy + Eq + Ord,
492 N: Node<K, T>,
493{
494 fn get_ordered_node_identifiers_mirrored(&self, output: &mut Vec<K>);
498 fn get_ordered_node_identifiers_mirrored_from(&self, id: &K, output: &mut Vec<K>);
502}
503
504pub trait ImmutableActiveSingularWeave<K, N, T>: ImmutableWeave<K, N, T>
506where
507 K: Hash + Copy + Eq + Ord,
508 N: Node<K, T>,
509{
510 #[must_use]
512 fn active(&self) -> Option<K>;
513}
514
515pub trait ImmutableActivePathWeave<K, N, T>: ImmutableWeave<K, N, T>
517where
518 K: Hash + Copy + Eq + Ord,
519 N: Node<K, T>,
520{
521 type Active;
523
524 #[must_use]
526 fn active(&self) -> &Self::Active;
527}
528
529#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
530enum Step<A, B> {
531 Enter(A),
532 Exit(B),
533}
534
535fn topological_sort<'a, K, N, T, S>(
536 nodes: &'a HashMap<K, N, S>,
537 id: &'a K,
538 scratchpad: &mut Vec<K>,
539 identifiers: &mut Vec<K>,
540 identifier_set: &mut HashSet<K, S>,
541 identifier_map: &mut HashMap<K, usize, S>,
542) where
543 K: Hash + Copy + Eq + Ord + 'a,
544 N: Node<K, T> + 'a,
545 <N as Node<K, T>>::From: 'a,
546 <N as Node<K, T>>::To: 'a,
547 &'a N::From: IntoIterator<Item = &'a K, IntoIter: DoubleEndedIterator + ExactSizeIterator>,
548 &'a N::To: IntoIterator<Item = &'a K, IntoIter: DoubleEndedIterator>,
549 S: BuildHasher + Default + Clone,
550{
551 scratchpad.push(*id);
552
553 while let Some(id) = scratchpad.pop() {
554 let node = &nodes[&id];
555
556 if identifier_set.contains(&id)
557 || identifier_map
558 .get(&id)
559 .copied()
560 .unwrap_or_else(|| node.from().into_iter().len())
561 != 0
562 {
563 continue;
564 }
565
566 identifiers.push(id);
567 identifier_set.insert(id);
568
569 for child in node.to().into_iter().rev().copied() {
570 let remaining = identifier_map
571 .entry(child)
572 .or_insert_with(|| nodes[&child].from().into_iter().len());
573 *remaining = remaining.strict_sub(1);
574
575 scratchpad.push(child);
576 }
577 }
578}
579
580fn topological_sort_subgraph<'a, K, N, T, S>(
581 nodes: &'a HashMap<K, N, S>,
582 filter: &impl Fn(&K) -> bool,
583 id: &'a K,
584 scratchpad: &mut Vec<K>,
585 identifiers: &mut Vec<K>,
586 identifier_set: &mut HashSet<K, S>,
587 identifier_map: &mut HashMap<K, usize, S>,
588) where
589 K: Hash + Copy + Eq + Ord + 'a,
590 N: Node<K, T> + 'a,
591 <N as Node<K, T>>::From: 'a,
592 <N as Node<K, T>>::To: 'a,
593 &'a N::From: IntoIterator<Item = &'a K, IntoIter: DoubleEndedIterator>,
594 &'a N::To: IntoIterator<Item = &'a K, IntoIter: DoubleEndedIterator>,
595 S: BuildHasher + Default + Clone,
596{
597 scratchpad.push(*id);
598
599 while let Some(id) = scratchpad.pop() {
600 let node = &nodes[&id];
601
602 if !filter(&id)
603 || identifier_set.contains(&id)
604 || identifier_map.get(&id).copied().unwrap_or_else(|| {
605 node.from()
606 .into_iter()
607 .filter(|&parent| filter(parent))
608 .count()
609 }) != 0
610 {
611 continue;
612 }
613
614 identifiers.push(id);
615 identifier_set.insert(id);
616
617 for child in node.to().into_iter().rev().copied() {
618 let remaining = identifier_map.entry(child).or_insert_with(|| {
619 nodes[&child]
620 .from()
621 .into_iter()
622 .filter(|&parent| filter(parent))
623 .count()
624 });
625 *remaining = remaining.strict_sub(1);
626
627 scratchpad.push(child);
628 }
629 }
630}
631
632fn topological_sort_subgraph_mirrored<'a, K, N, T, S>(
633 nodes: &'a HashMap<K, N, S>,
634 filter: &impl Fn(&K) -> bool,
635 id: &'a K,
636 scratchpad: &mut Vec<K>,
637 identifiers: &mut Vec<K>,
638 identifier_set: &mut HashSet<K, S>,
639 identifier_map: &mut HashMap<K, usize, S>,
640) where
641 K: Hash + Copy + Eq + Ord + 'a,
642 N: Node<K, T> + 'a,
643 <N as Node<K, T>>::From: 'a,
644 <N as Node<K, T>>::To: 'a,
645 &'a N::From: IntoIterator<Item = &'a K, IntoIter: DoubleEndedIterator>,
646 &'a N::To: IntoIterator<Item = &'a K, IntoIter: DoubleEndedIterator>,
647 S: BuildHasher + Default + Clone,
648{
649 scratchpad.push(*id);
650
651 while let Some(id) = scratchpad.pop() {
652 let node = &nodes[&id];
653
654 if !filter(&id)
655 || identifier_set.contains(&id)
656 || identifier_map.get(&id).copied().unwrap_or_else(|| {
657 node.from()
658 .into_iter()
659 .filter(|&parent| filter(parent))
660 .count()
661 }) != 0
662 {
663 continue;
664 }
665
666 identifiers.push(id);
667 identifier_set.insert(id);
668
669 for child in node.to().into_iter().copied() {
670 let remaining = identifier_map.entry(child).or_insert_with(|| {
671 nodes[&child]
672 .from()
673 .into_iter()
674 .filter(|&parent| filter(parent))
675 .count()
676 });
677 *remaining = remaining.strict_sub(1);
678
679 scratchpad.push(child);
680 }
681 }
682}
683
684fn topological_sort_mirrored<'a, K, N, T, S>(
685 nodes: &'a HashMap<K, N, S>,
686 id: &'a K,
687 scratchpad: &mut Vec<K>,
688 identifiers: &mut Vec<K>,
689 identifier_set: &mut HashSet<K, S>,
690 identifier_map: &mut HashMap<K, usize, S>,
691) where
692 K: Hash + Copy + Eq + Ord + 'a,
693 N: Node<K, T> + 'a,
694 <N as Node<K, T>>::From: 'a,
695 <N as Node<K, T>>::To: 'a,
696 &'a N::From: IntoIterator<Item = &'a K, IntoIter: DoubleEndedIterator + ExactSizeIterator>,
697 &'a N::To: IntoIterator<Item = &'a K, IntoIter: DoubleEndedIterator>,
698 S: BuildHasher + Default + Clone,
699{
700 scratchpad.push(*id);
701
702 while let Some(id) = scratchpad.pop() {
703 let node = &nodes[&id];
704
705 if identifier_set.contains(&id)
706 || identifier_map
707 .get(&id)
708 .copied()
709 .unwrap_or_else(|| node.from().into_iter().len())
710 != 0
711 {
712 continue;
713 }
714
715 identifiers.push(id);
716 identifier_set.insert(id);
717
718 for child in node.to().into_iter().copied() {
719 let remaining = identifier_map
720 .entry(child)
721 .or_insert_with(|| nodes[&child].from().into_iter().len());
722 *remaining = remaining.strict_sub(1);
723
724 scratchpad.push(child);
725 }
726 }
727}
728
729fn detect_cycles<'a, K, N, T, S>(
730 nodes: &'a HashMap<K, N, S>,
731 roots: impl Iterator<Item = K>,
732 scratchpad: &mut Vec<Step<K, K>>,
733 scratchpad_map: &mut HashMap<K, bool, S>,
734) -> bool
735where
736 K: Hash + Copy + Eq + Ord + 'a,
737 N: Node<K, T> + 'a,
738 <N as Node<K, T>>::From: 'a,
739 <N as Node<K, T>>::To: 'a,
740 &'a N::From: IntoIterator<Item = &'a K, IntoIter: DoubleEndedIterator>,
741 &'a N::To: IntoIterator<Item = &'a K, IntoIter: DoubleEndedIterator + ExactSizeIterator>,
742 S: BuildHasher + Default + Clone,
743{
744 for root in roots {
745 if scratchpad_map.contains_key(&root) {
746 continue;
747 }
748
749 scratchpad.push(Step::Enter(root));
750
751 while let Some(step) = scratchpad.pop() {
752 match step {
753 Step::Enter(id) => {
754 scratchpad.push(Step::Exit(id));
755
756 match scratchpad_map.entry(id) {
757 Entry::Occupied(entry) => {
758 if !entry.get() {
759 return true;
760 }
761 }
762 Entry::Vacant(entry) => {
763 entry.insert_entry(false);
764
765 scratchpad.extend(
766 nodes[&id].to().into_iter().rev().copied().map(Step::Enter),
767 );
768 }
769 }
770 }
771 Step::Exit(id) => {
772 scratchpad_map.insert(id, true);
773 }
774 }
775 }
776 }
777
778 scratchpad_map.len() != nodes.len()
779}
780
781fn shortest_path_to_ancestor<'a, K, N, T, S>(
782 nodes: &'a HashMap<K, N, S>,
783 id: &'a K,
784 target: &impl Fn(&'a N) -> bool,
785 scratchpad: &mut VecDeque<K>,
786 scratchpad_map: &mut HashMap<K, K, S>,
787 scratchpad_set: &mut HashSet<K, S>,
788 path: &mut Vec<K>,
789) where
790 K: Hash + Copy + Eq + Ord + 'a,
791 N: Node<K, T> + 'a,
792 <N as Node<K, T>>::From: 'a,
793 <N as Node<K, T>>::To: 'a,
794 &'a N::From: IntoIterator<Item = &'a K, IntoIter: DoubleEndedIterator>,
795 &'a N::To: IntoIterator<Item = &'a K, IntoIter: DoubleEndedIterator>,
796 S: BuildHasher + Default + Clone,
797{
798 scratchpad.push_front(*id);
799 scratchpad_set.insert(*id);
800
801 while let Some(id) = scratchpad.pop_back() {
802 let node = &nodes[&id];
803
804 if target(node) {
805 scratchpad.clear();
806
807 path.push(id);
808
809 while let Some(child) = scratchpad_map.remove(path.last().unwrap()) {
810 path.push(child);
811 }
812
813 return;
814 }
815
816 for parent in node.from().into_iter().copied() {
817 if scratchpad_set.insert(parent) {
818 scratchpad.push_front(parent);
819 scratchpad_map.insert(parent, id);
820 }
821 }
822 }
823}
824
825fn longest_candidate_path_to_root<'a, K, N, T, S>(
826 nodes: &'a HashMap<K, N, S>,
827 topological_order: &[K],
828 is_candidate: &impl Fn(&K) -> bool,
829 scratchpad_map: &mut HashMap<K, usize, S>,
830 reversed_path: &mut Vec<K>,
831) where
832 K: Hash + Copy + Eq + Ord + 'a,
833 N: Node<K, T> + 'a,
834 <N as Node<K, T>>::From: 'a,
835 <N as Node<K, T>>::To: 'a,
836 &'a N::From: IntoIterator<Item = &'a K, IntoIter: DoubleEndedIterator>,
837 &'a N::To: IntoIterator<Item = &'a K, IntoIter: DoubleEndedIterator>,
838 S: BuildHasher + Default + Clone,
839{
840 let mut longest_distance = None;
841
842 for id in topological_order {
843 if !is_candidate(id) {
844 continue;
845 }
846
847 let node = &nodes[id];
848 let distance = if node.from().into_iter().next().is_none() {
849 Some(0)
850 } else {
851 node.from()
852 .into_iter()
853 .filter_map(|parent| scratchpad_map.get(parent).copied())
854 .max()
855 .map(|l| l.strict_add(1))
856 };
857
858 if let Some(distance) = distance {
859 scratchpad_map.insert(*id, distance);
860
861 if longest_distance.is_none_or(|(value, _)| distance > value) {
862 longest_distance = Some((distance, id));
863 }
864 }
865 }
866
867 let mut current = longest_distance.map(|(_, id)| id);
868
869 while let Some(id) = current {
870 reversed_path.push(*id);
871
872 current = nodes[id]
873 .from()
874 .into_iter()
875 .filter(|id| scratchpad_map.contains_key(*id))
876 .min_by_key(|id| Reverse(scratchpad_map[*id]));
877 }
878}
879
880fn ancestor_subgraph<'a, K, N, T, S>(
881 nodes: &'a HashMap<K, N, S>,
882 id: K,
883 scratchpad: &mut Vec<K>,
884 identifiers: &mut HashSet<K, S>,
885) where
886 K: Hash + Copy + Eq + Ord + 'a,
887 N: Node<K, T>,
888 <N as Node<K, T>>::From: 'a,
889 <N as Node<K, T>>::To: 'a,
890 &'a N::From: IntoIterator<Item = &'a K, IntoIter: DoubleEndedIterator>,
891 &'a N::To: IntoIterator<Item = &'a K, IntoIter: DoubleEndedIterator>,
892 S: BuildHasher + Default + Clone,
893{
894 scratchpad.push(id);
895
896 while let Some(id) = scratchpad.pop() {
897 if identifiers.insert(id) {
898 scratchpad.extend(nodes[&id].from().into_iter().rev().copied());
899 }
900 }
901}
902
903fn descendant_subgraph<'a, K, N, T, S>(
904 nodes: &'a HashMap<K, N, S>,
905 id: K,
906 scratchpad: &mut Vec<K>,
907 identifiers: &mut HashSet<K, S>,
908) where
909 K: Hash + Copy + Eq + Ord + 'a,
910 N: Node<K, T>,
911 <N as Node<K, T>>::From: 'a,
912 <N as Node<K, T>>::To: 'a,
913 &'a N::From: IntoIterator<Item = &'a K, IntoIter: DoubleEndedIterator>,
914 &'a N::To: IntoIterator<Item = &'a K, IntoIter: DoubleEndedIterator>,
915 S: BuildHasher + Default + Clone,
916{
917 scratchpad.push(id);
918
919 while let Some(id) = scratchpad.pop() {
920 if identifiers.insert(id) {
921 scratchpad.extend(nodes[&id].to().into_iter().rev().copied());
922 }
923 }
924}