w5500-ll 0.10.4

Low level driver for the Wiznet W5500 internet offload chip.
Documentation
//! Networking data types.
//!
//! There may a standard for embedded networking in the future, see
//! [rust-embedded issue 348] and [RFC 2832]
//!
//! This is mostly ripped from [`std::net`].
//!
//! [rust-embedded issue 348]: https://github.com/rust-embedded/wg/issues/348
//! [`std::net`]: https://doc.rust-lang.org/std/net/index.html
//! [RFC 2832]: https://github.com/rust-lang/rfcs/pull/2832

/// Ipv4Addr address struct.
///
/// Can be instantiated with [`Ipv4Addr::new`].
#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Debug, Hash, Default)]
pub struct Ipv4Addr {
    /// Octets of the [`Ipv4Addr`] address.
    pub octets: [u8; 4],
}

impl Ipv4Addr {
    /// Creates a new IPv4 address from four eight-bit octets.
    ///
    /// The result will represent the IP address `a`.`b`.`c`.`d`.
    ///
    /// # Examples
    ///
    /// ```
    /// use w5500_ll::net::Ipv4Addr;
    ///
    /// let addr = Ipv4Addr::new(127, 0, 0, 1);
    /// ```
    #[allow(clippy::many_single_char_names)]
    pub const fn new(a: u8, b: u8, c: u8, d: u8) -> Ipv4Addr {
        Ipv4Addr {
            octets: [a, b, c, d],
        }
    }

    /// An IPv4 address with the address pointing to localhost: 127.0.0.1.
    ///
    /// # Examples
    ///
    /// ```
    /// use w5500_ll::net::Ipv4Addr;
    ///
    /// let addr = Ipv4Addr::LOCALHOST;
    /// assert_eq!(addr, Ipv4Addr::new(127, 0, 0, 1));
    /// ```
    pub const LOCALHOST: Self = Ipv4Addr::new(127, 0, 0, 1);

    /// An IPv4 address representing an unspecified address: 0.0.0.0
    ///
    /// # Examples
    ///
    /// ```
    /// use w5500_ll::net::Ipv4Addr;
    ///
    /// let addr = Ipv4Addr::UNSPECIFIED;
    /// assert_eq!(addr, Ipv4Addr::new(0, 0, 0, 0));
    /// ```
    pub const UNSPECIFIED: Self = Ipv4Addr::new(0, 0, 0, 0);

    /// An IPv4 address representing the broadcast address: 255.255.255.255
    ///
    /// # Examples
    ///
    /// ```
    /// use w5500_ll::net::Ipv4Addr;
    ///
    /// let addr = Ipv4Addr::BROADCAST;
    /// assert_eq!(addr, Ipv4Addr::new(255, 255, 255, 255));
    /// ```
    pub const BROADCAST: Self = Ipv4Addr::new(255, 255, 255, 255);

    /// Returns [`true`] for the special 'unspecified' address (0.0.0.0).
    ///
    /// This property is defined in _UNIX Network Programming, Second Edition_,
    /// W. Richard Stevens, p. 891; see also [ip7].
    ///
    /// [ip7]: http://man7.org/linux/man-pages/man7/ip.7.html
    ///
    /// # Examples
    ///
    /// ```
    /// use w5500_ll::net::Ipv4Addr;
    ///
    /// assert_eq!(Ipv4Addr::new(0, 0, 0, 0).is_unspecified(), true);
    /// assert_eq!(Ipv4Addr::new(45, 22, 13, 197).is_unspecified(), false);
    /// ```
    pub const fn is_unspecified(&self) -> bool {
        self.octets[0] == 0 && self.octets[1] == 0 && self.octets[2] == 0 && self.octets[3] == 0
    }

    /// Returns [`true`] if this is a loopback address (127.0.0.0/8).
    ///
    /// This property is defined by [IETF RFC 1122].
    ///
    /// [IETF RFC 1122]: https://tools.ietf.org/html/rfc1122
    ///
    /// # Examples
    ///
    /// ```
    /// use w5500_ll::net::Ipv4Addr;
    ///
    /// assert_eq!(Ipv4Addr::new(127, 0, 0, 1).is_loopback(), true);
    /// assert_eq!(Ipv4Addr::new(45, 22, 13, 197).is_loopback(), false);
    /// ```
    pub const fn is_loopback(&self) -> bool {
        self.octets[0] == 127
    }

    /// Returns [`true`] if this is a private address.
    ///
    /// The private address ranges are defined in [IETF RFC 1918] and include:
    ///
    ///  - 10.0.0.0/8
    ///  - 172.16.0.0/12
    ///  - 192.168.0.0/16
    ///
    /// [IETF RFC 1918]: https://tools.ietf.org/html/rfc1918
    ///
    /// # Examples
    ///
    /// ```
    /// use w5500_ll::net::Ipv4Addr;
    ///
    /// assert_eq!(Ipv4Addr::new(10, 0, 0, 1).is_private(), true);
    /// assert_eq!(Ipv4Addr::new(10, 10, 10, 10).is_private(), true);
    /// assert_eq!(Ipv4Addr::new(172, 16, 10, 10).is_private(), true);
    /// assert_eq!(Ipv4Addr::new(172, 29, 45, 14).is_private(), true);
    /// assert_eq!(Ipv4Addr::new(172, 32, 0, 2).is_private(), false);
    /// assert_eq!(Ipv4Addr::new(192, 168, 0, 2).is_private(), true);
    /// assert_eq!(Ipv4Addr::new(192, 169, 0, 2).is_private(), false);
    /// ```
    #[allow(clippy::manual_range_contains)]
    pub const fn is_private(&self) -> bool {
        match self.octets {
            [10, ..] => true,
            [172, b, ..] if b >= 16 && b <= 31 => true,
            [192, 168, ..] => true,
            _ => false,
        }
    }

    /// Returns [`true`] if the address is link-local (169.254.0.0/16).
    ///
    /// This property is defined by [IETF RFC 3927].
    ///
    /// [IETF RFC 3927]: https://tools.ietf.org/html/rfc3927
    ///
    /// # Examples
    ///
    /// ```
    /// use w5500_ll::net::Ipv4Addr;
    ///
    /// assert_eq!(Ipv4Addr::new(169, 254, 0, 0).is_link_local(), true);
    /// assert_eq!(Ipv4Addr::new(169, 254, 10, 65).is_link_local(), true);
    /// assert_eq!(Ipv4Addr::new(16, 89, 10, 65).is_link_local(), false);
    /// ```
    pub const fn is_link_local(&self) -> bool {
        matches!(self.octets, [169, 254, ..])
    }

    /// Returns [`true`] if this is a multicast address (224.0.0.0/4).
    ///
    /// Multicast addresses have a most significant octet between 224 and 239,
    /// and is defined by [IETF RFC 5771].
    ///
    /// [IETF RFC 5771]: https://tools.ietf.org/html/rfc5771
    ///
    /// # Examples
    ///
    /// ```
    /// use w5500_ll::net::Ipv4Addr;
    ///
    /// assert_eq!(Ipv4Addr::new(224, 254, 0, 0).is_multicast(), true);
    /// assert_eq!(Ipv4Addr::new(236, 168, 10, 65).is_multicast(), true);
    /// assert_eq!(Ipv4Addr::new(172, 16, 10, 65).is_multicast(), false);
    /// ```
    pub const fn is_multicast(&self) -> bool {
        self.octets[0] >= 224 && self.octets[0] <= 239
    }

    /// Returns [`true`] if this is a broadcast address (255.255.255.255).
    ///
    /// A broadcast address has all octets set to 255 as defined in [IETF RFC 919].
    ///
    /// [IETF RFC 919]: https://tools.ietf.org/html/rfc919
    ///
    /// # Examples
    ///
    /// ```
    /// use w5500_ll::net::Ipv4Addr;
    ///
    /// assert_eq!(Ipv4Addr::new(255, 255, 255, 255).is_broadcast(), true);
    /// assert_eq!(Ipv4Addr::new(236, 168, 10, 65).is_broadcast(), false);
    /// ```
    pub const fn is_broadcast(&self) -> bool {
        u32::from_be_bytes(self.octets) == u32::from_be_bytes(Self::BROADCAST.octets)
    }

    /// Returns [`true`] if this address is in a range designated for documentation.
    ///
    /// This is defined in [IETF RFC 5737]:
    ///
    /// - 192.0.2.0/24 (TEST-NET-1)
    /// - 198.51.100.0/24 (TEST-NET-2)
    /// - 203.0.113.0/24 (TEST-NET-3)
    ///
    /// [IETF RFC 5737]: https://tools.ietf.org/html/rfc5737
    ///
    /// # Examples
    ///
    /// ```
    /// use w5500_ll::net::Ipv4Addr;
    ///
    /// assert_eq!(Ipv4Addr::new(192, 0, 2, 255).is_documentation(), true);
    /// assert_eq!(Ipv4Addr::new(198, 51, 100, 65).is_documentation(), true);
    /// assert_eq!(Ipv4Addr::new(203, 0, 113, 6).is_documentation(), true);
    /// assert_eq!(Ipv4Addr::new(193, 34, 17, 19).is_documentation(), false);
    /// ```
    #[allow(clippy::match_like_matches_macro)]
    pub const fn is_documentation(&self) -> bool {
        match self.octets {
            [192, 0, 2, _] => true,
            [198, 51, 100, _] => true,
            [203, 0, 113, _] => true,
            _ => false,
        }
    }
}

impl ::core::fmt::Display for Ipv4Addr {
    /// String formatter for [`Ipv4Addr`] addresses.
    fn fmt(&self, fmt: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
        write!(
            fmt,
            "{}.{}.{}.{}",
            self.octets[0], self.octets[1], self.octets[2], self.octets[3],
        )
    }
}

impl From<[u8; 4]> for Ipv4Addr {
    /// Creates an `Ipv4Addr` from a four element byte array.
    ///
    /// # Examples
    ///
    /// ```
    /// use w5500_ll::net::Ipv4Addr;
    ///
    /// let addr = Ipv4Addr::from([13u8, 12u8, 11u8, 10u8]);
    /// assert_eq!(Ipv4Addr::new(13, 12, 11, 10), addr);
    /// ```
    fn from(octets: [u8; 4]) -> Self {
        Ipv4Addr { octets }
    }
}

#[cfg(feature = "defmt")]
impl defmt::Format for Ipv4Addr {
    fn format(&self, fmt: defmt::Formatter) {
        defmt::write!(
            fmt,
            "{}.{}.{}.{}",
            self.octets[0],
            self.octets[1],
            self.octets[2],
            self.octets[3]
        )
    }
}

#[cfg(feature = "std")]
impl From<std::net::Ipv4Addr> for Ipv4Addr {
    fn from(ip: std::net::Ipv4Addr) -> Self {
        Ipv4Addr::new(
            ip.octets()[0],
            ip.octets()[1],
            ip.octets()[2],
            ip.octets()[3],
        )
    }
}

#[cfg(feature = "std")]
impl From<&std::net::Ipv4Addr> for Ipv4Addr {
    fn from(ip: &std::net::Ipv4Addr) -> Self {
        Ipv4Addr::new(
            ip.octets()[0],
            ip.octets()[1],
            ip.octets()[2],
            ip.octets()[3],
        )
    }
}

#[cfg(feature = "std")]
impl From<Ipv4Addr> for std::net::Ipv4Addr {
    fn from(ip: Ipv4Addr) -> Self {
        std::net::Ipv4Addr::new(ip.octets[0], ip.octets[1], ip.octets[2], ip.octets[3])
    }
}

#[cfg(feature = "std")]
impl From<&Ipv4Addr> for std::net::Ipv4Addr {
    fn from(ip: &Ipv4Addr) -> Self {
        std::net::Ipv4Addr::new(ip.octets[0], ip.octets[1], ip.octets[2], ip.octets[3])
    }
}

#[cfg(feature = "std")]
impl From<Ipv4Addr> for std::net::IpAddr {
    fn from(ip: Ipv4Addr) -> Self {
        std::net::IpAddr::V4(ip.into())
    }
}

#[cfg(feature = "std")]
impl From<&Ipv4Addr> for std::net::IpAddr {
    fn from(ip: &Ipv4Addr) -> Self {
        std::net::IpAddr::V4(ip.into())
    }
}

/// EUI-48 MAC address struct.
///
/// Can be instantiated with [`Eui48Addr::new`].
///
/// This is an EUI-48 [MAC address] (previously called MAC-48).
///
/// [MAC address]: https://en.wikipedia.org/wiki/MAC_address
#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Debug, Hash, Default)]
pub struct Eui48Addr {
    /// Octets of the MAC address.
    pub octets: [u8; 6],
}

impl Eui48Addr {
    /// Creates a new EUI-48 MAC address from six eight-bit octets.
    ///
    /// The result will represent the EUI-48 MAC address
    /// `a`:`b`:`c`:`d`:`e`:`f`.
    ///
    /// # Examples
    ///
    /// ```
    /// use w5500_ll::net::Eui48Addr;
    ///
    /// let addr = Eui48Addr::new(0x00, 0x00, 0x5E, 0x00, 0x00, 0x00);
    /// ```
    #[allow(clippy::many_single_char_names)]
    pub const fn new(a: u8, b: u8, c: u8, d: u8, e: u8, f: u8) -> Eui48Addr {
        Eui48Addr {
            octets: [a, b, c, d, e, f],
        }
    }

    /// An EUI-48 MAC address representing an unspecified address:
    /// 00:00:00:00:00:00
    ///
    /// # Examples
    ///
    /// ```
    /// use w5500_ll::net::Eui48Addr;
    ///
    /// let addr = Eui48Addr::UNSPECIFIED;
    /// assert_eq!(addr, Eui48Addr::new(0x00, 0x00, 0x00, 0x00, 0x00, 0x00));
    /// ```
    pub const UNSPECIFIED: Self = Eui48Addr::new(0, 0, 0, 0, 0, 0);
}

impl ::core::fmt::Display for Eui48Addr {
    /// String formatter for [`Eui48Addr`] addresses.
    fn fmt(&self, fmt: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
        write!(
            fmt,
            "{:02X}:{:02X}:{:02X}:{:02X}:{:02X}:{:02X}",
            self.octets[0],
            self.octets[1],
            self.octets[2],
            self.octets[3],
            self.octets[4],
            self.octets[5],
        )
    }
}

#[cfg(feature = "defmt")]
impl defmt::Format for Eui48Addr {
    fn format(&self, fmt: defmt::Formatter) {
        defmt::write!(
            fmt,
            "{:02X}:{:02X}:{:02X}:{:02X}:{:02X}:{:02X}",
            self.octets[0],
            self.octets[1],
            self.octets[2],
            self.octets[3],
            self.octets[4],
            self.octets[5],
        )
    }
}

impl From<[u8; 6]> for Eui48Addr {
    /// Creates an `Eui48Addr` from a six element byte array.
    ///
    /// # Examples
    ///
    /// ```
    /// use w5500_ll::net::Eui48Addr;
    ///
    /// let addr = Eui48Addr::from([0x12, 0x34, 0x56, 0x78, 0x9A, 0xBC]);
    /// assert_eq!(Eui48Addr::new(0x12, 0x34, 0x56, 0x78, 0x9A, 0xBC), addr);
    /// ```
    fn from(octets: [u8; 6]) -> Self {
        Eui48Addr { octets }
    }
}

/// An IPv4 socket address.
///
/// This is mostly ripped from [`std::net::SocketAddrV4`].
///
/// IPv4 socket addresses consist of an [`IPv4` address] and a 16-bit port
/// number, as stated in [IETF RFC 793].
///
/// Can be instantiated with [`SocketAddrV4::new`].
///
/// # Examples
///
/// ```
/// use w5500_ll::net::{Ipv4Addr, SocketAddrV4};
///
/// let socket = SocketAddrV4::new(Ipv4Addr::new(127, 0, 0, 1), 8080);
///
/// assert_eq!(socket.ip(), &Ipv4Addr::new(127, 0, 0, 1));
/// assert_eq!(socket.port(), 8080);
/// ```
///
/// [IETF RFC 793]: https://tools.ietf.org/html/rfc793
/// [`IPv4` address]: Ipv4Addr
/// [`std::net::SocketAddrV4`]: https://doc.rust-lang.org/std/net/struct.SocketAddrV4.html
#[derive(Debug, PartialEq, Eq, Clone, Copy, PartialOrd, Ord, Hash, Default)]
pub struct SocketAddrV4 {
    ip: Ipv4Addr,
    port: u16,
}

impl SocketAddrV4 {
    /// Creates a new socket address from an [`IPv4` address] and a port number.
    ///
    /// [`IPv4` address]: Ipv4Addr
    ///
    /// # Examples
    ///
    /// ```
    /// use w5500_ll::net::{Ipv4Addr, SocketAddrV4};
    ///
    /// let addr = SocketAddrV4::new(Ipv4Addr::new(127, 0, 0, 1), 8080);
    /// ```
    pub const fn new(ip: Ipv4Addr, port: u16) -> SocketAddrV4 {
        SocketAddrV4 { ip, port }
    }

    /// Returns the IP address associated with this socket address.
    ///
    /// # Examples
    ///
    /// ```
    /// use w5500_ll::net::{Ipv4Addr, SocketAddrV4};
    ///
    /// let addr = SocketAddrV4::new(Ipv4Addr::new(127, 0, 0, 1), 8080);
    /// assert_eq!(addr.ip(), &Ipv4Addr::new(127, 0, 0, 1));
    /// ```
    pub const fn ip(&self) -> &Ipv4Addr {
        &self.ip
    }

    /// Changes the IP address associated with this socket address.
    ///
    /// # Examples
    ///
    /// ```
    /// use w5500_ll::net::{Ipv4Addr, SocketAddrV4};
    ///
    /// let mut addr = SocketAddrV4::new(Ipv4Addr::new(127, 0, 0, 1), 8080);
    /// addr.set_ip(Ipv4Addr::new(192, 168, 0, 1));
    /// assert_eq!(addr.ip(), &Ipv4Addr::new(192, 168, 0, 1));
    /// ```
    pub fn set_ip(&mut self, new_ip: Ipv4Addr) {
        self.ip = new_ip
    }

    /// Returns the port number associated with this socket address.
    ///
    /// # Examples
    ///
    /// ```
    /// use w5500_ll::net::{Ipv4Addr, SocketAddrV4};
    ///
    /// let addr = SocketAddrV4::new(Ipv4Addr::new(127, 0, 0, 1), 8080);
    /// assert_eq!(addr.port(), 8080);
    /// ```
    pub const fn port(&self) -> u16 {
        self.port
    }

    /// Changes the port number associated with this socket address.
    ///
    /// # Examples
    ///
    /// ```
    /// use w5500_ll::net::{Ipv4Addr, SocketAddrV4};
    ///
    /// let mut addr = SocketAddrV4::new(Ipv4Addr::new(127, 0, 0, 1), 8080);
    /// addr.set_port(4242);
    /// assert_eq!(addr.port(), 4242);
    /// ```
    pub fn set_port(&mut self, new_port: u16) {
        self.port = new_port
    }
}

impl ::core::fmt::Display for SocketAddrV4 {
    /// String formatter for [`SocketAddrV4`] addresses.
    fn fmt(&self, fmt: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
        write!(fmt, "{}:{}", self.ip(), self.port())
    }
}

#[cfg(feature = "defmt")]
impl defmt::Format for SocketAddrV4 {
    fn format(&self, fmt: defmt::Formatter) {
        defmt::write!(fmt, "{:?}:{}", self.ip(), self.port())
    }
}

#[cfg(feature = "std")]
impl From<std::net::SocketAddrV4> for SocketAddrV4 {
    fn from(addr: std::net::SocketAddrV4) -> Self {
        SocketAddrV4::new(addr.ip().into(), addr.port())
    }
}

#[cfg(feature = "std")]
impl From<&std::net::SocketAddrV4> for SocketAddrV4 {
    fn from(addr: &std::net::SocketAddrV4) -> Self {
        SocketAddrV4::new(addr.ip().into(), addr.port())
    }
}

#[cfg(feature = "std")]
impl From<SocketAddrV4> for std::net::SocketAddrV4 {
    fn from(addr: SocketAddrV4) -> Self {
        std::net::SocketAddrV4::new(addr.ip().into(), addr.port)
    }
}

#[cfg(feature = "std")]
impl From<&SocketAddrV4> for std::net::SocketAddrV4 {
    fn from(addr: &SocketAddrV4) -> Self {
        std::net::SocketAddrV4::new(addr.ip().into(), addr.port)
    }
}

#[cfg(feature = "std")]
impl From<&SocketAddrV4> for std::net::SocketAddr {
    fn from(addr: &SocketAddrV4) -> Self {
        std::net::SocketAddr::V4(addr.into())
    }
}

#[cfg(feature = "std")]
impl From<SocketAddrV4> for std::net::SocketAddr {
    fn from(addr: SocketAddrV4) -> Self {
        std::net::SocketAddr::V4(addr.into())
    }
}