bacnet_npdu/reject.rs
1//! [`RejectMessageToNetwork`]: the data a Reject-Message-To-Network carries.
2
3use core::fmt;
4
5use crate::RejectMessageReason;
6
7/// What a Reject-Message-To-Network carries after its type (Clause 6.4.4):
8/// one reason octet, then the two-octet network the refused message was for.
9///
10/// It is the one reader and writer of that data in the stack: the router
11/// core, the hosted network layer and the client all go through it. It
12/// checks layout only; whether the enclosing NPDU is a reject is the
13/// caller's question, and so is what the reason means for a route.
14///
15/// ```
16/// use bacnet_npdu::{RejectMessageReason, RejectMessageToNetwork};
17///
18/// let reject = RejectMessageToNetwork::decode(&[4, 0x0B, 0xB8])?;
19/// assert_eq!(reject.reason, RejectMessageReason::MESSAGE_TOO_LONG);
20/// assert_eq!(reject.network, 3000);
21/// assert_eq!(reject.to_bytes(), [4, 0x0B, 0xB8]);
22/// # Ok::<(), bacnet_npdu::RejectLengthError>(())
23/// ```
24#[derive(Debug, Clone, Copy, PartialEq, Eq)]
25pub struct RejectMessageToNetwork {
26 /// Why the message was refused. The set is open: an octet the standard
27 /// doesn't name is kept as received.
28 pub reason: RejectMessageReason,
29 /// The network the refused message was for (its DNET).
30 pub network: u16,
31}
32
33impl RejectMessageToNetwork {
34 /// The data's length, in octets.
35 pub const LEN: usize = 3;
36
37 /// Read exactly a reason octet and a network number. Any other length
38 /// is refused, so a router never acts on a cut-short or padded reject.
39 pub const fn decode(payload: &[u8]) -> Result<Self, RejectLengthError> {
40 match *payload {
41 [reason, high, low] => Ok(Self {
42 reason: RejectMessageReason::from_raw(reason),
43 network: u16::from_be_bytes([high, low]),
44 }),
45 _ => Err(RejectLengthError {
46 length: payload.len(),
47 }),
48 }
49 }
50
51 /// The data, as sent.
52 #[must_use]
53 pub const fn to_bytes(self) -> [u8; Self::LEN] {
54 let [high, low] = self.network.to_be_bytes();
55 [self.reason.to_raw(), high, low]
56 }
57}
58
59/// A Reject-Message-To-Network's data isn't
60/// [`RejectMessageToNetwork::LEN`] octets: it ends inside the network, or
61/// goes on past it.
62///
63/// It is `#[non_exhaustive]`: only the crate builds one.
64#[derive(Debug, Clone, Copy, PartialEq, Eq)]
65#[non_exhaustive]
66pub struct RejectLengthError {
67 /// The data's length, in octets.
68 pub length: usize,
69}
70
71impl fmt::Display for RejectLengthError {
72 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
73 write!(
74 f,
75 "a reject's data is {} octets, not {}",
76 self.length,
77 RejectMessageToNetwork::LEN
78 )
79 }
80}
81
82impl core::error::Error for RejectLengthError {}