diff --git a/uefi-raw/CHANGELOG.md b/uefi-raw/CHANGELOG.md index 3584b5c94..99a2f1690 100644 --- a/uefi-raw/CHANGELOG.md +++ b/uefi-raw/CHANGELOG.md @@ -12,6 +12,14 @@ - Added `::ZERO` constant for `IpAddress` - `Ipv4Address` and `Ipv6Address` now implement `Display`. They use the same formatting as `core::net::{Ipv4Addr, Ipv6Addr}` +- Added comprehensive integration with `core::net::{IpAddr, Ipv4Addr, Ipv6Addr}` + via `From` impls to better integrate uefi-raw types `IpAddress`, + `Ipv4Address`, and `Ipv6Address` with the Rust ecosystem. +- Added convenient `From` impls: + - `[u8; 6]` <--> `MacAddress` + - `[u8; 32]` --> `MacAddress` + - `[u8; 4]` --> `Ipv4Address`, `IpAddress` + - `[u8; 16]` --> `Ipv6Address`, `IpAddress` ## Changed - **Breaking:** The MSRV is now 1.85.1 and the crate uses the Rust 2024 edition. diff --git a/uefi-raw/src/net.rs b/uefi-raw/src/net.rs index fffdf561a..fc726e275 100644 --- a/uefi-raw/src/net.rs +++ b/uefi-raw/src/net.rs @@ -11,6 +11,13 @@ use core::fmt::{self, Debug, Display, Formatter}; /// An IPv4 internet protocol address. +/// +/// # Conversions and Relation to [`core::net`] +/// +/// The following [`From`] implementations exist: +/// - `[u8; 4]` -> [`Ipv4Address`] +/// - [`core::net::Ipv4Addr`] -> [`Ipv4Address`] +/// - [`core::net::IpAddr`] -> [`Ipv4Address`] #[derive(Clone, Copy, Debug, Default, Eq, PartialEq, Ord, PartialOrd, Hash)] #[repr(transparent)] pub struct Ipv4Address(pub [u8; 4]); @@ -35,6 +42,12 @@ impl From for core::net::Ipv4Addr { } } +impl From<[u8; 4]> for Ipv4Address { + fn from(octets: [u8; 4]) -> Self { + Self(octets) + } +} + impl Display for Ipv4Address { fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { let ip = core::net::Ipv4Addr::from(*self); @@ -43,6 +56,13 @@ impl Display for Ipv4Address { } /// An IPv6 internet protocol address. +/// +/// # Conversions and Relation to [`core::net`] +/// +/// The following [`From`] implementations exist: +/// - `[u8; 16]` -> [`Ipv6Address`] +/// - [`core::net::Ipv6Addr`] -> [`Ipv6Address`] +/// - [`core::net::IpAddr`] -> [`Ipv6Address`] #[derive(Clone, Copy, Debug, Default, Eq, PartialEq, Ord, PartialOrd, Hash)] #[repr(transparent)] pub struct Ipv6Address(pub [u8; 16]); @@ -67,6 +87,12 @@ impl From for core::net::Ipv6Addr { } } +impl From<[u8; 16]> for Ipv6Address { + fn from(octets: [u8; 16]) -> Self { + Self(octets) + } +} + impl Display for Ipv6Address { fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { let ip = core::net::Ipv6Addr::from(*self); @@ -80,6 +106,15 @@ impl Display for Ipv6Address { /// type is defined in the same way as edk2 for compatibility with C code. Note /// that this is an untagged union, so there's no way to tell which type of /// address an `IpAddress` value contains without additional context. +/// +/// # Conversions and Relation to [`core::net`] +/// +/// The following [`From`] implementations exist: +/// - `[u8; 4]` -> [`IpAddress`] +/// - `[u8; 16]` -> [`IpAddress`] +/// - [`core::net::Ipv4Addr`] -> [`IpAddress`] +/// - [`core::net::Ipv6Addr`] -> [`IpAddress`] +/// - [`core::net::IpAddr`] -> [`IpAddress`] #[derive(Clone, Copy)] #[repr(C)] pub union IpAddress { @@ -170,6 +205,30 @@ impl From for IpAddress { } } +impl From for IpAddress { + fn from(value: core::net::Ipv4Addr) -> Self { + Self::new_v4(value.octets()) + } +} + +impl From for IpAddress { + fn from(value: core::net::Ipv6Addr) -> Self { + Self::new_v6(value.octets()) + } +} + +impl From<[u8; 4]> for IpAddress { + fn from(octets: [u8; 4]) -> Self { + Self::new_v4(octets) + } +} + +impl From<[u8; 16]> for IpAddress { + fn from(octets: [u8; 16]) -> Self { + Self::new_v6(octets) + } +} + /// UEFI Media Access Control (MAC) address. /// /// UEFI supports multiple network protocols and hardware types, not just @@ -179,6 +238,13 @@ impl From for IpAddress { /// /// In most cases, this is just a typical `[u8; 6]` Ethernet style MAC /// address with the rest of the bytes being zero. +/// +/// # Conversions and Relation to [`core::net`] +/// +/// There is no matching type in [`core::net`] but the following [`From`] +/// implementations exist: +/// - `[u8; 6]` <-> [`MacAddress`] +/// - `[u8; 32]` -> [`MacAddress`] #[derive(Clone, Copy, Debug, Default, Eq, PartialEq, Ord, PartialOrd, Hash)] #[repr(transparent)] pub struct MacAddress(pub [u8; 32]); @@ -200,7 +266,7 @@ impl MacAddress { } } -// Normal/typical MAC addresses, such as in Ethernet. +// Normal Ethernet MAC address. impl From<[u8; 6]> for MacAddress { fn from(octets: [u8; 6]) -> Self { let mut buffer = [0; 32]; @@ -209,12 +275,20 @@ impl From<[u8; 6]> for MacAddress { } } +// Normal Ethernet MAC address. impl From for [u8; 6] { fn from(MacAddress(o): MacAddress) -> Self { [o[0], o[1], o[2], o[3], o[4], o[5]] } } +// UEFI MAC addresses. +impl From<[u8; 32]> for MacAddress { + fn from(octets: [u8; 32]) -> Self { + Self(octets) + } +} + #[cfg(test)] mod tests { use super::*; @@ -267,4 +341,66 @@ mod tests { assert_eq!(align_of::>(), 1); assert_eq!(size_of::>(), 16); } + + /// Tests the From-impls from the documentation. + #[test] + fn test_promised_from_impls() { + // octets -> Ipv4Address + { + let octets = [0_u8, 1, 2, 3]; + assert_eq!(Ipv4Address::from(octets), Ipv4Address(octets)); + let uefi_addr = IpAddress::from(octets); + assert_eq!(&octets, &unsafe { uefi_addr.v4.octets() }); + } + // octets -> Ipv6Address + { + let octets = [0_u8, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]; + assert_eq!(Ipv6Address::from(octets), Ipv6Address(octets)); + let uefi_addr = IpAddress::from(octets); + assert_eq!(&octets, &unsafe { uefi_addr.v6.octets() }); + } + // StdIpv4Addr -> Ipv4Address + { + let octets = [7, 5, 3, 1]; + let core_ipv4_addr = core::net::Ipv4Addr::from(octets); + assert_eq!(Ipv4Address::from(core_ipv4_addr).octets(), octets); + assert_eq!( + unsafe { IpAddress::from(core_ipv4_addr).v4.octets() }, + octets + ); + } + // StdIpv6Addr -> Ipv6Address + { + let octets = [7, 5, 3, 1, 6, 3, 8, 5, 2, 5, 2, 7, 3, 5, 2, 6]; + let core_ipv6_addr = core::net::Ipv6Addr::from(octets); + assert_eq!(Ipv6Address::from(core_ipv6_addr).octets(), octets); + assert_eq!( + unsafe { IpAddress::from(core_ipv6_addr).v6.octets() }, + octets + ); + } + // StdIpAddr -> IpAddress + { + let octets = [8, 8, 2, 6]; + let core_ip_addr = core::net::IpAddr::from(octets); + assert_eq!(unsafe { IpAddress::from(core_ip_addr).v4.octets() }, octets); + } + // octets <-> MacAddress + { + let octets = [8, 8, 2, 6, 6, 7]; + let uefi_mac_addr = MacAddress::from(octets); + assert_eq!(uefi_mac_addr.octets()[0..6], octets); + let octets2: [u8; 6] = uefi_mac_addr.into(); + assert_eq!(octets2, octets) + } + // octets -> MacAddress + { + let octets = [ + 8_u8, 8, 2, 6, 6, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 7, 0, 0, 0, + 0, 0, 0, 0, 42, + ]; + let uefi_mac_addr = MacAddress::from(octets); + assert_eq!(uefi_mac_addr.octets(), octets); + } + } }