1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
//! # abyo-crdt
//!
//! Pure Rust CRDT library implementing an [Eg-walker]-style event log over a
//! [Fugue-Maximal] list, with companion [`Map`], [`Counter`], and [`Set`]
//! CRDTs and [Peritext] rich text planned for v0.3.
//!
//! See the [`README`](https://github.com/abyo-software/abyo-crdt) for design
//! background and the [crate-level plan](https://github.com/abyo-software/abyo-crdt/blob/main/abyo_crdt_plan.md)
//! for the roadmap.
//!
//! [Eg-walker]: https://arxiv.org/abs/2409.14252
//! [Fugue-Maximal]: https://arxiv.org/abs/2305.00583
//! [Peritext]: https://www.inkandswitch.com/peritext/
//!
//! ## Available data types
//!
//! | Type | Algorithm | Status |
//! |----------------|------------------|------------|
//! | [`List<T>`] | Fugue-Maximal | v0.1 ✅ |
//! | [`Map<K, V>`] | LWW with Lamport | v0.2 ✅ |
//! | [`Counter`] | PN-Counter | v0.2 ✅ |
//! | [`Set<T>`] | OR-Set, add-wins | v0.2 ✅ |
//! | `Text` | Peritext | v0.3 🚧 |
//!
//! Every CRDT in the crate ships an event log (`ops()`), supports incremental
//! sync via [`VersionVector`] (`ops_since(&version)`), and is `Serialize +
//! Deserialize` under the default `serde` feature.
//!
//! ## Quick start
//!
//! ```
//! use abyo_crdt::List;
//!
//! let mut alice = List::<char>::new(1);
//! alice.insert(0, 'H');
//! alice.insert(1, 'i');
//!
//! let mut bob = List::<char>::new(2);
//! bob.merge(&alice);
//!
//! bob.insert(2, '!');
//! alice.merge(&bob);
//!
//! assert_eq!(alice.to_vec(), vec!['H', 'i', '!']);
//! assert_eq!(bob.to_vec(), vec!['H', 'i', '!']);
//! ```
//!
//! ## Concurrent edits never interleave
//!
//! Fugue-Maximal guarantees that contiguous bursts of typing stay contiguous
//! after merge, regardless of timing.
//!
//! ```
//! use abyo_crdt::List;
//!
//! let mut alice = List::<char>::new(1);
//! let mut bob = List::<char>::new(2);
//!
//! // Both start from a shared "ab" doc
//! alice.insert(0, 'a');
//! alice.insert(1, 'b');
//! bob.merge(&alice);
//!
//! // Concurrent inserts at position 1 — Alice types "Hello", Bob types "World"
//! for (i, c) in "Hello".chars().enumerate() {
//! alice.insert(1 + i, c);
//! }
//! for (i, c) in "World".chars().enumerate() {
//! bob.insert(1 + i, c);
//! }
//!
//! alice.merge(&bob);
//! bob.merge(&alice);
//!
//! let merged: String = alice.iter().collect();
//! // Either "aHelloWorldb" or "aWorldHellob" — never interleaved.
//! assert!(merged == "aHelloWorldb" || merged == "aWorldHellob");
//! assert_eq!(merged, bob.iter().collect::<String>());
//! ```
pub use ;
pub use ;
pub use Error;
pub use ;
pub use ;
pub use ;
pub use ;
pub use ;
pub use VersionVector;