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) where
542 K: Hash + Copy + Eq + Ord + 'a,
543 N: Node<K, T> + 'a,
544 <N as Node<K, T>>::From: 'a,
545 <N as Node<K, T>>::To: 'a,
546 &'a N::From: IntoIterator<Item = &'a K, IntoIter: DoubleEndedIterator>,
547 &'a N::To: IntoIterator<Item = &'a K, IntoIter: DoubleEndedIterator>,
548 S: BuildHasher + Default + Clone,
549{
550 scratchpad.push(*id);
551
552 while let Some(id) = scratchpad.pop() {
553 let node = &nodes[&id];
554
555 if !identifier_set.contains(&id)
556 && node
557 .from()
558 .into_iter()
559 .all(|parent| identifier_set.contains(parent))
560 {
561 identifiers.push(id);
562 identifier_set.insert(id);
563 scratchpad.extend(node.to().into_iter().rev().copied());
564 }
565 }
566}
567
568fn topological_sort_subgraph<'a, K, N, T, S>(
569 nodes: &'a HashMap<K, N, S>,
570 filter: &impl Fn(&K) -> bool,
571 id: &'a K,
572 scratchpad: &mut Vec<K>,
573 identifiers: &mut Vec<K>,
574 identifier_set: &mut HashSet<K, S>,
575) where
576 K: Hash + Copy + Eq + Ord + 'a,
577 N: Node<K, T> + 'a,
578 <N as Node<K, T>>::From: 'a,
579 <N as Node<K, T>>::To: 'a,
580 &'a N::From: IntoIterator<Item = &'a K, IntoIter: DoubleEndedIterator>,
581 &'a N::To: IntoIterator<Item = &'a K, IntoIter: DoubleEndedIterator>,
582 S: BuildHasher + Default + Clone,
583{
584 scratchpad.push(*id);
585
586 while let Some(id) = scratchpad.pop() {
587 let node = &nodes[&id];
588
589 if filter(&id)
590 && !identifier_set.contains(&id)
591 && node
592 .from()
593 .into_iter()
594 .all(|parent| identifier_set.contains(parent) || !filter(parent))
595 {
596 identifiers.push(id);
597 identifier_set.insert(id);
598 scratchpad.extend(node.to().into_iter().rev().copied());
599 }
600 }
601}
602
603fn topological_sort_subgraph_mirrored<'a, K, N, T, S>(
604 nodes: &'a HashMap<K, N, S>,
605 filter: &impl Fn(&K) -> bool,
606 id: &'a K,
607 scratchpad: &mut Vec<K>,
608 identifiers: &mut Vec<K>,
609 identifier_set: &mut HashSet<K, S>,
610) where
611 K: Hash + Copy + Eq + Ord + 'a,
612 N: Node<K, T> + 'a,
613 <N as Node<K, T>>::From: 'a,
614 <N as Node<K, T>>::To: 'a,
615 &'a N::From: IntoIterator<Item = &'a K, IntoIter: DoubleEndedIterator>,
616 &'a N::To: IntoIterator<Item = &'a K, IntoIter: DoubleEndedIterator>,
617 S: BuildHasher + Default + Clone,
618{
619 scratchpad.push(*id);
620
621 while let Some(id) = scratchpad.pop() {
622 let node = &nodes[&id];
623
624 if filter(&id)
625 && !identifier_set.contains(&id)
626 && node
627 .from()
628 .into_iter()
629 .all(|parent| identifier_set.contains(parent) || !filter(parent))
630 {
631 identifiers.push(id);
632 identifier_set.insert(id);
633 scratchpad.extend(node.to().into_iter().copied());
634 }
635 }
636}
637
638fn topological_sort_mirrored<'a, K, N, T, S>(
639 nodes: &'a HashMap<K, N, S>,
640 id: &'a K,
641 scratchpad: &mut Vec<K>,
642 identifiers: &mut Vec<K>,
643 identifier_set: &mut HashSet<K, S>,
644) where
645 K: Hash + Copy + Eq + Ord + 'a,
646 N: Node<K, T> + 'a,
647 <N as Node<K, T>>::From: 'a,
648 <N as Node<K, T>>::To: 'a,
649 &'a N::From: IntoIterator<Item = &'a K, IntoIter: DoubleEndedIterator>,
650 &'a N::To: IntoIterator<Item = &'a K, IntoIter: DoubleEndedIterator>,
651 S: BuildHasher + Default + Clone,
652{
653 scratchpad.push(*id);
654
655 while let Some(id) = scratchpad.pop() {
656 let node = &nodes[&id];
657
658 if !identifier_set.contains(&id)
659 && node
660 .from()
661 .into_iter()
662 .all(|parent| identifier_set.contains(parent))
663 {
664 identifiers.push(id);
665 identifier_set.insert(id);
666 scratchpad.extend(node.to().into_iter().copied());
667 }
668 }
669}
670
671fn detect_cycles<'a, K, N, T, S>(
672 nodes: &'a HashMap<K, N, S>,
673 roots: impl Iterator<Item = K>,
674 scratchpad: &mut Vec<Step<K, K>>,
675 scratchpad_map: &mut HashMap<K, bool, S>,
676) -> bool
677where
678 K: Hash + Copy + Eq + Ord + 'a,
679 N: Node<K, T> + 'a,
680 <N as Node<K, T>>::From: 'a,
681 <N as Node<K, T>>::To: 'a,
682 &'a N::From: IntoIterator<Item = &'a K, IntoIter: DoubleEndedIterator>,
683 &'a N::To: IntoIterator<Item = &'a K, IntoIter: DoubleEndedIterator + ExactSizeIterator>,
684 S: BuildHasher + Default + Clone,
685{
686 for root in roots {
687 if scratchpad_map.contains_key(&root) {
688 continue;
689 }
690
691 scratchpad.push(Step::Enter(root));
692
693 while let Some(step) = scratchpad.pop() {
694 match step {
695 Step::Enter(id) => {
696 scratchpad.push(Step::Exit(id));
697
698 match scratchpad_map.entry(id) {
699 Entry::Occupied(entry) => {
700 if !entry.get() {
701 return true;
702 }
703 }
704 Entry::Vacant(entry) => {
705 entry.insert_entry(false);
706
707 scratchpad.extend(
708 nodes[&id].to().into_iter().rev().copied().map(Step::Enter),
709 );
710 }
711 }
712 }
713 Step::Exit(id) => {
714 scratchpad_map.insert(id, true);
715 }
716 }
717 }
718 }
719
720 scratchpad_map.len() != nodes.len()
721}
722
723fn shortest_path_to_ancestor<'a, K, N, T, S>(
724 nodes: &'a HashMap<K, N, S>,
725 id: &'a K,
726 target: &impl Fn(&'a N) -> bool,
727 scratchpad: &mut VecDeque<K>,
728 scratchpad_map: &mut HashMap<K, K, S>,
729 scratchpad_set: &mut HashSet<K, S>,
730 path: &mut Vec<K>,
731) where
732 K: Hash + Copy + Eq + Ord + 'a,
733 N: Node<K, T> + 'a,
734 <N as Node<K, T>>::From: 'a,
735 <N as Node<K, T>>::To: 'a,
736 &'a N::From: IntoIterator<Item = &'a K, IntoIter: DoubleEndedIterator>,
737 &'a N::To: IntoIterator<Item = &'a K, IntoIter: DoubleEndedIterator>,
738 S: BuildHasher + Default + Clone,
739{
740 scratchpad.push_front(*id);
741 scratchpad_set.insert(*id);
742
743 while let Some(id) = scratchpad.pop_back() {
744 let node = &nodes[&id];
745
746 if target(node) {
747 scratchpad.clear();
748
749 path.push(id);
750
751 while let Some(child) = scratchpad_map.remove(path.last().unwrap()) {
752 path.push(child);
753 }
754
755 return;
756 }
757
758 for parent in node.from().into_iter().copied() {
759 if scratchpad_set.insert(parent) {
760 scratchpad.push_front(parent);
761 scratchpad_map.insert(parent, id);
762 }
763 }
764 }
765}
766
767fn longest_candidate_path_to_root<'a, K, N, T, S>(
768 nodes: &'a HashMap<K, N, S>,
769 topological_order: &[K],
770 is_candidate: &impl Fn(&K) -> bool,
771 scratchpad_map: &mut HashMap<K, usize, S>,
772 reversed_path: &mut Vec<K>,
773) where
774 K: Hash + Copy + Eq + Ord + 'a,
775 N: Node<K, T> + 'a,
776 <N as Node<K, T>>::From: 'a,
777 <N as Node<K, T>>::To: 'a,
778 &'a N::From: IntoIterator<Item = &'a K, IntoIter: DoubleEndedIterator>,
779 &'a N::To: IntoIterator<Item = &'a K, IntoIter: DoubleEndedIterator>,
780 S: BuildHasher + Default + Clone,
781{
782 let mut longest_distance = None;
783
784 for id in topological_order {
785 if !is_candidate(id) {
786 continue;
787 }
788
789 let node = &nodes[id];
790 let distance = if node.from().into_iter().next().is_none() {
791 Some(0)
792 } else {
793 node.from()
794 .into_iter()
795 .filter_map(|parent| scratchpad_map.get(parent).copied())
796 .max()
797 .map(|l| l.strict_add(1))
798 };
799
800 if let Some(distance) = distance {
801 scratchpad_map.insert(*id, distance);
802
803 if longest_distance.is_none_or(|(value, _)| distance > value) {
804 longest_distance = Some((distance, id));
805 }
806 }
807 }
808
809 let mut current = longest_distance.map(|(_, id)| id);
810
811 while let Some(id) = current {
812 reversed_path.push(*id);
813
814 current = nodes[id]
815 .from()
816 .into_iter()
817 .filter(|id| scratchpad_map.contains_key(*id))
818 .min_by_key(|id| Reverse(scratchpad_map[*id]));
819 }
820}
821
822fn ancestor_subgraph<'a, K, N, T, S>(
823 nodes: &'a HashMap<K, N, S>,
824 id: K,
825 scratchpad: &mut Vec<K>,
826 identifiers: &mut HashSet<K, S>,
827) where
828 K: Hash + Copy + Eq + Ord + 'a,
829 N: Node<K, T>,
830 <N as Node<K, T>>::From: 'a,
831 <N as Node<K, T>>::To: 'a,
832 &'a N::From: IntoIterator<Item = &'a K, IntoIter: DoubleEndedIterator>,
833 &'a N::To: IntoIterator<Item = &'a K, IntoIter: DoubleEndedIterator>,
834 S: BuildHasher + Default + Clone,
835{
836 scratchpad.push(id);
837
838 while let Some(id) = scratchpad.pop() {
839 if identifiers.insert(id) {
840 scratchpad.extend(nodes[&id].from().into_iter().rev().copied());
841 }
842 }
843}
844
845fn descendant_subgraph<'a, K, N, T, S>(
846 nodes: &'a HashMap<K, N, S>,
847 id: K,
848 scratchpad: &mut Vec<K>,
849 identifiers: &mut HashSet<K, S>,
850) where
851 K: Hash + Copy + Eq + Ord + 'a,
852 N: Node<K, T>,
853 <N as Node<K, T>>::From: 'a,
854 <N as Node<K, T>>::To: 'a,
855 &'a N::From: IntoIterator<Item = &'a K, IntoIter: DoubleEndedIterator>,
856 &'a N::To: IntoIterator<Item = &'a K, IntoIter: DoubleEndedIterator>,
857 S: BuildHasher + Default + Clone,
858{
859 scratchpad.push(id);
860
861 while let Some(id) = scratchpad.pop() {
862 if identifiers.insert(id) {
863 scratchpad.extend(nodes[&id].to().into_iter().rev().copied());
864 }
865 }
866}