Skip to content

Commit

Permalink
Add Ipv6Addr::is_ipv4_mapped
Browse files Browse the repository at this point in the history
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] #86490
  • Loading branch information
CDirkx authored and jstasiak committed Dec 18, 2023
1 parent 37340a1 commit 605504c
Show file tree
Hide file tree
Showing 2 changed files with 36 additions and 1 deletion.
25 changes: 25 additions & 0 deletions library/core/src/net/ip_addr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1777,6 +1777,31 @@ impl Ipv6Addr {
(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,
/// as defined in [IETF RFC 4291 section 2.5.5.2], otherwise returns [`None`].
///
Expand Down
12 changes: 11 additions & 1 deletion library/core/tests/net/ip_addr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -508,6 +508,7 @@ fn ipv6_properties() {
| multicast_realm_local
| multicast_site_local
| multicast_organization_local;
let ipv4_mapped: u32 = 1 << 17;

if ($mask & unspecified) == unspecified {
assert!(ip!($s).is_unspecified());
Expand Down Expand Up @@ -584,6 +585,11 @@ fn ipv6_properties() {
assert_eq!(ip!($s).multicast_scope().unwrap(),
Ipv6MulticastScope::Global);
}
if ($mask & ipv4_mapped) == ipv4_mapped {
assert!(ip!($s).is_ipv4_mapped());
} else {
assert!(!ip!($s).is_ipv4_mapped());
}
}
}

Expand All @@ -602,6 +608,7 @@ fn ipv6_properties() {
let multicast_site_local: u32 = 1 << 13;
let multicast_organization_local: u32 = 1 << 14;
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);

Expand All @@ -614,7 +621,7 @@ fn ipv6_properties() {
check!(
"::ffff:127.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!(
Expand Down Expand Up @@ -982,6 +989,9 @@ fn ipv6_const() {
const IS_MULTICAST: bool = IP_ADDRESS.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();
assert_eq!(IP_V4.unwrap(), Ipv4Addr::new(0, 0, 0, 1));
}
Expand Down

0 comments on commit 605504c

Please sign in to comment.