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 #[must_use]
196 fn get_node_parents(&self, id: &K) -> Option<&N::From>;
197 #[must_use]
199 fn get_node_children(&self, id: &K) -> Option<&N::To>;
200 fn get_ordered_node_identifiers(&mut self, output: &mut Vec<K>);
202 fn get_ordered_node_identifiers_from(&mut self, id: &K, output: &mut Vec<K>);
204 fn get_active_path(&mut self, output: &mut Vec<K>);
208 fn get_path_from(&mut self, id: &K, output: &mut Vec<K>);
212 fn add_node(&mut self, node: N) -> bool;
216 fn set_node_active_status(&mut self, id: &K, value: bool) -> bool;
220 fn remove_node(&mut self, id: &K) -> Option<N>;
226 fn remove_node_tracked(&mut self, id: &K, on_removal: impl FnMut(N)) -> bool;
234 fn remove_all_nodes(&mut self);
236}
237
238pub trait MetadataWeave<K, N, T, M>: Weave<K, N, T>
244where
245 K: Hash + Copy + Eq + Ord,
246 N: Node<K, T>,
247{
248 #[must_use]
250 fn metadata(&self) -> &M;
251 fn metadata_mut<O>(&mut self, callback: impl FnOnce(&mut M) -> O) -> O;
257}
258
259pub trait BookmarkableWeave<K, N, T>: Weave<K, N, T>
261where
262 K: Hash + Copy + Eq + Ord,
263 N: Node<K, T>,
264{
265 type Bookmarks;
267
268 #[must_use]
270 fn bookmarks(&self) -> &Self::Bookmarks;
271 #[must_use]
273 fn contains_bookmark(&self, id: &K) -> bool;
274 fn set_node_bookmarked_status(&mut self, id: &K, value: bool) -> bool;
276}
277
278pub trait SortableWeave<K, N, T>: Weave<K, N, T>
284where
285 K: Hash + Copy + Eq + Ord,
286 N: Node<K, T>,
287{
288 fn sort_node_children_by(&mut self, id: &K, cmp: impl FnMut(&N, &N) -> Ordering) -> bool;
294 fn sort_node_children_by_id(&mut self, id: &K, cmp: impl FnMut(&K, &K) -> Ordering) -> bool;
300 fn sort_roots_by(&mut self, cmp: impl FnMut(&N, &N) -> Ordering);
306 fn sort_roots_by_id(&mut self, cmp: impl FnMut(&K, &K) -> Ordering);
312}
313
314pub trait SortableBookmarkableWeave<K, N, T>:
320 BookmarkableWeave<K, N, T> + SortableWeave<K, N, T>
321where
322 K: Hash + Copy + Eq + Ord,
323 N: Node<K, T>,
324{
325 fn sort_bookmarks_by(&mut self, cmp: impl FnMut(&N, &N) -> Ordering);
331 fn sort_bookmarks_by_id(&mut self, cmp: impl FnMut(&K, &K) -> Ordering);
337}
338
339pub trait ActiveSingularWeave<K, N, T>: Weave<K, N, T>
341where
342 K: Hash + Copy + Eq + Ord,
343 N: Node<K, T>,
344{
345 #[must_use]
347 fn active(&self) -> Option<K>;
348}
349
350pub trait ActivePathWeave<K, N, T>: Weave<K, N, T>
352where
353 K: Hash + Copy + Eq + Ord,
354 N: Node<K, T>,
355{
356 type Active;
358
359 #[must_use]
361 fn active(&self) -> &Self::Active;
362 fn set_active_path(&mut self, active: impl Iterator<Item = K>);
366}
367
368pub trait IndependentWeave<K, N, T>: Weave<K, N, T> + SemiIndependentWeave<K, N, T>
370where
371 K: Hash + Copy + Eq + Ord,
372 N: Node<K, T>,
373 T: IndependentContents,
374{
375 fn move_node(&mut self, id: &K, new_parents: &[K]) -> bool;
379}
380
381pub trait SemiIndependentWeave<K, N, T>: Weave<K, N, T>
387where
388 K: Hash + Copy + Eq + Ord,
389 N: Node<K, T>,
390 T: IndependentContents,
391{
392 fn get_contents_mut<O>(&mut self, id: &K, callback: impl FnOnce(&mut T) -> O) -> Option<O>;
398}
399
400pub trait DiscreteWeave<K, N, T>: Weave<K, N, T>
406where
407 K: Hash + Copy + Eq + Ord,
408 N: Node<K, T>,
409 T: DiscreteContents,
410{
411 fn split_node(&mut self, id: &K, at: usize, new_id: K) -> bool;
419 fn merge_with_parent(&mut self, id: &K) -> Option<K>;
427}
428
429#[must_use]
431pub trait ImmutableWeave<K, N, T>
432where
433 K: Hash + Copy + Eq + Ord,
434 N: Node<K, T>,
435{
436 type Nodes;
438 type Roots;
440
441 #[must_use]
443 fn len(&self) -> usize;
444 #[must_use]
446 fn is_empty(&self) -> bool;
447 #[must_use]
449 fn nodes(&self) -> &Self::Nodes;
450 #[must_use]
452 fn roots(&self) -> &Self::Roots;
453 #[must_use]
455 fn contains(&self, id: &K) -> bool;
456 #[must_use]
460 fn contains_active(&self, id: &K) -> bool;
461 #[must_use]
463 fn get_node(&self, id: &K) -> Option<&N>;
464 #[must_use]
466 fn get_node_parents(&self, id: &K) -> Option<&N::From>;
467 #[must_use]
469 fn get_node_children<'a>(&'a self, id: &K) -> Option<&'a N::To>;
470 fn get_ordered_node_identifiers(&self, output: &mut Vec<K>);
472 fn get_ordered_node_identifiers_from(&self, id: &K, output: &mut Vec<K>);
474 fn get_active_path(&self, output: &mut Vec<K>);
478 fn get_path_from(&self, id: &K, output: &mut Vec<K>);
482}
483
484pub trait ImmutableMetadataWeave<K, N, T, M>: ImmutableWeave<K, N, T>
486where
487 K: Hash + Copy + Eq + Ord,
488 N: Node<K, T>,
489{
490 #[must_use]
492 fn metadata(&self) -> &M;
493}
494
495pub trait ImmutableBookmarkableWeave<K, N, T>: ImmutableWeave<K, N, T>
497where
498 K: Hash + Copy + Eq + Ord,
499 N: Node<K, T>,
500{
501 type Bookmarks;
503
504 #[must_use]
506 fn bookmarks(&self) -> &Self::Bookmarks;
507 #[must_use]
509 fn contains_bookmark(&self, id: &K) -> bool;
510}
511
512pub trait ImmutableActiveSingularWeave<K, N, T>: ImmutableWeave<K, N, T>
514where
515 K: Hash + Copy + Eq + Ord,
516 N: Node<K, T>,
517{
518 #[must_use]
520 fn active(&self) -> Option<K>;
521}
522
523pub trait ImmutableActivePathWeave<K, N, T>: ImmutableWeave<K, N, T>
525where
526 K: Hash + Copy + Eq + Ord,
527 N: Node<K, T>,
528{
529 type Active;
531
532 #[must_use]
534 fn active(&self) -> &Self::Active;
535}
536
537#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
538enum Step<A, B> {
539 Enter(A),
540 Exit(B),
541}
542
543fn topological_sort<'a, K, N, T, S>(
544 nodes: &'a HashMap<K, N, S>,
545 id: &'a K,
546 scratchpad: &mut Vec<K>,
547 identifiers: &mut Vec<K>,
548 identifier_set: &mut HashSet<K, S>,
549 identifier_map: &mut HashMap<K, usize, S>,
550) where
551 K: Hash + Copy + Eq + Ord + 'a,
552 N: Node<K, T> + 'a,
553 <N as Node<K, T>>::From: 'a,
554 <N as Node<K, T>>::To: 'a,
555 &'a N::From: IntoIterator<Item = &'a K, IntoIter: DoubleEndedIterator + ExactSizeIterator>,
556 &'a N::To: IntoIterator<Item = &'a K, IntoIter: DoubleEndedIterator>,
557 S: BuildHasher + Default + Clone,
558{
559 scratchpad.push(*id);
560
561 while let Some(id) = scratchpad.pop() {
562 let node = &nodes[&id];
563
564 if identifier_set.contains(&id)
565 || identifier_map
566 .get(&id)
567 .copied()
568 .unwrap_or_else(|| node.from().into_iter().len())
569 != 0
570 {
571 continue;
572 }
573
574 identifiers.push(id);
575 identifier_set.insert(id);
576
577 for child in node.to().into_iter().rev().copied() {
578 let remaining = identifier_map
579 .entry(child)
580 .or_insert_with(|| nodes[&child].from().into_iter().len());
581 *remaining = remaining.strict_sub(1);
582
583 scratchpad.push(child);
584 }
585 }
586}
587
588fn topological_sort_subgraph<'a, K, N, T, S>(
589 nodes: &'a HashMap<K, N, S>,
590 filter: &impl Fn(&K) -> bool,
591 id: &'a K,
592 scratchpad: &mut Vec<K>,
593 identifiers: &mut Vec<K>,
594 identifier_set: &mut HashSet<K, S>,
595 identifier_map: &mut HashMap<K, usize, S>,
596) where
597 K: Hash + Copy + Eq + Ord + 'a,
598 N: Node<K, T> + 'a,
599 <N as Node<K, T>>::From: 'a,
600 <N as Node<K, T>>::To: 'a,
601 &'a N::From: IntoIterator<Item = &'a K, IntoIter: DoubleEndedIterator>,
602 &'a N::To: IntoIterator<Item = &'a K, IntoIter: DoubleEndedIterator>,
603 S: BuildHasher + Default + Clone,
604{
605 scratchpad.push(*id);
606
607 while let Some(id) = scratchpad.pop() {
608 let node = &nodes[&id];
609
610 if !filter(&id)
611 || identifier_set.contains(&id)
612 || identifier_map.get(&id).copied().unwrap_or_else(|| {
613 node.from()
614 .into_iter()
615 .filter(|&parent| filter(parent))
616 .count()
617 }) != 0
618 {
619 continue;
620 }
621
622 identifiers.push(id);
623 identifier_set.insert(id);
624
625 for child in node.to().into_iter().rev().copied() {
626 let remaining = identifier_map.entry(child).or_insert_with(|| {
627 nodes[&child]
628 .from()
629 .into_iter()
630 .filter(|&parent| filter(parent))
631 .count()
632 });
633 *remaining = remaining.strict_sub(1);
634
635 scratchpad.push(child);
636 }
637 }
638}
639
640fn detect_cycles<'a, K, N, T, S>(
641 nodes: &'a HashMap<K, N, S>,
642 roots: impl Iterator<Item = K>,
643 scratchpad: &mut Vec<Step<K, K>>,
644 scratchpad_map: &mut HashMap<K, bool, S>,
645) -> bool
646where
647 K: Hash + Copy + Eq + Ord + 'a,
648 N: Node<K, T> + 'a,
649 <N as Node<K, T>>::From: 'a,
650 <N as Node<K, T>>::To: 'a,
651 &'a N::From: IntoIterator<Item = &'a K, IntoIter: DoubleEndedIterator>,
652 &'a N::To: IntoIterator<Item = &'a K, IntoIter: DoubleEndedIterator + ExactSizeIterator>,
653 S: BuildHasher + Default + Clone,
654{
655 for root in roots {
656 if scratchpad_map.contains_key(&root) {
657 continue;
658 }
659
660 scratchpad.push(Step::Enter(root));
661
662 while let Some(step) = scratchpad.pop() {
663 match step {
664 Step::Enter(id) => {
665 scratchpad.push(Step::Exit(id));
666
667 match scratchpad_map.entry(id) {
668 Entry::Occupied(entry) => {
669 if !entry.get() {
670 return true;
671 }
672 }
673 Entry::Vacant(entry) => {
674 entry.insert_entry(false);
675
676 scratchpad.extend(
677 nodes[&id].to().into_iter().rev().copied().map(Step::Enter),
678 );
679 }
680 }
681 }
682 Step::Exit(id) => {
683 scratchpad_map.insert(id, true);
684 }
685 }
686 }
687 }
688
689 scratchpad_map.len() != nodes.len()
690}
691
692fn shortest_path_to_ancestor<'a, K, N, T, S>(
693 nodes: &'a HashMap<K, N, S>,
694 id: &'a K,
695 target: &impl Fn(&'a N) -> bool,
696 scratchpad: &mut VecDeque<K>,
697 scratchpad_map: &mut HashMap<K, K, S>,
698 scratchpad_set: &mut HashSet<K, S>,
699 path: &mut Vec<K>,
700) where
701 K: Hash + Copy + Eq + Ord + 'a,
702 N: Node<K, T> + 'a,
703 <N as Node<K, T>>::From: 'a,
704 <N as Node<K, T>>::To: 'a,
705 &'a N::From: IntoIterator<Item = &'a K, IntoIter: DoubleEndedIterator>,
706 &'a N::To: IntoIterator<Item = &'a K, IntoIter: DoubleEndedIterator>,
707 S: BuildHasher + Default + Clone,
708{
709 scratchpad.push_front(*id);
710 scratchpad_set.insert(*id);
711
712 while let Some(id) = scratchpad.pop_back() {
713 let node = &nodes[&id];
714
715 if target(node) {
716 scratchpad.clear();
717
718 path.push(id);
719
720 while let Some(child) = scratchpad_map.remove(path.last().unwrap()) {
721 path.push(child);
722 }
723
724 return;
725 }
726
727 for parent in node.from().into_iter().copied() {
728 if scratchpad_set.insert(parent) {
729 scratchpad.push_front(parent);
730 scratchpad_map.insert(parent, id);
731 }
732 }
733 }
734}
735
736fn longest_candidate_path_to_root<'a, K, N, T, S>(
737 nodes: &'a HashMap<K, N, S>,
738 topological_order: &[K],
739 is_candidate: &impl Fn(&K) -> bool,
740 scratchpad_map: &mut HashMap<K, usize, S>,
741 reversed_path: &mut Vec<K>,
742) where
743 K: Hash + Copy + Eq + Ord + 'a,
744 N: Node<K, T> + 'a,
745 <N as Node<K, T>>::From: 'a,
746 <N as Node<K, T>>::To: 'a,
747 &'a N::From: IntoIterator<Item = &'a K, IntoIter: DoubleEndedIterator>,
748 &'a N::To: IntoIterator<Item = &'a K, IntoIter: DoubleEndedIterator>,
749 S: BuildHasher + Default + Clone,
750{
751 let mut longest_distance = None;
752
753 for id in topological_order {
754 if !is_candidate(id) {
755 continue;
756 }
757
758 let node = &nodes[id];
759 let distance = if node.from().into_iter().next().is_none() {
760 Some(0)
761 } else {
762 node.from()
763 .into_iter()
764 .filter_map(|parent| scratchpad_map.get(parent).copied())
765 .max()
766 .map(|l| l.strict_add(1))
767 };
768
769 if let Some(distance) = distance {
770 scratchpad_map.insert(*id, distance);
771
772 if longest_distance.is_none_or(|(value, _)| distance > value) {
773 longest_distance = Some((distance, id));
774 }
775 }
776 }
777
778 let mut current = longest_distance.map(|(_, id)| id);
779
780 while let Some(id) = current {
781 reversed_path.push(*id);
782
783 current = nodes[id]
784 .from()
785 .into_iter()
786 .filter(|id| scratchpad_map.contains_key(*id))
787 .min_by_key(|id| Reverse(scratchpad_map[*id]));
788 }
789}
790
791fn ancestor_subgraph<'a, K, N, T, S>(
792 nodes: &'a HashMap<K, N, S>,
793 id: K,
794 scratchpad: &mut Vec<K>,
795 identifiers: &mut HashSet<K, S>,
796) where
797 K: Hash + Copy + Eq + Ord + 'a,
798 N: Node<K, T>,
799 <N as Node<K, T>>::From: 'a,
800 <N as Node<K, T>>::To: 'a,
801 &'a N::From: IntoIterator<Item = &'a K, IntoIter: DoubleEndedIterator>,
802 &'a N::To: IntoIterator<Item = &'a K, IntoIter: DoubleEndedIterator>,
803 S: BuildHasher + Default + Clone,
804{
805 scratchpad.push(id);
806
807 while let Some(id) = scratchpad.pop() {
808 if identifiers.insert(id) {
809 scratchpad.extend(nodes[&id].from().into_iter().rev().copied());
810 }
811 }
812}
813
814fn descendant_subgraph<'a, K, N, T, S>(
815 nodes: &'a HashMap<K, N, S>,
816 id: K,
817 scratchpad: &mut Vec<K>,
818 identifiers: &mut HashSet<K, S>,
819) where
820 K: Hash + Copy + Eq + Ord + 'a,
821 N: Node<K, T>,
822 <N as Node<K, T>>::From: 'a,
823 <N as Node<K, T>>::To: 'a,
824 &'a N::From: IntoIterator<Item = &'a K, IntoIter: DoubleEndedIterator>,
825 &'a N::To: IntoIterator<Item = &'a K, IntoIter: DoubleEndedIterator>,
826 S: BuildHasher + Default + Clone,
827{
828 scratchpad.push(id);
829
830 while let Some(id) = scratchpad.pop() {
831 if identifiers.insert(id) {
832 scratchpad.extend(nodes[&id].to().into_iter().rev().copied());
833 }
834 }
835}