mod arbitrary; mod comment; mod destination; mod gps; mod identification; mod node_info; mod route; mod timestamp; mod unknown; use crate::error::DecodeError; pub use self::{ arbitrary::Arbitrary, comment::Comment, destination::Destination, gps::Gps, identification::Identification, node_info::{NodeInfo, NodeInfoBuilder}, route::{PastHop, Route, RouteHop, RouteIter}, timestamp::Timestamp, unknown::Unknown, }; pub(crate) const IDENTIFICATION_TYPE: u8 = 0x00; pub(crate) const TIMESTAMP_TYPE: u8 = 0x01; pub(crate) const GPS_TYPE: u8 = 0x02; pub(crate) const COMMENT_TYPE: u8 = 0x03; pub(crate) const ROUTE_TYPE: u8 = 0x04; pub(crate) const DESTINATION_TYPE: u8 = 0x05; pub(crate) const ARBITRARY_TYPE: u8 = 0x06; pub(crate) const NODE_INFO_TYPE: u8 = 0x09; #[derive(Debug)] pub enum Whisker { Identification(Identification), Timestamp(Timestamp), Gps(Gps), Comment(Comment), Route(Route), Destination(Destination), Arbitrary(Arbitrary), NodeInfo(NodeInfo), Unknown(Unknown), } pub struct WhiskerIter<'a> { data: &'a [u8], i: usize, // for detecting duplicates has_ident: bool, has_timestamp: bool, has_gps: bool, has_route: bool, } impl<'a> WhiskerIter<'a> { pub fn new(data: &'a [u8]) -> Self { Self { data, i: 0, has_ident: false, has_timestamp: false, has_gps: false, has_route: false, } } fn decode(&mut self) -> Result<Whisker, DecodeError> { let position = self.i; let t = *self .data .get(self.i) .ok_or(DecodeError::UnexpectedEndOfInput)?; let len = usize::from( *self .data .get(self.i + 1) .ok_or(DecodeError::UnexpectedEndOfInput)?, ); let data = self .data .get((self.i + 1)..(self.i + 2 + len)) .ok_or(DecodeError::UnexpectedEndOfInput)?; self.i += len + 2; let out = match t { IDENTIFICATION_TYPE => { if self.has_ident { return Err(DecodeError::DuplicateWhisker { position }); } self.has_ident = true; Whisker::Identification( Identification::decode(data) .ok_or(DecodeError::MalformedWhisker { position })?, ) } TIMESTAMP_TYPE => { if self.has_timestamp { return Err(DecodeError::DuplicateWhisker { position }); } self.has_timestamp = true; Whisker::Timestamp( Timestamp::decode(data).ok_or(DecodeError::MalformedWhisker { position })?, ) } GPS_TYPE => { if self.has_gps { return Err(DecodeError::DuplicateWhisker { position }); } self.has_gps = true; Whisker::Gps(Gps::decode(data).ok_or(DecodeError::MalformedWhisker { position })?) } COMMENT_TYPE => Whisker::Comment( Comment::decode(data).ok_or(DecodeError::MalformedWhisker { position })?, ), ROUTE_TYPE => { if self.has_route { return Err(DecodeError::DuplicateWhisker { position }); } self.has_route = true; Whisker::Route( Route::decode(data).ok_or(DecodeError::MalformedWhisker { position })?, ) } DESTINATION_TYPE => Whisker::Destination( Destination::decode(data).ok_or(DecodeError::MalformedWhisker { position })?, ), ARBITRARY_TYPE => Whisker::Arbitrary( Arbitrary::decode(data).ok_or(DecodeError::MalformedWhisker { position })?, ), NODE_INFO_TYPE => Whisker::NodeInfo( NodeInfo::decode(data).ok_or(DecodeError::MalformedWhisker { position })?, ), // safe to unwrap because we know len has to be 255 or less, since it's a u8 whisker_type => { Whisker::Unknown(Unknown::new(whisker_type, data[1..].try_into().unwrap())) } }; Ok(out) } } impl Iterator for WhiskerIter<'_> { type Item = Result<Whisker, DecodeError>; fn next(&mut self) -> Option<Self::Item> { if self.i == self.data.len() { return None; } Some(self.decode()) } } pub struct ValidatedWhiskerIter<'a> { iter: WhiskerIter<'a>, } impl<'a> ValidatedWhiskerIter<'a> { pub(crate) fn new(data: &'a [u8]) -> Self { Self { iter: WhiskerIter::new(data), } } } impl Iterator for ValidatedWhiskerIter<'_> { type Item = Whisker; fn next(&mut self) -> Option<Self::Item> { self.iter.next().map(|w| w.unwrap()) } } #[cfg(test)] mod tests { use half::f16; use crate::{ identity::Identity, whisker::route::{PastHop, RouteHop}, }; use super::*; #[test] fn ident_e2e() { let icon = 2738; let call = "VE9ABCDEFGZZ4839-???"; let ssid = 17; let ident = Identification::new(call, ssid, icon).unwrap(); let mut buf = [0; 256]; let encoded = ident.encode(&mut buf).unwrap(); let decoded = Identification::decode(encoded).unwrap(); assert_eq!(ident, decoded); assert_eq!(call, &decoded.callsign); assert_eq!(ssid, decoded.ssid); } #[test] fn new_timestamp() { let t = 34894; assert_eq!(t, Timestamp::new(t).unwrap().unix_time()); let t = 1 << (5 * 8); assert_eq!(None, Timestamp::new(t)); } #[test] fn timestamp_e2e() { let t = 34894; let timestamp = Timestamp::new(t).unwrap(); let mut buf = [0; 256]; let encoded = timestamp.encode(&mut buf).unwrap(); let decoded = Timestamp::decode(encoded).unwrap(); assert_eq!(timestamp, decoded); assert_eq!(t, timestamp.unix_time()); } #[test] fn new_gps() { let gps = Gps::new( 90.0, -180.0, f16::from_f32(45.02), 24, 123.45, f16::from_f32(12.3), ); assert_eq!(89.99899999704212, gps.latitude()); assert_eq!(-179.9989999551326, gps.longitude()); assert_eq!(123.75, gps.heading()); } #[test] fn gps_max_heading() { let gps = Gps::new( 4.0, 23.45, f16::from_f32(45.02), 24, 359.0, f16::from_f32(12.3), ); assert_eq!(358.59375, gps.heading()); let gps = Gps::new( 4.0, 23.45, f16::from_f32(45.02), 24, 957.47, f16::from_f32(12.3), ); assert_eq!(957.65625 - 360.0 * 2.0, gps.heading()); } #[test] fn gps_min_heading() { let gps = Gps::new( 4.0, 23.45, f16::from_f32(45.02), 24, 0.0, f16::from_f32(12.3), ); assert_eq!(0.0, gps.heading()); let gps = Gps::new( 4.0, 23.45, f16::from_f32(45.02), 24, -22.0, f16::from_f32(12.3), ); assert_eq!(337.5, gps.heading()); let gps = Gps::new( 4.0, 23.45, f16::from_f32(45.02), 24, -1206.0, f16::from_f32(12.3), ); assert_eq!(233.4375, gps.heading()); } #[test] fn gps_e2e() { let gps = Gps::new( 90.0, -180.0, f16::from_f32(45.02), 24, 123.45, f16::from_f32(12.3), ); let mut buf = [0; 256]; let encoded = gps.encode(&mut buf).unwrap(); let decoded = Gps::decode(encoded).unwrap(); assert_eq!(gps, decoded); } #[test] fn comment_e2e() { let data = b"Hello world! This is an example comment"; let comment = Comment::new(data).unwrap(); let mut buf = [0; 256]; let encoded = comment.encode(&mut buf).unwrap(); let decoded = Comment::decode(encoded).unwrap(); let decoded2 = Comment::decode(&buf).unwrap(); assert_eq!(data[..], decoded.internal_data()[..]); assert_eq!(data[..], decoded2.internal_data()[..]); } #[test] fn route_push_and_iter() { let mut route = Route::new(34); route .push_past(PastHop::new(Identity::new("VE2XYZ", 23), None)) .unwrap(); route.push_internet().unwrap(); route.push_internet().unwrap(); route.push_internet().unwrap(); route.push_future(Identity::new("VE9AAAAA", 94)).unwrap(); // past after future - not allowed assert!(route .push_past(PastHop::new(Identity::new("VE9AAAAA", 94), None)) .is_none()); // too long assert!(route .push_future(Identity::new( "lsdfjslkdfjlksdjflksfjsdklfjsdklfjsdklfjsdklfjsklfsef;jklsdfjkl;sdf;klsdf;klsjdfJSDJFSKL:DFJDSL:KFskldfj;slkdfjsdkl;fjdskl;fjsdfl;kjsdfl;ksdjfkl;ssdfl;kjsdfl;ksdjf;sdklsd;lfkjsdlfk;jsdl;fkjsd;klfjsd;fljsf;oidfjgwper0tujdfgndfjkl;gjnergjol;kehfgo;dijge;oghdfkl;gjdfkl;gjdeior;lgjedr;ioghjdorighndeklo;grjiop[", 20, )).is_none()); route .push_future(Identity::new("This is the last callsign", 0)) .unwrap(); route.push_internet().unwrap(); let mut iter = route.iter(); assert_eq!( RouteHop::Past(PastHop::new(Identity::new("VE2XYZ", 23), None)), iter.next().unwrap() ); assert_eq!(RouteHop::Internet, iter.next().unwrap()); assert_eq!(RouteHop::Internet, iter.next().unwrap()); assert_eq!(RouteHop::Internet, iter.next().unwrap()); assert_eq!( RouteHop::Future(Identity::new("VE9AAAAA", 94)), iter.next().unwrap() ); assert_eq!( RouteHop::Future(Identity::new("This is the last callsign", 0)), iter.next().unwrap() ); assert_eq!(RouteHop::Internet, iter.next().unwrap()); assert_eq!(None, iter.next()); assert_eq!(34, route.max_hops); } #[test] fn route_e2e() { let mut route = Route::new(34); route .push_past(PastHop::new(Identity::new("VE2XYZ", 23), Some(0.0))) .unwrap(); route.push_internet().unwrap(); route.push_internet().unwrap(); route.push_internet().unwrap(); route.push_future(Identity::new("VE9AAAAA", 94)).unwrap(); route .push_future(Identity::new("This is the last callsign", 0)) .unwrap(); route.push_internet().unwrap(); let mut buf = [0; 256]; let encoded = route.encode(&mut buf).unwrap(); let decoded = Route::decode(encoded).unwrap(); assert_eq!(route, decoded); } // verify examples in the standard doc #[test] fn route_doc_examples() { let mut ex1 = Route::new(4); ex1.push_past(PastHop::new(Identity::new("VE1ABC", 0), Some(-96.0))) .unwrap(); ex1.push_past(PastHop::new(Identity::new("VE2DEF", 234), Some(-13.0))) .unwrap(); ex1.push_past(PastHop::new(Identity::new("VE3XYZ", 14), Some(-106.0))) .unwrap(); let mut buf = [0; 256]; let encoded = ex1.encode(&mut buf).unwrap(); assert_eq!( &[ 0x1C, 0x04, 0x56, 0x45, 0x31, 0x41, 0x42, 0x43, 0xFF, 0x00, 0x60, 0x56, 0x45, 0x32, 0x44, 0x45, 0x46, 0xFF, 0xEA, 0xDC, 0x56, 0x45, 0x33, 0x58, 0x59, 0x5A, 0xFF, 0x0E, 0x51 ], &encoded ); let mut ex1_5 = Route::new(4); ex1_5 .push_past(PastHop::new(Identity::new("VE1ABC", 0), Some(-96.0))) .unwrap(); ex1_5.push_future(Identity::new("VE2DEF", 234)).unwrap(); ex1_5.push_future(Identity::new("VE3XYZ", 14)).unwrap(); let mut buf = [0; 256]; let encoded = ex1_5.encode(&mut buf).unwrap(); assert_eq!( &[ 0x1A, 0x04, 0x56, 0x45, 0x31, 0x41, 0x42, 0x43, 0xFF, 0x00, 0x60, 0x56, 0x45, 0x32, 0x44, 0x45, 0x46, 0xFD, 0xEA, 0x56, 0x45, 0x33, 0x58, 0x59, 0x5A, 0xFD, 0x0E, ], &encoded ); let mut ex2 = Route::new(3); ex2.push_past(PastHop::new(Identity::new("VE1ABC", 0), None)) .unwrap(); ex2.push_internet(); ex2.push_past(PastHop::new(Identity::new("VE2DEF", 234), Some(-86.5))) .unwrap(); ex2.push_internet(); ex2.push_past(PastHop::new(Identity::new("VE3XYZ", 14), Some(-65.0))) .unwrap(); let encoded = ex2.encode(&mut buf).unwrap(); assert_eq!( &[ 0x1E, 0x03, 0x56, 0x45, 0x31, 0x41, 0x42, 0x43, 0xFF, 0x00, 0x00, 0xFE, 0x56, 0x45, 0x32, 0x44, 0x45, 0x46, 0xFF, 0xEA, 0x6E, 0xFE, 0x56, 0x45, 0x33, 0x58, 0x59, 0x5A, 0xFF, 0x0E, 0x8E ], &encoded ); let mut ex3 = Route::new(0); ex3.push_past(PastHop::new(Identity::new("VE1ABC", 0), Some(-42.5))) .unwrap(); ex3.push_internet(); ex3.push_internet(); let encoded = ex3.encode(&mut buf).unwrap(); assert_eq!( &[0x0C, 0x00, 0x56, 0x45, 0x31, 0x41, 0x42, 0x43, 0xFF, 0x00, 0xB0, 0xFE, 0xFE], &encoded ); } #[test] fn dest_e2e() { assert_eq!(None, Destination::new(true, 0, "dest", 36)); assert_eq!(None, Destination::new(false, 128, "abc", 0)); assert!(Destination::new(false, 0, "anc", 8).is_some()); let dest = Destination::new(true, 64, "mrow", 31).unwrap(); let mut buf = [0; 256]; let encoded = dest.encode(&mut buf).unwrap(); let decoded = Destination::decode(encoded).unwrap(); assert_eq!(dest, decoded); } #[test] fn dest_ack() { let dest = Destination::new(true, 84, "abc", 17).unwrap(); assert_eq!(84, dest.ack_num()); assert!(dest.is_ack()); assert_eq!("abc", dest.callsign()); assert_eq!(17, dest.ssid()); } #[test] fn arbitrary_e2e() { let data = b"Hello world! This is an example comment"; let arbitrary = Arbitrary::new(data).unwrap(); let mut buf = [0; 256]; let encoded = arbitrary.encode(&mut buf).unwrap(); let decoded = Arbitrary::decode(encoded).unwrap(); let decoded2 = Arbitrary::decode(&buf).unwrap(); assert_eq!(data[..], decoded.0[..]); assert_eq!(data[..], decoded2.0[..]); } }