1use core::{fmt, ops::DerefMut};
8
9use crate::{
10 bytewords,
11 collections::Set,
12 fountain::{chooser, chooser::BaseFragmentChooser, util::xor_into},
13};
14
15#[derive(Debug, Clone, PartialEq, Eq, Hash)]
19pub struct MessageDescription {
20 pub sequence_count: u32,
22 pub message_length: usize,
24 pub checksum: u32,
26 pub fragment_length: usize,
28}
29
30#[derive(Clone, Debug, PartialEq, Eq)]
36#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
37pub struct Part<'a> {
38 pub sequence: u32,
41 pub sequence_count: u32,
43 pub message_length: usize,
45 pub checksum: u32,
47 pub data: &'a [u8],
54}
55
56impl<'a> Part<'a> {
57 pub fn is_valid(&self) -> bool {
65 self.sequence > 0
66 && self.sequence_count > 0
67 && self.message_length > 0
68 && !self.data.is_empty()
69 && self.data.len() <= self.message_length
70 }
71
72 pub fn indexes<C, I>(&self) -> I
78 where
79 C: chooser::Types,
80 I: Set<usize>,
81 {
82 BaseFragmentChooser::<C>::default().choose_fragments(
83 self.sequence,
84 self.sequence_count,
85 self.checksum,
86 )
87 }
88
89 pub const fn max_encoded_len() -> usize {
92 #[rustfmt::skip]
93 const MAX_CBOR: &[u8] = &[
94 0x85, 0x1A, 0xFF, 0xFF, 0xFF, 0xFF, 0x1B, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x1B, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x1A, 0xFF, 0xFF, 0xFF, 0xFF, 0x5B, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, ];
101
102 MAX_CBOR.len()
103 }
104
105 pub fn to_message_description(&self) -> MessageDescription {
107 MessageDescription {
108 sequence_count: self.sequence_count,
109 message_length: self.message_length,
110 checksum: self.checksum,
111 fragment_length: self.data.len(),
112 }
113 }
114}
115
116impl<'a> fmt::Display for Part<'a> {
118 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
119 let mut encoder = minicbor::Encoder::new(bytewords::minicbor::Writer::new(f));
122 encoder.encode(self).map_err(|_| fmt::Error)?;
123
124 encoder.into_writer().finish()?;
126
127 Ok(())
128 }
129}
130
131impl<'a> PartialEq<MessageDescription> for Part<'a> {
132 fn eq(&self, other: &MessageDescription) -> bool {
133 self.sequence_count == other.sequence_count
134 && self.message_length == other.message_length
135 && self.checksum == other.checksum
136 && self.data.len() == other.fragment_length
137 }
138}
139
140impl<'a, C> minicbor::Encode<C> for Part<'a> {
142 fn encode<W: minicbor::encode::Write>(
143 &self,
144 e: &mut minicbor::Encoder<W>,
145 _ctx: &mut C,
146 ) -> Result<(), minicbor::encode::Error<W::Error>> {
147 e.array(5)?
148 .u32(self.sequence)?
149 .u64(u64::from(self.sequence_count))?
150 .u64(
151 self.message_length
152 .try_into()
153 .map_err(|_| minicbor::encode::Error::message("expected u64"))?,
154 )?
155 .u32(self.checksum)?
156 .bytes(self.data)?;
157
158 Ok(())
159 }
160}
161
162impl<'b, C> minicbor::Decode<'b, C> for Part<'b> {
164 fn decode(
165 d: &mut minicbor::Decoder<'b>,
166 _ctx: &mut C,
167 ) -> Result<Self, minicbor::decode::Error> {
168 if !matches!(d.array()?, Some(5)) {
169 return Err(minicbor::decode::Error::message(
170 "invalid CBOR array length",
171 ));
172 }
173
174 Ok(Self {
175 sequence: d.u32()?,
176 sequence_count: d.u32()?,
177 message_length: d
178 .u32()?
179 .try_into()
180 .map_err(|_| minicbor::decode::Error::message("expected usize"))?,
181 checksum: d.u32()?,
182 data: d.bytes()?,
183 })
184 }
185}
186
187#[derive(Debug, Clone)]
189pub struct IndexedPart<D, I> {
190 pub data: D,
192 pub indexes: I,
194}
195
196impl<D, I> IndexedPart<D, I> {
197 pub fn new(data: D, indexes: I) -> Self {
200 Self { data, indexes }
201 }
202
203 #[inline]
208 pub fn is_simple(&self) -> bool
209 where
210 I: Set<usize>,
211 {
212 self.indexes.len() == 1
213 }
214
215 pub fn reduce(&mut self, part: &IndexedPart<D, I>)
221 where
222 D: DerefMut<Target = [u8]>,
223 I: Set<usize>,
224 {
225 if self.indexes.len() == 1 {
226 return;
227 }
228
229 if part.indexes.is_subset(&self.indexes) {
230 self.indexes = self.indexes.sub(&part.indexes);
231 xor_into(&mut self.data, &part.data);
232 }
233 }
234
235 pub fn reduce_by_simple(&mut self, data: &[u8], index: usize)
241 where
242 D: DerefMut<Target = [u8]>,
243 I: Set<usize>,
244 {
245 assert!(self.indexes.len() > 1, "cannot reduce a simple part");
246
247 if self.indexes.contains(&index) {
248 self.indexes.remove(&index);
249 xor_into(&mut self.data, data);
250 }
251 }
252}
253
254#[cfg(test)]
255pub mod tests {
256 use super::*;
257
258 #[test]
259 #[cfg(feature = "alloc")]
260 fn test_part_cbor_roundtrip() {
261 const PART: Part = Part {
262 sequence: 12,
263 sequence_count: 8,
264 message_length: 100,
265 checksum: 0x1234_5678,
266 data: &[1, 5, 3, 3, 5],
267 };
268
269 let mut cbor = alloc::vec::Vec::new();
270 minicbor::encode(&PART, &mut cbor).unwrap();
271
272 let part2: Part = minicbor::decode(&cbor).unwrap();
273 assert_eq!(part2, PART);
274
275 let mut cbor2 = alloc::vec::Vec::new();
276 minicbor::encode(&part2, &mut cbor2).unwrap();
277 assert_eq!(cbor, cbor2);
278 }
279
280 #[test]
281 fn test_part_cbor_decode() {
282 assert!(minicbor::decode::<'_, Part>(&[0x18]).is_err());
285 assert!(minicbor::decode::<'_, Part>(&[0x1]).is_err());
287 assert!(minicbor::decode::<'_, Part>(&[0x84, 0x1, 0x2, 0x3, 0x4]).is_err());
289 assert!(minicbor::decode::<'_, Part>(&[0x86, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6]).is_err());
290 assert!(
292 minicbor::decode::<'_, Part>(&[0x85, 0x41, 0x1, 0x2, 0x3, 0x4, 0x41, 0x1]).is_err()
293 );
294 assert!(
296 minicbor::decode::<'_, Part>(&[0x85, 0x1, 0x41, 0x2, 0x3, 0x4, 0x41, 0x1]).is_err()
297 );
298 assert!(
300 minicbor::decode::<'_, Part>(&[0x85, 0x1, 0x2, 0x41, 0x3, 0x4, 0x41, 0x1]).is_err()
301 );
302 assert!(
304 minicbor::decode::<'_, Part>(&[0x85, 0x1, 0x2, 0x3, 0x41, 0x4, 0x41, 0x1]).is_err()
305 );
306 assert!(minicbor::decode::<'_, Part>(&[0x85, 0x1, 0x2, 0x3, 0x4, 0x5]).is_err());
308 assert!(minicbor::decode::<'_, Part>(&[0x85, 0x1, 0x2, 0x3, 0x4, 0x5]).is_err());
309 minicbor::decode::<'_, Part>(&[0x85, 0x1, 0x2, 0x3, 0x4, 0x41, 0x5]).unwrap();
310 }
311
312 #[test]
313 fn test_part_cbor_decode_unsigned_types() {
314 minicbor::decode::<'_, Part>(&[0x85, 0x1, 0x2, 0x3, 0x4, 0x41, 0x5]).unwrap();
316 minicbor::decode::<'_, Part>(&[
318 0x85, 0x19, 0x1, 0x2, 0x19, 0x3, 0x4, 0x19, 0x5, 0x6, 0x19, 0x7, 0x8, 0x41, 0x5,
319 ])
320 .unwrap();
321 minicbor::decode::<'_, Part>(&[
323 0x85, 0x1a, 0x1, 0x2, 0x3, 0x4, 0x1a, 0x5, 0x6, 0x7, 0x8, 0x1a, 0x9, 0x10, 0x11, 0x12,
324 0x1a, 0x13, 0x14, 0x15, 0x16, 0x41, 0x5,
325 ])
326 .unwrap();
327 assert!(minicbor::decode::<'_, Part>(&[
329 0x85, 0x1b, 0x1, 0x2, 0x3, 0x4, 0xa, 0xb, 0xc, 0xd, 0x1a, 0x5, 0x6, 0x7, 0x8, 0x1a,
330 0x9, 0x10, 0x11, 0x12, 0x1a, 0x13, 0x14, 0x15, 0x16, 0x41, 0x5,
331 ])
332 .is_err());
333 assert!(minicbor::decode::<'_, Part>(&[
334 0x85, 0x1a, 0x1, 0x2, 0x3, 0x4, 0x1b, 0x5, 0x6, 0x7, 0x8, 0xa, 0xb, 0xc, 0xd, 0x1a,
335 0x9, 0x10, 0x11, 0x12, 0x1a, 0x13, 0x14, 0x15, 0x16, 0x41, 0x5,
336 ])
337 .is_err());
338 assert!(minicbor::decode::<'_, Part>(&[
339 0x85, 0x1a, 0x1, 0x2, 0x3, 0x4, 0x1a, 0x5, 0x6, 0x7, 0x8, 0x1b, 0x9, 0x10, 0x11, 0x12,
340 0xa, 0xb, 0xc, 0xd, 0x1a, 0x13, 0x14, 0x15, 0x16, 0x41, 0x5,
341 ])
342 .is_err());
343 assert!(minicbor::decode::<'_, Part>(&[
344 0x85, 0x1a, 0x1, 0x2, 0x3, 0x4, 0x1a, 0x5, 0x6, 0x7, 0x8, 0x1a, 0x9, 0x10, 0x11, 0x12,
345 0x1b, 0x13, 0x14, 0x15, 0x16, 0xa, 0xb, 0xc, 0xd, 0x41, 0x5,
346 ])
347 .is_err());
348 }
349}