#![allow(unsafe_code)]
use core::cmp::Ordering;
use core::mem::transmute;
#[cfg_attr(staged_api, stable(feature = "ip_addr", since = "1.7.0"))]
#[derive(Copy, Clone, Eq, PartialEq, Hash, PartialOrd, Ord)]
pub enum IpAddr {
#[cfg_attr(staged_api, stable(feature = "ip_addr", since = "1.7.0"))]
V4(#[cfg_attr(staged_api, stable(feature = "ip_addr", since = "1.7.0"))] Ipv4Addr),
#[cfg_attr(staged_api, stable(feature = "ip_addr", since = "1.7.0"))]
V6(#[cfg_attr(staged_api, stable(feature = "ip_addr", since = "1.7.0"))] Ipv6Addr),
}
#[derive(Copy, Clone, PartialEq, Eq, Hash)]
#[cfg_attr(staged_api, stable(feature = "rust1", since = "1.0.0"))]
pub struct Ipv4Addr {
octets: [u8; 4],
}
#[derive(Copy, Clone, PartialEq, Eq, Hash)]
#[cfg_attr(staged_api, stable(feature = "rust1", since = "1.0.0"))]
pub struct Ipv6Addr {
octets: [u8; 16],
}
#[derive(Copy, PartialEq, Eq, Clone, Hash, Debug)]
#[cfg_attr(staged_api, unstable(feature = "ip", issue = "27709"))]
#[non_exhaustive]
pub enum Ipv6MulticastScope {
InterfaceLocal,
LinkLocal,
RealmLocal,
AdminLocal,
SiteLocal,
OrganizationLocal,
Global,
}
impl IpAddr {
#[cfg_attr(
staged_api,
rustc_const_stable(feature = "const_ip_50", since = "1.50.0")
)]
#[cfg_attr(staged_api, stable(feature = "ip_shared", since = "1.12.0"))]
#[must_use]
#[inline]
pub const fn is_unspecified(&self) -> bool {
match self {
IpAddr::V4(ip) => ip.is_unspecified(),
IpAddr::V6(ip) => ip.is_unspecified(),
}
}
#[cfg_attr(
staged_api,
rustc_const_stable(feature = "const_ip_50", since = "1.50.0")
)]
#[cfg_attr(staged_api, stable(feature = "ip_shared", since = "1.12.0"))]
#[must_use]
#[inline]
pub const fn is_loopback(&self) -> bool {
match self {
IpAddr::V4(ip) => ip.is_loopback(),
IpAddr::V6(ip) => ip.is_loopback(),
}
}
#[cfg_attr(
staged_api,
rustc_const_unstable(feature = "const_ip", issue = "76205")
)]
#[cfg_attr(staged_api, unstable(feature = "ip", issue = "27709"))]
#[must_use]
#[inline]
pub const fn is_global(&self) -> bool {
match self {
IpAddr::V4(ip) => ip.is_global(),
IpAddr::V6(ip) => ip.is_global(),
}
}
#[cfg_attr(
staged_api,
rustc_const_stable(feature = "const_ip_50", since = "1.50.0")
)]
#[cfg_attr(staged_api, stable(feature = "ip_shared", since = "1.12.0"))]
#[must_use]
#[inline]
pub const fn is_multicast(&self) -> bool {
match self {
IpAddr::V4(ip) => ip.is_multicast(),
IpAddr::V6(ip) => ip.is_multicast(),
}
}
#[cfg_attr(
staged_api,
rustc_const_unstable(feature = "const_ip", issue = "76205")
)]
#[cfg_attr(staged_api, unstable(feature = "ip", issue = "27709"))]
#[must_use]
#[inline]
pub const fn is_documentation(&self) -> bool {
match self {
IpAddr::V4(ip) => ip.is_documentation(),
IpAddr::V6(ip) => ip.is_documentation(),
}
}
#[cfg_attr(staged_api, unstable(feature = "ip", issue = "27709"))]
#[must_use]
#[inline]
pub const fn is_benchmarking(&self) -> bool {
match self {
IpAddr::V4(ip) => ip.is_benchmarking(),
IpAddr::V6(ip) => ip.is_benchmarking(),
}
}
#[cfg_attr(
staged_api,
rustc_const_stable(feature = "const_ip_50", since = "1.50.0")
)]
#[cfg_attr(staged_api, stable(feature = "ipaddr_checker", since = "1.16.0"))]
#[must_use]
#[inline]
pub const fn is_ipv4(&self) -> bool {
matches!(self, IpAddr::V4(_))
}
#[cfg_attr(
staged_api,
rustc_const_stable(feature = "const_ip_50", since = "1.50.0")
)]
#[cfg_attr(staged_api, stable(feature = "ipaddr_checker", since = "1.16.0"))]
#[must_use]
#[inline]
pub const fn is_ipv6(&self) -> bool {
matches!(self, IpAddr::V6(_))
}
#[inline]
#[must_use = "this returns the result of the operation, \
without modifying the original"]
#[cfg_attr(
staged_api,
rustc_const_unstable(feature = "const_ip", issue = "76205")
)]
#[cfg_attr(staged_api, 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 {
#[cfg_attr(
staged_api,
rustc_const_stable(feature = "const_ip_32", since = "1.32.0")
)]
#[cfg_attr(staged_api, stable(feature = "rust1", since = "1.0.0"))]
#[must_use]
#[inline]
pub const fn new(a: u8, b: u8, c: u8, d: u8) -> Ipv4Addr {
Ipv4Addr {
octets: [a, b, c, d],
}
}
#[cfg_attr(staged_api, stable(feature = "ip_constructors", since = "1.30.0"))]
pub const LOCALHOST: Self = Ipv4Addr::new(127, 0, 0, 1);
#[doc(alias = "INADDR_ANY")]
#[cfg_attr(staged_api, stable(feature = "ip_constructors", since = "1.30.0"))]
pub const UNSPECIFIED: Self = Ipv4Addr::new(0, 0, 0, 0);
#[cfg_attr(staged_api, stable(feature = "ip_constructors", since = "1.30.0"))]
pub const BROADCAST: Self = Ipv4Addr::new(255, 255, 255, 255);
#[cfg_attr(
staged_api,
rustc_const_stable(feature = "const_ip_50", since = "1.50.0")
)]
#[cfg_attr(staged_api, stable(feature = "rust1", since = "1.0.0"))]
#[must_use]
#[inline]
pub const fn octets(&self) -> [u8; 4] {
self.octets
}
#[cfg_attr(
staged_api,
rustc_const_stable(feature = "const_ip_32", since = "1.32.0")
)]
#[cfg_attr(staged_api, stable(feature = "ip_shared", since = "1.12.0"))]
#[must_use]
#[inline]
pub const fn is_unspecified(&self) -> bool {
u32::from_be_bytes(self.octets) == 0
}
#[cfg_attr(
staged_api,
rustc_const_stable(feature = "const_ip_50", since = "1.50.0")
)]
#[cfg_attr(staged_api, stable(since = "1.7.0", feature = "ip_17"))]
#[must_use]
#[inline]
pub const fn is_loopback(&self) -> bool {
self.octets()[0] == 127
}
#[cfg_attr(
staged_api,
rustc_const_stable(feature = "const_ip_50", since = "1.50.0")
)]
#[cfg_attr(staged_api, stable(since = "1.7.0", feature = "ip_17"))]
#[must_use]
#[inline]
pub const fn is_private(&self) -> bool {
match self.octets() {
[10, ..] => true,
[172, b, ..] if b >= 16 && b <= 31 => true,
[192, 168, ..] => true,
_ => false,
}
}
#[cfg_attr(
staged_api,
rustc_const_stable(feature = "const_ip_50", since = "1.50.0")
)]
#[cfg_attr(staged_api, stable(since = "1.7.0", feature = "ip_17"))]
#[must_use]
#[inline]
pub const fn is_link_local(&self) -> bool {
matches!(self.octets(), [169, 254, ..])
}
#[cfg_attr(
staged_api,
rustc_const_unstable(feature = "const_ipv4", issue = "76205")
)]
#[cfg_attr(staged_api, unstable(feature = "ip", issue = "27709"))]
#[must_use]
#[inline]
pub const fn is_global(&self) -> bool {
!(self.octets()[0] == 0 || self.is_private()
|| self.is_shared()
|| self.is_loopback()
|| self.is_link_local()
||(self.octets()[0] == 192 && self.octets()[1] == 0 && self.octets()[2] == 0)
|| self.is_documentation()
|| self.is_benchmarking()
|| self.is_reserved()
|| self.is_broadcast())
}
#[cfg_attr(
staged_api,
rustc_const_unstable(feature = "const_ipv4", issue = "76205")
)]
#[cfg_attr(staged_api, unstable(feature = "ip", issue = "27709"))]
#[must_use]
#[inline]
pub const fn is_shared(&self) -> bool {
self.octets()[0] == 100 && (self.octets()[1] & 0b1100_0000 == 0b0100_0000)
}
#[cfg_attr(
staged_api,
rustc_const_unstable(feature = "const_ipv4", issue = "76205")
)]
#[cfg_attr(staged_api, unstable(feature = "ip", issue = "27709"))]
#[must_use]
#[inline]
pub const fn is_benchmarking(&self) -> bool {
self.octets()[0] == 198 && (self.octets()[1] & 0xfe) == 18
}
#[cfg_attr(
staged_api,
rustc_const_unstable(feature = "const_ipv4", issue = "76205")
)]
#[cfg_attr(staged_api, unstable(feature = "ip", issue = "27709"))]
#[must_use]
#[inline]
pub const fn is_reserved(&self) -> bool {
self.octets()[0] & 240 == 240 && !self.is_broadcast()
}
#[cfg_attr(
staged_api,
rustc_const_stable(feature = "const_ip_50", since = "1.50.0")
)]
#[cfg_attr(staged_api, stable(since = "1.7.0", feature = "ip_17"))]
#[must_use]
#[inline]
pub const fn is_multicast(&self) -> bool {
self.octets()[0] >= 224 && self.octets()[0] <= 239
}
#[cfg_attr(
staged_api,
rustc_const_stable(feature = "const_ip_50", since = "1.50.0")
)]
#[cfg_attr(staged_api, stable(since = "1.7.0", feature = "ip_17"))]
#[must_use]
#[inline]
pub const fn is_broadcast(&self) -> bool {
u32::from_be_bytes(self.octets()) == u32::from_be_bytes(Self::BROADCAST.octets())
}
#[cfg_attr(
staged_api,
rustc_const_stable(feature = "const_ip_50", since = "1.50.0")
)]
#[cfg_attr(staged_api, stable(since = "1.7.0", feature = "ip_17"))]
#[must_use]
#[inline]
pub const fn is_documentation(&self) -> bool {
matches!(
self.octets(),
[192, 0, 2, _] | [198, 51, 100, _] | [203, 0, 113, _]
)
}
#[cfg_attr(
staged_api,
rustc_const_stable(feature = "const_ip_50", since = "1.50.0")
)]
#[cfg_attr(staged_api, stable(feature = "rust1", since = "1.0.0"))]
#[must_use = "this returns the result of the operation, \
without modifying the original"]
#[inline]
pub const fn to_ipv6_compatible(&self) -> Ipv6Addr {
let [a, b, c, d] = self.octets();
Ipv6Addr {
octets: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, a, b, c, d],
}
}
#[cfg_attr(
staged_api,
rustc_const_stable(feature = "const_ip_50", since = "1.50.0")
)]
#[cfg_attr(staged_api, stable(feature = "rust1", since = "1.0.0"))]
#[must_use = "this returns the result of the operation, \
without modifying the original"]
#[inline]
pub const fn to_ipv6_mapped(&self) -> Ipv6Addr {
let [a, b, c, d] = self.octets();
Ipv6Addr {
octets: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xFF, 0xFF, a, b, c, d],
}
}
}
#[cfg_attr(staged_api, stable(feature = "ip_from_ip", since = "1.16.0"))]
impl From<Ipv4Addr> for IpAddr {
#[inline]
fn from(ipv4: Ipv4Addr) -> IpAddr {
IpAddr::V4(ipv4)
}
}
#[cfg_attr(staged_api, stable(feature = "ip_from_ip", since = "1.16.0"))]
impl From<Ipv6Addr> for IpAddr {
#[inline]
fn from(ipv6: Ipv6Addr) -> IpAddr {
IpAddr::V6(ipv6)
}
}
#[cfg_attr(staged_api, stable(feature = "ip_cmp", since = "1.16.0"))]
impl PartialEq<Ipv4Addr> for IpAddr {
#[inline]
fn eq(&self, other: &Ipv4Addr) -> bool {
match self {
IpAddr::V4(v4) => v4 == other,
IpAddr::V6(_) => false,
}
}
}
#[cfg_attr(staged_api, stable(feature = "ip_cmp", since = "1.16.0"))]
impl PartialEq<IpAddr> for Ipv4Addr {
#[inline]
fn eq(&self, other: &IpAddr) -> bool {
match other {
IpAddr::V4(v4) => self == v4,
IpAddr::V6(_) => false,
}
}
}
#[cfg_attr(staged_api, stable(feature = "rust1", since = "1.0.0"))]
impl PartialOrd for Ipv4Addr {
#[inline]
fn partial_cmp(&self, other: &Ipv4Addr) -> Option<Ordering> {
Some(self.cmp(other))
}
}
#[cfg_attr(staged_api, stable(feature = "ip_cmp", since = "1.16.0"))]
impl PartialOrd<Ipv4Addr> for IpAddr {
#[inline]
fn partial_cmp(&self, other: &Ipv4Addr) -> Option<Ordering> {
match self {
IpAddr::V4(v4) => v4.partial_cmp(other),
IpAddr::V6(_) => Some(Ordering::Greater),
}
}
}
#[cfg_attr(staged_api, stable(feature = "ip_cmp", since = "1.16.0"))]
impl PartialOrd<IpAddr> for Ipv4Addr {
#[inline]
fn partial_cmp(&self, other: &IpAddr) -> Option<Ordering> {
match other {
IpAddr::V4(v4) => self.partial_cmp(v4),
IpAddr::V6(_) => Some(Ordering::Less),
}
}
}
#[cfg_attr(staged_api, stable(feature = "rust1", since = "1.0.0"))]
impl Ord for Ipv4Addr {
#[inline]
fn cmp(&self, other: &Ipv4Addr) -> Ordering {
self.octets.cmp(&other.octets)
}
}
#[cfg_attr(staged_api, stable(feature = "ip_u32", since = "1.1.0"))]
impl From<Ipv4Addr> for u32 {
#[inline]
fn from(ip: Ipv4Addr) -> u32 {
u32::from_be_bytes(ip.octets)
}
}
#[cfg_attr(staged_api, stable(feature = "ip_u32", since = "1.1.0"))]
impl From<u32> for Ipv4Addr {
#[inline]
fn from(ip: u32) -> Ipv4Addr {
Ipv4Addr {
octets: ip.to_be_bytes(),
}
}
}
#[cfg_attr(staged_api, stable(feature = "from_slice_v4", since = "1.9.0"))]
impl From<[u8; 4]> for Ipv4Addr {
#[inline]
fn from(octets: [u8; 4]) -> Ipv4Addr {
Ipv4Addr { octets }
}
}
#[cfg_attr(staged_api, stable(feature = "ip_from_slice", since = "1.17.0"))]
impl From<[u8; 4]> for IpAddr {
#[inline]
fn from(octets: [u8; 4]) -> IpAddr {
IpAddr::V4(Ipv4Addr::from(octets))
}
}
impl Ipv6Addr {
#[cfg_attr(
staged_api,
rustc_const_stable(feature = "const_ip_32", since = "1.32.0")
)]
#[cfg_attr(staged_api, stable(feature = "rust1", since = "1.0.0"))]
#[allow(clippy::too_many_arguments)]
#[must_use]
#[inline]
pub const fn new(a: u16, b: u16, c: u16, d: u16, e: u16, f: u16, g: u16, h: u16) -> Ipv6Addr {
let addr16 = [
a.to_be(),
b.to_be(),
c.to_be(),
d.to_be(),
e.to_be(),
f.to_be(),
g.to_be(),
h.to_be(),
];
Ipv6Addr {
octets: unsafe { transmute::<_, [u8; 16]>(addr16) },
}
}
#[doc(alias = "IN6ADDR_LOOPBACK_INIT")]
#[doc(alias = "in6addr_loopback")]
#[cfg_attr(staged_api, stable(feature = "ip_constructors", since = "1.30.0"))]
pub const LOCALHOST: Self = Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1);
#[doc(alias = "IN6ADDR_ANY_INIT")]
#[doc(alias = "in6addr_any")]
#[cfg_attr(staged_api, stable(feature = "ip_constructors", since = "1.30.0"))]
pub const UNSPECIFIED: Self = Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0);
#[cfg_attr(
staged_api,
rustc_const_stable(feature = "const_ip_50", since = "1.50.0")
)]
#[cfg_attr(staged_api, stable(feature = "rust1", since = "1.0.0"))]
#[must_use]
#[inline]
pub const fn segments(&self) -> [u16; 8] {
let [a, b, c, d, e, f, g, h] = unsafe { transmute::<_, [u16; 8]>(self.octets) };
[
u16::from_be(a),
u16::from_be(b),
u16::from_be(c),
u16::from_be(d),
u16::from_be(e),
u16::from_be(f),
u16::from_be(g),
u16::from_be(h),
]
}
#[cfg_attr(
staged_api,
rustc_const_stable(feature = "const_ip_50", since = "1.50.0")
)]
#[cfg_attr(staged_api, stable(since = "1.7.0", feature = "ip_17"))]
#[must_use]
#[inline]
pub const fn is_unspecified(&self) -> bool {
u128::from_be_bytes(self.octets()) == u128::from_be_bytes(Ipv6Addr::UNSPECIFIED.octets())
}
#[cfg_attr(
staged_api,
rustc_const_stable(feature = "const_ip_50", since = "1.50.0")
)]
#[cfg_attr(staged_api, stable(since = "1.7.0", feature = "ip_17"))]
#[must_use]
#[inline]
pub const fn is_loopback(&self) -> bool {
u128::from_be_bytes(self.octets()) == u128::from_be_bytes(Ipv6Addr::LOCALHOST.octets())
}
#[cfg_attr(
staged_api,
rustc_const_unstable(feature = "const_ipv6", issue = "76205")
)]
#[cfg_attr(staged_api, unstable(feature = "ip", issue = "27709"))]
#[must_use]
#[inline]
pub const fn is_global(&self) -> bool {
!(self.is_unspecified()
|| self.is_loopback()
|| matches!(self.segments(), [0, 0, 0, 0, 0, 0xffff, _, _])
|| matches!(self.segments(), [0x64, 0xff9b, 1, _, _, _, _, _])
|| matches!(self.segments(), [0x100, 0, 0, 0, _, _, _, _])
|| (matches!(self.segments(), [0x2001, b, _, _, _, _, _, _] if b < 0x200)
&& !(
u128::from_be_bytes(self.octets()) == 0x2001_0001_0000_0000_0000_0000_0000_0001
|| u128::from_be_bytes(self.octets()) == 0x2001_0001_0000_0000_0000_0000_0000_0002
|| matches!(self.segments(), [0x2001, 3, _, _, _, _, _, _])
|| matches!(self.segments(), [0x2001, 4, 0x112, _, _, _, _, _])
|| matches!(self.segments(), [0x2001, b, _, _, _, _, _, _] if b >= 0x20 && b <= 0x2F)
))
|| self.is_documentation()
|| self.is_unique_local()
|| self.is_unicast_link_local())
}
#[cfg_attr(
staged_api,
rustc_const_unstable(feature = "const_ipv6", issue = "76205")
)]
#[cfg_attr(staged_api, unstable(feature = "ip", issue = "27709"))]
#[must_use]
#[inline]
pub const fn is_unique_local(&self) -> bool {
(self.segments()[0] & 0xfe00) == 0xfc00
}
#[cfg_attr(
staged_api,
rustc_const_unstable(feature = "const_ipv6", issue = "76205")
)]
#[cfg_attr(staged_api, unstable(feature = "ip", issue = "27709"))]
#[must_use]
#[inline]
pub const fn is_unicast(&self) -> bool {
!self.is_multicast()
}
#[cfg_attr(
staged_api,
rustc_const_unstable(feature = "const_ipv6", issue = "76205")
)]
#[cfg_attr(staged_api, unstable(feature = "ip", issue = "27709"))]
#[must_use]
#[inline]
pub const fn is_unicast_link_local(&self) -> bool {
(self.segments()[0] & 0xffc0) == 0xfe80
}
#[cfg_attr(
staged_api,
rustc_const_unstable(feature = "const_ipv6", issue = "76205")
)]
#[cfg_attr(staged_api, unstable(feature = "ip", issue = "27709"))]
#[must_use]
#[inline]
pub const fn is_documentation(&self) -> bool {
(self.segments()[0] == 0x2001) && (self.segments()[1] == 0xdb8)
}
#[cfg_attr(staged_api, unstable(feature = "ip", issue = "27709"))]
#[must_use]
#[inline]
pub const fn is_benchmarking(&self) -> bool {
(self.segments()[0] == 0x2001) && (self.segments()[1] == 0x2) && (self.segments()[2] == 0)
}
#[cfg_attr(
staged_api,
rustc_const_unstable(feature = "const_ipv6", issue = "76205")
)]
#[cfg_attr(staged_api, unstable(feature = "ip", issue = "27709"))]
#[must_use]
#[inline]
pub const fn is_unicast_global(&self) -> bool {
self.is_unicast()
&& !self.is_loopback()
&& !self.is_unicast_link_local()
&& !self.is_unique_local()
&& !self.is_unspecified()
&& !self.is_documentation()
&& !self.is_benchmarking()
}
#[cfg_attr(
staged_api,
rustc_const_unstable(feature = "const_ipv6", issue = "76205")
)]
#[cfg_attr(staged_api, unstable(feature = "ip", issue = "27709"))]
#[must_use]
#[inline]
pub const fn multicast_scope(&self) -> Option<Ipv6MulticastScope> {
if self.is_multicast() {
match self.segments()[0] & 0x000f {
1 => Some(Ipv6MulticastScope::InterfaceLocal),
2 => Some(Ipv6MulticastScope::LinkLocal),
3 => Some(Ipv6MulticastScope::RealmLocal),
4 => Some(Ipv6MulticastScope::AdminLocal),
5 => Some(Ipv6MulticastScope::SiteLocal),
8 => Some(Ipv6MulticastScope::OrganizationLocal),
14 => Some(Ipv6MulticastScope::Global),
_ => None,
}
} else {
None
}
}
#[cfg_attr(
staged_api,
rustc_const_stable(feature = "const_ip_50", since = "1.50.0")
)]
#[cfg_attr(staged_api, stable(since = "1.7.0", feature = "ip_17"))]
#[must_use]
#[inline]
pub const fn is_multicast(&self) -> bool {
(self.segments()[0] & 0xff00) == 0xff00
}
#[cfg_attr(
staged_api,
rustc_const_unstable(feature = "const_ipv6", issue = "76205")
)]
#[cfg_attr(staged_api, stable(feature = "ipv6_to_ipv4_mapped", since = "1.63.0"))]
#[must_use = "this returns the result of the operation, \
without modifying the original"]
#[inline]
pub const fn to_ipv4_mapped(&self) -> Option<Ipv4Addr> {
match self.octets() {
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xff, 0xff, a, b, c, d] => {
Some(Ipv4Addr::new(a, b, c, d))
}
_ => None,
}
}
#[cfg_attr(
staged_api,
rustc_const_stable(feature = "const_ip_50", since = "1.50.0")
)]
#[cfg_attr(staged_api, stable(feature = "rust1", since = "1.0.0"))]
#[must_use = "this returns the result of the operation, \
without modifying the original"]
#[inline]
pub const fn to_ipv4(&self) -> Option<Ipv4Addr> {
if let [0, 0, 0, 0, 0, 0 | 0xffff, ab, cd] = self.segments() {
let [a, b] = ab.to_be_bytes();
let [c, d] = cd.to_be_bytes();
Some(Ipv4Addr::new(a, b, c, d))
} else {
None
}
}
#[cfg_attr(
staged_api,
rustc_const_unstable(feature = "const_ipv6", issue = "76205")
)]
#[cfg_attr(staged_api, unstable(feature = "ip", issue = "27709"))]
#[must_use = "this returns the result of the operation, \
without modifying the original"]
#[inline]
pub const fn to_canonical(&self) -> IpAddr {
if let Some(mapped) = self.to_ipv4_mapped() {
return IpAddr::V4(mapped);
}
IpAddr::V6(*self)
}
#[cfg_attr(
staged_api,
rustc_const_stable(feature = "const_ip_32", since = "1.32.0")
)]
#[cfg_attr(staged_api, stable(feature = "ipv6_to_octets", since = "1.12.0"))]
#[must_use]
#[inline]
pub const fn octets(&self) -> [u8; 16] {
self.octets
}
}
#[cfg_attr(staged_api, stable(feature = "ip_cmp", since = "1.16.0"))]
impl PartialEq<IpAddr> for Ipv6Addr {
#[inline]
fn eq(&self, other: &IpAddr) -> bool {
match other {
IpAddr::V4(_) => false,
IpAddr::V6(v6) => self == v6,
}
}
}
#[cfg_attr(staged_api, stable(feature = "ip_cmp", since = "1.16.0"))]
impl PartialEq<Ipv6Addr> for IpAddr {
#[inline]
fn eq(&self, other: &Ipv6Addr) -> bool {
match self {
IpAddr::V4(_) => false,
IpAddr::V6(v6) => v6 == other,
}
}
}
#[cfg_attr(staged_api, stable(feature = "rust1", since = "1.0.0"))]
impl PartialOrd for Ipv6Addr {
#[inline]
fn partial_cmp(&self, other: &Ipv6Addr) -> Option<Ordering> {
Some(self.cmp(other))
}
}
#[cfg_attr(staged_api, stable(feature = "ip_cmp", since = "1.16.0"))]
impl PartialOrd<Ipv6Addr> for IpAddr {
#[inline]
fn partial_cmp(&self, other: &Ipv6Addr) -> Option<Ordering> {
match self {
IpAddr::V4(_) => Some(Ordering::Less),
IpAddr::V6(v6) => v6.partial_cmp(other),
}
}
}
#[cfg_attr(staged_api, stable(feature = "ip_cmp", since = "1.16.0"))]
impl PartialOrd<IpAddr> for Ipv6Addr {
#[inline]
fn partial_cmp(&self, other: &IpAddr) -> Option<Ordering> {
match other {
IpAddr::V4(_) => Some(Ordering::Greater),
IpAddr::V6(v6) => self.partial_cmp(v6),
}
}
}
#[cfg_attr(staged_api, stable(feature = "rust1", since = "1.0.0"))]
impl Ord for Ipv6Addr {
#[inline]
fn cmp(&self, other: &Ipv6Addr) -> Ordering {
self.segments().cmp(&other.segments())
}
}
#[cfg_attr(staged_api, stable(feature = "i128", since = "1.26.0"))]
impl From<Ipv6Addr> for u128 {
#[inline]
fn from(ip: Ipv6Addr) -> u128 {
u128::from_be_bytes(ip.octets)
}
}
#[cfg_attr(staged_api, stable(feature = "i128", since = "1.26.0"))]
impl From<u128> for Ipv6Addr {
#[inline]
fn from(ip: u128) -> Ipv6Addr {
Ipv6Addr::from(ip.to_be_bytes())
}
}
#[cfg_attr(staged_api, stable(feature = "ipv6_from_octets", since = "1.9.0"))]
impl From<[u8; 16]> for Ipv6Addr {
#[inline]
fn from(octets: [u8; 16]) -> Ipv6Addr {
Ipv6Addr { octets }
}
}
#[cfg_attr(staged_api, stable(feature = "ipv6_from_segments", since = "1.16.0"))]
impl From<[u16; 8]> for Ipv6Addr {
#[inline]
fn from(segments: [u16; 8]) -> Ipv6Addr {
let [a, b, c, d, e, f, g, h] = segments;
Ipv6Addr::new(a, b, c, d, e, f, g, h)
}
}
#[cfg_attr(staged_api, stable(feature = "ip_from_slice", since = "1.17.0"))]
impl From<[u8; 16]> for IpAddr {
#[inline]
fn from(octets: [u8; 16]) -> IpAddr {
IpAddr::V6(Ipv6Addr::from(octets))
}
}
#[cfg_attr(staged_api, stable(feature = "ip_from_slice", since = "1.17.0"))]
impl From<[u16; 8]> for IpAddr {
#[inline]
fn from(segments: [u16; 8]) -> IpAddr {
IpAddr::V6(Ipv6Addr::from(segments))
}
}