Skip to main content

rustbac_datalink/
address.rs

1use core::fmt;
2use std::net::{IpAddr, Ipv4Addr, SocketAddr};
3
4/// A data-link-layer address identifying a BACnet peer.
5#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
6#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
7pub enum DataLinkAddress {
8    /// A BACnet/IP endpoint (IPv4 or IPv6 socket address).
9    Ip(SocketAddr),
10    /// An MS/TP node MAC address (0–127, or 255 for broadcast).
11    Mstp(u8),
12}
13
14impl DataLinkAddress {
15    /// The default BACnet/IP UDP port (`0xBAC0` = 47808).
16    pub const BACNET_IP_DEFAULT_PORT: u16 = 47808;
17
18    /// Returns a broadcast address on the given port.
19    pub fn local_broadcast(port: u16) -> Self {
20        Self::Ip(SocketAddr::new(IpAddr::V4(Ipv4Addr::BROADCAST), port))
21    }
22
23    pub fn bacnet_default(addr: IpAddr) -> Self {
24        Self::Ip(SocketAddr::new(addr, Self::BACNET_IP_DEFAULT_PORT))
25    }
26
27    /// Returns the inner [`SocketAddr`] if this is an `Ip` address.
28    ///
29    /// # Panics
30    ///
31    /// Panics if called on an `Mstp` address.
32    pub fn as_socket_addr(self) -> SocketAddr {
33        match self {
34            Self::Ip(addr) => addr,
35            Self::Mstp(_) => panic!("as_socket_addr called on Mstp address"),
36        }
37    }
38}
39
40impl fmt::Display for DataLinkAddress {
41    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
42        match self {
43            Self::Ip(addr) => write!(f, "{addr}"),
44            Self::Mstp(mac) => write!(f, "mstp:{mac}"),
45        }
46    }
47}