1use serde::{Deserialize, Serialize};
2
3use crate::Frame;
4
5#[derive(Copy, Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
12pub struct ConnectionStatus {
13 pub disconnected: bool,
15 pub last_frame: Frame,
17}
18
19impl Default for ConnectionStatus {
20 fn default() -> Self {
21 Self {
22 disconnected: false,
23 last_frame: Frame::NULL,
24 }
25 }
26}
27
28impl std::fmt::Display for ConnectionStatus {
29 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
30 let Self {
32 disconnected,
33 last_frame,
34 } = self;
35
36 if *disconnected {
37 write!(f, "Disconnected(last_frame={})", last_frame.as_i32())
38 } else {
39 write!(f, "Connected(last_frame={})", last_frame.as_i32())
40 }
41 }
42}
43
44#[derive(Copy, Clone, Debug, PartialEq, Eq, Serialize, Deserialize, Default)]
45pub(crate) struct SyncRequest {
46 pub random_request: u32, }
48
49#[derive(Copy, Clone, Debug, PartialEq, Eq, Serialize, Deserialize, Default)]
50pub(crate) struct SyncReply {
51 pub random_reply: u32, }
53
54#[derive(Clone, PartialEq, Eq, Serialize, Deserialize)]
55pub(crate) struct Input {
56 pub peer_connect_status: Vec<ConnectionStatus>,
57 pub disconnect_requested: bool,
58 pub start_frame: Frame,
59 pub ack_frame: Frame,
60 pub bytes: Vec<u8>,
61}
62
63impl Default for Input {
64 fn default() -> Self {
65 Self {
66 peer_connect_status: Vec::new(),
67 disconnect_requested: false,
68 start_frame: Frame::NULL,
69 ack_frame: Frame::NULL,
70 bytes: Vec::new(),
71 }
72 }
73}
74
75impl std::fmt::Debug for Input {
76 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
77 let Self {
79 peer_connect_status,
80 disconnect_requested,
81 start_frame,
82 ack_frame,
83 bytes,
84 } = self;
85
86 f.debug_struct("Input")
87 .field("peer_connect_status", peer_connect_status)
88 .field("disconnect_requested", disconnect_requested)
89 .field("start_frame", start_frame)
90 .field("ack_frame", ack_frame)
91 .field("bytes", &BytesDebug(bytes))
92 .finish()
93 }
94}
95struct BytesDebug<'a>(&'a [u8]);
96
97impl std::fmt::Debug for BytesDebug<'_> {
98 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
99 f.write_str("0x")?;
100 for byte in self.0 {
101 write!(f, "{:02x}", byte)?;
102 }
103 Ok(())
104 }
105}
106
107#[derive(Copy, Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
108pub(crate) struct InputAck {
109 pub ack_frame: Frame,
110}
111
112impl Default for InputAck {
113 fn default() -> Self {
114 Self {
115 ack_frame: Frame::NULL,
116 }
117 }
118}
119
120#[derive(Copy, Clone, Debug, PartialEq, Eq, Serialize, Deserialize, Default)]
121pub(crate) struct QualityReport {
122 pub frame_advantage: i16,
135 pub ping: u128,
136}
137
138#[derive(Copy, Clone, Debug, PartialEq, Eq, Serialize, Deserialize, Default)]
139pub(crate) struct QualityReply {
140 pub pong: u128,
141}
142
143#[derive(Copy, Clone, Debug, PartialEq, Eq, Serialize, Deserialize, Default)]
144pub(crate) struct ChecksumReport {
145 pub checksum: u128,
146 pub frame: Frame,
147}
148
149#[derive(Copy, Clone, Debug, PartialEq, Eq, Serialize, Deserialize, Default)]
150pub(crate) struct MessageHeader {
151 pub magic: u16,
152}
153
154#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
155pub(crate) enum MessageBody {
156 SyncRequest(SyncRequest),
157 SyncReply(SyncReply),
158 Input(Input),
159 InputAck(InputAck),
160 QualityReport(QualityReport),
161 QualityReply(QualityReply),
162 ChecksumReport(ChecksumReport),
163 KeepAlive,
164}
165
166#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
171pub struct Message {
172 pub(crate) header: MessageHeader,
173 pub(crate) body: MessageBody,
174}
175
176#[cfg(test)]
177#[allow(
178 clippy::panic,
179 clippy::unwrap_used,
180 clippy::expect_used,
181 clippy::indexing_slicing
182)]
183mod tests {
184 use super::*;
185
186 #[test]
187 fn test_connection_status_default() {
188 let status = ConnectionStatus::default();
189 assert!(!status.disconnected);
190 assert_eq!(status.last_frame, Frame::NULL);
191 }
192
193 #[test]
194 fn test_connection_status_debug_clone() {
195 let status = ConnectionStatus {
196 disconnected: true,
197 last_frame: Frame::new(100),
198 };
199 let cloned = status;
200 assert!(cloned.disconnected);
201 assert_eq!(cloned.last_frame, Frame::new(100));
202 let debug = format!("{:?}", status);
203 assert!(debug.contains("ConnectionStatus"));
204 }
205
206 #[test]
207 fn test_connection_status_display_connected() {
208 let status = ConnectionStatus {
209 disconnected: false,
210 last_frame: Frame::new(42),
211 };
212 let display = format!("{}", status);
213 assert_eq!(display, "Connected(last_frame=42)");
214 }
215
216 #[test]
217 fn test_connection_status_display_disconnected() {
218 let status = ConnectionStatus {
219 disconnected: true,
220 last_frame: Frame::new(100),
221 };
222 let display = format!("{}", status);
223 assert_eq!(display, "Disconnected(last_frame=100)");
224 }
225
226 #[test]
227 fn test_connection_status_display_null_frame() {
228 let status = ConnectionStatus::default();
229 let display = format!("{}", status);
230 assert_eq!(display, "Connected(last_frame=-1)");
231 }
232
233 #[test]
234 fn test_sync_request_default() {
235 let req = SyncRequest::default();
236 assert_eq!(req.random_request, 0);
237 }
238
239 #[test]
240 fn test_sync_reply_default() {
241 let reply = SyncReply::default();
242 assert_eq!(reply.random_reply, 0);
243 }
244
245 #[test]
246 fn test_input_default() {
247 let input = Input::default();
248 assert!(input.peer_connect_status.is_empty());
249 assert!(!input.disconnect_requested);
250 assert_eq!(input.start_frame, Frame::NULL);
251 assert_eq!(input.ack_frame, Frame::NULL);
252 assert!(input.bytes.is_empty());
253 }
254
255 #[test]
256 fn test_input_debug() {
257 let input = Input {
258 peer_connect_status: vec![ConnectionStatus::default()],
259 disconnect_requested: true,
260 start_frame: Frame::new(10),
261 ack_frame: Frame::new(5),
262 bytes: vec![0xDE, 0xAD, 0xBE, 0xEF],
263 };
264 let debug = format!("{:?}", input);
265 assert!(debug.contains("Input"));
266 assert!(debug.contains("disconnect_requested"));
267 assert!(debug.contains("0xdeadbeef"));
268 }
269
270 #[test]
271 fn test_input_ack_default() {
272 let ack = InputAck::default();
273 assert_eq!(ack.ack_frame, Frame::NULL);
274 }
275
276 #[test]
277 fn test_quality_report_default() {
278 let report = QualityReport::default();
279 assert_eq!(report.frame_advantage, 0);
280 assert_eq!(report.ping, 0);
281 }
282
283 #[test]
284 fn test_quality_reply_default() {
285 let reply = QualityReply::default();
286 assert_eq!(reply.pong, 0);
287 }
288
289 #[test]
290 fn test_checksum_report_default() {
291 let report = ChecksumReport::default();
292 assert_eq!(report.checksum, 0);
293 assert_eq!(report.frame, Frame::default());
294 }
295
296 #[test]
297 fn test_message_header_default() {
298 let header = MessageHeader::default();
299 assert_eq!(header.magic, 0);
300 }
301
302 #[test]
303 fn test_message_body_variants() {
304 let sync_req = MessageBody::SyncRequest(SyncRequest { random_request: 42 });
306 let sync_req2 = MessageBody::SyncRequest(SyncRequest { random_request: 42 });
307 assert_eq!(sync_req, sync_req2);
308
309 let sync_reply = MessageBody::SyncReply(SyncReply { random_reply: 123 });
310 let debug = format!("{:?}", sync_reply);
311 assert!(debug.contains("SyncReply"));
312
313 let input = MessageBody::Input(Input::default());
314 assert!(matches!(input, MessageBody::Input(_)));
315
316 let input_ack = MessageBody::InputAck(InputAck::default());
317 assert!(matches!(input_ack, MessageBody::InputAck(_)));
318
319 let quality_report = MessageBody::QualityReport(QualityReport::default());
320 assert!(matches!(quality_report, MessageBody::QualityReport(_)));
321
322 let quality_reply = MessageBody::QualityReply(QualityReply::default());
323 assert!(matches!(quality_reply, MessageBody::QualityReply(_)));
324
325 let checksum_report = MessageBody::ChecksumReport(ChecksumReport::default());
326 assert!(matches!(checksum_report, MessageBody::ChecksumReport(_)));
327
328 let keep_alive = MessageBody::KeepAlive;
329 assert!(matches!(keep_alive, MessageBody::KeepAlive));
330 }
331
332 #[test]
333 #[allow(clippy::redundant_clone)] fn test_message_clone_eq() {
335 let msg = Message {
336 header: MessageHeader { magic: 0x1234 },
337 body: MessageBody::KeepAlive,
338 };
339 let cloned = msg.clone();
340 assert_eq!(msg, cloned);
341 }
342
343 #[test]
344 fn test_message_serialization() {
345 use crate::network::codec;
346
347 let msg = Message {
348 header: MessageHeader { magic: 0xABCD },
349 body: MessageBody::SyncRequest(SyncRequest {
350 random_request: 999,
351 }),
352 };
353
354 let serialized = codec::encode(&msg).expect("serialization should succeed");
356 let (deserialized, _): (Message, _) =
357 codec::decode(&serialized).expect("deserialization should succeed");
358 assert_eq!(msg, deserialized);
359 }
360
361 #[test]
362 fn test_input_serialization() {
363 use crate::network::codec;
364
365 let input = Input {
366 peer_connect_status: vec![
367 ConnectionStatus {
368 disconnected: false,
369 last_frame: Frame::new(10),
370 },
371 ConnectionStatus {
372 disconnected: true,
373 last_frame: Frame::new(20),
374 },
375 ],
376 disconnect_requested: false,
377 start_frame: Frame::new(100),
378 ack_frame: Frame::new(50),
379 bytes: vec![1, 2, 3, 4, 5],
380 };
381
382 let serialized = codec::encode(&input).expect("serialization should succeed");
383 let (deserialized, _): (Input, _) =
384 codec::decode(&serialized).expect("deserialization should succeed");
385 assert_eq!(input, deserialized);
386 }
387
388 #[test]
389 fn test_bytes_debug_empty() {
390 let input = Input {
391 peer_connect_status: vec![],
392 disconnect_requested: false,
393 start_frame: Frame::NULL,
394 ack_frame: Frame::NULL,
395 bytes: vec![],
396 };
397 let debug = format!("{:?}", input);
398 assert!(debug.contains("0x")); }
400}