From a5cdff3bd42e82f58de45dd49d468a6d4c54b54b Mon Sep 17 00:00:00 2001 From: The8472 Date: Mon, 2 Aug 2021 20:28:31 +0200 Subject: [PATCH] Add convenience for handling ipv4-mapped addresses by canonicalizing them This simplifies checking common properties in an address-family-agnostic way since since #86335 commits to not checking IPv4 semantics of IPv4-mapped addresses in the `Ipv6Addr` property methods. --- library/std/src/net/ip.rs | 45 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 45 insertions(+) diff --git a/library/std/src/net/ip.rs b/library/std/src/net/ip.rs index 88309875978e2..2108c62b4cdf4 100644 --- a/library/std/src/net/ip.rs +++ b/library/std/src/net/ip.rs @@ -291,6 +291,29 @@ impl IpAddr { pub const fn is_ipv6(&self) -> bool { matches!(self, IpAddr::V6(_)) } + + /// Converts this address to an `IpAddr::V4` if it is a IPv4-mapped IPv6 addresses, otherwise it + /// return `self` as-is. + /// + /// # Examples + /// + /// ``` + /// #![feature(ip)] + /// use std::net::{IpAddr, Ipv4Addr, Ipv6Addr}; + /// + /// assert_eq!(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)).to_canonical().is_loopback(), true); + /// assert_eq!(IpAddr::V6(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0x7f00, 0x1)).is_loopback(), false); + /// assert_eq!(IpAddr::V6(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0x7f00, 0x1)).to_canonical().is_loopback(), true); + /// ``` + #[inline] + #[rustc_const_unstable(feature = "const_ip", issue = "76205")] + #[unstable(feature = "ip", issue = "27709")] + pub const fn to_canonical(&self) -> IpAddr { + match self { + &v4 @ IpAddr::V4(_) => v4, + IpAddr::V6(v6) => v6.to_canonical(), + } + } } impl Ipv4Addr { @@ -1532,6 +1555,28 @@ impl Ipv6Addr { } } + /// Converts this address to an `IpAddr::V4` if it is a IPv4-mapped addresses, otherwise it + /// returns self wrapped in a `IpAddr::V6`. + /// + /// # Examples + /// + /// ``` + /// #![feature(ip)] + /// use std::net::Ipv6Addr; + /// + /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0x7f00, 0x1).is_loopback(), false); + /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0x7f00, 0x1).to_canonical().is_loopback(), true); + /// ``` + #[inline] + #[rustc_const_unstable(feature = "const_ipv6", issue = "76205")] + #[unstable(feature = "ip", issue = "27709")] + pub const fn to_canonical(&self) -> IpAddr { + if let Some(mapped) = self.to_ipv4_mapped() { + return IpAddr::V4(mapped); + } + IpAddr::V6(*self) + } + /// Returns the sixteen eight-bit integers the IPv6 address consists of. /// /// ```