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,
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 {
147 #[must_use]
149 fn is_duplicate_of(&self, other: &Self) -> bool;
150}
151
152#[must_use]
162pub trait Weave<K, N, T>
163where
164 K: Hash + Copy + Eq + Ord,
165 N: Node<K, T>,
166{
167 type Nodes;
169 type Roots;
171
172 #[must_use]
174 fn len(&self) -> usize;
175 #[must_use]
177 fn is_empty(&self) -> bool;
178 #[must_use]
180 fn nodes(&self) -> &Self::Nodes;
181 #[must_use]
183 fn roots(&self) -> &Self::Roots;
184 #[must_use]
186 fn contains(&self, id: &K) -> bool;
187 #[must_use]
191 fn contains_active(&self, id: &K) -> bool;
192 #[must_use]
194 fn get_node(&self, id: &K) -> Option<&N>;
195 fn get_ordered_node_identifiers(&mut self, output: &mut Vec<K>);
197 fn get_ordered_node_identifiers_from(&mut self, id: &K, output: &mut Vec<K>);
199 fn get_active_path(&mut self, output: &mut Vec<K>);
201 fn get_path_from(&mut self, id: &K, output: &mut Vec<K>);
203 fn add_node(&mut self, node: N) -> bool;
207 fn set_node_active_status(&mut self, id: &K, value: bool) -> bool;
211 fn remove_node(&mut self, id: &K) -> Option<N>;
217 fn remove_node_tracked(&mut self, id: &K, on_removal: impl FnMut(N)) -> bool;
225 fn remove_all_nodes(&mut self);
227}
228
229pub trait MetadataWeave<K, N, T, M>: Weave<K, N, T>
231where
232 K: Hash + Copy + Eq + Ord,
233 N: Node<K, T>,
234{
235 #[must_use]
237 fn metadata(&self) -> &M;
238 fn metadata_mut<O>(&mut self, callback: impl FnOnce(&mut M) -> O) -> O;
244}
245
246pub trait BookmarkableWeave<K, N, T>: Weave<K, N, T>
248where
249 K: Hash + Copy + Eq + Ord,
250 N: Node<K, T>,
251{
252 type Bookmarks;
254
255 #[must_use]
257 fn bookmarks(&self) -> &Self::Bookmarks;
258 #[must_use]
260 fn contains_bookmark(&self, id: &K) -> bool;
261 fn set_node_bookmarked_status(&mut self, id: &K, value: bool) -> bool;
263}
264
265pub trait SortableWeave<K, N, T>: Weave<K, N, T>
267where
268 K: Hash + Copy + Eq + Ord,
269 N: Node<K, T>,
270{
271 fn get_ordered_node_identifiers_mirrored(&mut self, output: &mut Vec<K>);
275 fn get_ordered_node_identifiers_mirrored_from(&mut self, id: &K, output: &mut Vec<K>);
279 fn sort_node_children_by(&mut self, id: &K, cmp: impl FnMut(&N, &N) -> Ordering) -> bool;
285 fn sort_node_children_by_id(&mut self, id: &K, cmp: impl FnMut(&K, &K) -> Ordering) -> bool;
291 fn sort_roots_by(&mut self, cmp: impl FnMut(&N, &N) -> Ordering);
297 fn sort_roots_by_id(&mut self, cmp: impl FnMut(&K, &K) -> Ordering);
303}
304
305pub trait SortableBookmarkableWeave<K, N, T>:
307 BookmarkableWeave<K, N, T> + SortableWeave<K, N, T>
308where
309 K: Hash + Copy + Eq + Ord,
310 N: Node<K, T>,
311{
312 fn sort_bookmarks_by(&mut self, cmp: impl FnMut(&N, &N) -> Ordering);
318 fn sort_bookmarks_by_id(&mut self, cmp: impl FnMut(&K, &K) -> Ordering);
324}
325
326pub trait ActiveSingularWeave<K, N, T>: Weave<K, N, T>
328where
329 K: Hash + Copy + Eq + Ord,
330 N: Node<K, T>,
331{
332 #[must_use]
334 fn active(&self) -> Option<K>;
335}
336
337pub trait ActivePathWeave<K, N, T>: Weave<K, N, T>
339where
340 K: Hash + Copy + Eq + Ord,
341 N: Node<K, T>,
342{
343 type Active;
345
346 #[must_use]
348 fn active(&self) -> &Self::Active;
349 fn set_active_path(&mut self, active: impl Iterator<Item = K>);
353}
354
355pub trait IndependentWeave<K, N, T>: Weave<K, N, T> + SemiIndependentWeave<K, N, T>
357where
358 K: Hash + Copy + Eq + Ord,
359 N: Node<K, T>,
360 T: IndependentContents,
361{
362 fn move_node(&mut self, id: &K, new_parents: &[K]) -> bool;
366}
367
368pub trait SemiIndependentWeave<K, N, T>: Weave<K, N, T>
370where
371 K: Hash + Copy + Eq + Ord,
372 N: Node<K, T>,
373 T: IndependentContents,
374{
375 fn get_contents_mut<O>(&mut self, id: &K, callback: impl FnOnce(&mut T) -> O) -> Option<O>;
381}
382
383pub trait DiscreteWeave<K, N, T>: Weave<K, N, T>
385where
386 K: Hash + Copy + Eq + Ord,
387 N: Node<K, T>,
388 T: DiscreteContents,
389{
390 fn split_node(&mut self, id: &K, at: usize, new_id: K) -> bool;
394 fn merge_with_parent(&mut self, id: &K) -> Option<K>;
398}
399
400pub trait DeduplicatableWeave<K, N, T>: Weave<K, N, T>
402where
403 K: Hash + Copy + Eq + Ord,
404 N: Node<K, T>,
405 T: DeduplicatableContents,
406{
407 #[must_use]
409 fn find_duplicates(&self, id: &K) -> impl Iterator<Item = K>;
410}
411
412#[must_use]
414pub trait ImmutableWeave<K, N, T>
415where
416 K: Hash + Copy + Eq + Ord,
417 N: Node<K, T>,
418{
419 type Nodes;
421 type Roots;
423
424 #[must_use]
426 fn len(&self) -> usize;
427 #[must_use]
429 fn is_empty(&self) -> bool;
430 #[must_use]
432 fn nodes(&self) -> &Self::Nodes;
433 #[must_use]
435 fn roots(&self) -> &Self::Roots;
436 #[must_use]
438 fn contains(&self, id: &K) -> bool;
439 #[must_use]
443 fn contains_active(&self, id: &K) -> bool;
444 #[must_use]
446 fn get_node(&self, id: &K) -> Option<&N>;
447 fn get_ordered_node_identifiers(&self, output: &mut Vec<K>);
449 fn get_ordered_node_identifiers_from(&self, id: &K, output: &mut Vec<K>);
451 fn get_active_path(&self, output: &mut Vec<K>);
453 fn get_path_from(&self, id: &K, output: &mut Vec<K>);
455}
456
457pub trait ImmutableMetadataWeave<K, N, T, M>: ImmutableWeave<K, N, T>
459where
460 K: Hash + Copy + Eq + Ord,
461 N: Node<K, T>,
462{
463 #[must_use]
465 fn metadata(&self) -> &M;
466}
467
468pub trait ImmutableBookmarkableWeave<K, N, T>: ImmutableWeave<K, N, T>
470where
471 K: Hash + Copy + Eq + Ord,
472 N: Node<K, T>,
473{
474 type Bookmarks;
476
477 #[must_use]
479 fn bookmarks(&self) -> &Self::Bookmarks;
480 #[must_use]
482 fn contains_bookmark(&self, id: &K) -> bool;
483}
484
485pub trait ImmutableSortableWeave<K, N, T>: ImmutableWeave<K, N, T>
487where
488 K: Hash + Copy + Eq + Ord,
489 N: Node<K, T>,
490{
491 fn get_ordered_node_identifiers_mirrored(&self, output: &mut Vec<K>);
495 fn get_ordered_node_identifiers_mirrored_from(&self, id: &K, output: &mut Vec<K>);
499}
500
501pub trait ImmutableActiveSingularWeave<K, N, T>: ImmutableWeave<K, N, T>
503where
504 K: Hash + Copy + Eq + Ord,
505 N: Node<K, T>,
506{
507 #[must_use]
509 fn active(&self) -> Option<K>;
510}
511
512pub trait ImmutableActivePathWeave<K, N, T>: ImmutableWeave<K, N, T>
514where
515 K: Hash + Copy + Eq + Ord,
516 N: Node<K, T>,
517{
518 type Active;
520
521 #[must_use]
523 fn active(&self) -> &Self::Active;
524}
525
526#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
527enum Step<A, B> {
528 Enter(A),
529 Exit(B),
530}
531
532fn topological_sort<'a, K, N, T, S>(
533 nodes: &'a HashMap<K, N, S>,
534 id: &'a K,
535 scratchpad: &mut Vec<K>,
536 identifiers: &mut Vec<K>,
537 identifier_set: &mut HashSet<K, S>,
538) where
539 K: Hash + Copy + Eq + Ord + 'a,
540 N: Node<K, T> + 'a,
541 <N as Node<K, T>>::From: 'a,
542 <N as Node<K, T>>::To: 'a,
543 &'a N::From: IntoIterator<Item = &'a K, IntoIter: DoubleEndedIterator>,
544 &'a N::To: IntoIterator<Item = &'a K, IntoIter: DoubleEndedIterator>,
545 S: BuildHasher + Default + Clone,
546{
547 scratchpad.push(*id);
548
549 while let Some(id) = scratchpad.pop() {
550 let node = &nodes[&id];
551
552 if !identifier_set.contains(&id)
553 && node
554 .from()
555 .into_iter()
556 .all(|parent| identifier_set.contains(parent))
557 {
558 identifiers.push(id);
559 identifier_set.insert(id);
560 scratchpad.extend(node.to().into_iter().rev().copied());
561 }
562 }
563}
564
565fn topological_sort_subgraph<'a, K, N, T, S>(
566 nodes: &'a HashMap<K, N, S>,
567 filter: &impl Fn(&K) -> bool,
568 id: &'a K,
569 scratchpad: &mut Vec<K>,
570 identifiers: &mut Vec<K>,
571 identifier_set: &mut HashSet<K, S>,
572) where
573 K: Hash + Copy + Eq + Ord + 'a,
574 N: Node<K, T> + 'a,
575 <N as Node<K, T>>::From: 'a,
576 <N as Node<K, T>>::To: 'a,
577 &'a N::From: IntoIterator<Item = &'a K, IntoIter: DoubleEndedIterator>,
578 &'a N::To: IntoIterator<Item = &'a K, IntoIter: DoubleEndedIterator>,
579 S: BuildHasher + Default + Clone,
580{
581 scratchpad.push(*id);
582
583 while let Some(id) = scratchpad.pop() {
584 let node = &nodes[&id];
585
586 if filter(&id)
587 && !identifier_set.contains(&id)
588 && node
589 .from()
590 .into_iter()
591 .all(|parent| identifier_set.contains(parent) || !filter(parent))
592 {
593 identifiers.push(id);
594 identifier_set.insert(id);
595 scratchpad.extend(node.to().into_iter().rev().copied());
596 }
597 }
598}
599
600fn topological_sort_subgraph_mirrored<'a, K, N, T, S>(
601 nodes: &'a HashMap<K, N, S>,
602 filter: &impl Fn(&K) -> bool,
603 id: &'a K,
604 scratchpad: &mut Vec<K>,
605 identifiers: &mut Vec<K>,
606 identifier_set: &mut HashSet<K, S>,
607) where
608 K: Hash + Copy + Eq + Ord + 'a,
609 N: Node<K, T> + 'a,
610 <N as Node<K, T>>::From: 'a,
611 <N as Node<K, T>>::To: 'a,
612 &'a N::From: IntoIterator<Item = &'a K, IntoIter: DoubleEndedIterator>,
613 &'a N::To: IntoIterator<Item = &'a K, IntoIter: DoubleEndedIterator>,
614 S: BuildHasher + Default + Clone,
615{
616 scratchpad.push(*id);
617
618 while let Some(id) = scratchpad.pop() {
619 let node = &nodes[&id];
620
621 if filter(&id)
622 && !identifier_set.contains(&id)
623 && node
624 .from()
625 .into_iter()
626 .all(|parent| identifier_set.contains(parent) || !filter(parent))
627 {
628 identifiers.push(id);
629 identifier_set.insert(id);
630 scratchpad.extend(node.to().into_iter().copied());
631 }
632 }
633}
634
635fn topological_sort_mirrored<'a, K, N, T, S>(
636 nodes: &'a HashMap<K, N, S>,
637 id: &'a K,
638 scratchpad: &mut Vec<K>,
639 identifiers: &mut Vec<K>,
640 identifier_set: &mut HashSet<K, S>,
641) where
642 K: Hash + Copy + Eq + Ord + 'a,
643 N: Node<K, T> + 'a,
644 <N as Node<K, T>>::From: 'a,
645 <N as Node<K, T>>::To: 'a,
646 &'a N::From: IntoIterator<Item = &'a K, IntoIter: DoubleEndedIterator>,
647 &'a N::To: IntoIterator<Item = &'a K, IntoIter: DoubleEndedIterator>,
648 S: BuildHasher + Default + Clone,
649{
650 scratchpad.push(*id);
651
652 while let Some(id) = scratchpad.pop() {
653 let node = &nodes[&id];
654
655 if !identifier_set.contains(&id)
656 && node
657 .from()
658 .into_iter()
659 .all(|parent| identifier_set.contains(parent))
660 {
661 identifiers.push(id);
662 identifier_set.insert(id);
663 scratchpad.extend(node.to().into_iter().copied());
664 }
665 }
666}
667
668fn detect_cycles<'a, K, N, T, S>(
669 nodes: &'a HashMap<K, N, S>,
670 roots: impl Iterator<Item = K>,
671 scratchpad: &mut Vec<Step<K, K>>,
672 scratchpad_map: &mut HashMap<K, bool, S>,
673) -> bool
674where
675 K: Hash + Copy + Eq + Ord + 'a,
676 N: Node<K, T> + 'a,
677 <N as Node<K, T>>::From: 'a,
678 <N as Node<K, T>>::To: 'a,
679 &'a N::From: IntoIterator<Item = &'a K, IntoIter: DoubleEndedIterator>,
680 &'a N::To: IntoIterator<Item = &'a K, IntoIter: DoubleEndedIterator + ExactSizeIterator>,
681 S: BuildHasher + Default + Clone,
682{
683 for root in roots {
684 if scratchpad_map.contains_key(&root) {
685 continue;
686 }
687
688 scratchpad.push(Step::Enter(root));
689
690 while let Some(step) = scratchpad.pop() {
691 match step {
692 Step::Enter(id) => {
693 scratchpad.push(Step::Exit(id));
694
695 match scratchpad_map.entry(id) {
696 Entry::Occupied(entry) => {
697 if !entry.get() {
698 return true;
699 }
700 }
701 Entry::Vacant(entry) => {
702 entry.insert_entry(false);
703
704 scratchpad.extend(
705 nodes[&id].to().into_iter().rev().copied().map(Step::Enter),
706 );
707 }
708 }
709 }
710 Step::Exit(id) => {
711 scratchpad_map.insert(id, true);
712 }
713 }
714 }
715 }
716
717 scratchpad_map.len() != nodes.len()
718}
719
720fn shortest_path_to_ancestor<'a, K, N, T, S>(
721 nodes: &'a HashMap<K, N, S>,
722 id: &'a K,
723 target: &impl Fn(&'a N) -> bool,
724 scratchpad: &mut VecDeque<K>,
725 scratchpad_map: &mut HashMap<K, K, S>,
726 scratchpad_set: &mut HashSet<K, S>,
727 path: &mut Vec<K>,
728) where
729 K: Hash + Copy + Eq + Ord + 'a,
730 N: Node<K, T> + 'a,
731 <N as Node<K, T>>::From: 'a,
732 <N as Node<K, T>>::To: 'a,
733 &'a N::From: IntoIterator<Item = &'a K, IntoIter: DoubleEndedIterator>,
734 &'a N::To: IntoIterator<Item = &'a K, IntoIter: DoubleEndedIterator>,
735 S: BuildHasher + Default + Clone,
736{
737 scratchpad.push_front(*id);
738 scratchpad_set.insert(*id);
739
740 while let Some(id) = scratchpad.pop_back() {
741 let node = &nodes[&id];
742
743 if target(node) {
744 scratchpad.clear();
745
746 path.push(id);
747
748 while let Some(child) = scratchpad_map.remove(path.last().unwrap()) {
749 path.push(child);
750 }
751
752 return;
753 }
754
755 for parent in node.from().into_iter().copied() {
756 if scratchpad_set.insert(parent) {
757 scratchpad.push_front(parent);
758 scratchpad_map.insert(parent, id);
759 }
760 }
761 }
762}
763
764fn longest_candidate_path_to_root<'a, K, N, T, S>(
765 nodes: &'a HashMap<K, N, S>,
766 topological_order: &[K],
767 is_candidate: &impl Fn(&K) -> bool,
768 scratchpad_map: &mut HashMap<K, usize, S>,
769 reversed_path: &mut Vec<K>,
770) where
771 K: Hash + Copy + Eq + Ord + 'a,
772 N: Node<K, T> + 'a,
773 <N as Node<K, T>>::From: 'a,
774 <N as Node<K, T>>::To: 'a,
775 &'a N::From: IntoIterator<Item = &'a K, IntoIter: DoubleEndedIterator>,
776 &'a N::To: IntoIterator<Item = &'a K, IntoIter: DoubleEndedIterator>,
777 S: BuildHasher + Default + Clone,
778{
779 let mut longest_distance = None;
780
781 for id in topological_order {
782 if !is_candidate(id) {
783 continue;
784 }
785
786 let node = &nodes[id];
787 let distance = if node.from().into_iter().next().is_none() {
788 Some(0)
789 } else {
790 node.from()
791 .into_iter()
792 .filter_map(|parent| scratchpad_map.get(parent).copied())
793 .max()
794 .map(|l| l.strict_add(1))
795 };
796
797 if let Some(distance) = distance {
798 scratchpad_map.insert(*id, distance);
799
800 if longest_distance.is_none_or(|(value, _)| distance > value) {
801 longest_distance = Some((distance, id));
802 }
803 }
804 }
805
806 let mut current = longest_distance.map(|(_, id)| id);
807
808 while let Some(id) = current {
809 reversed_path.push(*id);
810
811 current = nodes[id]
812 .from()
813 .into_iter()
814 .filter(|id| scratchpad_map.contains_key(*id))
815 .max_by_key(|id| scratchpad_map[*id]);
816 }
817}
818
819fn ancestor_subgraph<'a, K, N, T, S>(
820 nodes: &'a HashMap<K, N, S>,
821 id: K,
822 scratchpad: &mut Vec<K>,
823 identifiers: &mut HashSet<K, S>,
824) where
825 K: Hash + Copy + Eq + Ord + 'a,
826 N: Node<K, T>,
827 <N as Node<K, T>>::From: 'a,
828 <N as Node<K, T>>::To: 'a,
829 &'a N::From: IntoIterator<Item = &'a K, IntoIter: DoubleEndedIterator>,
830 &'a N::To: IntoIterator<Item = &'a K, IntoIter: DoubleEndedIterator>,
831 S: BuildHasher + Default + Clone,
832{
833 scratchpad.push(id);
834
835 while let Some(id) = scratchpad.pop() {
836 if identifiers.insert(id) {
837 scratchpad.extend(nodes[&id].from().into_iter().rev().copied());
838 }
839 }
840}
841
842fn descendant_subgraph<'a, K, N, T, S>(
843 nodes: &'a HashMap<K, N, S>,
844 id: K,
845 scratchpad: &mut Vec<K>,
846 identifiers: &mut HashSet<K, S>,
847) where
848 K: Hash + Copy + Eq + Ord + 'a,
849 N: Node<K, T>,
850 <N as Node<K, T>>::From: 'a,
851 <N as Node<K, T>>::To: 'a,
852 &'a N::From: IntoIterator<Item = &'a K, IntoIter: DoubleEndedIterator>,
853 &'a N::To: IntoIterator<Item = &'a K, IntoIter: DoubleEndedIterator>,
854 S: BuildHasher + Default + Clone,
855{
856 scratchpad.push(id);
857
858 while let Some(id) = scratchpad.pop() {
859 if identifiers.insert(id) {
860 scratchpad.extend(nodes[&id].to().into_iter().rev().copied());
861 }
862 }
863}