Skip to content
Snippets Groups Projects
Select Git revision
  • 1b1dfcfb469fdeded748c65e1bdb9a5a1b1ab457
  • master default protected
2 results

mod.rs

Blame
  • Forked from CATS / ham-cats
    Source project has a limited visibility.
    mod.rs 12.03 KiB
    mod arbitrary;
    mod comment;
    mod destination;
    mod gps;
    mod identification;
    mod route;
    mod timestamp;
    mod unknown;
    
    use crate::error::DecodeError;
    
    pub use self::{
        arbitrary::Arbitrary,
        comment::Comment,
        destination::Destination,
        gps::Gps,
        identification::Identification,
        route::{Route, RouteIter, RouteNode},
        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;
    
    #[derive(Debug)]
    pub enum Whisker {
        Identification(Identification),
        Timestamp(Timestamp),
        Gps(Gps),
        Comment(Comment),
        Route(Route),
        Destination(Destination),
        Arbitrary(Arbitrary),
        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 })?,
                ),
    
                // 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<'a> Iterator for WhiskerIter<'a> {
        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<'a> Iterator for ValidatedWhiskerIter<'a> {
        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::whisker::route::RouteNode;
    
        use super::*;
    
        #[test]
        fn ident_e2e() {
            let icon = 2738;
            let call = "VE9ABCDEFGZZ4839-???";
            let ssid = 17;
    
            let ident = Identification::new(icon, call, ssid).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!(120.9375, gps.heading());
        }
    
        #[test]
        fn gps_max_heading() {
            let gps = Gps::new(
                4.0,
                23.45,
                f16::from_f32(45.02),
                24,
                360.0,
                f16::from_f32(12.3),
            );
    
            assert_eq!(357.1875, 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_callsign("VE2XYZ", 23, false).unwrap();
            route.push_internet().unwrap();
            route.push_internet().unwrap();
            route.push_internet().unwrap();
            route.push_callsign("VE9AAAAA", 94, true).unwrap();
            assert!(route.push_callsign("VE9AAAAA", 94, false).is_none());
    
            // too long
            assert!(route
                .push_callsign(
                    "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,
                    true,
                ).is_none());
    
            route
                .push_callsign("This is the last callsign", 0, true)
                .unwrap();
            route.push_internet().unwrap();
    
            let mut iter = route.iter();
            assert_eq!(
                RouteNode::Identity("VE2XYZ", 23, false),
                iter.next().unwrap()
            );
            assert_eq!(RouteNode::Internet, iter.next().unwrap());
            assert_eq!(RouteNode::Internet, iter.next().unwrap());
            assert_eq!(RouteNode::Internet, iter.next().unwrap());
            assert_eq!(
                RouteNode::Identity("VE9AAAAA", 94, true),
                iter.next().unwrap()
            );
            assert_eq!(
                RouteNode::Identity("This is the last callsign", 0, true),
                iter.next().unwrap()
            );
            assert_eq!(RouteNode::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_callsign("VE2XYZ", 23, false).unwrap();
            route.push_internet().unwrap();
            route.push_internet().unwrap();
            route.push_internet().unwrap();
            route.push_callsign("VE9AAAAA", 94, true).unwrap();
            route
                .push_callsign("This is the last callsign", 0, true)
                .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_callsign("VE1ABC", 0, false);
            ex1.push_callsign("VE2DEF", 234, false);
            ex1.push_callsign("VE3XYZ", 14, false);
    
            let mut buf = [0; 256];
            let encoded = ex1.encode(&mut buf).unwrap();
            assert_eq!(
                &[
                    0x19, 0x04, 0x56, 0x45, 0x31, 0x41, 0x42, 0x43, 0xFF, 0x00, 0x56, 0x45, 0x32, 0x44,
                    0x45, 0x46, 0xFF, 0xEA, 0x56, 0x45, 0x33, 0x58, 0x59, 0x5A, 0xFF, 0x0E
                ],
                &encoded
            );
    
            let mut ex2 = Route::new(3);
            ex2.push_callsign("VE1ABC", 0, false);
            ex2.push_internet();
            ex2.push_callsign("VE2DEF", 234, false);
            ex2.push_internet();
            ex2.push_callsign("VE3XYZ", 14, false);
    
            let encoded = ex2.encode(&mut buf).unwrap();
            assert_eq!(
                &[
                    0x1B, 0x03, 0x56, 0x45, 0x31, 0x41, 0x42, 0x43, 0xFF, 0x00, 0xFE, 0x56, 0x45, 0x32,
                    0x44, 0x45, 0x46, 0xFF, 0xEA, 0xFE, 0x56, 0x45, 0x33, 0x58, 0x59, 0x5A, 0xFF, 0x0E
                ],
                &encoded
            );
    
            let mut ex3 = Route::new(0);
            ex3.push_callsign("VE1ABC", 0, false);
            ex3.push_internet();
            ex3.push_internet();
    
            let encoded = ex3.encode(&mut buf).unwrap();
            assert_eq!(
                &[0x0B, 0x00, 0x56, 0x45, 0x31, 0x41, 0x42, 0x43, 0xFF, 0x00, 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 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[..]);
        }
    }