umsh_text/engine/
repair.rs1use umsh_core::PublicKey;
5
6use crate::model::{ConversationKey, MessageSequence};
7
8#[derive(Clone, Copy, Debug)]
10pub struct PendingLookup {
11 pub request_id: u32,
12 pub conversation: ConversationKey,
14 pub requester: PublicKey,
17 pub sequence: MessageSequence,
18}
19
20#[derive(Clone, Debug, Default)]
25pub struct CoalesceRing {
26 entries: heapless::Vec<(ConversationKey, u8, Option<u8>, u64), 16>,
27}
28
29impl CoalesceRing {
30 pub fn recently_answered(
32 &self,
33 conversation: &ConversationKey,
34 sequence: &MessageSequence,
35 now_ms: u64,
36 window_ms: u64,
37 ) -> bool {
38 let fragment = sequence.fragment.map(|fragment| fragment.index);
39 self.entries.iter().any(|(conv, id, frag, at)| {
40 conv == conversation
41 && *id == sequence.message_id
42 && *frag == fragment
43 && now_ms.saturating_sub(*at) < window_ms
44 })
45 }
46
47 pub fn record(
48 &mut self,
49 conversation: ConversationKey,
50 sequence: &MessageSequence,
51 now_ms: u64,
52 ) {
53 let fragment = sequence.fragment.map(|fragment| fragment.index);
54 self.record_frame(conversation, sequence.message_id, fragment, now_ms);
55 }
56
57 pub fn record_frame(
60 &mut self,
61 conversation: ConversationKey,
62 message_id: u8,
63 fragment: Option<u8>,
64 now_ms: u64,
65 ) {
66 self.entries.retain(|(conv, id, frag, _)| {
67 !(*conv == conversation && *id == message_id && *frag == fragment)
68 });
69 if self.entries.is_full() {
70 self.entries.remove(0);
71 }
72 let _ = self
73 .entries
74 .push((conversation, message_id, fragment, now_ms));
75 }
76}
77
78#[derive(Clone, Debug)]
84pub struct JitterSource {
85 state: u64,
86}
87
88impl JitterSource {
89 pub fn new(seed: u64) -> Self {
90 Self { state: seed }
91 }
92
93 pub fn next_u64(&mut self) -> u64 {
94 self.state = self.state.wrapping_add(0x9E37_79B9_7F4A_7C15);
95 let mut value = self.state;
96 value = (value ^ (value >> 30)).wrapping_mul(0xBF58_476D_1CE4_E5B9);
97 value = (value ^ (value >> 27)).wrapping_mul(0x94D0_49BB_1331_11EB);
98 value ^ (value >> 31)
99 }
100
101 pub fn jitter_ms(&mut self, bound_ms: u64) -> u64 {
103 if bound_ms == 0 {
104 0
105 } else {
106 self.next_u64() % bound_ms
107 }
108 }
109}