Add Ipv6Addr::is_ipv4_mapped

This change consists of cherry-picking the content from the original
PR[1], which got closed due to inactivity, and applying the following
changes:

* Resolving merge conflicts (obviously)
* Linked to to_ipv4_mapped instead of to_ipv4 in the documentation (seems
  more appropriate)
* Added the must_use and rustc_const_unstable attributes the original
  didn't have

I think it's a reasonably useful method.

[1] https://github.com/rust-lang/rust/pull/86490
This commit is contained in:
Christiaan Dirkx 2021-06-19 16:41:38 +02:00 committed by Jakub Stasiak
parent 37340a12c7
commit 605504c5bf
2 changed files with 36 additions and 1 deletions

View File

@ -1777,6 +1777,31 @@ pub const fn is_multicast(&self) -> bool {
(self.segments()[0] & 0xff00) == 0xff00 (self.segments()[0] & 0xff00) == 0xff00
} }
/// Returns [`true`] if the address is an IPv4-mapped address (`::ffff:0:0/96`).
///
/// IPv4-mapped addresses can be converted to their canonical IPv4 address with
/// [`to_ipv4_mapped`](Ipv6Addr::to_ipv4_mapped).
///
/// # Examples
/// ```
/// #![feature(ip)]
///
/// use std::net::{Ipv4Addr, Ipv6Addr};
///
/// let ipv4_mapped = Ipv4Addr::new(192, 0, 2, 255).to_ipv6_mapped();
/// assert_eq!(ipv4_mapped.is_ipv4_mapped(), true);
/// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc000, 0x2ff).is_ipv4_mapped(), true);
///
/// assert_eq!(Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 0).is_ipv4_mapped(), false);
/// ```
#[rustc_const_unstable(feature = "const_ipv6", issue = "76205")]
#[unstable(feature = "ip", issue = "27709")]
#[must_use]
#[inline]
pub const fn is_ipv4_mapped(&self) -> bool {
matches!(self.segments(), [0, 0, 0, 0, 0, 0xffff, _, _])
}
/// Converts this address to an [`IPv4` address] if it's an [IPv4-mapped] address, /// Converts this address to an [`IPv4` address] if it's an [IPv4-mapped] address,
/// as defined in [IETF RFC 4291 section 2.5.5.2], otherwise returns [`None`]. /// as defined in [IETF RFC 4291 section 2.5.5.2], otherwise returns [`None`].
/// ///

View File

@ -508,6 +508,7 @@ macro_rules! check {
| multicast_realm_local | multicast_realm_local
| multicast_site_local | multicast_site_local
| multicast_organization_local; | multicast_organization_local;
let ipv4_mapped: u32 = 1 << 17;
if ($mask & unspecified) == unspecified { if ($mask & unspecified) == unspecified {
assert!(ip!($s).is_unspecified()); assert!(ip!($s).is_unspecified());
@ -584,6 +585,11 @@ macro_rules! check {
assert_eq!(ip!($s).multicast_scope().unwrap(), assert_eq!(ip!($s).multicast_scope().unwrap(),
Ipv6MulticastScope::Global); Ipv6MulticastScope::Global);
} }
if ($mask & ipv4_mapped) == ipv4_mapped {
assert!(ip!($s).is_ipv4_mapped());
} else {
assert!(!ip!($s).is_ipv4_mapped());
}
} }
} }
@ -602,6 +608,7 @@ macro_rules! check {
let multicast_site_local: u32 = 1 << 13; let multicast_site_local: u32 = 1 << 13;
let multicast_organization_local: u32 = 1 << 14; let multicast_organization_local: u32 = 1 << 14;
let multicast_global: u32 = 1 << 15; let multicast_global: u32 = 1 << 15;
let ipv4_mapped: u32 = 1 << 17;
check!("::", &[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], unspecified); check!("::", &[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], unspecified);
@ -614,7 +621,7 @@ macro_rules! check {
check!( check!(
"::ffff:127.0.0.1", "::ffff:127.0.0.1",
&[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xff, 0xff, 0x7f, 0, 0, 1], &[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xff, 0xff, 0x7f, 0, 0, 1],
unicast_global unicast_global | ipv4_mapped
); );
check!( check!(
@ -982,6 +989,9 @@ fn ipv6_const() {
const IS_MULTICAST: bool = IP_ADDRESS.is_multicast(); const IS_MULTICAST: bool = IP_ADDRESS.is_multicast();
assert!(!IS_MULTICAST); assert!(!IS_MULTICAST);
const IS_IPV4_MAPPED: bool = IP_ADDRESS.is_ipv4_mapped();
assert!(!IS_IPV4_MAPPED);
const IP_V4: Option<Ipv4Addr> = IP_ADDRESS.to_ipv4(); const IP_V4: Option<Ipv4Addr> = IP_ADDRESS.to_ipv4();
assert_eq!(IP_V4.unwrap(), Ipv4Addr::new(0, 0, 0, 1)); assert_eq!(IP_V4.unwrap(), Ipv4Addr::new(0, 0, 0, 1));
} }