#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
pub struct NetworkNumber {
number: u16,
quality: u8,
}
impl NetworkNumber {
pub const fn configured(number: u16) -> Option<Self> {
if number == u16::MAX {
return None;
}
Some(Self {
number,
quality: if number == 0 { 0 } else { 3 },
})
}
pub fn snapshot(self) -> (u16, u8) {
(self.number, self.quality)
}
pub fn observe(&mut self, number: u16, flag: u8) -> Observation {
if number == 0 || number == u16::MAX || flag > 1 {
return Observation::Ignored;
}
if self.quality == 3 {
return if flag == 1 && number != self.number {
Observation::ConfiguredConflict
} else {
Observation::Ignored
};
}
if flag == 1 || self.quality < 2 {
self.number = number;
self.quality = if flag == 1 { 2 } else { 1 };
Observation::Applied
} else {
Observation::Ignored
}
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum Observation {
Applied,
Ignored,
ConfiguredConflict,
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn network_number_quality_precedence_and_numeric_policy() {
assert_eq!(NetworkNumber::configured(u16::MAX), None);
let mut state = NetworkNumber::default();
assert_eq!(state.snapshot(), (0, 0));
for (number, flag, expected) in [
(10, 0, (10, 1)),
(11, 0, (11, 1)),
(11, 1, (11, 2)),
(11, 0, (11, 2)),
(12, 0, (11, 2)),
(12, 1, (12, 2)),
(0, 1, (12, 2)),
(65535, 1, (12, 2)),
(15, 2, (12, 2)),
(65534, 1, (65534, 2)),
(1, 1, (1, 2)),
] {
state.observe(number, flag);
assert_eq!(state.snapshot(), expected);
}
let mut configured = NetworkNumber::configured(17).unwrap();
assert_eq!(configured.observe(18, 1), Observation::ConfiguredConflict);
configured.observe(19, 0);
assert_eq!(configured.snapshot(), (17, 3));
assert_eq!(NetworkNumber::configured(0).unwrap().snapshot(), (0, 0));
}
}