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(
24 clippy::field_scoped_visibility_modifiers,
25 reason = "Used by IndependentWeave::from()"
26)]
27#![allow(
28 clippy::missing_inline_in_public_items,
29 reason = "Reasonable candidates have already been inlined"
30)]
31#![allow(clippy::exhaustive_enums, reason = "API")]
32#![allow(clippy::exhaustive_structs, reason = "API")]
33#![allow(clippy::little_endian_bytes, reason = "API")]
34#![allow(clippy::partial_pub_fields, reason = "API")]
35#![allow(clippy::pub_use, reason = "API")]
36#![allow(clippy::arbitrary_source_item_ordering, reason = "Readability")]
37#![allow(clippy::question_mark_used, reason = "Readability")]
38#![allow(clippy::single_call_fn, reason = "Readability")]
39#![allow(clippy::single_char_lifetime_names, reason = "Readability")]
40#![allow(clippy::else_if_without_else, reason = "Style")]
41#![allow(clippy::if_then_some_else_none, reason = "Style")]
42#![allow(clippy::implicit_return, reason = "Style")]
43#![allow(clippy::min_ident_chars, reason = "Style")]
44#![allow(clippy::mod_module_files, reason = "Style")]
45#![allow(clippy::module_name_repetitions, reason = "Style")]
46#![allow(clippy::multiple_inherent_impl, reason = "Style")]
47#![allow(clippy::try_err, reason = "Style")]
48#![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;
71pub mod dependent;
72pub mod independent;
73pub mod wrappers;
74
75#[cfg(feature = "rkyv")]
76pub mod versioning;
77
78pub use contracts;
79pub use hashbrown;
80pub use indexmap;
81
82#[cfg(feature = "rkyv")]
83pub use rkyv;
84
85#[cfg(feature = "loro")]
86pub use loro;
87
88extern crate alloc;
89
90use alloc::{collections::vec_deque::VecDeque, vec::Vec};
91use core::{
92 cmp::{Ordering, Reverse},
93 hash::{BuildHasher, Hash},
94};
95
96#[cfg(feature = "rkyv")]
97use rkyv::collections::swiss_table::ArchivedIndexSet;
98
99use hashbrown::{HashMap, HashSet, hash_map::Entry};
100
101#[cfg(feature = "serde")]
102pub use serde;
103
104#[must_use]
106pub trait Node<K, T>
107where
108 K: Hash + Copy + Eq + Ord,
109{
110 type From;
112 type To;
114
115 #[must_use]
117 fn id(&self) -> K;
118 #[must_use]
120 fn from(&self) -> &Self::From;
121 #[must_use]
123 fn to(&self) -> &Self::To;
124 #[must_use]
128 fn is_active(&self) -> bool;
129 #[must_use]
131 fn contents(&self) -> &T;
132}
133
134pub trait DiscreteContents: Sized {
136 fn split(self, at: usize) -> DiscreteContentResult<Self>;
140 fn merge(self, value: Self) -> DiscreteContentResult<Self>;
144}
145
146#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
148#[allow(missing_docs, reason = "Enum items are self-explanatory")]
149#[must_use]
150pub enum DiscreteContentResult<T> {
151 One(T),
152 Two(T, T),
153}
154
155pub trait IndependentContents {}
157
158pub trait DeduplicatableContents {
162 #[must_use]
164 fn is_duplicate_of(&self, other: &Self) -> bool;
165}
166
167#[must_use]
177pub trait Weave<K, N, T>
178where
179 K: Hash + Copy + Eq + Ord,
180 N: Node<K, T>,
181{
182 type Nodes;
184 type Roots;
186
187 #[must_use]
189 fn len(&self) -> usize;
190 #[must_use]
192 fn is_empty(&self) -> bool;
193 #[must_use]
195 fn nodes(&self) -> &Self::Nodes;
196 #[must_use]
198 fn roots(&self) -> &Self::Roots;
199 #[must_use]
201 fn contains(&self, id: &K) -> bool;
202 #[must_use]
206 fn contains_active(&self, id: &K) -> bool;
207 #[must_use]
209 fn get(&self, id: &K) -> Option<&N>;
210 #[must_use]
212 fn get_parents(&self, id: &K) -> Option<&N::From>;
213 #[must_use]
215 fn get_children(&self, id: &K) -> Option<&N::To>;
216 #[must_use]
218 fn get_contents(&self, id: &K) -> Option<&T>;
219 fn get_ordered_identifiers(&mut self, output: &mut Vec<K>);
221 fn get_ordered_identifiers_from(&mut self, id: &K, output: &mut Vec<K>);
225 fn get_active_path(&mut self, output: &mut Vec<K>);
229 fn get_path_from(&mut self, id: &K, output: &mut Vec<K>);
233 fn insert(&mut self, node: N) -> bool;
237 fn set_active(&mut self, id: &K, value: bool) -> bool;
241 fn remove(&mut self, id: &K) -> Option<N>;
247 fn remove_tracked(&mut self, id: &K, on_removal: impl FnMut(N)) -> bool;
255 fn clear(&mut self);
259}
260
261pub trait MetadataWeave<K, N, T, M>: Weave<K, N, T>
267where
268 K: Hash + Copy + Eq + Ord,
269 N: Node<K, T>,
270{
271 #[must_use]
273 fn metadata(&self) -> &M;
274 fn metadata_mut<O>(&mut self, callback: impl FnOnce(&mut M) -> O) -> O;
280}
281
282pub trait BookmarkableWeave<K, N, T>: Weave<K, N, T>
284where
285 K: Hash + Copy + Eq + Ord,
286 N: Node<K, T>,
287{
288 type Bookmarks;
290
291 #[must_use]
293 fn bookmarks(&self) -> &Self::Bookmarks;
294 #[must_use]
296 fn contains_bookmark(&self, id: &K) -> bool;
297 fn set_bookmarked(&mut self, id: &K, value: bool) -> bool;
299}
300
301pub trait SortableWeave<K, N, T>: Weave<K, N, T>
307where
308 K: Hash + Copy + Eq + Ord,
309 N: Node<K, T>,
310{
311 fn sort_children_by(&mut self, id: &K, cmp: impl FnMut(&N, &N) -> Ordering) -> bool;
317 fn sort_children_by_id(&mut self, id: &K, cmp: impl FnMut(&K, &K) -> Ordering) -> bool;
323 fn sort_roots_by(&mut self, cmp: impl FnMut(&N, &N) -> Ordering);
329 fn sort_roots_by_id(&mut self, cmp: impl FnMut(&K, &K) -> Ordering);
335}
336
337pub trait SortableBookmarkableWeave<K, N, T>:
343 BookmarkableWeave<K, N, T> + SortableWeave<K, N, T>
344where
345 K: Hash + Copy + Eq + Ord,
346 N: Node<K, T>,
347{
348 fn sort_bookmarks_by(&mut self, cmp: impl FnMut(&N, &N) -> Ordering);
354 fn sort_bookmarks_by_id(&mut self, cmp: impl FnMut(&K, &K) -> Ordering);
360}
361
362pub trait ActiveSingularWeave<K, N, T>: Weave<K, N, T>
364where
365 K: Hash + Copy + Eq + Ord,
366 N: Node<K, T>,
367{
368 #[must_use]
370 fn active(&self) -> Option<K>;
371}
372
373pub trait ActivePathWeave<K, N, T>: Weave<K, N, T>
375where
376 K: Hash + Copy + Eq + Ord,
377 N: Node<K, T>,
378{
379 type Active;
381
382 #[must_use]
384 fn active(&self) -> &Self::Active;
385 fn set_active_path(&mut self, active: impl Iterator<Item = K>);
389}
390
391pub trait IndependentWeave<K, N, T>: Weave<K, N, T> + SemiIndependentWeave<K, N, T>
393where
394 K: Hash + Copy + Eq + Ord,
395 N: Node<K, T>,
396 T: IndependentContents,
397{
398 fn move_to(&mut self, id: &K, new_parents: &[K]) -> bool;
402}
403
404pub trait SemiIndependentWeave<K, N, T>: Weave<K, N, T>
410where
411 K: Hash + Copy + Eq + Ord,
412 N: Node<K, T>,
413 T: IndependentContents,
414{
415 #[must_use]
423 fn get_contents_mut<O>(&mut self, id: &K, callback: impl FnOnce(&mut T) -> O) -> Option<O>;
424}
425
426pub trait DiscreteWeave<K, N, T>: Weave<K, N, T>
432where
433 K: Hash + Copy + Eq + Ord,
434 N: Node<K, T>,
435 T: DiscreteContents,
436{
437 fn split(&mut self, id: &K, at: usize, new_id: K) -> bool;
447 fn merge_with_parent(&mut self, id: &K) -> Option<K>;
455}
456
457#[must_use]
459pub trait ImmutableWeave<K, N, T>
460where
461 K: Hash + Copy + Eq + Ord,
462 N: Node<K, T>,
463{
464 type Nodes;
466 type Roots;
468
469 #[must_use]
471 fn len(&self) -> usize;
472 #[must_use]
474 fn is_empty(&self) -> bool;
475 #[must_use]
477 fn nodes(&self) -> &Self::Nodes;
478 #[must_use]
480 fn roots(&self) -> &Self::Roots;
481 #[must_use]
483 fn contains(&self, id: &K) -> bool;
484 #[must_use]
488 fn contains_active(&self, id: &K) -> bool;
489 #[must_use]
491 fn get(&self, id: &K) -> Option<&N>;
492 #[must_use]
494 fn get_parents(&self, id: &K) -> Option<&N::From>;
495 #[must_use]
497 fn get_children(&self, id: &K) -> Option<&N::To>;
498 #[must_use]
500 fn get_contents(&self, id: &K) -> Option<&T>;
501 fn get_ordered_identifiers(&self, output: &mut Vec<K>);
503 fn get_ordered_identifiers_from(&self, id: &K, output: &mut Vec<K>);
507 fn get_active_path(&self, output: &mut Vec<K>);
511 fn get_path_from(&self, id: &K, output: &mut Vec<K>);
515}
516
517pub trait ImmutableMetadataWeave<K, N, T, M>: ImmutableWeave<K, N, T>
519where
520 K: Hash + Copy + Eq + Ord,
521 N: Node<K, T>,
522{
523 #[must_use]
525 fn metadata(&self) -> &M;
526}
527
528pub trait ImmutableBookmarkableWeave<K, N, T>: ImmutableWeave<K, N, T>
530where
531 K: Hash + Copy + Eq + Ord,
532 N: Node<K, T>,
533{
534 type Bookmarks;
536
537 #[must_use]
539 fn bookmarks(&self) -> &Self::Bookmarks;
540 #[must_use]
542 fn contains_bookmark(&self, id: &K) -> bool;
543}
544
545pub trait ImmutableActiveSingularWeave<K, N, T>: ImmutableWeave<K, N, T>
547where
548 K: Hash + Copy + Eq + Ord,
549 N: Node<K, T>,
550{
551 #[must_use]
553 fn active(&self) -> Option<K>;
554}
555
556pub trait ImmutableActivePathWeave<K, N, T>: ImmutableWeave<K, N, T>
558where
559 K: Hash + Copy + Eq + Ord,
560 N: Node<K, T>,
561{
562 type Active;
564
565 #[must_use]
567 fn active(&self) -> &Self::Active;
568}
569
570#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
571enum Step<A, B> {
572 Enter(A),
573 Exit(B),
574}
575
576fn topological_sort<'a, K, N, T, S>(
577 nodes: &'a HashMap<K, N, S>,
578 roots: impl DoubleEndedIterator<Item = K>,
579 scratchpad: &mut Vec<K>,
580 identifiers: &mut Vec<K>,
581 identifier_map: &mut HashMap<K, usize, S>,
582) where
583 K: Hash + Copy + Eq + Ord + 'a,
584 N: Node<K, T> + 'a,
585 <N as Node<K, T>>::From: 'a,
586 <N as Node<K, T>>::To: 'a,
587 &'a N::From: IntoIterator<Item = &'a K, IntoIter: DoubleEndedIterator + ExactSizeIterator>,
588 &'a N::To: IntoIterator<Item = &'a K, IntoIter: DoubleEndedIterator>,
589 S: BuildHasher + Default + Clone,
590{
591 scratchpad.extend(roots.rev());
592
593 while let Some(id) = scratchpad.pop() {
594 identifiers.push(id);
595
596 for child in nodes[&id].to().into_iter().rev().copied() {
597 let remaining = identifier_map
598 .entry(child)
599 .or_insert_with(|| nodes[&child].from().into_iter().len());
600 *remaining = remaining.strict_sub(1);
601
602 if *remaining == 0 {
603 scratchpad.push(child);
604 }
605 }
606 }
607}
608
609fn topological_sort_subgraph<'a, K, N, T, S>(
610 nodes: &'a HashMap<K, N, S>,
611 filter: &impl Fn(&K) -> bool,
612 subgraph_root: K,
613 scratchpad: &mut Vec<K>,
614 identifiers: &mut Vec<K>,
615 identifier_map: &mut HashMap<K, usize, S>,
616) where
617 K: Hash + Copy + Eq + Ord + 'a,
618 N: Node<K, T> + 'a,
619 <N as Node<K, T>>::From: 'a,
620 <N as Node<K, T>>::To: 'a,
621 &'a N::From: IntoIterator<Item = &'a K, IntoIter: DoubleEndedIterator>,
622 &'a N::To: IntoIterator<Item = &'a K, IntoIter: DoubleEndedIterator>,
623 S: BuildHasher + Default + Clone,
624{
625 scratchpad.push(subgraph_root);
638
639 while let Some(id) = scratchpad.pop() {
640 identifiers.push(id);
641
642 for child in nodes[&id].to().into_iter().rev().copied() {
643 if !filter(&child) {
644 continue;
645 }
646
647 let remaining = identifier_map.entry(child).or_insert_with(|| {
648 nodes[&child]
649 .from()
650 .into_iter()
651 .filter(|&parent| filter(parent))
652 .count()
653 });
654 *remaining = remaining.strict_sub(1);
655
656 if *remaining == 0 {
657 scratchpad.push(child);
658 }
659 }
660 }
661}
662
663fn detect_cycles<'a, K, N, T, S>(
664 nodes: &'a HashMap<K, N, S>,
665 roots: impl Iterator<Item = K>,
666 scratchpad: &mut Vec<Step<K, K>>,
667 scratchpad_map: &mut HashMap<K, bool, S>,
668) -> bool
669where
670 K: Hash + Copy + Eq + Ord + 'a,
671 N: Node<K, T> + 'a,
672 <N as Node<K, T>>::From: 'a,
673 <N as Node<K, T>>::To: 'a,
674 &'a N::From: IntoIterator<Item = &'a K, IntoIter: DoubleEndedIterator>,
675 &'a N::To: IntoIterator<Item = &'a K, IntoIter: DoubleEndedIterator + ExactSizeIterator>,
676 S: BuildHasher + Default + Clone,
677{
678 for root in roots {
679 if scratchpad_map.contains_key(&root) {
680 continue;
681 }
682
683 scratchpad.push(Step::Enter(root));
684
685 while let Some(step) = scratchpad.pop() {
686 match step {
687 Step::Enter(id) => {
688 scratchpad.push(Step::Exit(id));
689
690 match scratchpad_map.entry(id) {
691 Entry::Occupied(entry) => {
692 if !entry.get() {
693 return true;
694 }
695 }
696 Entry::Vacant(entry) => {
697 entry.insert_entry(false);
698
699 scratchpad.extend(
700 nodes[&id].to().into_iter().rev().copied().map(Step::Enter),
701 );
702 }
703 }
704 }
705 Step::Exit(id) => {
706 scratchpad_map.insert(id, true);
707 }
708 }
709 }
710 }
711
712 scratchpad_map.len() != nodes.len()
713}
714
715fn shortest_path_to_ancestor<'a, K, N, T, S>(
716 nodes: &'a HashMap<K, N, S>,
717 id: &'a K,
718 target: &impl Fn(&'a N) -> bool,
719 scratchpad: &mut VecDeque<K>,
720 scratchpad_map: &mut HashMap<K, K, S>,
721 scratchpad_set: &mut HashSet<K, S>,
722 path: &mut Vec<K>,
723) where
724 K: Hash + Copy + Eq + Ord + 'a,
725 N: Node<K, T> + 'a,
726 <N as Node<K, T>>::From: 'a,
727 <N as Node<K, T>>::To: 'a,
728 &'a N::From: IntoIterator<Item = &'a K, IntoIter: DoubleEndedIterator>,
729 &'a N::To: IntoIterator<Item = &'a K, IntoIter: DoubleEndedIterator>,
730 S: BuildHasher + Default + Clone,
731{
732 scratchpad.push_front(*id);
733 scratchpad_set.insert(*id);
734
735 while let Some(id) = scratchpad.pop_back() {
736 let node = &nodes[&id];
737
738 if target(node) {
739 scratchpad.clear();
740
741 path.push(id);
742
743 while let Some(child) = scratchpad_map.remove(path.last().unwrap()) {
744 path.push(child);
745 }
746
747 return;
748 }
749
750 for parent in node.from().into_iter().copied() {
751 if scratchpad_set.insert(parent) {
752 scratchpad.push_front(parent);
753 scratchpad_map.insert(parent, id);
754 }
755 }
756 }
757}
758
759fn longest_candidate_path_to_root<'a, K, N, T, S>(
760 nodes: &'a HashMap<K, N, S>,
761 topological_order: &[K],
762 is_candidate: &impl Fn(&K) -> bool,
763 scratchpad_map: &mut HashMap<K, usize, S>,
764 reversed_path: &mut Vec<K>,
765) where
766 K: Hash + Copy + Eq + Ord + 'a,
767 N: Node<K, T> + 'a,
768 <N as Node<K, T>>::From: 'a,
769 <N as Node<K, T>>::To: 'a,
770 &'a N::From: IntoIterator<Item = &'a K, IntoIter: DoubleEndedIterator>,
771 &'a N::To: IntoIterator<Item = &'a K, IntoIter: DoubleEndedIterator>,
772 S: BuildHasher + Default + Clone,
773{
774 let mut longest_distance = None;
775
776 for id in topological_order {
777 if !is_candidate(id) {
778 continue;
779 }
780
781 let node = &nodes[id];
782 let distance = if node.from().into_iter().next().is_none() {
783 Some(0)
784 } else {
785 node.from()
786 .into_iter()
787 .filter_map(|parent| scratchpad_map.get(parent).copied())
788 .max()
789 .map(|l| l.strict_add(1))
790 };
791
792 if let Some(distance) = distance {
793 scratchpad_map.insert(*id, distance);
794
795 if longest_distance.is_none_or(|(value, _)| distance > value) {
796 longest_distance = Some((distance, id));
797 }
798 }
799 }
800
801 let mut current = longest_distance.map(|(_, id)| id);
802
803 while let Some(id) = current {
804 reversed_path.push(*id);
805
806 current = nodes[id]
807 .from()
808 .into_iter()
809 .filter(|id| scratchpad_map.contains_key(*id))
810 .min_by_key(|id| Reverse(scratchpad_map[*id]));
811 }
812}
813
814fn ancestor_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].from().into_iter().rev().copied());
833 }
834 }
835}
836
837fn descendant_subgraph<'a, K, N, T, S>(
838 nodes: &'a HashMap<K, N, S>,
839 id: K,
840 scratchpad: &mut Vec<K>,
841 identifiers: &mut HashSet<K, S>,
842) where
843 K: Hash + Copy + Eq + Ord + 'a,
844 N: Node<K, T>,
845 <N as Node<K, T>>::From: 'a,
846 <N as Node<K, T>>::To: 'a,
847 &'a N::From: IntoIterator<Item = &'a K, IntoIter: DoubleEndedIterator>,
848 &'a N::To: IntoIterator<Item = &'a K, IntoIter: DoubleEndedIterator>,
849 S: BuildHasher + Default + Clone,
850{
851 scratchpad.push(id);
852
853 while let Some(id) = scratchpad.pop() {
854 if identifiers.insert(id) {
855 scratchpad.extend(nodes[&id].to().into_iter().rev().copied());
856 }
857 }
858}
859
860#[cfg(feature = "rkyv")]
861fn archived_set_reverse_order<T>(set: &ArchivedIndexSet<T>) -> impl Iterator<Item = &T> {
862 (0..set.len())
863 .into_iter()
864 .rev()
865 .filter_map(|index| set.get_index(index))
866}