rns_embedded_core/
packet.rs1use crate::{EmbeddedError, EmbeddedResult};
2use alloc::vec::Vec;
3
4const MAGIC: &[u8; 4] = b"RNE1";
5const VERSION: u8 = 0x01;
6const HEADER_LEN: usize = 14;
7pub const MAX_PAYLOAD_BYTES: usize = 1024 * 1024;
8
9#[derive(Debug, Clone, Eq, PartialEq)]
10pub struct PacketFrame {
11 pub kind: u8,
12 pub sequence: u32,
13 pub payload: Vec<u8>,
14}
15
16impl PacketFrame {
17 pub fn new(kind: u8, sequence: u32, payload: Vec<u8>) -> EmbeddedResult<Self> {
18 if payload.is_empty() || payload.len() > MAX_PAYLOAD_BYTES {
19 return Err(EmbeddedError::InvalidInput);
20 }
21 Ok(Self { kind, sequence, payload })
22 }
23}
24
25pub fn encode_frame(frame: &PacketFrame) -> EmbeddedResult<Vec<u8>> {
26 if frame.payload.is_empty() || frame.payload.len() > MAX_PAYLOAD_BYTES {
27 return Err(EmbeddedError::InvalidInput);
28 }
29 let payload_len_u32 =
30 u32::try_from(frame.payload.len()).map_err(|_| EmbeddedError::InvalidInput)?;
31
32 let mut out = Vec::with_capacity(HEADER_LEN + frame.payload.len());
33 out.extend_from_slice(MAGIC);
34 out.push(VERSION);
35 out.push(frame.kind);
36 out.extend_from_slice(&frame.sequence.to_le_bytes());
37 out.extend_from_slice(&payload_len_u32.to_le_bytes());
38 out.extend_from_slice(&frame.payload);
39 Ok(out)
40}
41
42pub fn decode_frame(bytes: &[u8]) -> EmbeddedResult<PacketFrame> {
43 if bytes.len() < HEADER_LEN {
44 return Err(EmbeddedError::InvalidInput);
45 }
46 if &bytes[0..4] != MAGIC {
47 return Err(EmbeddedError::IntegrityFailure);
48 }
49 if bytes[4] != VERSION {
50 return Err(EmbeddedError::Unsupported);
51 }
52 let kind = bytes[5];
53 let sequence = u32::from_le_bytes([bytes[6], bytes[7], bytes[8], bytes[9]]);
54 let payload_len = u32::from_le_bytes([bytes[10], bytes[11], bytes[12], bytes[13]]);
55 let payload_len = usize::try_from(payload_len).map_err(|_| EmbeddedError::InvalidInput)?;
56 if payload_len == 0 || payload_len > MAX_PAYLOAD_BYTES {
57 return Err(EmbeddedError::InvalidInput);
58 }
59 if bytes.len() != HEADER_LEN + payload_len {
60 return Err(EmbeddedError::InvalidInput);
61 }
62 let payload = bytes[HEADER_LEN..].to_vec();
63 PacketFrame::new(kind, sequence, payload)
64}
65
66#[cfg(test)]
67mod tests {
68 use super::{decode_frame, encode_frame, PacketFrame};
69 use serde::Deserialize;
70
71 #[derive(Debug, Deserialize)]
72 struct PacketFixture {
73 id: String,
74 kind: u8,
75 sequence: u32,
76 payload_hex: String,
77 encoded_hex: String,
78 }
79
80 #[test]
81 fn fixture_vectors_roundtrip() {
82 let fixtures: Vec<PacketFixture> = serde_json::from_str(include_str!(
83 "../../../../docs/fixtures/embedded/native_packet_vectors.json"
84 ))
85 .expect("fixture json parse");
86 for fixture in fixtures {
87 let payload = hex::decode(&fixture.payload_hex).expect("payload hex");
88 let expected = hex::decode(&fixture.encoded_hex).expect("encoded hex");
89
90 let frame = PacketFrame::new(fixture.kind, fixture.sequence, payload.clone())
91 .expect("frame init");
92 let encoded = encode_frame(&frame).expect("encode");
93 assert_eq!(encoded, expected, "fixture {} encode mismatch", fixture.id);
94
95 let decoded = decode_frame(&expected).expect("decode");
96 assert_eq!(decoded.kind, fixture.kind, "fixture {} kind mismatch", fixture.id);
97 assert_eq!(
98 decoded.sequence, fixture.sequence,
99 "fixture {} sequence mismatch",
100 fixture.id
101 );
102 assert_eq!(decoded.payload, payload, "fixture {} payload mismatch", fixture.id);
103 }
104 }
105
106 #[test]
107 fn rejects_truncated_frame() {
108 let bytes = vec![0_u8; 8];
109 assert!(decode_frame(&bytes).is_err());
110 }
111}