Skip to main content

bacnet_bip_codec/ipv6/
error.rs

1//! Typed failures emitted by the B/IPv6 BVLL codec.
2
3use core::fmt;
4
5use super::Bvlc6Function;
6use crate::SinkFull;
7
8/// A B/IPv6 BVLL message could not be decoded or encoded.
9///
10/// The variants mirror [`BvllError`](crate::BvllError)'s, for Annex U's
11/// type octet, address length and functions; B/IPv6 messages carry no
12/// tables. Each one names the direction it comes from. None of them
13/// allocates, so the type is `Copy`. Later releases may add variants, so a
14/// match outside this crate needs a wildcard arm.
15#[derive(Debug, Clone, Copy, PartialEq, Eq)]
16#[non_exhaustive]
17pub enum Bvll6Error {
18    /// Decode: the datagram is shorter than the 4-octet BVLL header.
19    TooShort {
20        /// Octets in the datagram.
21        length: usize,
22    },
23    /// Decode: the BVLC Type octet is not 0x82, so the datagram is not a
24    /// B/IPv6 BVLL message (Annex U.2).
25    NotBip6 {
26        /// The type octet received.
27        bvlc_type: u8,
28    },
29    /// Decode: the Length field disagrees with the datagram. It counts the
30    /// whole message, header included (Annex U.2), so a datagram cut short
31    /// and one with octets after the message both fail here.
32    LengthMismatch {
33        /// Length the header declares.
34        declared: usize,
35        /// Octets in the datagram.
36        received: usize,
37    },
38    /// Decode: a function code Annex U.2 doesn't define, so its payload has
39    /// no known layout.
40    UnknownFunction {
41        /// The function octet.
42        function: u8,
43    },
44    /// Decode: the payload doesn't fit its function's layout (see
45    /// [`Bvlc6Function::payload_shape`]).
46    PayloadLength {
47        /// The message's function.
48        function: Bvlc6Function,
49        /// Octets after the header.
50        length: usize,
51    },
52    /// A B/IPv6 address that is not 18 octets long (Annex U.1.1.2).
53    AddressLength {
54        /// Octets supplied.
55        length: usize,
56    },
57    /// Encode: the message is longer than its 16-bit Length field can state.
58    TooLong {
59        /// Octets the message would take.
60        length: usize,
61    },
62    /// Encode: a BVLC-Result whose code Annex U.2.1.1 doesn't define.
63    UndefinedResultCode {
64        /// The code supplied.
65        code: u16,
66    },
67    /// Encode: the sink has no room for the message. Nothing was written to
68    /// a sink with a fixed capacity.
69    BufferExhausted {
70        /// Octets the write needed.
71        needed: usize,
72        /// Room the sink had.
73        available: usize,
74    },
75}
76
77impl fmt::Display for Bvll6Error {
78    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
79        match self {
80            Self::TooShort { length } => write!(
81                f,
82                "BVLC6 datagram too short: {length} octets, header needs 4"
83            ),
84            Self::NotBip6 { bvlc_type } => {
85                write!(f, "BVLC type {bvlc_type:#04X} is not B/IPv6 (0x82)")
86            }
87            Self::LengthMismatch { declared, received } => write!(
88                f,
89                "BVLC6 length {declared} does not match the {received}-octet datagram"
90            ),
91            Self::UnknownFunction { function } => {
92                write!(f, "unknown BVLC6 function {function:#04X}")
93            }
94            Self::PayloadLength { function, length } => {
95                write!(f, "{function} cannot carry a {length}-octet payload")
96            }
97            Self::AddressLength { length } => {
98                write!(f, "B/IPv6 address must be 18 octets, got {length}")
99            }
100            Self::TooLong { length } => write!(
101                f,
102                "BVLC6 message of {length} octets exceeds the 16-bit BVLC6 length field"
103            ),
104            Self::UndefinedResultCode { code } => {
105                write!(f, "BVLC6 result code {code:#06X} is not defined")
106            }
107            Self::BufferExhausted { needed, available } => {
108                write!(f, "buffer exhausted: need {needed}, have {available}")
109            }
110        }
111    }
112}
113
114impl core::error::Error for Bvll6Error {}
115
116impl From<SinkFull> for Bvll6Error {
117    fn from(full: SinkFull) -> Self {
118        Self::BufferExhausted {
119            needed: full.needed,
120            available: full.available,
121        }
122    }
123}