1use crate::{EventId, NodeId, StateId, StateTime, TimeIntent, VersionVector};
8
9#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
11#[repr(u8)]
12pub enum EventType {
13 StateCreate = 0x01,
15 StateUpdate = 0x02,
16 StateDelete = 0x03,
17
18 AuthorityGrant = 0x10,
20 AuthorityRevoke = 0x11,
21
22 SessionJoin = 0x20,
24 SessionLeave = 0x21,
25 SessionSync = 0x22,
26
27 TimeSync = 0x30,
29 TimeCorrection = 0x31,
30
31 StateRequest = 0x40,
33 StateResponse = 0x41,
34 GapFill = 0x42,
35
36 TextAppend = 0x80,
38 TextEdit = 0x81,
39 TextDelete = 0x82,
40 TextReact = 0x83,
41
42 VoiceFrame = 0x90,
43 VoiceMute = 0x91,
44
45 PresenceUpdate = 0xA0,
46 TypingStart = 0xA1,
47 TypingStop = 0xA2,
48
49 VisualKeyframe = 0xB0,
50 VisualDelta = 0xB1,
51
52 StreamStart = 0xC0,
53 StreamEnd = 0xC1,
54
55 FeedAppend = 0xD0,
56 FeedDelete = 0xD1,
57}
58
59impl EventType {
60 pub fn from_byte(b: u8) -> Option<Self> {
61 match b {
62 0x01 => Some(EventType::StateCreate),
63 0x02 => Some(EventType::StateUpdate),
64 0x03 => Some(EventType::StateDelete),
65 0x10 => Some(EventType::AuthorityGrant),
66 0x11 => Some(EventType::AuthorityRevoke),
67 0x20 => Some(EventType::SessionJoin),
68 0x21 => Some(EventType::SessionLeave),
69 0x22 => Some(EventType::SessionSync),
70 0x30 => Some(EventType::TimeSync),
71 0x31 => Some(EventType::TimeCorrection),
72 0x40 => Some(EventType::StateRequest),
73 0x41 => Some(EventType::StateResponse),
74 0x42 => Some(EventType::GapFill),
75 0x80 => Some(EventType::TextAppend),
76 0x81 => Some(EventType::TextEdit),
77 0x82 => Some(EventType::TextDelete),
78 0x83 => Some(EventType::TextReact),
79 0x90 => Some(EventType::VoiceFrame),
80 0x91 => Some(EventType::VoiceMute),
81 0xA0 => Some(EventType::PresenceUpdate),
82 0xA1 => Some(EventType::TypingStart),
83 0xA2 => Some(EventType::TypingStop),
84 0xB0 => Some(EventType::VisualKeyframe),
85 0xB1 => Some(EventType::VisualDelta),
86 0xC0 => Some(EventType::StreamStart),
87 0xC1 => Some(EventType::StreamEnd),
88 0xD0 => Some(EventType::FeedAppend),
89 0xD1 => Some(EventType::FeedDelete),
90 _ => None,
91 }
92 }
93
94 #[inline]
95 pub fn to_byte(self) -> u8 {
96 self as u8
97 }
98
99 pub fn is_core_protocol(self) -> bool {
101 (self as u8) < 0x80
102 }
103}
104
105#[derive(Clone, Debug)]
107pub enum MutationOp {
108 Set(Vec<u8>),
110 Increment(i64),
112 Append(Vec<u8>),
114 Merge(Vec<u8>),
116 Delete,
118 Blend { value: Vec<u8>, weight: f32 },
120}
121
122impl MutationOp {
123 pub fn encode(&self) -> Vec<u8> {
125 let mut buf = Vec::new();
126 match self {
127 MutationOp::Set(data) => {
128 buf.push(0x01);
129 buf.extend_from_slice(&(data.len() as u16).to_le_bytes());
130 buf.extend_from_slice(data);
131 }
132 MutationOp::Increment(delta) => {
133 buf.push(0x02);
134 buf.extend_from_slice(&delta.to_le_bytes());
135 }
136 MutationOp::Append(data) => {
137 buf.push(0x03);
138 buf.extend_from_slice(&(data.len() as u16).to_le_bytes());
139 buf.extend_from_slice(data);
140 }
141 MutationOp::Merge(data) => {
142 buf.push(0x04);
143 buf.extend_from_slice(&(data.len() as u16).to_le_bytes());
144 buf.extend_from_slice(data);
145 }
146 MutationOp::Delete => {
147 buf.push(0x05);
148 }
149 MutationOp::Blend { value, weight } => {
150 buf.push(0x06);
151 buf.extend_from_slice(&weight.to_le_bytes());
152 buf.extend_from_slice(&(value.len() as u16).to_le_bytes());
153 buf.extend_from_slice(value);
154 }
155 }
156 buf
157 }
158
159 pub fn decode(buf: &[u8]) -> Option<(Self, usize)> {
161 if buf.is_empty() {
162 return None;
163 }
164
165 match buf[0] {
166 0x01 => {
167 if buf.len() < 3 {
169 return None;
170 }
171 let len = u16::from_le_bytes([buf[1], buf[2]]) as usize;
172 if buf.len() < 3 + len {
173 return None;
174 }
175 Some((MutationOp::Set(buf[3..3 + len].to_vec()), 3 + len))
176 }
177 0x02 => {
178 if buf.len() < 9 {
180 return None;
181 }
182 let delta = i64::from_le_bytes(buf[1..9].try_into().ok()?);
183 Some((MutationOp::Increment(delta), 9))
184 }
185 0x03 => {
186 if buf.len() < 3 {
188 return None;
189 }
190 let len = u16::from_le_bytes([buf[1], buf[2]]) as usize;
191 if buf.len() < 3 + len {
192 return None;
193 }
194 Some((MutationOp::Append(buf[3..3 + len].to_vec()), 3 + len))
195 }
196 0x04 => {
197 if buf.len() < 3 {
199 return None;
200 }
201 let len = u16::from_le_bytes([buf[1], buf[2]]) as usize;
202 if buf.len() < 3 + len {
203 return None;
204 }
205 Some((MutationOp::Merge(buf[3..3 + len].to_vec()), 3 + len))
206 }
207 0x05 => {
208 Some((MutationOp::Delete, 1))
210 }
211 0x06 => {
212 if buf.len() < 7 {
214 return None;
215 }
216 let weight = f32::from_le_bytes(buf[1..5].try_into().ok()?);
217 let len = u16::from_le_bytes([buf[5], buf[6]]) as usize;
218 if buf.len() < 7 + len {
219 return None;
220 }
221 Some((
222 MutationOp::Blend {
223 value: buf[7..7 + len].to_vec(),
224 weight,
225 },
226 7 + len,
227 ))
228 }
229 _ => None,
230 }
231 }
232}
233
234#[derive(Clone, Debug)]
236pub struct AuthorityProof {
237 pub signature: [u8; 64],
239 pub delegation_chain: Option<Vec<DelegationLink>>,
241}
242
243impl AuthorityProof {
244 pub fn new(signature: [u8; 64]) -> Self {
245 AuthorityProof {
246 signature,
247 delegation_chain: None,
248 }
249 }
250
251 pub fn with_delegation(mut self, chain: Vec<DelegationLink>) -> Self {
252 self.delegation_chain = Some(chain);
253 self
254 }
255}
256
257#[derive(Clone, Debug)]
259pub struct DelegationLink {
260 pub delegator: NodeId,
261 pub delegate: NodeId,
262 pub scope: Vec<u8>, pub signature: [u8; 64],
264}
265
266#[derive(Clone, Copy, Debug, Default)]
268pub struct EntropyHint {
269 pub entropy: f32,
271 pub confidence: f32,
273}
274
275impl EntropyHint {
276 pub fn new(entropy: f32, confidence: f32) -> Self {
277 EntropyHint {
278 entropy,
279 confidence,
280 }
281 }
282
283 pub fn certain() -> Self {
284 EntropyHint {
285 entropy: 0.0,
286 confidence: 1.0,
287 }
288 }
289
290 pub fn predicted(entropy: f32) -> Self {
291 EntropyHint {
292 entropy,
293 confidence: 0.5,
294 }
295 }
296}
297
298#[derive(Clone, Debug)]
300pub struct Event {
301 pub id: EventId,
303 pub event_type: EventType,
305 pub source: NodeId,
307 pub target_state: StateId,
309 pub version_ref: VersionVector,
311 pub mutation: MutationOp,
313 pub time_intent: TimeIntent,
315 pub authority_proof: AuthorityProof,
317 pub entropy_hint: EntropyHint,
319}
320
321impl Event {
322 pub fn new(
324 source: NodeId,
325 seq: u64,
326 event_type: EventType,
327 target_state: StateId,
328 mutation: MutationOp,
329 ) -> Self {
330 Event {
331 id: EventId::new(source, seq),
332 event_type,
333 source,
334 target_state,
335 version_ref: VersionVector::new(),
336 mutation,
337 time_intent: TimeIntent::default(),
338 authority_proof: AuthorityProof::new([0u8; 64]),
339 entropy_hint: EntropyHint::certain(),
340 }
341 }
342
343 pub fn with_version(mut self, version: VersionVector) -> Self {
345 self.version_ref = version;
346 self
347 }
348
349 pub fn with_time_intent(mut self, intent: TimeIntent) -> Self {
351 self.time_intent = intent;
352 self
353 }
354
355 pub fn with_authority_proof(mut self, proof: AuthorityProof) -> Self {
357 self.authority_proof = proof;
358 self
359 }
360
361 pub fn with_entropy_hint(mut self, hint: EntropyHint) -> Self {
363 self.entropy_hint = hint;
364 self
365 }
366
367 pub fn absolute_time(&self, reference: StateTime) -> StateTime {
369 self.time_intent.to_absolute(reference)
370 }
371}
372
373#[derive(Clone, Debug)]
375pub struct ValidatedEvent {
376 pub event: Event,
377 pub validated_at: StateTime,
378}
379
380impl ValidatedEvent {
381 pub fn new(event: Event, validated_at: StateTime) -> Self {
382 ValidatedEvent {
383 event,
384 validated_at,
385 }
386 }
387}
388
389#[derive(Clone, Debug)]
391pub enum EventResult {
392 Applied,
394 Merged,
396 LateCorrected,
398 Buffered,
400 Duplicate,
402 Rejected(RejectReason),
404}
405
406#[derive(Clone, Debug)]
408pub enum RejectReason {
409 Unauthorized,
411 InvalidSignature,
413 AuthorityRevoked,
415 CausalityViolation,
417 MissingDependency(EventId),
419 OutOfBounds,
421 RateLimitExceeded,
423 EntropyExceeded,
425 TooLate,
427 ReplayDetected,
429}
430
431#[cfg(test)]
432mod tests {
433 use super::*;
434
435 #[test]
436 fn test_event_type_roundtrip() {
437 for event_type in [
438 EventType::StateCreate,
439 EventType::StateUpdate,
440 EventType::TextAppend,
441 EventType::VoiceFrame,
442 EventType::VisualKeyframe,
443 EventType::StreamStart,
444 EventType::FeedAppend,
445 ] {
446 let byte = event_type.to_byte();
447 let recovered = EventType::from_byte(byte).unwrap();
448 assert_eq!(event_type, recovered);
449 }
450 }
451
452 #[test]
453 fn test_mutation_op_encode_decode() {
454 let ops = vec![
455 MutationOp::Set(vec![1, 2, 3, 4]),
456 MutationOp::Increment(42),
457 MutationOp::Append(vec![5, 6, 7]),
458 MutationOp::Delete,
459 MutationOp::Blend {
460 value: vec![8, 9],
461 weight: 0.5,
462 },
463 ];
464
465 for op in ops {
466 let encoded = op.encode();
467 let (decoded, len) = MutationOp::decode(&encoded).unwrap();
468 assert_eq!(len, encoded.len());
469
470 assert_eq!(op.encode(), decoded.encode());
472 }
473 }
474
475 #[test]
476 fn test_event_creation() {
477 let source = NodeId::new(1);
478 let target = StateId::new(100);
479 let event = Event::new(
480 source,
481 1,
482 EventType::TextAppend,
483 target,
484 MutationOp::Append(b"Hello".to_vec()),
485 );
486
487 assert_eq!(event.source, source);
488 assert_eq!(event.target_state, target);
489 assert_eq!(event.id.seq, 1);
490 }
491}