1use heapless::Vec;
2
3use crate::{MiniError, MiniResult};
4
5pub const HASH_LENGTH: usize = 16;
6pub const SIGNATURE_LENGTH: usize = 64;
7pub const WIRE_HEADER_LENGTH: usize = HASH_LENGTH + HASH_LENGTH + SIGNATURE_LENGTH;
8
9const MSGPACK_ARRAY_4: u8 = 0x94;
10const MSGPACK_ARRAY_5: u8 = 0x95;
11const MSGPACK_NIL: u8 = 0xc0;
12const MSGPACK_F64: u8 = 0xcb;
13const MSGPACK_BIN8: u8 = 0xc4;
14const MSGPACK_BIN16: u8 = 0xc5;
15const MSGPACK_BIN32: u8 = 0xc6;
16const MSGPACK_STR8: u8 = 0xd9;
17const MSGPACK_STR16: u8 = 0xda;
18const MSGPACK_STR32: u8 = 0xdb;
19
20#[derive(Debug, Clone, Eq, PartialEq)]
21pub struct MiniMessage<const TITLE: usize, const CONTENT: usize> {
22 pub destination: [u8; HASH_LENGTH],
23 pub source: [u8; HASH_LENGTH],
24 pub signature: [u8; SIGNATURE_LENGTH],
25 pub timestamp: u64,
26 pub title: Vec<u8, TITLE>,
27 pub content: Vec<u8, CONTENT>,
28}
29
30impl<const TITLE: usize, const CONTENT: usize> MiniMessage<TITLE, CONTENT> {
31 pub fn new(
32 destination: [u8; HASH_LENGTH],
33 source: [u8; HASH_LENGTH],
34 signature: [u8; SIGNATURE_LENGTH],
35 timestamp: f64,
36 title: &[u8],
37 content: &[u8],
38 ) -> MiniResult<Self> {
39 if destination == [0; HASH_LENGTH] || source == [0; HASH_LENGTH] {
40 return Err(MiniError::InvalidInput);
41 }
42 let mut title_buf = Vec::new();
43 title_buf.extend_from_slice(title).map_err(|_| MiniError::CapacityExceeded)?;
44 let mut content_buf = Vec::new();
45 content_buf.extend_from_slice(content).map_err(|_| MiniError::CapacityExceeded)?;
46 Ok(Self {
47 destination,
48 source,
49 signature,
50 timestamp: timestamp.to_bits(),
51 title: title_buf,
52 content: content_buf,
53 })
54 }
55
56 pub fn timestamp(&self) -> f64 {
57 f64::from_bits(self.timestamp)
58 }
59
60 pub fn encoded_len(&self) -> MiniResult<usize> {
61 Ok(WIRE_HEADER_LENGTH
62 + 1
63 + 9
64 + bin_encoded_len(self.title.len())?
65 + bin_encoded_len(self.content.len())?
66 + 1)
67 }
68
69 pub fn encode(&self, out: &mut [u8]) -> MiniResult<usize> {
70 let needed = self.encoded_len()?;
71 if out.len() < needed {
72 return Err(MiniError::BufferTooSmall);
73 }
74
75 let mut idx = 0;
76 write_bytes(out, &mut idx, &self.destination)?;
77 write_bytes(out, &mut idx, &self.source)?;
78 write_bytes(out, &mut idx, &self.signature)?;
79 write_u8(out, &mut idx, MSGPACK_ARRAY_4)?;
80 write_u8(out, &mut idx, MSGPACK_F64)?;
81 write_bytes(out, &mut idx, &self.timestamp.to_be_bytes())?;
82 write_bin(out, &mut idx, &self.title)?;
83 write_bin(out, &mut idx, &self.content)?;
84 write_u8(out, &mut idx, MSGPACK_NIL)?;
85 Ok(idx)
86 }
87
88 pub fn decode(bytes: &[u8]) -> MiniResult<Self> {
89 if bytes.len() < WIRE_HEADER_LENGTH {
90 return Err(MiniError::InvalidWire);
91 }
92
93 let mut destination = [0u8; HASH_LENGTH];
94 let mut source = [0u8; HASH_LENGTH];
95 let mut signature = [0u8; SIGNATURE_LENGTH];
96 destination.copy_from_slice(&bytes[0..HASH_LENGTH]);
97 source.copy_from_slice(&bytes[HASH_LENGTH..HASH_LENGTH * 2]);
98 signature.copy_from_slice(&bytes[HASH_LENGTH * 2..WIRE_HEADER_LENGTH]);
99
100 let mut cursor = WIRE_HEADER_LENGTH;
101 let array_len = read_u8(bytes, &mut cursor)?;
102 if array_len == MSGPACK_ARRAY_5 {
103 return Err(MiniError::Unsupported);
104 }
105 if array_len != MSGPACK_ARRAY_4 {
106 return Err(MiniError::InvalidWire);
107 }
108 if read_u8(bytes, &mut cursor)? != MSGPACK_F64 {
109 return Err(MiniError::InvalidWire);
110 }
111 let timestamp = read_u64_be(bytes, &mut cursor)?;
112 let title_slice = read_bin_or_str(bytes, &mut cursor)?;
113 let content_slice = read_bin_or_str(bytes, &mut cursor)?;
114 if read_u8(bytes, &mut cursor)? != MSGPACK_NIL || cursor != bytes.len() {
115 return Err(MiniError::InvalidWire);
116 }
117
118 let mut title = Vec::new();
119 title.extend_from_slice(title_slice).map_err(|_| MiniError::CapacityExceeded)?;
120 let mut content = Vec::new();
121 content.extend_from_slice(content_slice).map_err(|_| MiniError::CapacityExceeded)?;
122 Ok(Self { destination, source, signature, timestamp, title, content })
123 }
124}
125
126fn bin_encoded_len(len: usize) -> MiniResult<usize> {
127 if len <= u8::MAX as usize {
128 Ok(2 + len)
129 } else if len <= u16::MAX as usize {
130 Ok(3 + len)
131 } else if len <= u32::MAX as usize {
132 Ok(5 + len)
133 } else {
134 Err(MiniError::InvalidInput)
135 }
136}
137
138fn write_u8(out: &mut [u8], idx: &mut usize, value: u8) -> MiniResult<()> {
139 if *idx >= out.len() {
140 return Err(MiniError::BufferTooSmall);
141 }
142 out[*idx] = value;
143 *idx += 1;
144 Ok(())
145}
146
147fn write_bytes(out: &mut [u8], idx: &mut usize, bytes: &[u8]) -> MiniResult<()> {
148 let end = idx.checked_add(bytes.len()).ok_or(MiniError::BufferTooSmall)?;
149 if end > out.len() {
150 return Err(MiniError::BufferTooSmall);
151 }
152 out[*idx..end].copy_from_slice(bytes);
153 *idx = end;
154 Ok(())
155}
156
157fn write_bin(out: &mut [u8], idx: &mut usize, bytes: &[u8]) -> MiniResult<()> {
158 if bytes.len() <= u8::MAX as usize {
159 write_u8(out, idx, MSGPACK_BIN8)?;
160 write_u8(out, idx, bytes.len() as u8)?;
161 } else if bytes.len() <= u16::MAX as usize {
162 write_u8(out, idx, MSGPACK_BIN16)?;
163 write_bytes(out, idx, &(bytes.len() as u16).to_be_bytes())?;
164 } else if bytes.len() <= u32::MAX as usize {
165 write_u8(out, idx, MSGPACK_BIN32)?;
166 write_bytes(out, idx, &(bytes.len() as u32).to_be_bytes())?;
167 } else {
168 return Err(MiniError::InvalidInput);
169 }
170 write_bytes(out, idx, bytes)
171}
172
173fn read_u8(bytes: &[u8], cursor: &mut usize) -> MiniResult<u8> {
174 let value = *bytes.get(*cursor).ok_or(MiniError::InvalidWire)?;
175 *cursor += 1;
176 Ok(value)
177}
178
179fn read_u64_be(bytes: &[u8], cursor: &mut usize) -> MiniResult<u64> {
180 let end = cursor.checked_add(8).ok_or(MiniError::InvalidWire)?;
181 let raw = bytes.get(*cursor..end).ok_or(MiniError::InvalidWire)?;
182 let mut out = [0u8; 8];
183 out.copy_from_slice(raw);
184 *cursor = end;
185 Ok(u64::from_be_bytes(out))
186}
187
188fn read_len(bytes: &[u8], cursor: &mut usize, marker: u8) -> MiniResult<usize> {
189 match marker {
190 MSGPACK_BIN8 | MSGPACK_STR8 => Ok(read_u8(bytes, cursor)? as usize),
191 MSGPACK_BIN16 | MSGPACK_STR16 => {
192 let end = cursor.checked_add(2).ok_or(MiniError::InvalidWire)?;
193 let raw = bytes.get(*cursor..end).ok_or(MiniError::InvalidWire)?;
194 *cursor = end;
195 Ok(u16::from_be_bytes([raw[0], raw[1]]) as usize)
196 }
197 MSGPACK_BIN32 | MSGPACK_STR32 => {
198 let end = cursor.checked_add(4).ok_or(MiniError::InvalidWire)?;
199 let raw = bytes.get(*cursor..end).ok_or(MiniError::InvalidWire)?;
200 *cursor = end;
201 Ok(u32::from_be_bytes([raw[0], raw[1], raw[2], raw[3]]) as usize)
202 }
203 0xa0..=0xbf => Ok((marker & 0x1f) as usize),
204 _ => Err(MiniError::InvalidWire),
205 }
206}
207
208fn read_bin_or_str<'a>(bytes: &'a [u8], cursor: &mut usize) -> MiniResult<&'a [u8]> {
209 let marker = read_u8(bytes, cursor)?;
210 let len = read_len(bytes, cursor, marker)?;
211 let end = cursor.checked_add(len).ok_or(MiniError::InvalidWire)?;
212 let out = bytes.get(*cursor..end).ok_or(MiniError::InvalidWire)?;
213 *cursor = end;
214 Ok(out)
215}