#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[repr(u8)]
pub enum MsgType {
TaskRoute = 0x01,
SyncCrdt = 0x02,
DeviceOrch = 0x03,
DhtFindNode = 0x10,
DhtGetValue = 0x11,
DhtPutValue = 0x12,
GossipBroadcast = 0x20,
GossipSubscribe = 0x21,
ProvisionRequest = 0x30,
ProvisionCert = 0x31,
ProvisionRevoke = 0x32,
}
impl MsgType {
pub const fn from_byte(b: u8) -> Option<MsgType> {
match b {
0x01 => Some(MsgType::TaskRoute),
0x02 => Some(MsgType::SyncCrdt),
0x03 => Some(MsgType::DeviceOrch),
0x10 => Some(MsgType::DhtFindNode),
0x11 => Some(MsgType::DhtGetValue),
0x12 => Some(MsgType::DhtPutValue),
0x20 => Some(MsgType::GossipBroadcast),
0x21 => Some(MsgType::GossipSubscribe),
0x30 => Some(MsgType::ProvisionRequest),
0x31 => Some(MsgType::ProvisionCert),
0x32 => Some(MsgType::ProvisionRevoke),
_ => None,
}
}
pub const fn as_byte(self) -> u8 {
self as u8
}
pub const fn range_of(b: u8) -> MsgRange {
match b {
0x01..=0x0F => MsgRange::Core,
0x10..=0x1F => MsgRange::Dht,
0x20..=0x2F => MsgRange::Gossip,
0x30..=0x3F => MsgRange::Provisioning,
0x40..=0x4F => MsgRange::Heartbeat,
0xF0..=0xFF => MsgRange::Vendor,
_ => MsgRange::Unknown,
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum MsgRange {
Core,
Dht,
Gossip,
Provisioning,
Heartbeat,
Vendor,
Unknown,
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn all_variants_roundtrip() {
let variants = [
MsgType::TaskRoute,
MsgType::SyncCrdt,
MsgType::DeviceOrch,
MsgType::DhtFindNode,
MsgType::DhtGetValue,
MsgType::DhtPutValue,
MsgType::GossipBroadcast,
MsgType::GossipSubscribe,
MsgType::ProvisionRequest,
MsgType::ProvisionCert,
MsgType::ProvisionRevoke,
];
for v in variants {
assert_eq!(
MsgType::from_byte(v.as_byte()),
Some(v),
"roundtrip failed for {:?}",
v
);
}
}
#[test]
fn byte_values_are_stable() {
assert_eq!(MsgType::TaskRoute.as_byte(), 0x01);
assert_eq!(MsgType::SyncCrdt.as_byte(), 0x02);
assert_eq!(MsgType::DeviceOrch.as_byte(), 0x03);
assert_eq!(MsgType::DhtFindNode.as_byte(), 0x10);
assert_eq!(MsgType::DhtGetValue.as_byte(), 0x11);
assert_eq!(MsgType::DhtPutValue.as_byte(), 0x12);
assert_eq!(MsgType::GossipBroadcast.as_byte(), 0x20);
assert_eq!(MsgType::GossipSubscribe.as_byte(), 0x21);
assert_eq!(MsgType::ProvisionRequest.as_byte(), 0x30);
assert_eq!(MsgType::ProvisionCert.as_byte(), 0x31);
assert_eq!(MsgType::ProvisionRevoke.as_byte(), 0x32);
}
#[test]
fn from_byte_returns_none_for_unknown() {
assert_eq!(MsgType::from_byte(0x00), None);
assert_eq!(MsgType::from_byte(0x04), None); assert_eq!(MsgType::from_byte(0x13), None); assert_eq!(MsgType::from_byte(0x80), None);
assert_eq!(MsgType::from_byte(0xFF), None);
}
#[test]
fn range_boundaries() {
assert_eq!(MsgType::range_of(0x01), MsgRange::Core);
assert_eq!(MsgType::range_of(0x0F), MsgRange::Core);
assert_eq!(MsgType::range_of(0x10), MsgRange::Dht);
assert_eq!(MsgType::range_of(0x1F), MsgRange::Dht);
assert_eq!(MsgType::range_of(0x20), MsgRange::Gossip);
assert_eq!(MsgType::range_of(0x2F), MsgRange::Gossip);
assert_eq!(MsgType::range_of(0x30), MsgRange::Provisioning);
assert_eq!(MsgType::range_of(0x3F), MsgRange::Provisioning);
assert_eq!(MsgType::range_of(0x40), MsgRange::Heartbeat);
assert_eq!(MsgType::range_of(0x4F), MsgRange::Heartbeat);
assert_eq!(MsgType::range_of(0xF0), MsgRange::Vendor);
assert_eq!(MsgType::range_of(0xFF), MsgRange::Vendor);
}
#[test]
fn gaps_are_unknown() {
assert_eq!(MsgType::range_of(0x00), MsgRange::Unknown);
assert_eq!(MsgType::range_of(0x50), MsgRange::Unknown);
assert_eq!(MsgType::range_of(0x80), MsgRange::Unknown);
assert_eq!(MsgType::range_of(0xEF), MsgRange::Unknown);
}
#[test]
fn defined_variants_in_correct_range() {
assert_eq!(
MsgType::range_of(MsgType::TaskRoute.as_byte()),
MsgRange::Core
);
assert_eq!(
MsgType::range_of(MsgType::SyncCrdt.as_byte()),
MsgRange::Core
);
assert_eq!(
MsgType::range_of(MsgType::DeviceOrch.as_byte()),
MsgRange::Core
);
assert_eq!(
MsgType::range_of(MsgType::DhtFindNode.as_byte()),
MsgRange::Dht
);
assert_eq!(
MsgType::range_of(MsgType::DhtGetValue.as_byte()),
MsgRange::Dht
);
assert_eq!(
MsgType::range_of(MsgType::DhtPutValue.as_byte()),
MsgRange::Dht
);
assert_eq!(
MsgType::range_of(MsgType::GossipBroadcast.as_byte()),
MsgRange::Gossip
);
assert_eq!(
MsgType::range_of(MsgType::GossipSubscribe.as_byte()),
MsgRange::Gossip
);
assert_eq!(
MsgType::range_of(MsgType::ProvisionRequest.as_byte()),
MsgRange::Provisioning
);
assert_eq!(
MsgType::range_of(MsgType::ProvisionCert.as_byte()),
MsgRange::Provisioning
);
assert_eq!(
MsgType::range_of(MsgType::ProvisionRevoke.as_byte()),
MsgRange::Provisioning
);
}
}