Newer
Older
#[derive(Debug, PartialEq, Eq, Clone)]
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
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 mut path = ArrayVec::new();
path.try_extend_from_slice(&data[1..]).unwrap();
let has_future = data[1..].iter().any(|x| *x == 0xFD);

Stephen D
committed
let s = Self {

Stephen D
committed
};
if UntrustedRouteIter::new(&s).any(|v| v.is_err()) {

Stephen D
committed
return None;
}
Some(s)
}
}
#[derive(Debug, Eq, PartialEq)]
pub enum RouteNode<'a> {
Internet,
Identity(&'a str, u8, bool),
}
#[derive(Debug)]

Stephen D
committed
struct UntrustedRouteIter<'a> {

Stephen D
committed
seen_future: bool,
dead: bool,

Stephen D
committed
impl<'a> UntrustedRouteIter<'a> {

Stephen D
committed
Self {
route,
i: 0,
seen_future: false,
dead: false,
}
// 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(|_| ())?;

Stephen D
committed
let is_future = *self.route.path.get(self.i).ok_or(())? == 0xFD;

Stephen D
committed
if self.seen_future && !is_future {
// past after future - not allowed

Stephen D
committed
}
self.seen_future |= is_future;
let ssid = *self.route.path.get(self.i).ok_or(())?;
Ok(RouteNode::Identity(callsign, ssid, is_future))

Stephen D
committed
}
}
impl<'a> Iterator for UntrustedRouteIter<'a> {

Stephen D
committed
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;

Stephen D
committed
}

Stephen D
committed
}
}
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())