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