Expand description
§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 for design
background and the crate-level plan
for the roadmap.
§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>());Modules§
- storage
- Storage abstraction for persisting CRDT state across process restarts.
- yjs_
compat - Wire-format compatibility with Yjs — primitives, state-vector exchange, and a minimal Y.Update v1 snapshot encoder.
Structs§
- Counter
- PN-Counter CRDT (signed). See the module docs for semantics.
- Counter
Op - A single
CounterCRDT operation. - DeltaOp
- One run in a Quill/Yjs Delta — a chunk of text with optional attributes.
- List
- List CRDT with Fugue-Maximal positioning over an Eg-walker event log.
- Map
- LWW-Map CRDT. See the module docs for semantics.
- MarkSet
- Set of marks active at a single character position.
- OpId
- Globally unique identifier for a single CRDT operation.
- Selection
- A range selection — two cursors marking the endpoints of a contiguous span.
- Set
- OR-Set CRDT. See the module docs for semantics.
- Span
- A format-mark span: applies a named annotation between two anchors.
- Text
- Rich-text CRDT — a
List<char>augmented with Peritext-style format spans. - Version
Vector - Summary of “what ops a replica has seen”, indexed by replica.
Enums§
- Anchor
- A position in the text, expressed relative to a specific character or the document boundaries.
- Anchor
Side - Which side of an anchored character the anchor sits on.
- Attr
Value - Value of a single attribute in a Quill/Yjs
Deltaoperation. - Cursor
- A position in a
Listthat follows concurrent edits. - Cursor
Side - Which side of the anchored character the cursor sits on.
- Error
- Errors that can occur in
abyo-crdt. - Expand
Rule - Stickiness rule for mark anchors.
- ListOp
- A single
ListCRDT operation. Wire-format and event-log entry. - MapOp
- A single
MapCRDT operation. - Mark
Value - What a mark currently “is” at a character position.
- SetOp
- A single
SetCRDT operation. - Side
- Side of a parent that an item is anchored to in the Fugue tree.
- Span
Value - The “value” carried by a format span — boolean on/off for marks like
bold/italic, or a string value for marks likehref/color. - TextOp
- A single text-CRDT operation.
Functions§
- new_
replica_ id - Generate a random
ReplicaIdfrom OS entropy.
Type Aliases§
- Replica
Id - Identifier for a replica (collaborator).