Skip to main content

bacnet_npdu/
priority.rs

1//! [`NetworkPriority`]: the two priority bits of an NPDU's control octet.
2
3use core::fmt;
4
5/// An NPDU's network priority (Clause 6.2.2): the control octet's two low
6/// bits, in increasing order of urgency.
7///
8/// The field is two bits wide, so the set is closed: every value has a
9/// variant. [`from_control`](Self::from_control) reads the bits from a
10/// control octet, `try_from` takes a value that must be 0 to 3, and
11/// [`to_raw`](Self::to_raw) (or `u8::from`) gives the value back. The order
12/// is the numeric one, so [`LifeSafety`](Self::LifeSafety) compares
13/// greatest, and a queue that serves the greatest first serves it first.
14///
15/// ```
16/// use bacnet_npdu::NetworkPriority;
17///
18/// assert_eq!(NetworkPriority::try_from(3), Ok(NetworkPriority::LifeSafety));
19/// assert_eq!(NetworkPriority::from_control(0x06), NetworkPriority::CriticalEquipment);
20/// assert_eq!(u8::from(NetworkPriority::Urgent), 1);
21/// assert!(NetworkPriority::try_from(4).is_err());
22/// assert!(NetworkPriority::LifeSafety > NetworkPriority::Normal);
23/// ```
24#[repr(u8)]
25#[derive(Clone, Copy, Debug, Default, Eq, Ord, PartialEq, PartialOrd, Hash)]
26pub enum NetworkPriority {
27    /// Normal traffic (`0`), the default.
28    #[default]
29    Normal = 0,
30    /// Urgent traffic (`1`).
31    Urgent = 1,
32    /// Critical-equipment traffic (`2`).
33    CriticalEquipment = 2,
34    /// Life-safety traffic (`3`).
35    LifeSafety = 3,
36}
37
38impl NetworkPriority {
39    /// Every priority, in increasing order.
40    pub const ALL: [Self; 4] = [
41        Self::Normal,
42        Self::Urgent,
43        Self::CriticalEquipment,
44        Self::LifeSafety,
45    ];
46
47    /// The priority a control octet carries in its two low bits; the other
48    /// bits are ignored.
49    #[must_use]
50    pub const fn from_control(control: u8) -> Self {
51        match control & 0x03 {
52            0 => Self::Normal,
53            1 => Self::Urgent,
54            2 => Self::CriticalEquipment,
55            _ => Self::LifeSafety,
56        }
57    }
58
59    /// The numeric value, 0 to 3: the control octet's two low bits.
60    #[must_use]
61    pub const fn to_raw(self) -> u8 {
62        self as u8
63    }
64}
65
66/// The numeric value, 0 to 3; anything else is refused.
67impl TryFrom<u8> for NetworkPriority {
68    type Error = PriorityError;
69
70    fn try_from(value: u8) -> Result<Self, Self::Error> {
71        if value > 3 {
72            return Err(PriorityError { value });
73        }
74        Ok(Self::from_control(value))
75    }
76}
77
78/// The numeric value, 0 to 3.
79impl From<NetworkPriority> for u8 {
80    fn from(priority: NetworkPriority) -> Self {
81        priority.to_raw()
82    }
83}
84
85/// A value [`NetworkPriority::try_from`] refuses: a network priority is two
86/// bits, 0 to 3.
87#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)]
88#[non_exhaustive]
89pub struct PriorityError {
90    /// The value offered.
91    pub value: u8,
92}
93
94impl fmt::Display for PriorityError {
95    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
96        write!(f, "network priority {} is not 0 to 3", self.value)
97    }
98}
99
100impl core::error::Error for PriorityError {}