1#![no_std]
11#![forbid(non_ascii_idents)]
12#![warn(missing_docs)]
13#![warn(let_underscore)]
14#![warn(clippy::pedantic)]
15#![warn(clippy::cargo)]
16#![allow(clippy::multiple_crate_versions, reason = "Unresolvable")]
17#![warn(clippy::nursery)]
18#![warn(clippy::restriction)]
19#![allow(clippy::blanket_clippy_restriction_lints, reason = "Conflicting lint")]
20#![allow(clippy::allow_attributes, reason = "Conflicting lint")]
21#![allow(clippy::pattern_type_mismatch, reason = "Conflicting lint")]
22#![allow(clippy::separated_literal_suffix, reason = "Conflicting lint")]
23#![allow(clippy::semicolon_outside_block, 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;
72pub mod dependent;
73pub mod independent;
74pub mod wrappers;
75
76#[cfg(feature = "rkyv")]
77pub mod versioning;
78
79pub use contracts;
80pub use hashbrown;
81pub use indexmap;
82
83#[cfg(feature = "rkyv")]
84pub use rkyv;
85
86#[cfg(feature = "serde")]
87pub use serde;
88
89#[cfg(feature = "loro")]
90pub use loro;
91
92extern crate alloc;
93
94use alloc::vec::Vec;
95use core::{
96 cmp::{Ordering, Reverse},
97 hash::{BuildHasher, Hash},
98};
99
100use hashbrown::HashMap;
101use scratchpads::{ScratchpadMap, ScratchpadSet, ScratchpadVec};
102
103#[cfg(feature = "rkyv")]
104use rkyv::collections::swiss_table::{ArchivedHashMap, ArchivedIndexSet};
105
106#[must_use]
108pub trait Node<K, T>
109where
110 K: Hash + Copy + Eq + Ord,
111{
112 type From;
114 type To;
116
117 #[must_use]
119 fn id(&self) -> K;
120 #[must_use]
122 fn from(&self) -> &Self::From;
123 #[must_use]
125 fn to(&self) -> &Self::To;
126 #[must_use]
130 fn is_active(&self) -> bool;
131 #[must_use]
133 fn contents(&self) -> &T;
134}
135
136pub trait DiscreteContents: Sized {
138 fn split(self, at: usize) -> DiscreteContentResult<Self>;
142 fn merge(self, value: Self) -> DiscreteContentResult<Self>;
146}
147
148#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
150#[allow(missing_docs, reason = "Enum items are self-explanatory")]
151#[must_use]
152pub enum DiscreteContentResult<T> {
153 One(T),
154 Two(T, T),
155}
156
157pub trait IndependentContents {}
159
160pub trait DeduplicatableContents {
164 #[must_use]
166 fn is_duplicate_of(&self, other: &Self) -> bool;
167}
168
169#[must_use]
179pub trait Weave<K, N, T>
180where
181 K: Hash + Copy + Eq + Ord,
182 N: Node<K, T>,
183{
184 type Nodes;
186 type Roots;
188
189 #[must_use]
191 fn len(&self) -> usize;
192 #[must_use]
194 fn is_empty(&self) -> bool;
195 #[must_use]
197 fn nodes(&self) -> &Self::Nodes;
198 #[must_use]
200 fn roots(&self) -> &Self::Roots;
201 #[must_use]
203 fn contains(&self, id: &K) -> bool;
204 #[must_use]
208 fn contains_active(&self, id: &K) -> bool;
209 #[must_use]
211 fn get(&self, id: &K) -> Option<&N>;
212 #[must_use]
214 fn get_parents(&self, id: &K) -> Option<&N::From>;
215 #[must_use]
217 fn get_children(&self, id: &K) -> Option<&N::To>;
218 #[must_use]
220 fn get_contents(&self, id: &K) -> Option<&T>;
221 fn get_ordered_identifiers(&mut self, output: &mut Vec<K>);
223 fn get_ordered_identifiers_from(&mut self, id: &K, output: &mut Vec<K>);
227 fn get_active_path(&mut self, output: &mut Vec<K>);
231 fn get_path_from(&mut self, id: &K, output: &mut Vec<K>);
235 fn insert(&mut self, node: N) -> bool;
239 fn set_active(&mut self, id: &K, value: bool) -> bool;
243 fn remove(&mut self, id: &K) -> Option<N>;
249 fn remove_tracked(&mut self, id: &K, on_removal: impl FnMut(N)) -> bool;
257 fn clear(&mut self);
261}
262
263pub trait MetadataWeave<K, N, T, M>: Weave<K, N, T>
269where
270 K: Hash + Copy + Eq + Ord,
271 N: Node<K, T>,
272{
273 #[must_use]
275 fn metadata(&self) -> &M;
276 fn metadata_mut<O>(&mut self, callback: impl FnOnce(&mut M) -> O) -> O;
282}
283
284pub trait BookmarkableWeave<K, N, T>: Weave<K, N, T>
286where
287 K: Hash + Copy + Eq + Ord,
288 N: Node<K, T>,
289{
290 type Bookmarks;
292
293 #[must_use]
295 fn bookmarks(&self) -> &Self::Bookmarks;
296 #[must_use]
298 fn contains_bookmark(&self, id: &K) -> bool;
299 fn set_bookmarked(&mut self, id: &K, value: bool) -> bool;
301}
302
303pub trait SortableWeave<K, N, T>: Weave<K, N, T>
309where
310 K: Hash + Copy + Eq + Ord,
311 N: Node<K, T>,
312{
313 fn sort_children_by(&mut self, id: &K, cmp: impl FnMut(&N, &N) -> Ordering) -> bool;
319 fn sort_children_by_id(&mut self, id: &K, cmp: impl FnMut(&K, &K) -> Ordering) -> bool;
325 fn sort_roots_by(&mut self, cmp: impl FnMut(&N, &N) -> Ordering);
331 fn sort_roots_by_id(&mut self, cmp: impl FnMut(&K, &K) -> Ordering);
337}
338
339pub trait SortableBookmarkableWeave<K, N, T>:
345 BookmarkableWeave<K, N, T> + SortableWeave<K, N, T>
346where
347 K: Hash + Copy + Eq + Ord,
348 N: Node<K, T>,
349{
350 fn sort_bookmarks_by(&mut self, cmp: impl FnMut(&N, &N) -> Ordering);
356 fn sort_bookmarks_by_id(&mut self, cmp: impl FnMut(&K, &K) -> Ordering);
362}
363
364pub trait ActiveSingularWeave<K, N, T>: Weave<K, N, T>
366where
367 K: Hash + Copy + Eq + Ord,
368 N: Node<K, T>,
369{
370 #[must_use]
372 fn active(&self) -> Option<K>;
373}
374
375pub trait ActivePathWeave<K, N, T>: Weave<K, N, T>
377where
378 K: Hash + Copy + Eq + Ord,
379 N: Node<K, T>,
380{
381 type Active;
383
384 #[must_use]
386 fn active(&self) -> &Self::Active;
387 fn set_active_path(&mut self, active: impl Iterator<Item = K>);
391}
392
393pub trait IndependentWeave<K, N, T>: Weave<K, N, T> + SemiIndependentWeave<K, N, T>
395where
396 K: Hash + Copy + Eq + Ord,
397 N: Node<K, T>,
398 T: IndependentContents,
399{
400 fn move_to(&mut self, id: &K, new_parents: &[K]) -> bool;
404}
405
406pub trait SemiIndependentWeave<K, N, T>: Weave<K, N, T>
412where
413 K: Hash + Copy + Eq + Ord,
414 N: Node<K, T>,
415 T: IndependentContents,
416{
417 #[must_use]
425 fn get_contents_mut<O>(&mut self, id: &K, callback: impl FnOnce(&mut T) -> O) -> Option<O>;
426}
427
428pub trait DiscreteWeave<K, N, T>: Weave<K, N, T>
434where
435 K: Hash + Copy + Eq + Ord,
436 N: Node<K, T>,
437 T: DiscreteContents,
438{
439 fn split(&mut self, id: &K, at: usize, new_id: K) -> bool;
449 fn merge_with_parent(&mut self, id: &K) -> Option<K>;
457}
458
459#[must_use]
461pub trait ImmutableWeave<K, N, T>
462where
463 K: Hash + Copy + Eq + Ord,
464 N: Node<K, T>,
465{
466 type Nodes;
468 type Roots;
470
471 #[must_use]
473 fn len(&self) -> usize;
474 #[must_use]
476 fn is_empty(&self) -> bool;
477 #[must_use]
479 fn nodes(&self) -> &Self::Nodes;
480 #[must_use]
482 fn roots(&self) -> &Self::Roots;
483 #[must_use]
485 fn contains(&self, id: &K) -> bool;
486 #[must_use]
490 fn contains_active(&self, id: &K) -> bool;
491 #[must_use]
493 fn get(&self, id: &K) -> Option<&N>;
494 #[must_use]
496 fn get_parents(&self, id: &K) -> Option<&N::From>;
497 #[must_use]
499 fn get_children(&self, id: &K) -> Option<&N::To>;
500 #[must_use]
502 fn get_contents(&self, id: &K) -> Option<&T>;
503 fn get_ordered_identifiers(&self, output: &mut Vec<K>);
505 fn get_ordered_identifiers_from(&self, id: &K, output: &mut Vec<K>);
509 fn get_active_path(&self, output: &mut Vec<K>);
513 fn get_path_from(&self, id: &K, output: &mut Vec<K>);
517}
518
519pub trait ImmutableMetadataWeave<K, N, T, M>: ImmutableWeave<K, N, T>
521where
522 K: Hash + Copy + Eq + Ord,
523 N: Node<K, T>,
524{
525 #[must_use]
527 fn metadata(&self) -> &M;
528}
529
530pub trait ImmutableBookmarkableWeave<K, N, T>: ImmutableWeave<K, N, T>
532where
533 K: Hash + Copy + Eq + Ord,
534 N: Node<K, T>,
535{
536 type Bookmarks;
538
539 #[must_use]
541 fn bookmarks(&self) -> &Self::Bookmarks;
542 #[must_use]
544 fn contains_bookmark(&self, id: &K) -> bool;
545}
546
547pub trait ImmutableActiveSingularWeave<K, N, T>: ImmutableWeave<K, N, T>
549where
550 K: Hash + Copy + Eq + Ord,
551 N: Node<K, T>,
552{
553 #[must_use]
555 fn active(&self) -> Option<K>;
556}
557
558pub trait ImmutableActivePathWeave<K, N, T>: ImmutableWeave<K, N, T>
560where
561 K: Hash + Copy + Eq + Ord,
562 N: Node<K, T>,
563{
564 type Active;
566
567 #[must_use]
569 fn active(&self) -> &Self::Active;
570}
571
572#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
573enum Step<A, B> {
574 Enter(A),
575 Exit(B),
576}
577
578fn topological_sort<'a, K, N, T, S>(
579 nodes: &'a HashMap<K, N, S>,
580 roots: impl DoubleEndedIterator<Item = K>,
581 stack: &mut ScratchpadVec<'_, K>,
582 mut identifier_callback: impl FnMut(K),
583 identifier_map: &mut ScratchpadMap<'_, K, usize, S>,
584) where
585 K: Hash + Copy + Eq + Ord + 'a,
586 N: Node<K, T> + 'a,
587 <N as Node<K, T>>::From: 'a,
588 <N as Node<K, T>>::To: 'a,
589 &'a N::From: IntoIterator<Item = &'a K, IntoIter: DoubleEndedIterator + ExactSizeIterator>,
590 &'a N::To: IntoIterator<Item = &'a K, IntoIter: DoubleEndedIterator>,
591 S: BuildHasher + Default + Clone,
592{
593 stack.extend(roots.rev());
594
595 while let Some(id) = stack.pop() {
596 identifier_callback(id);
597
598 for child in nodes[&id].to().into_iter().rev().copied() {
599 let remaining = identifier_map
600 .entry(child)
601 .or_insert_with(|| nodes[&child].from().into_iter().len());
602 *remaining = remaining.strict_sub(1);
603
604 if *remaining == 0 {
605 stack.push(child);
606 }
607 }
608 }
609}
610
611#[cfg(feature = "rkyv")]
612fn archived_topological_sort<'a, K, N, T, S>(
613 nodes: &'a ArchivedHashMap<K, N>,
614 roots: &'a ArchivedIndexSet<K>,
615 stack: &mut ScratchpadVec<'_, K>,
616 mut identifier_callback: impl FnMut(K),
617 identifier_map: &mut ScratchpadMap<'_, K, usize, S>,
618) where
619 K: Hash + Copy + Eq + Ord + 'a,
620 N: Node<K, T, From = ArchivedIndexSet<K>, To = ArchivedIndexSet<K>> + 'a,
621 S: BuildHasher + Default + Clone,
622{
623 stack.extend(archived_set_reverse_order(roots));
624
625 while let Some(id) = stack.pop() {
626 identifier_callback(id);
627
628 for child in archived_set_reverse_order(nodes[&id].to()).copied() {
629 let remaining = identifier_map
630 .entry(child)
631 .or_insert_with(|| nodes[&child].from().iter().len());
632 *remaining = remaining.strict_sub(1);
633
634 if *remaining == 0 {
635 stack.push(child);
636 }
637 }
638 }
639}
640
641fn topological_sort_subgraph<'a, K, N, T, S>(
642 nodes: &'a HashMap<K, N, S>,
643 filter: &impl Fn(&K) -> bool,
644 subgraph_root: K,
645 stack: &mut ScratchpadVec<'_, K>,
646 mut identifier_callback: impl FnMut(K),
647 identifier_map: &mut ScratchpadMap<'_, K, usize, S>,
648) where
649 K: Hash + Copy + Eq + Ord + 'a,
650 N: Node<K, T> + 'a,
651 <N as Node<K, T>>::From: 'a,
652 <N as Node<K, T>>::To: 'a,
653 &'a N::From: IntoIterator<Item = &'a K, IntoIter: DoubleEndedIterator>,
654 &'a N::To: IntoIterator<Item = &'a K, IntoIter: DoubleEndedIterator>,
655 S: BuildHasher + Default + Clone,
656{
657 stack.push(subgraph_root);
670
671 while let Some(id) = stack.pop() {
672 identifier_callback(id);
673
674 for child in nodes[&id].to().into_iter().rev().copied() {
675 if !filter(&child) {
676 continue;
677 }
678
679 let remaining = identifier_map.entry(child).or_insert_with(|| {
680 nodes[&child]
681 .from()
682 .into_iter()
683 .filter(|&parent| filter(parent))
684 .count()
685 });
686 *remaining = remaining.strict_sub(1);
687
688 if *remaining == 0 {
689 stack.push(child);
690 }
691 }
692 }
693}
694
695#[cfg(feature = "rkyv")]
696fn archived_topological_sort_subgraph<'a, K, N, T, S>(
697 nodes: &'a ArchivedHashMap<K, N>,
698 filter: &impl Fn(&K) -> bool,
699 subgraph_root: K,
700 stack: &mut ScratchpadVec<'_, K>,
701 mut identifier_callback: impl FnMut(K),
702 identifier_map: &mut ScratchpadMap<'_, K, usize, S>,
703) where
704 K: Hash + Copy + Eq + Ord + 'a,
705 N: Node<K, T, From = ArchivedIndexSet<K>, To = ArchivedIndexSet<K>> + 'a,
706 S: BuildHasher + Default + Clone,
707{
708 stack.push(subgraph_root);
721
722 while let Some(id) = stack.pop() {
723 identifier_callback(id);
724
725 for child in archived_set_reverse_order(nodes[&id].to()).copied() {
726 if !filter(&child) {
727 continue;
728 }
729
730 let remaining = identifier_map.entry(child).or_insert_with(|| {
731 nodes[&child]
732 .from()
733 .iter()
734 .filter(|&parent| filter(parent))
735 .count()
736 });
737 *remaining = remaining.strict_sub(1);
738
739 if *remaining == 0 {
740 stack.push(child);
741 }
742 }
743 }
744}
745
746fn shortest_path_to_ancestor<'a, K, N, T, S>(
747 nodes: &'a HashMap<K, N, S>,
748 id: &'a K,
749 target: &impl Fn(&'a N) -> bool,
750 scratchpad: &mut ScratchpadVec<'_, K>,
751 scratchpad_map: &mut ScratchpadMap<'_, K, K, S>,
752 scratchpad_set: &mut ScratchpadSet<'_, K, S>,
753 path: &mut Vec<K>,
754) where
755 K: Hash + Copy + Eq + Ord + 'a,
756 N: Node<K, T> + 'a,
757 <N as Node<K, T>>::From: 'a,
758 <N as Node<K, T>>::To: 'a,
759 &'a N::From: IntoIterator<Item = &'a K, IntoIter: DoubleEndedIterator>,
760 &'a N::To: IntoIterator<Item = &'a K, IntoIter: DoubleEndedIterator>,
761 S: BuildHasher + Default + Clone,
762{
763 scratchpad.push(*id);
764 scratchpad_set.insert(*id);
765
766 let mut head = 0;
767
768 while head < scratchpad.len() {
769 let id = scratchpad[head];
770 head = head.strict_add(1);
771
772 let node = &nodes[&id];
773
774 if target(node) {
775 path.push(id);
776
777 while let Some(child) = scratchpad_map.remove(path.last().unwrap()) {
778 path.push(child);
779 }
780
781 return;
782 }
783
784 for parent in node.from().into_iter().copied() {
785 if scratchpad_set.insert(parent) {
786 scratchpad.push(parent);
787 scratchpad_map.insert(parent, id);
788 }
789 }
790 }
791}
792
793#[cfg(feature = "rkyv")]
794fn archived_shortest_path_to_ancestor<'a, K, N, T, S>(
795 nodes: &'a ArchivedHashMap<K, N>,
796 id: &'a K,
797 target: &impl Fn(&'a N) -> bool,
798 scratchpad: &mut ScratchpadVec<'_, K>,
799 scratchpad_map: &mut ScratchpadMap<'_, K, K, S>,
800 scratchpad_set: &mut ScratchpadSet<'_, K, S>,
801 path: &mut Vec<K>,
802) where
803 K: Hash + Copy + Eq + Ord + 'a,
804 N: Node<K, T, From = ArchivedIndexSet<K>> + 'a,
805 S: BuildHasher + Default + Clone,
806{
807 scratchpad.push(*id);
808 scratchpad_set.insert(*id);
809
810 let mut head = 0;
811
812 while head < scratchpad.len() {
813 let id = scratchpad[head];
814 head = head.strict_add(1);
815
816 let node = &nodes[&id];
817
818 if target(node) {
819 path.push(id);
820
821 while let Some(child) = scratchpad_map.remove(path.last().unwrap()) {
822 path.push(child);
823 }
824
825 return;
826 }
827
828 for parent in node.from().iter().copied() {
829 if scratchpad_set.insert(parent) {
830 scratchpad.push(parent);
831 scratchpad_map.insert(parent, id);
832 }
833 }
834 }
835}
836
837fn longest_candidate_path_to_root<'a, K, N, T, S>(
838 nodes: &'a HashMap<K, N, S>,
839 topological_order: &[K],
840 is_candidate: &impl Fn(&K) -> bool,
841 scratchpad_map: &mut ScratchpadMap<'_, K, usize, S>,
842 mut reversed_path_callback: impl FnMut(K),
843) where
844 K: Hash + Copy + Eq + Ord + 'a,
845 N: Node<K, T> + 'a,
846 <N as Node<K, T>>::From: 'a,
847 <N as Node<K, T>>::To: 'a,
848 &'a N::From: IntoIterator<Item = &'a K, IntoIter: DoubleEndedIterator>,
849 &'a N::To: IntoIterator<Item = &'a K, IntoIter: DoubleEndedIterator>,
850 S: BuildHasher + Default + Clone,
851{
852 let mut longest_distance = None;
853
854 for id in topological_order {
855 if !is_candidate(id) {
856 continue;
857 }
858
859 let node = &nodes[id];
860 let distance = if node.from().into_iter().next().is_none() {
861 Some(0)
862 } else {
863 node.from()
864 .into_iter()
865 .filter_map(|parent| scratchpad_map.get(parent).copied())
866 .max()
867 .map(|l| l.strict_add(1))
868 };
869
870 if let Some(distance) = distance {
871 scratchpad_map.insert(*id, distance);
872
873 if longest_distance.is_none_or(|(value, _)| distance > value) {
874 longest_distance = Some((distance, id));
875 }
876 }
877 }
878
879 let mut current = longest_distance.map(|(_, id)| id);
880
881 while let Some(id) = current {
882 reversed_path_callback(*id);
883
884 current = nodes[id]
885 .from()
886 .into_iter()
887 .filter(|id| scratchpad_map.contains_key(*id))
888 .min_by_key(|id| Reverse(scratchpad_map[*id]));
889 }
890}
891
892#[cfg(feature = "rkyv")]
893fn archived_longest_candidate_path_to_root<'a, K, N, T, S>(
894 nodes: &'a ArchivedHashMap<K, N>,
895 topological_order: &'a [K],
896 is_candidate: &impl Fn(&K) -> bool,
897 scratchpad_map: &mut ScratchpadMap<'_, K, usize, S>,
898 mut reversed_path_callback: impl FnMut(K),
899) where
900 K: Hash + Copy + Eq + Ord + 'a,
901 N: Node<K, T, From = ArchivedIndexSet<K>> + 'a,
902 S: BuildHasher + Default + Clone,
903{
904 let mut longest_distance = None;
905
906 for id in topological_order {
907 if !is_candidate(id) {
908 continue;
909 }
910
911 let node = &nodes[id];
912 let distance = if node.from().is_empty() {
913 Some(0)
914 } else {
915 node.from()
916 .iter()
917 .filter_map(|parent| scratchpad_map.get(parent).copied())
918 .max()
919 .map(|l| l.strict_add(1))
920 };
921
922 if let Some(distance) = distance {
923 scratchpad_map.insert(*id, distance);
924
925 if longest_distance.is_none_or(|(value, _)| distance > value) {
926 longest_distance = Some((distance, id));
927 }
928 }
929 }
930
931 let mut current = longest_distance.map(|(_, id)| id);
932
933 while let Some(id) = current {
934 reversed_path_callback(*id);
935
936 current = nodes[id]
937 .from()
938 .iter()
939 .filter(|id| scratchpad_map.contains_key(*id))
940 .min_by_key(|id| Reverse(scratchpad_map[*id]));
941 }
942}
943
944fn ancestor_subgraph<'a, K, N, T, S>(
945 nodes: &'a HashMap<K, N, S>,
946 id: K,
947 stack: &mut ScratchpadVec<'_, K>,
948 identifiers: &mut ScratchpadSet<'_, K, S>,
949) where
950 K: Hash + Copy + Eq + Ord + 'a,
951 N: Node<K, T>,
952 <N as Node<K, T>>::From: 'a,
953 <N as Node<K, T>>::To: 'a,
954 &'a N::From: IntoIterator<Item = &'a K, IntoIter: DoubleEndedIterator>,
955 &'a N::To: IntoIterator<Item = &'a K, IntoIter: DoubleEndedIterator>,
956 S: BuildHasher + Default + Clone,
957{
958 stack.push(id);
959
960 while let Some(id) = stack.pop() {
961 if identifiers.insert(id) {
962 stack.extend(nodes[&id].from().into_iter().rev().copied());
963 }
964 }
965}
966
967#[cfg(feature = "rkyv")]
968fn archived_ancestor_subgraph<'a, K, N, T, S>(
969 nodes: &'a ArchivedHashMap<K, N>,
970 id: K,
971 stack: &mut ScratchpadVec<'_, K>,
972 identifiers: &mut ScratchpadSet<'_, K, S>,
973) where
974 K: Hash + Copy + Eq + Ord + 'a,
975 N: Node<K, T, From = ArchivedIndexSet<K>> + 'a,
976 S: BuildHasher + Default + Clone,
977{
978 stack.push(id);
979
980 while let Some(id) = stack.pop() {
981 if identifiers.insert(id) {
982 stack.extend(archived_set_reverse_order(nodes[&id].from()).copied());
983 }
984 }
985}
986
987fn descendant_subgraph<'a, K, N, T, S>(
988 nodes: &'a HashMap<K, N, S>,
989 id: K,
990 stack: &mut ScratchpadVec<'_, K>,
991 identifiers: &mut ScratchpadSet<'_, K, S>,
992) where
993 K: Hash + Copy + Eq + Ord + 'a,
994 N: Node<K, T>,
995 <N as Node<K, T>>::From: 'a,
996 <N as Node<K, T>>::To: 'a,
997 &'a N::From: IntoIterator<Item = &'a K, IntoIter: DoubleEndedIterator>,
998 &'a N::To: IntoIterator<Item = &'a K, IntoIter: DoubleEndedIterator>,
999 S: BuildHasher + Default + Clone,
1000{
1001 stack.push(id);
1002
1003 while let Some(id) = stack.pop() {
1004 if identifiers.insert(id) {
1005 stack.extend(nodes[&id].to().into_iter().rev().copied());
1006 }
1007 }
1008}
1009
1010#[cfg(feature = "rkyv")]
1011fn archived_descendant_subgraph<'a, K, N, T, S>(
1012 nodes: &'a ArchivedHashMap<K, N>,
1013 id: K,
1014 stack: &mut ScratchpadVec<'_, K>,
1015 identifiers: &mut ScratchpadSet<'_, K, S>,
1016) where
1017 K: Hash + Copy + Eq + Ord + 'a,
1018 N: Node<K, T, To = ArchivedIndexSet<K>> + 'a,
1019 S: BuildHasher + Default + Clone,
1020{
1021 stack.push(id);
1022
1023 while let Some(id) = stack.pop() {
1024 if identifiers.insert(id) {
1025 stack.extend(archived_set_reverse_order(nodes[&id].to()).copied());
1026 }
1027 }
1028}
1029
1030#[cfg(feature = "rkyv")]
1031fn archived_set_reverse_order<T>(set: &ArchivedIndexSet<T>) -> impl Iterator<Item = &T> {
1032 (0..set.len())
1033 .into_iter()
1034 .rev()
1035 .filter_map(|index| set.get_index(index))
1036}