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
// (c) Copyright 2025 Helsing GmbH. All rights reserved.
//! The example simulates a scenario where two replicas modify the same data and
//! then synchronize their states, arriving at a consistent final result.
use dson::{CausalDotStore, Identifier, OrMap, crdts::NoExtensionTypes};
use std::error::Error;
fn main() -> Result<(), Box<dyn Error>> {
// Create a unique identifier for replica A.
let replica_a_id = Identifier::new(0, 0);
// Initialize the state for replica A. The `CausalDotStore` holds the CRDT data
// and its associated causal context. We use an `OrMap` (Observed-Remove Map)
// with String values as our top-level CRDT.
let mut replica_a_state = CausalDotStore::<OrMap<String>>::default();
// --- Replica A: Set email for "alice" ---
// The following operation creates a delta that represents the change of setting
// the email for the key "alice". This delta only contains the change set, not
// the full state.
let delta_from_a = dson::api::map::apply_to_map::<_, NoExtensionTypes, _>(
|inner_map, ctx, id| {
// Within the "alice" map, we apply a change to the "email" register.
dson::api::map::apply_to_register(
// The new value for the register.
|reg, ctx, id| reg.write("alice@example.com".to_string().into(), ctx, id),
"email".to_string(),
)(inner_map, ctx, id)
},
"alice".to_string(),
)(
// The operation is based on the current state of replica A.
&replica_a_state.store,
&replica_a_state.context,
replica_a_id,
);
// Apply the generated delta to replica A's own state.
replica_a_state.join_or_replace_with(delta_from_a.store.clone(), &delta_from_a.context);
// --- Synchronization: A -> B ---
// In a real-world scenario, the `delta_from_a` would be sent over a network
// to other replicas. Here, we simulate this by creating a second replica and
// applying the delta to it.
// Create a unique identifier for replica B.
let replica_b_id = Identifier::new(1, 0);
// Initialize the state for replica B.
let mut replica_b_state = CausalDotStore::<OrMap<String>>::default();
// Apply the delta from replica A to replica B's state.
replica_b_state.join_or_replace_with(delta_from_a.store.clone(), &delta_from_a.context);
// After synchronization, the states of both replicas should be identical.
assert_eq!(replica_a_state, replica_b_state);
// --- Replica B: Update email for "alice" ---
// Now, replica B makes a change to the same data. This will create a new
// delta based on replica B's current state.
let delta_from_b = dson::api::map::apply_to_map::<_, NoExtensionTypes, _>(
|inner_map, ctx, id| {
dson::api::map::apply_to_register(
|reg, ctx, id| reg.write("bob@example.com".to_string().into(), ctx, id),
"email".to_string(),
)(inner_map, ctx, id)
},
"alice".to_string(),
)(
&replica_b_state.store,
&replica_b_state.context,
replica_b_id,
);
// Apply the new delta to replica B's own state.
replica_b_state.join_or_replace_with(delta_from_b.store.clone(), &delta_from_b.context);
// --- Synchronization: B -> A ---
// Propagate the delta from replica B back to replica A.
replica_a_state.join_or_replace_with(delta_from_b.store.clone(), &delta_from_b.context);
// After this final synchronization, both replicas should once again have
// identical states, reflecting the latest change made by replica B.
assert_eq!(replica_a_state, replica_b_state);
Ok(())
}