use core::fmt::Debug; use arrayvec::{ArrayVec, CapacityError}; use crc::{Crc, CRC_16_IBM_SDLC}; use crate::{ buffer::{Buffer, BufferOverflow}, error::{CommentError, DecodeError, EncodeError}, interleaver, ldpc, utf8, whisker::{ Arbitrary, Comment, Destination, Gps, Identification, Route, Timestamp, ValidatedWhiskerIter, Whisker, WhiskerIter, COMMENT_TYPE, }, whitener, }; const X25: Crc<u16> = Crc::<u16>::new(&CRC_16_IBM_SDLC); macro_rules! uniq_whisker { ($t:meta) => { ::paste::paste! { pub fn [<$t:lower>](&self) -> Option<$t> { self.iter().find_map(|w| match w { Whisker::$t(x) => Some(x), _ => None, }) } pub fn [<add_ $t:lower>](&mut self, w: $t) -> Result<(), EncodeError> { if self.[<$t:lower>]().is_some() { return Err(EncodeError::DuplicateData); } try_lock(&mut self.data, |data| { let mut buf = [0; 256]; // safe to unwrap since we know we have enough space let out = w.encode(&mut buf).unwrap(); data.try_push(crate::whisker::[<$t:upper _TYPE>]).ok().ok_or(EncodeError::CatsOverflow)?; data.try_extend_from_slice(out).ok().ok_or(EncodeError::CatsOverflow)?; Ok(()) })?; Ok(()) } pub fn [<clear_ $t:lower>](&mut self) { self.clear_by_type(crate::whisker::[<$t:upper _TYPE>], false); } } }; } macro_rules! poly_whisker { ($t: meta) => { ::paste::paste! { pub fn [<$t:lower _iter>](&self) -> core::iter::FilterMap<ValidatedWhiskerIter, fn(Whisker) -> Option<$t>> { fn filt(w: Whisker) -> Option<$t> { match w { Whisker::$t(x) => Some(x), _ => None } } self.iter().filter_map(filt) } pub fn [<add_ $t:lower>](&mut self, w: $t) -> Result<(), EncodeError> { try_lock(self.buf.as_slice_mut(), |data| { let mut buf = [0; 256]; // safe to unwrap since we know we have enough space let out = w.encode(&mut buf).unwrap(); data.try_push(crate::whisker::[<$t:upper _TYPE>]).ok().ok_or(EncodeError::CatsOverflow)?; data.try_extend_from_slice(out).ok().ok_or(EncodeError::CatsOverflow)?; Ok(()) })?; Ok(()) } pub fn [<clear_ $t:lower>](&mut self) { self.clear_by_type(crate::whisker::[<$t:upper _TYPE>], true); } } }; } /// N is the maximum packet size we can handle /// Panics if N >= 8191 pub struct Packet<'a, const N: usize> { buf: Buffer<'a, N>, } // TODO need a method for cloning packets impl<'a, const N: usize> Packet<'a, N> { pub fn new(buf: &'a mut [u8; N]) -> Self { Self { buf: buf.into() } } /// Expects bytes in the `buf` /// `buf` is used as the backing buffer for the Packet pub fn decode(buf: Buffer<'a, N>) -> Result<Self, DecodeError> { assert!(N <= 8191); // validate the data for w in WhiskerIter::new(&buf) { w?; } let comment_iter = WhiskerIter::new(&buf) .filter_map(|w| match w.unwrap() { Whisker::Comment(c) => Some(c.internal_data().clone()), _ => None, }) .flatten(); if !utf8::validate(comment_iter) { return Err(DecodeError::InvalidComment); } Ok(Self { buf }) } pub fn encode(&self) -> &[u8] { &self.buf } /// Directly after the CRC block in The Pipeline pub fn semi_encode(mut self) -> Result<Buffer<'a, N>, (EncodeError, Self)> { let crc = X25.checksum(&self.buf).to_le_bytes(); let res: Result<(), BufferOverflow> = try_lock(&mut self.buf, |data| { data.try_push(crc[0])?; data.try_push(crc[1])?; Ok(()) }); match res { Ok(()) => Ok(self.buf), Err(_) => Err((EncodeError::CatsOverflow, self)), } } /// Directly after the CRC block in The Pipeline /// Expects bytes in the `buf` /// `buf` is used as the backing buffer for the Packet pub fn semi_decode(buf: Buffer<'a, N>) -> Result<Self, DecodeError> { let crc1 = buf.pop().ok_or(DecodeError::UnexpectedEndOfInput)?; let crc0 = buf.pop().ok_or(DecodeError::UnexpectedEndOfInput)?; let crc_expected = u16::from_le_bytes([crc0, crc1]); let crc_actual = X25.checksum(&buf); if crc_expected != crc_actual { return Err(DecodeError::CrcMismatch); } Self::decode(buf) } /// Encodes packet for transmission on the air. /// Includes the data length L, but does not include the preamble or sync word. // TODO buffer-ify this pub fn fully_encode(self) -> Result<ArrayVec<u8, N>, EncodeError> { let mut data = self.semi_encode().map_err(|(err, _)| err)?; whitener::whiten(&mut data); ldpc::encode(&mut data)?; let mut out: ArrayVec<u8, N> = ArrayVec::new(); // safe to unwrap - length must be below 8191 out.try_extend_from_slice(&u16::try_from(data.len()).unwrap().to_le_bytes()) .map_err(|_| EncodeError::CatsOverflow)?; interleaver::interleave(&data, &mut out)?; Ok(out) } /// Decodes packet that was received over the air. /// Packet shouldn't have preamble, sync word, or data langth L. /// Expects bytes in the `buf` /// `buf` is used as the backing buffer for the Packet pub fn fully_decode(buf: Buffer<'a, N>) -> Result<Self, DecodeError> { let mut data = interleaver::uninterleave(buf).map_err(|_| DecodeError::Overflow)?; ldpc::decode(&mut data).ok_or(DecodeError::LdpcError)?; whitener::whiten(&mut data); Self::semi_decode(data) } pub fn iter(&self) -> ValidatedWhiskerIter { ValidatedWhiskerIter::new(&self.data) } uniq_whisker!(Identification); uniq_whisker!(Timestamp); uniq_whisker!(Gps); uniq_whisker!(Route); poly_whisker!(Destination); poly_whisker!(Arbitrary); pub fn comment<'b>(&self, buf: &'b mut [u8]) -> Result<&'a str, CommentError> { let iter = self.iter().filter_map(|w| match w { Whisker::Comment(c) => Some(c), _ => None, }); let mut i = 0; let mut has_comment = false; for c in iter { has_comment = true; let data = c.internal_data(); buf.get_mut(i..(i + data.len())) .ok_or(CommentError::BufferOverflow)? .copy_from_slice(data); i += data.len(); } if !has_comment { return Err(CommentError::NoComment); } // Safe to unwrap since the comment was pre-validated Ok(core::str::from_utf8(&buf[0..i]).unwrap()) } pub fn add_comment(&mut self, comment: &str) -> Result<(), EncodeError> { if self.iter().any(|w| matches!(w, Whisker::Comment(_))) { // we already have a comment return Err(EncodeError::DuplicateData); } try_lock(&mut self.data, |data| { let mut comment = comment.as_bytes(); while comment.len() > 255 { let c = Comment::new(&comment[0..255]).unwrap(); let mut buf = [0; 256]; let out = c.encode(&mut buf).unwrap(); data.try_push(COMMENT_TYPE) .map_err(|_| EncodeError::CatsOverflow)?; data.try_extend_from_slice(out) .map_err(|_| EncodeError::CatsOverflow)?; comment = &comment[255..]; } let c = Comment::new(comment).unwrap(); let mut buf = [0; 256]; let out = c.encode(&mut buf).unwrap(); data.try_push(COMMENT_TYPE) .map_err(|_| EncodeError::CatsOverflow)?; data.try_extend_from_slice(out) .map_err(|_| EncodeError::CatsOverflow)?; Ok(()) })?; Ok(()) } pub fn clear_comment(&mut self) { self.clear_by_type(COMMENT_TYPE, true); } fn clear_by_type(&mut self, whisker_type: u8, all: bool) { let mut i = 0; while i < self.data.len() { let t = self.data[i]; let step = usize::from(self.data[i + 1]) + 2; if t == whisker_type { self.data.drain(i..(i + step)); if !all { return; } } else { i += step; } } } } impl<'a, const N: usize> Debug for Packet<'a, N> { fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { f.debug_list() .entries(ValidatedWhiskerIter::new(self.buf.as_slice())) .finish() } } // if the function returns an error, we roll back the array // by rolling it back, we really just pop bytes off the end until the length matches fn try_lock<'a, const N: usize, T, E, F: Fn(&mut Buffer<'a, N>) -> Result<T, E>>( buf: &mut Buffer<'a, N>, f: F, ) -> Result<T, E> { let len = buf.len(); match f(buf) { Ok(x) => Ok(x), Err(e) => { buf.truncate(len); Err(e) } } } #[cfg(test)] mod tests { use arrayvec::ArrayString; use super::*; #[test] fn dest() { let d1 = Destination::new(false, 7, "CALL1", 23).unwrap(); let d2 = Destination::new(true, 23, "CALL2", 2).unwrap(); let mut packet: Packet<1024> = Packet::default(); packet.add_destination(d1.clone()).unwrap(); packet.add_destination(d2.clone()).unwrap(); let mut dests = packet.destination_iter(); assert_eq!(d1, dests.next().unwrap()); assert_eq!(d2, dests.next().unwrap()); assert_eq!(None, dests.next()); } #[test] fn route_clear() { let mut p: Packet<1024> = Packet::default(); p.add_identification(Identification::new(123, "call", 43).unwrap()) .unwrap(); let mut r = Route::new(8); r.push_internet().unwrap(); p.add_route(r).unwrap(); p.add_comment("This is a comment").unwrap(); p.clear_route(); assert_eq!( Identification::new(123, "call", 43).unwrap(), p.identification().unwrap() ); assert_eq!(None, p.route()); let mut buf = [0; 32]; assert_eq!("This is a comment", p.comment(&mut buf).unwrap()); } #[test] fn semi_e2e() { let comment = "Hello world! This is a comment. It's long so that it needs to be split across more than one whisker.Hello world! This is a comment. It's long so that it needs to be split across more than one whisker.Hello world! This is a comment. It's long so that it needs to be split across more than one whisker.Hello world! This is a comment. It's long so that it needs to be split across more than one whisker.Hello world! This is a comment. It's long so that it needs to be split across more than one whisker.Hello world! This is a comment. It's long so that it needs to be split across more than one whisker.Hello world! This is a comment. It's long so that it needs to be split across more than one whisker.Hello world! This is a comment. It's long so that it needs to be split across more than one whisker.Hello world! This is a comment. It's long so that it needs to be split across more than one whisker.Hello world! This is a comment. It's long so that it needs to be split across more than one whisker."; let mut packet = Packet::<2048>::default(); packet .add_identification(Identification { icon: 123, callsign: ArrayString::from("ABCXYZ_LONG_CALL").unwrap(), ssid: 43, }) .unwrap(); packet.add_comment(comment).unwrap(); let res = packet.add_identification(Identification { icon: 456, callsign: ArrayString::from("NOPE").unwrap(), ssid: 0, }); assert!(matches!(res, Err(EncodeError::DuplicateData))); let semi = packet.semi_encode().unwrap(); let packet2 = Packet::semi_decode(semi).unwrap(); assert_eq!( Identification { icon: 123, callsign: ArrayString::from("ABCXYZ_LONG_CALL").unwrap(), ssid: 43, }, packet2.identification().unwrap() ); let mut buf = [0; 1024]; assert_eq!(comment, packet2.comment(&mut buf).unwrap()); } #[test] fn full_e2e() { let comment = "Hello world! This is a comment. It's long so that it needs to be split across more than one whisker.Hello world! This is a comment. It's long so that it needs to be split across more than one whisker.Hello world! This is a comment. It's long so that it needs to be split across more than one whisker.Hello world! This is a comment. It's long so that it needs to be split across more than one whisker.Hello world! This is a comment. It's long so that it needs to be split across more than one whisker.Hello world! This is a comment. It's long so that it needs to be split across more than one whisker.Hello world! This is a comment. It's long so that it needs to be split across more than one whisker.Hello world! This is a comment. It's long so that it needs to be split across more than one whisker.Hello world! This is a comment. It's long so that it needs to be split across more than one whisker.Hello world! This is a comment. It's long so that it needs to be split across more than one whisker."; let mut packet = Packet::<4096>::default(); packet .add_identification(Identification { icon: 123, callsign: ArrayString::from("ABCXYZ_LONG_CALL").unwrap(), ssid: 43, }) .unwrap(); packet.add_comment(comment).unwrap(); let res = packet.add_identification(Identification { icon: 456, callsign: ArrayString::from("NOPE").unwrap(), ssid: 0, }); assert!(matches!(res, Err(EncodeError::DuplicateData))); let mut fully = packet.fully_encode().unwrap(); fully[40] ^= 0x55; fully[844] ^= 0x7B; // exclude length let packet2: Packet<8191> = Packet::fully_decode(&fully[2..]).unwrap(); assert_eq!( Identification { icon: 123, callsign: ArrayString::from("ABCXYZ_LONG_CALL").unwrap(), ssid: 43, }, packet2.identification().unwrap() ); let mut buf = [0; 1024]; assert_eq!(comment, packet2.comment(&mut buf).unwrap()); } #[test] fn fully_decode_fuzz_tests() { let data = [ 112, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 74, 0, 0, 0, 0, 41, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 39, 114, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 10, 112, 0, 0, 0, 0, 0, 0, 2, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 74, 0, 0, 0, 0, 41, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 39, 114, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 247, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 7, 0, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 145, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 59, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 7, 0, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 59, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 37, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 228, 0, 0, 0, 64, 0, 65, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 7, 0, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 1, 0, 0, 10, 118, 118, 118, 118, 118, 118, 118, 118, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 37, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 228, 0, 0, 0, 64, 0, 65, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 7, 0, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 1, 0, 0, 10, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 1, 2, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 0, 0, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 0, 0, 0, 0, 96, 96, ]; let _ = Packet::<1024>::fully_decode(&data); } #[test] fn semi_decode_fuzz_tests() { let data: ArrayVec<u8, 1024> = ArrayVec::try_from( &[ 42, 64, 64, 64, 229, 40, 64, 64, 0, 0, 173, 173, 173, 173, 173, 173, 173, 173, 64, 64, 0, 0, 173, 187, 187, 187, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 187, 187, 187, 101, 157, 138, 74, 101, 157, 138, 74, 0, 0, 0, 0, 1, 126, 255, 255, 255, 187, 187, 187, 187, 187, 187, 187, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 187, 101, 157, 138, 74, 101, 157, 138, 106, 0, 0, 0, 0, 1, 126, 255, 255, 255, 0, 212, 0, 0, 0, 0, 1, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 173, 187, 187, 187, 101, 157, 138, 74, 101, 157, 138, 74, 0, 0, 0, 0, 1, 126, 255, 255, 255, 0, 212, 0, 0, 0, 0, 1, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 157, 138, 74, 0, 0, 0, 0, 1, 126, 255, 255, 255, 0, 212, 0, 0, 0, 0, 1, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 173, 187, 187, 64, 187, 101, 157, 138, 74, 101, 157, 50, 138, 74, 0, 0, 0, 0, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 1, 126, 255, 255, 255, 0, 212, 0, 0, 0, 0, 1, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 64, 64, 0, 0, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 187, 187, 187, 101, 157, 138, 74, 101, 157, 138, 74, 0, 0, 0, 0, 1, 126, 255, 255, 255, 0, 212, 0, 0, 0, 0, 1, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 173, 187, 187, 187, 101, 157, 138, 74, 101, 157, 138, 74, 0, 0, 0, 0, 1, 126, 255, 255, 255, 0, 212, 0, 0, 0, 0, 1, 187, 187, 0, 0, 192, 192, 0, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 64, 64, 0, 0, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 187, 187, 187, 101, 157, 138, 74, 101, 157, 138, 74, 0, 0, 0, 0, 1, 126, 255, 255, 255, 0, 212, 0, 0, 0, 0, 1, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 126, ][..], ) .unwrap(); let _ = Packet::<1024>::semi_decode(data); } #[test] fn decode_fuzz_tests() { let data = ArrayVec::try_from(&[4, 0, 0, 0][..]).unwrap(); let _ = Packet::<1024>::decode(data); } }