#![allow(unsafe_code)]
use crate::imp::c;
use crate::imp::net::ext::{in6_addr_new, in6_addr_s6_addr, in_addr_new, in_addr_s_addr};
use core::cmp::Ordering;
use core::hash;
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)]
#[cfg_attr(staged_api, stable(feature = "rust1", since = "1.0.0"))]
pub struct Ipv4Addr {
pub(crate) inner: c::in_addr,
}
#[derive(Copy)]
#[cfg_attr(staged_api, stable(feature = "rust1", since = "1.0.0"))]
pub struct Ipv6Addr {
pub(crate) inner: c::in6_addr,
}
#[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", 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", 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", 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", 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", 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_ipv4", 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 {
inner: in_addr_new(u32::from_ne_bytes([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_ipv4", 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] {
in_addr_s_addr(self.inner).to_ne_bytes()
}
#[cfg_attr(
staged_api,
rustc_const_stable(feature = "const_ipv4", 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 {
in_addr_s_addr(self.inner) == 0
}
#[cfg_attr(
staged_api,
rustc_const_stable(feature = "const_ipv4", 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_ipv4", 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_ipv4", 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 {
if u32::from_be_bytes(self.octets()) == 0xc0000009
|| u32::from_be_bytes(self.octets()) == 0xc000000a
{
return true;
}
!self.is_private()
&& !self.is_loopback()
&& !self.is_link_local()
&& !self.is_broadcast()
&& !self.is_documentation()
&& !self.is_shared()
&& !(self.octets()[0] == 192 && self.octets()[1] == 0 && self.octets()[2] == 0)
&& !self.is_reserved()
&& !self.is_benchmarking()
&& self.octets()[0] != 0
}
#[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_ipv4", 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_ipv4", 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_ipv4", 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 {
match self.octets() {
[192, 0, 2, _] => true,
[198, 51, 100, _] => true,
[203, 0, 113, _] => true,
_ => false,
}
}
#[cfg_attr(
staged_api,
rustc_const_stable(feature = "const_ipv4", 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 {
inner: in6_addr_new([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_ipv4", 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 {
inner: in6_addr_new([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 = "rust1", since = "1.0.0"))]
impl Clone for Ipv4Addr {
#[inline]
fn clone(&self) -> Ipv4Addr {
*self
}
}
#[cfg_attr(staged_api, stable(feature = "rust1", since = "1.0.0"))]
impl PartialEq for Ipv4Addr {
#[inline]
fn eq(&self, other: &Ipv4Addr) -> bool {
in_addr_s_addr(self.inner) == in_addr_s_addr(other.inner)
}
}
#[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 Eq for Ipv4Addr {}
#[cfg_attr(staged_api, stable(feature = "rust1", since = "1.0.0"))]
impl hash::Hash for Ipv4Addr {
#[inline]
fn hash<H: hash::Hasher>(&self, s: &mut H) {
{ in_addr_s_addr(self.inner) }.hash(s)
}
}
#[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 {
u32::from_be(in_addr_s_addr(self.inner)).cmp(&u32::from_be(in_addr_s_addr(other.inner)))
}
}
#[cfg_attr(staged_api, stable(feature = "ip_u32", since = "1.1.0"))]
impl From<Ipv4Addr> for u32 {
#[inline]
fn from(ip: Ipv4Addr) -> u32 {
let ip = ip.octets();
u32::from_be_bytes(ip)
}
}
#[cfg_attr(staged_api, stable(feature = "ip_u32", since = "1.1.0"))]
impl From<u32> for Ipv4Addr {
#[inline]
fn from(ip: u32) -> Ipv4Addr {
Ipv4Addr::from(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::new(octets[0], octets[1], octets[2], octets[3])
}
}
#[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_ipv6", since = "1.32.0")
)]
#[cfg_attr(staged_api, stable(feature = "rust1", since = "1.0.0"))]
#[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 {
inner: in6_addr_new(unsafe { transmute::<_, [u8; 16]>(addr16) }),
}
}
#[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);
#[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_ipv6", 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]>(in6_addr_s6_addr(self.inner)) };
[
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_ipv6", 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_ipv6", 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 {
match self.multicast_scope() {
Some(Ipv6MulticastScope::Global) => true,
None => self.is_unicast_global(),
_ => false,
}
}
#[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()
}
#[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_ipv6", 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, unstable(feature = "ip", issue = "27709"))]
#[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_ipv6", 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_ipv6", 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] {
in6_addr_s6_addr(self.inner)
}
}
#[cfg_attr(staged_api, stable(feature = "rust1", since = "1.0.0"))]
impl Clone for Ipv6Addr {
#[inline]
fn clone(&self) -> Ipv6Addr {
*self
}
}
#[cfg_attr(staged_api, stable(feature = "rust1", since = "1.0.0"))]
impl PartialEq for Ipv6Addr {
#[inline]
fn eq(&self, other: &Ipv6Addr) -> bool {
in6_addr_s6_addr(self.inner) == in6_addr_s6_addr(other.inner)
}
}
#[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 Eq for Ipv6Addr {}
#[cfg_attr(staged_api, stable(feature = "rust1", since = "1.0.0"))]
impl hash::Hash for Ipv6Addr {
#[inline]
fn hash<H: hash::Hasher>(&self, s: &mut H) {
in6_addr_s6_addr(self.inner).hash(s)
}
}
#[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 {
let ip = ip.octets();
u128::from_be_bytes(ip)
}
}
#[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 {
inner: in6_addr_new(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))
}
}