use super::constants::{RIP_AFI_AUTH, RIP_AFI_IP};
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum RipCommandStatus {
Assigned,
Obsolete,
Reserved,
Unassigned,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct RipCommandMeta {
pub code: u8,
pub name: &'static str,
pub status: RipCommandStatus,
}
pub const fn rip_command_meta(code: u8) -> RipCommandMeta {
let (name, status) = match code {
1 => ("Request", RipCommandStatus::Assigned),
2 => ("Response", RipCommandStatus::Assigned),
3 => ("Traceon", RipCommandStatus::Obsolete),
4 => ("Traceoff", RipCommandStatus::Obsolete),
5 => ("Sun reserved", RipCommandStatus::Reserved),
6 => ("Triggered Request", RipCommandStatus::Reserved),
7 => ("Triggered Response", RipCommandStatus::Reserved),
8 => ("Triggered Acknowledgement", RipCommandStatus::Reserved),
9 => ("Update Request", RipCommandStatus::Assigned),
10 => ("Update Response", RipCommandStatus::Assigned),
11 => ("Update Acknowledge", RipCommandStatus::Assigned),
_ => ("Unassigned", RipCommandStatus::Unassigned),
};
RipCommandMeta { code, name, status }
}
pub const fn rip_command_name(code: u8) -> Option<&'static str> {
let meta = rip_command_meta(code);
match meta.status {
RipCommandStatus::Unassigned => None,
_ => Some(meta.name),
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum RipAddressFamily {
Ip,
AuthMarker,
Other(u16),
}
pub const fn rip_address_family(afi: u16) -> RipAddressFamily {
match afi {
RIP_AFI_IP => RipAddressFamily::Ip,
RIP_AFI_AUTH => RipAddressFamily::AuthMarker,
other => RipAddressFamily::Other(other),
}
}
pub const fn is_rip_auth_marker(afi: u16) -> bool {
afi == RIP_AFI_AUTH
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum RipAuthType {
SimplePassword,
KeyedMessageDigest,
Other(u16),
}
pub const RIP_AUTH_TYPE_SIMPLE: u16 = 2;
pub const RIP_AUTH_TYPE_KEYED_DIGEST: u16 = 3;
pub const fn rip_auth_type(value: u16) -> RipAuthType {
match value {
RIP_AUTH_TYPE_SIMPLE => RipAuthType::SimplePassword,
RIP_AUTH_TYPE_KEYED_DIGEST => RipAuthType::KeyedMessageDigest,
other => RipAuthType::Other(other),
}
}
pub const fn rip_auth_type_code(kind: RipAuthType) -> u16 {
match kind {
RipAuthType::SimplePassword => RIP_AUTH_TYPE_SIMPLE,
RipAuthType::KeyedMessageDigest => RIP_AUTH_TYPE_KEYED_DIGEST,
RipAuthType::Other(value) => value,
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn rip_command_registry_classifies_codes() {
assert_eq!(rip_command_meta(1).status, RipCommandStatus::Assigned);
assert_eq!(rip_command_name(1), Some("Request"));
assert_eq!(rip_command_meta(2).status, RipCommandStatus::Assigned);
assert_eq!(rip_command_name(2), Some("Response"));
assert_eq!(rip_command_meta(9).status, RipCommandStatus::Assigned);
assert_eq!(rip_command_name(9), Some("Update Request"));
assert_eq!(rip_command_meta(10).status, RipCommandStatus::Assigned);
assert_eq!(rip_command_name(10), Some("Update Response"));
assert_eq!(rip_command_meta(11).status, RipCommandStatus::Assigned);
assert_eq!(rip_command_name(11), Some("Update Acknowledge"));
assert_eq!(rip_command_meta(200).status, RipCommandStatus::Unassigned);
assert_eq!(rip_command_name(200), None);
}
#[test]
fn rip_command_registry_covers_every_code_without_panic() {
for code in 0u8..=255 {
let meta = rip_command_meta(code);
assert_eq!(meta.code, code);
assert!(!meta.name.is_empty());
match meta.status {
RipCommandStatus::Unassigned => assert_eq!(rip_command_name(code), None),
_ => assert_eq!(rip_command_name(code), Some(meta.name)),
}
}
}
#[test]
fn rip_address_family_classifies_ip_and_auth() {
assert_eq!(rip_address_family(2), RipAddressFamily::Ip);
assert_eq!(rip_address_family(0xFFFF), RipAddressFamily::AuthMarker);
assert_eq!(rip_address_family(7), RipAddressFamily::Other(7));
assert!(is_rip_auth_marker(0xFFFF));
}
#[test]
fn rip_auth_type_roundtrips() {
assert_eq!(
rip_auth_type(RIP_AUTH_TYPE_SIMPLE),
RipAuthType::SimplePassword
);
assert_eq!(
rip_auth_type_code(RipAuthType::SimplePassword),
RIP_AUTH_TYPE_SIMPLE
);
assert_eq!(rip_auth_type_code(rip_auth_type(2)), 2);
assert_eq!(
rip_auth_type(RIP_AUTH_TYPE_KEYED_DIGEST),
RipAuthType::KeyedMessageDigest
);
assert_eq!(
rip_auth_type_code(RipAuthType::KeyedMessageDigest),
RIP_AUTH_TYPE_KEYED_DIGEST
);
assert_eq!(rip_auth_type_code(rip_auth_type(3)), 3);
assert_eq!(rip_auth_type(42), RipAuthType::Other(42));
assert_eq!(rip_auth_type_code(RipAuthType::Other(42)), 42);
assert_eq!(rip_auth_type_code(rip_auth_type(42)), 42);
}
}