Skip to content
Snippets Groups Projects
route.rs 4.7 KiB
Newer Older
use arrayvec::ArrayVec;

#[derive(Debug, PartialEq, Eq, Clone)]
pub struct Route {
    pub max_hops: u8,
    path: ArrayVec<u8, 254>,
    has_future: bool,
}

impl Route {
    pub fn new(max_hops: u8) -> Self {
        let path = ArrayVec::new();

        Self {
            max_hops,
            path,
            has_future: false,
        }
    }

    /// Returns `None` if there isn't enough space for the callsign
    /// Returns `None` if attempting to pushed is_used=true after an existing is_used=false
    /// is_future=false when this callsign has digipeated
    /// is_future=true when this callsign is expected to be part of the route, but isn't yet
    /// see the specs for more information
    pub fn push_callsign(&mut self, callsign: &str, ssid: u8, is_future: bool) -> Option<()> {
        let len = callsign.as_bytes().len() + 2;
        let free_space = self.path.capacity() - self.path.len();

        if len > free_space {
            return None;
        }

        self.has_future = self.has_future || is_future;
        if self.has_future && !is_future {
            return None;
        }

        // safe to unwrap since we already did a length check
        self.path
            .try_extend_from_slice(callsign.as_bytes())
            .unwrap();
        self.path.push(if is_future { 0xFD } else { 0xFF });
        self.path.push(ssid);

        Some(())
    }

    /// Returns `None` if there isn't enough space
    pub fn push_internet(&mut self) -> Option<()> {
        let free_space = self.path.capacity() - self.path.len();

        if free_space < 1 {
            return None;
        }

        self.path.push(0xFE);

        Some(())
    }

    pub fn iter(&'_ self) -> RouteIter<'_> {
        RouteIter::new(self)
    }

    pub fn encode<'a>(&self, buf: &'a mut [u8]) -> Option<&'a [u8]> {
        let packet_len = self.path.len() + 1;
        let buf = buf.get_mut(0..(packet_len + 1))?;
        buf[0] = packet_len.try_into().unwrap();
        buf[1] = self.max_hops;
        buf[2..(packet_len + 1)].copy_from_slice(&self.path);

        Some(buf)
    }

    pub fn decode(data: &[u8]) -> Option<Self> {
        let len: usize = (*data.first()?).into();
        let data = data.get(1..(len + 1))?;

        let max_hops = *data.first()?;

        let mut path = ArrayVec::new();
        path.try_extend_from_slice(&data[1..]).unwrap();

        let has_future = data[1..].iter().any(|x| *x == 0xFD);

            max_hops,
            path,
            has_future,
        if UntrustedRouteIter::new(&s).any(|v| v.is_err()) {
    }
}

#[derive(Debug, Eq, PartialEq)]
pub enum RouteNode<'a> {
    Internet,
    Identity(&'a str, u8, bool),
}

#[derive(Debug)]
    route: &'a Route,
    i: usize,
    fn new(route: &'a Route) -> Self {
    // Returns Err(()) if invalid
    fn maybe_next(&mut self) -> Result<RouteNode<'a>, ()> {
        let i_start = self.i;
        self.i += 1;

        if *self.route.path.get(i_start).ok_or(())? == 0xFE {
            return Ok(RouteNode::Internet);
        while *self.route.path.get(self.i).ok_or(())? != 0xFD && self.route.path[self.i] != 0xFF {
        let callsign = core::str::from_utf8(self.route.path.get(i_start..self.i).ok_or(())?)
            .map_err(|_| ())?;
        let is_future = *self.route.path.get(self.i).ok_or(())? == 0xFD;
        if self.seen_future && !is_future {
            // past after future - not allowed
            return Err(());
        self.i += 1;
        let ssid = *self.route.path.get(self.i).ok_or(())?;
        Ok(RouteNode::Identity(callsign, ssid, is_future))
    type Item = Result<RouteNode<'a>, ()>;

    fn next(&mut self) -> Option<Self::Item> {
        if self.dead {
            return None;
        }

        if self.i == self.route.path.len() {
            return None;
        }

        let r = self.maybe_next();

        if r.is_err() {
            self.dead = true;
    }
}

pub struct RouteIter<'a> {
    iter: UntrustedRouteIter<'a>,
}

impl<'a> RouteIter<'a> {
    fn new(route: &'a Route) -> Self {
        Self {
            iter: UntrustedRouteIter::new(route),
        }
    }
}

impl<'a> Iterator for RouteIter<'a> {
    type Item = RouteNode<'a>;

    fn next(&mut self) -> Option<Self::Item> {
        Some(self.iter.next()?.unwrap())