use crate::{BDT_ENTRY_LENGTH, BIP_ADDRESS_LENGTH, FDT_ENTRY_LENGTH};
macro_rules! named_codes {
(
$(#[$meta:meta])*
pub struct $Name:ident($inner:ty);
$(
$(#[$vmeta:meta])*
const $VARIANT:ident = $val:expr;
)*
) => {
$(#[$meta])*
#[derive(Clone, Copy, PartialEq, Eq, Hash)]
pub struct $Name($inner);
impl $Name {
$(
$(#[$vmeta])*
#[doc = ""]
#[doc = concat!("Wire value `", stringify!($val), "`.")]
pub const $VARIANT: Self = Self($val);
)*
pub const ALL_NAMED: &[(&str, Self)] = &[
$( (stringify!($VARIANT), Self($val)), )*
];
#[inline]
#[must_use]
pub const fn from_raw(value: $inner) -> Self {
Self(value)
}
#[inline]
#[must_use]
pub const fn to_raw(self) -> $inner {
self.0
}
#[must_use]
pub const fn name(self) -> Option<&'static str> {
match self.0 {
$( $val => Some(stringify!($VARIANT)), )*
_ => None,
}
}
#[must_use]
pub const fn is_defined(self) -> bool {
self.name().is_some()
}
}
impl core::fmt::Debug for $Name {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
match self.name() {
Some(name) => write!(f, "{}::{}", stringify!($Name), name),
None => write!(f, "{}({})", stringify!($Name), self.0),
}
}
}
impl core::fmt::Display for $Name {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
match self.name() {
Some(name) => f.write_str(name),
None => write!(f, "{}", self.0),
}
}
}
};
}
pub(crate) use named_codes;
named_codes! {
pub struct BvlcFunction(u8);
const BVLC_RESULT = 0x00;
const WRITE_BROADCAST_DISTRIBUTION_TABLE = 0x01;
const READ_BROADCAST_DISTRIBUTION_TABLE = 0x02;
const READ_BROADCAST_DISTRIBUTION_TABLE_ACK = 0x03;
const FORWARDED_NPDU = 0x04;
const REGISTER_FOREIGN_DEVICE = 0x05;
const READ_FOREIGN_DEVICE_TABLE = 0x06;
const READ_FOREIGN_DEVICE_TABLE_ACK = 0x07;
const DELETE_FOREIGN_DEVICE_TABLE_ENTRY = 0x08;
const DISTRIBUTE_BROADCAST_TO_NETWORK = 0x09;
const ORIGINAL_UNICAST_NPDU = 0x0A;
const ORIGINAL_BROADCAST_NPDU = 0x0B;
}
named_codes! {
pub struct BvlcResultCode(u16);
const SUCCESSFUL_COMPLETION = 0x0000;
const WRITE_BROADCAST_DISTRIBUTION_TABLE_NAK = 0x0010;
const READ_BROADCAST_DISTRIBUTION_TABLE_NAK = 0x0020;
const REGISTER_FOREIGN_DEVICE_NAK = 0x0030;
const READ_FOREIGN_DEVICE_TABLE_NAK = 0x0040;
const DELETE_FOREIGN_DEVICE_TABLE_ENTRY_NAK = 0x0050;
const DISTRIBUTE_BROADCAST_TO_NETWORK_NAK = 0x0060;
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum PayloadShape {
Fixed(usize),
Table {
entry_length: usize,
},
Npdu {
prefix: usize,
},
}
impl PayloadShape {
#[must_use]
pub const fn admits(self, length: usize) -> bool {
match self {
Self::Fixed(fixed) => length == fixed,
Self::Table { entry_length } => length.is_multiple_of(entry_length),
Self::Npdu { prefix } => length >= prefix,
}
}
}
impl BvlcFunction {
#[must_use]
pub const fn payload_shape(self) -> Option<PayloadShape> {
Some(match self {
Self::BVLC_RESULT | Self::REGISTER_FOREIGN_DEVICE => PayloadShape::Fixed(2),
Self::READ_BROADCAST_DISTRIBUTION_TABLE | Self::READ_FOREIGN_DEVICE_TABLE => {
PayloadShape::Fixed(0)
}
Self::DELETE_FOREIGN_DEVICE_TABLE_ENTRY => PayloadShape::Fixed(BIP_ADDRESS_LENGTH),
Self::WRITE_BROADCAST_DISTRIBUTION_TABLE
| Self::READ_BROADCAST_DISTRIBUTION_TABLE_ACK => PayloadShape::Table {
entry_length: BDT_ENTRY_LENGTH,
},
Self::READ_FOREIGN_DEVICE_TABLE_ACK => PayloadShape::Table {
entry_length: FDT_ENTRY_LENGTH,
},
Self::FORWARDED_NPDU => PayloadShape::Npdu {
prefix: BIP_ADDRESS_LENGTH,
},
Self::DISTRIBUTE_BROADCAST_TO_NETWORK
| Self::ORIGINAL_UNICAST_NPDU
| Self::ORIGINAL_BROADCAST_NPDU => PayloadShape::Npdu { prefix: 0 },
_ => return None,
})
}
#[must_use]
pub const fn nak(self) -> Option<BvlcResultCode> {
Some(match self {
Self::WRITE_BROADCAST_DISTRIBUTION_TABLE => {
BvlcResultCode::WRITE_BROADCAST_DISTRIBUTION_TABLE_NAK
}
Self::READ_BROADCAST_DISTRIBUTION_TABLE => {
BvlcResultCode::READ_BROADCAST_DISTRIBUTION_TABLE_NAK
}
Self::REGISTER_FOREIGN_DEVICE => BvlcResultCode::REGISTER_FOREIGN_DEVICE_NAK,
Self::READ_FOREIGN_DEVICE_TABLE => BvlcResultCode::READ_FOREIGN_DEVICE_TABLE_NAK,
Self::DELETE_FOREIGN_DEVICE_TABLE_ENTRY => {
BvlcResultCode::DELETE_FOREIGN_DEVICE_TABLE_ENTRY_NAK
}
Self::DISTRIBUTE_BROADCAST_TO_NETWORK => {
BvlcResultCode::DISTRIBUTE_BROADCAST_TO_NETWORK_NAK
}
_ => return None,
})
}
}