bacnet_types/data_link.rs
1//! The BACnet data links a transport can carry, as named in errors.
2
3use core::fmt;
4
5/// A BACnet data link.
6///
7/// Errors use it to say which data link an operation needs and which one an
8/// endpoint actually has, such as
9/// [`Error::UnsupportedTransport`](crate::error::Error::UnsupportedTransport).
10/// `Display` gives the short name a person would expect in a message.
11///
12/// ```
13/// use bacnet_types::data_link::DataLink;
14///
15/// assert_eq!(DataLink::Bip.to_string(), "BACnet/IP");
16/// assert_eq!(DataLink::Mstp.to_string(), "MS/TP");
17/// ```
18#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
19pub enum DataLink {
20 /// BACnet/IP over UDP (Annex J).
21 Bip,
22 /// BACnet/IPv6 over UDP (Annex U).
23 Bip6,
24 /// MS/TP over RS-485 (Clause 9).
25 Mstp,
26 /// BACnet Secure Connect over TLS WebSockets (Annex AB).
27 Sc,
28 /// BACnet over Ethernet LLC frames (Clause 7).
29 Ethernet,
30 /// An in-process loopback transport, not a wire data link.
31 Loopback,
32}
33
34impl DataLink {
35 /// The short name `Display` writes.
36 pub const fn name(self) -> &'static str {
37 match self {
38 Self::Bip => "BACnet/IP",
39 Self::Bip6 => "BACnet/IPv6",
40 Self::Mstp => "MS/TP",
41 Self::Sc => "BACnet/SC",
42 Self::Ethernet => "BACnet Ethernet",
43 Self::Loopback => "loopback",
44 }
45 }
46}
47
48impl fmt::Display for DataLink {
49 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
50 f.write_str(self.name())
51 }
52}
53
54#[cfg(test)]
55mod tests {
56 use super::*;
57
58 #[cfg(not(feature = "std"))]
59 use alloc::string::ToString;
60
61 #[test]
62 fn every_data_link_displays_its_short_name() {
63 let names = [
64 (DataLink::Bip, "BACnet/IP"),
65 (DataLink::Bip6, "BACnet/IPv6"),
66 (DataLink::Mstp, "MS/TP"),
67 (DataLink::Sc, "BACnet/SC"),
68 (DataLink::Ethernet, "BACnet Ethernet"),
69 (DataLink::Loopback, "loopback"),
70 ];
71 for (link, name) in names {
72 assert_eq!(link.name(), name);
73 assert_eq!(link.to_string(), name);
74 }
75 }
76}