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
//! Core traits for NOMAD protocol.
//!
//! These traits define the interface for state synchronization.
use ;
/// Core trait for any state that can be synchronized.
///
/// Implements the state type interface from 3-SYNC.md.
///
/// # Requirements
///
/// - `diff_from` MUST produce idempotent diffs
/// - `apply_diff` MUST handle repeated application
/// - `encode_diff`/`decode_diff` MUST roundtrip correctly
///
/// # Example
///
/// ```ignore
/// #[derive(Clone)]
/// struct Counter { value: u64 }
///
/// #[derive(Clone)]
/// struct CounterDiff { delta: i64 }
///
/// impl SyncState for Counter {
/// type Diff = CounterDiff;
/// const STATE_TYPE_ID: &'static str = "example.counter.v1";
///
/// fn diff_from(&self, old: &Self) -> Self::Diff {
/// CounterDiff { delta: self.value as i64 - old.value as i64 }
/// }
///
/// fn apply_diff(&mut self, diff: &Self::Diff) -> Result<(), ApplyError> {
/// self.value = (self.value as i64 + diff.delta) as u64;
/// Ok(())
/// }
///
/// fn encode_diff(diff: &Self::Diff) -> Vec<u8> {
/// diff.delta.to_le_bytes().to_vec()
/// }
///
/// fn decode_diff(data: &[u8]) -> Result<Self::Diff, DecodeError> {
/// if data.len() < 8 {
/// return Err(DecodeError::UnexpectedEof);
/// }
/// let delta = i64::from_le_bytes(data[..8].try_into().unwrap());
/// Ok(CounterDiff { delta })
/// }
/// }
/// ```
/// Optional trait for states that support client-side prediction.
///
/// See 4-EXTENSIONS.md for prediction specification.