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}