From 02e835a30d0fc193138131645a071a0e0566d4fd Mon Sep 17 00:00:00 2001 From: Corentin Henry Date: Wed, 20 Nov 2019 20:45:24 +0100 Subject: [PATCH 01/24] stabilize the "ip" feature and document stability guarantees Feature tracking issue: https://github.com/rust-lang/rust/issues/27709 - Stabilize the following methods: - `IpAddr::is_global` - `IpAddr::is_documentation` - `Ipv4Addr::is_global` - `Ipv4addr::is_shared` - `Ipv4Addr::is_ietf_protocol_assignment` - `Ipv4addr::is_benchmarking` - `Ipv4Addr::is_reserved` - `Ipv6Addr::is_global` - `Ipv6Addr::is_unique_local` - `Ipv6Addr::is_unicast_link_local_strict` - `Ipv6Addr::is_unicast_link_local` - `Ipv6Addr::is_unicast_site_local` - `Ipv6Addr::is_documentation` - `Ipv6Addr::is_unicast_global` - `Ipv6Addr::multicast_scope` - Stabilize the following enum: `Ipv6MulticastScope` - Document IP helpers stability guarantees (fixes https://github.com/rust-lang/rust/issues/60239) --- src/libstd/net/ip.rs | 2915 +++++++++++++++++++++++++++++++++++++++++ src/libstd/net/mod.rs | 132 ++ 2 files changed, 3047 insertions(+) create mode 100644 src/libstd/net/ip.rs create mode 100644 src/libstd/net/mod.rs diff --git a/src/libstd/net/ip.rs b/src/libstd/net/ip.rs new file mode 100644 index 0000000000000..60b613cfd8c32 --- /dev/null +++ b/src/libstd/net/ip.rs @@ -0,0 +1,2915 @@ +use crate::cmp::Ordering; +use crate::fmt; +use crate::hash; +use crate::io::Write; +use crate::sys::net::netc as c; +use crate::sys_common::{AsInner, FromInner}; + +/// An IP address, either IPv4 or IPv6. +/// +/// This enum can contain either an [`Ipv4Addr`] or an [`Ipv6Addr`], see their +/// respective documentation for more details. +/// +/// The size of an `IpAddr` instance may vary depending on the target operating +/// system. +/// +/// [`Ipv4Addr`]: ../../std/net/struct.Ipv4Addr.html +/// [`Ipv6Addr`]: ../../std/net/struct.Ipv6Addr.html +/// +/// # Examples +/// +/// ``` +/// use std::net::{IpAddr, Ipv4Addr, Ipv6Addr}; +/// +/// let localhost_v4 = IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)); +/// let localhost_v6 = IpAddr::V6(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1)); +/// +/// assert_eq!("127.0.0.1".parse(), Ok(localhost_v4)); +/// assert_eq!("::1".parse(), Ok(localhost_v6)); +/// +/// assert_eq!(localhost_v4.is_ipv6(), false); +/// assert_eq!(localhost_v4.is_ipv4(), true); +/// ``` +#[stable(feature = "ip_addr", since = "1.7.0")] +#[derive(Copy, Clone, Eq, PartialEq, Debug, Hash, PartialOrd, Ord)] +pub enum IpAddr { + /// An IPv4 address. + #[stable(feature = "ip_addr", since = "1.7.0")] + V4(#[stable(feature = "ip_addr", since = "1.7.0")] Ipv4Addr), + /// An IPv6 address. + #[stable(feature = "ip_addr", since = "1.7.0")] + V6(#[stable(feature = "ip_addr", since = "1.7.0")] Ipv6Addr), +} + +/// An IPv4 address. +/// +/// IPv4 addresses are defined as 32-bit integers in [IETF RFC 791]. +/// They are usually represented as four octets. +/// +/// See [`IpAddr`] for a type encompassing both IPv4 and IPv6 addresses. +/// +/// The size of an `Ipv4Addr` struct may vary depending on the target operating +/// system. +/// +/// [IETF RFC 791]: https://tools.ietf.org/html/rfc791 +/// [`IpAddr`]: ../../std/net/enum.IpAddr.html +/// +/// # Textual representation +/// +/// `Ipv4Addr` provides a [`FromStr`] implementation. The four octets are in decimal +/// notation, divided by `.` (this is called "dot-decimal notation"). +/// +/// [`FromStr`]: ../../std/str/trait.FromStr.html +/// +/// # Examples +/// +/// ``` +/// use std::net::Ipv4Addr; +/// +/// let localhost = Ipv4Addr::new(127, 0, 0, 1); +/// assert_eq!("127.0.0.1".parse(), Ok(localhost)); +/// assert_eq!(localhost.is_loopback(), true); +/// ``` +#[derive(Copy)] +#[stable(feature = "rust1", since = "1.0.0")] +pub struct Ipv4Addr { + inner: c::in_addr, +} + +/// An IPv6 address. +/// +/// IPv6 addresses are defined as 128-bit integers in [IETF RFC 4291]. +/// They are usually represented as eight 16-bit segments. +/// +/// See [`IpAddr`] for a type encompassing both IPv4 and IPv6 addresses. +/// +/// The size of an `Ipv6Addr` struct may vary depending on the target operating +/// system. +/// +/// [IETF RFC 4291]: https://tools.ietf.org/html/rfc4291 +/// [`IpAddr`]: ../../std/net/enum.IpAddr.html +/// +/// # Textual representation +/// +/// `Ipv6Addr` provides a [`FromStr`] implementation. There are many ways to represent +/// an IPv6 address in text, but in general, each segments is written in hexadecimal +/// notation, and segments are separated by `:`. For more information, see +/// [IETF RFC 5952]. +/// +/// [`FromStr`]: ../../std/str/trait.FromStr.html +/// [IETF RFC 5952]: https://tools.ietf.org/html/rfc5952 +/// +/// # Examples +/// +/// ``` +/// use std::net::Ipv6Addr; +/// +/// let localhost = Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1); +/// assert_eq!("::1".parse(), Ok(localhost)); +/// assert_eq!(localhost.is_loopback(), true); +/// ``` +#[derive(Copy)] +#[stable(feature = "rust1", since = "1.0.0")] +pub struct Ipv6Addr { + inner: c::in6_addr, +} + +/// Scope of an IPv6 address as defined in [section 2 of IETF RFC 7346] +/// +/// [section 2 of IETF RFC 7346]: https://tools.ietf.org/html/rfc7346#section-2 +#[derive(Copy, PartialEq, Eq, Clone, Hash, Debug)] +#[stable(feature = "ip", since = "1.42.0")] +pub enum Ipv6MulticastScope { + /// Interface-Local scope. See [RFC 4291] and [RFC 7346] + /// + /// [RFC 4291]: https://tools.ietf.org/html/rfc4291#section-2.7 + /// [RFC 7346]: https://tools.ietf.org/html/rfc7346#section-2 + #[stable(feature = "ip", since = "1.42.0")] + InterfaceLocal, + + /// Link-Local scope. See [RFC 4291] and [RFC 7346] + /// + /// [RFC 4291]: https://tools.ietf.org/html/rfc4291#section-2.7 + /// [RFC 7346]: https://tools.ietf.org/html/rfc7346#section-2 + #[stable(feature = "ip", since = "1.42.0")] + LinkLocal, + + /// Realm-Local scope. See [RFC 4291] and [RFC 7346] + /// + /// [RFC 4291]: https://tools.ietf.org/html/rfc4291#section-2.7 + /// [RFC 7346]: https://tools.ietf.org/html/rfc7346#section-2 + #[stable(feature = "ip", since = "1.42.0")] + RealmLocal, + + /// Admin-Local scope. See [RFC 4291] and [RFC 7346] + /// + /// [RFC 4291]: https://tools.ietf.org/html/rfc4291#section-2.7 + /// [RFC 7346]: https://tools.ietf.org/html/rfc7346#section-2 + #[stable(feature = "ip", since = "1.42.0")] + AdminLocal, + + /// Site-Local scope. See [RFC 4291] and [RFC 7346] + /// + /// [RFC 4291]: https://tools.ietf.org/html/rfc4291#section-2.7 + /// [RFC 7346]: https://tools.ietf.org/html/rfc7346#section-2 + #[stable(feature = "ip", since = "1.42.0")] + SiteLocal, + + /// Organization-Local scope. See [RFC 4291] and [RFC 7346] + /// + /// [RFC 4291]: https://tools.ietf.org/html/rfc4291#section-2.7 + /// [RFC 7346]: https://tools.ietf.org/html/rfc7346#section-2 + #[stable(feature = "ip", since = "1.42.0")] + OrganizationLocal, + + /// Global scope. See [RFC 4291] and [RFC 7346] + /// + /// [RFC 4291]: https://tools.ietf.org/html/rfc4291#section-2.7 + /// [RFC 7346]: https://tools.ietf.org/html/rfc7346#section-2 + #[stable(feature = "ip", since = "1.42.0")] + Global, +} + +impl IpAddr { + /// Returns [`true`] for the special 'unspecified' address. + /// + /// See the documentation for [`Ipv4Addr::is_unspecified`][IPv4] and + /// [`Ipv6Addr::is_unspecified`][IPv6] for more details. + /// + /// [IPv4]: ../../std/net/struct.Ipv4Addr.html#method.is_unspecified + /// [IPv6]: ../../std/net/struct.Ipv6Addr.html#method.is_unspecified + /// [`true`]: ../../std/primitive.bool.html + /// + /// # Examples + /// + /// ``` + /// use std::net::{IpAddr, Ipv4Addr, Ipv6Addr}; + /// + /// assert_eq!(IpAddr::V4(Ipv4Addr::new(0, 0, 0, 0)).is_unspecified(), true); + /// assert_eq!(IpAddr::V6(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0)).is_unspecified(), true); + /// ``` + /// + /// # Stability guarantees + /// + /// This method's behavior [may by subject to changes][changes] in the + /// future, as new RFCs are published. + /// + /// [changes]: ../net/index.html#stability-guarantees-for-ietf-defined-behavior + #[stable(feature = "ip_shared", since = "1.12.0")] + pub fn is_unspecified(&self) -> bool { + match self { + IpAddr::V4(ip) => ip.is_unspecified(), + IpAddr::V6(ip) => ip.is_unspecified(), + } + } + + /// Returns [`true`] if this is a loopback address. + /// + /// See the documentation for [`Ipv4Addr::is_loopback`][IPv4] and + /// [`Ipv6Addr::is_loopback`][IPv6] for more details. + /// + /// [IPv4]: ../../std/net/struct.Ipv4Addr.html#method.is_loopback + /// [IPv6]: ../../std/net/struct.Ipv6Addr.html#method.is_loopback + /// [`true`]: ../../std/primitive.bool.html + /// + /// # Examples + /// + /// ``` + /// use std::net::{IpAddr, Ipv4Addr, Ipv6Addr}; + /// + /// assert_eq!(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)).is_loopback(), true); + /// assert_eq!(IpAddr::V6(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0x1)).is_loopback(), true); + /// ``` + /// + /// # Stability guarantees + /// + /// This method's behavior [may by subject to changes][changes] in the + /// future, as new RFCs are published. + /// + /// [changes]: ../net/index.html#stability-guarantees-for-ietf-defined-behavior + #[stable(feature = "ip_shared", since = "1.12.0")] + pub fn is_loopback(&self) -> bool { + match self { + IpAddr::V4(ip) => ip.is_loopback(), + IpAddr::V6(ip) => ip.is_loopback(), + } + } + + /// Returns [`true`] if the address appears to be globally routable. + /// + /// See the documentation for [`Ipv4Addr::is_global`][IPv4] and + /// [`Ipv6Addr::is_global`][IPv6] for more details. + /// + /// [IPv4]: ../../std/net/struct.Ipv4Addr.html#method.is_global + /// [IPv6]: ../../std/net/struct.Ipv6Addr.html#method.is_global + /// [`true`]: ../../std/primitive.bool.html + /// + /// # Examples + /// + /// ``` + /// use std::net::{IpAddr, Ipv4Addr, Ipv6Addr}; + /// + /// assert_eq!(IpAddr::V4(Ipv4Addr::new(80, 9, 12, 3)).is_global(), true); + /// assert_eq!(IpAddr::V6(Ipv6Addr::new(0, 0, 0x1c9, 0, 0, 0xafc8, 0, 0x1)).is_global(), true); + /// ``` + /// + /// # Stability guarantees + /// + /// This method's behavior [may by subject to changes][changes] in the + /// future, as new RFCs are published. + /// + /// [changes]: ../net/index.html#stability-guarantees-for-ietf-defined-behavior + #[stable(feature = "ip", since = "1.42.0")] + pub fn is_global(&self) -> bool { + match self { + IpAddr::V4(ip) => ip.is_global(), + IpAddr::V6(ip) => ip.is_global(), + } + } + + /// Returns [`true`] if this is a multicast address. + /// + /// See the documentation for [`Ipv4Addr::is_multicast`][IPv4] and + /// [`Ipv6Addr::is_multicast`][IPv6] for more details. + /// + /// [IPv4]: ../../std/net/struct.Ipv4Addr.html#method.is_multicast + /// [IPv6]: ../../std/net/struct.Ipv6Addr.html#method.is_multicast + /// [`true`]: ../../std/primitive.bool.html + /// + /// # Examples + /// + /// ``` + /// use std::net::{IpAddr, Ipv4Addr, Ipv6Addr}; + /// + /// assert_eq!(IpAddr::V4(Ipv4Addr::new(224, 254, 0, 0)).is_multicast(), true); + /// assert_eq!(IpAddr::V6(Ipv6Addr::new(0xff00, 0, 0, 0, 0, 0, 0, 0)).is_multicast(), true); + /// ``` + /// + /// # Stability guarantees + /// + /// This method's behavior [may by subject to changes][changes] in the + /// future, as new RFCs are published. + /// + /// [changes]: ../net/index.html#stability-guarantees-for-ietf-defined-behavior + #[stable(feature = "ip_shared", since = "1.12.0")] + pub fn is_multicast(&self) -> bool { + match self { + IpAddr::V4(ip) => ip.is_multicast(), + IpAddr::V6(ip) => ip.is_multicast(), + } + } + + /// Returns [`true`] if this address is in a range designated for documentation. + /// + /// See the documentation for [`Ipv4Addr::is_documentation`][IPv4] and + /// [`Ipv6Addr::is_documentation`][IPv6] for more details. + /// + /// [IPv4]: ../../std/net/struct.Ipv4Addr.html#method.is_documentation + /// [IPv6]: ../../std/net/struct.Ipv6Addr.html#method.is_documentation + /// [`true`]: ../../std/primitive.bool.html + /// + /// # Examples + /// + /// ``` + /// use std::net::{IpAddr, Ipv4Addr, Ipv6Addr}; + /// + /// assert_eq!(IpAddr::V4(Ipv4Addr::new(203, 0, 113, 6)).is_documentation(), true); + /// assert_eq!( + /// IpAddr::V6(Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 0)).is_documentation(), + /// true + /// ); + /// ``` + /// + /// # Stability guarantees + /// + /// This method's behavior [may by subject to changes][changes] in the + /// future, as new RFCs are published. + /// + /// [changes]: ../net/index.html#stability-guarantees-for-ietf-defined-behavior + #[stable(feature = "ip", since = "1.42.0")] + pub fn is_documentation(&self) -> bool { + match self { + IpAddr::V4(ip) => ip.is_documentation(), + IpAddr::V6(ip) => ip.is_documentation(), + } + } + + /// Returns [`true`] if this address is an [IPv4 address], and [`false`] otherwise. + /// + /// [`true`]: ../../std/primitive.bool.html + /// [`false`]: ../../std/primitive.bool.html + /// [IPv4 address]: #variant.V4 + /// + /// # Examples + /// + /// ``` + /// use std::net::{IpAddr, Ipv4Addr, Ipv6Addr}; + /// + /// assert_eq!(IpAddr::V4(Ipv4Addr::new(203, 0, 113, 6)).is_ipv4(), true); + /// assert_eq!(IpAddr::V6(Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 0)).is_ipv4(), false); + /// ``` + /// + /// # Stability guarantees + /// + /// This method's behavior [may by subject to changes][changes] in the + /// future, as new RFCs are published. + /// + /// [changes]: ../net/index.html#stability-guarantees-for-ietf-defined-behavior + #[stable(feature = "ipaddr_checker", since = "1.16.0")] + pub fn is_ipv4(&self) -> bool { + matches!(self, IpAddr::V4(_)) + } + + /// Returns [`true`] if this address is an [IPv6 address], and [`false`] otherwise. + /// + /// [`true`]: ../../std/primitive.bool.html + /// [`false`]: ../../std/primitive.bool.html + /// [IPv6 address]: #variant.V6 + /// + /// # Examples + /// + /// ``` + /// use std::net::{IpAddr, Ipv4Addr, Ipv6Addr}; + /// + /// assert_eq!(IpAddr::V4(Ipv4Addr::new(203, 0, 113, 6)).is_ipv6(), false); + /// assert_eq!(IpAddr::V6(Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 0)).is_ipv6(), true); + /// ``` + /// + /// # Stability guarantees + /// + /// This method's behavior [may by subject to changes][changes] in the + /// future, as new RFCs are published. + /// + /// [changes]: ../net/index.html#stability-guarantees-for-ietf-defined-behavior + #[stable(feature = "ipaddr_checker", since = "1.16.0")] + pub fn is_ipv6(&self) -> bool { + matches!(self, IpAddr::V6(_)) + } +} + +impl Ipv4Addr { + /// Creates a new IPv4 address from four eight-bit octets. + /// + /// The result will represent the IP address `a`.`b`.`c`.`d`. + /// + /// # Examples + /// + /// ``` + /// use std::net::Ipv4Addr; + /// + /// let addr = Ipv4Addr::new(127, 0, 0, 1); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_const_stable(feature = "const_ipv4", since = "1.32.0")] + pub const fn new(a: u8, b: u8, c: u8, d: u8) -> Ipv4Addr { + // FIXME: should just be u32::from_be_bytes([a, b, c, d]), + // once that method is no longer rustc_const_unstable + Ipv4Addr { + inner: c::in_addr { + s_addr: u32::to_be( + ((a as u32) << 24) | ((b as u32) << 16) | ((c as u32) << 8) | (d as u32), + ), + }, + } + } + + /// An IPv4 address with the address pointing to localhost: 127.0.0.1. + /// + /// # Examples + /// + /// ``` + /// use std::net::Ipv4Addr; + /// + /// let addr = Ipv4Addr::LOCALHOST; + /// assert_eq!(addr, Ipv4Addr::new(127, 0, 0, 1)); + /// ``` + #[stable(feature = "ip_constructors", since = "1.30.0")] + pub const LOCALHOST: Self = Ipv4Addr::new(127, 0, 0, 1); + + /// An IPv4 address representing an unspecified address: 0.0.0.0 + /// + /// # Examples + /// + /// ``` + /// use std::net::Ipv4Addr; + /// + /// let addr = Ipv4Addr::UNSPECIFIED; + /// assert_eq!(addr, Ipv4Addr::new(0, 0, 0, 0)); + /// ``` + #[stable(feature = "ip_constructors", since = "1.30.0")] + pub const UNSPECIFIED: Self = Ipv4Addr::new(0, 0, 0, 0); + + /// An IPv4 address representing the broadcast address: 255.255.255.255 + /// + /// # Examples + /// + /// ``` + /// use std::net::Ipv4Addr; + /// + /// let addr = Ipv4Addr::BROADCAST; + /// assert_eq!(addr, Ipv4Addr::new(255, 255, 255, 255)); + /// ``` + #[stable(feature = "ip_constructors", since = "1.30.0")] + pub const BROADCAST: Self = Ipv4Addr::new(255, 255, 255, 255); + + /// Returns the four eight-bit integers that make up this address. + /// + /// # Examples + /// + /// ``` + /// use std::net::Ipv4Addr; + /// + /// let addr = Ipv4Addr::new(127, 0, 0, 1); + /// assert_eq!(addr.octets(), [127, 0, 0, 1]); + /// ``` + /// + /// # Stability guarantees + /// + /// This method's behavior [may by subject to changes][changes] in the + /// future, as new RFCs are published. + /// + /// [changes]: ../net/index.html#stability-guarantees-for-ietf-defined-behavior + #[stable(feature = "rust1", since = "1.0.0")] + pub fn octets(&self) -> [u8; 4] { + // This returns the order we want because s_addr is stored in big-endian. + self.inner.s_addr.to_ne_bytes() + } + + /// Returns [`true`] for the special 'unspecified' address (0.0.0.0). + /// + /// This property is defined in _UNIX Network Programming, Second Edition_, + /// W. Richard Stevens, p. 891; see also [ip7]. + /// + /// [ip7]: http://man7.org/linux/man-pages/man7/ip.7.html + /// [`true`]: ../../std/primitive.bool.html + /// + /// # Examples + /// + /// ``` + /// use std::net::Ipv4Addr; + /// + /// assert_eq!(Ipv4Addr::new(0, 0, 0, 0).is_unspecified(), true); + /// assert_eq!(Ipv4Addr::new(45, 22, 13, 197).is_unspecified(), false); + /// ``` + #[stable(feature = "ip_shared", since = "1.12.0")] + #[rustc_const_stable(feature = "const_ipv4", since = "1.32.0")] + pub const fn is_unspecified(&self) -> bool { + self.inner.s_addr == 0 + } + + /// Returns [`true`] if this is a loopback address (127.0.0.0/8). + /// + /// This property is defined by [IETF RFC 1122]. + /// + /// [IETF RFC 1122]: https://tools.ietf.org/html/rfc1122 + /// [`true`]: ../../std/primitive.bool.html + /// + /// # Examples + /// + /// ``` + /// use std::net::Ipv4Addr; + /// + /// assert_eq!(Ipv4Addr::new(127, 0, 0, 1).is_loopback(), true); + /// assert_eq!(Ipv4Addr::new(45, 22, 13, 197).is_loopback(), false); + /// ``` + /// + /// # Stability guarantees + /// + /// This method's behavior [may by subject to changes][changes] in the + /// future, as new RFCs are published. + /// + /// [changes]: ../net/index.html#stability-guarantees-for-ietf-defined-behavior + #[stable(since = "1.7.0", feature = "ip_17")] + pub fn is_loopback(&self) -> bool { + self.octets()[0] == 127 + } + + /// Returns [`true`] if this is a private address. + /// + /// The private address ranges are defined in [IETF RFC 1918] and include: + /// + /// - 10.0.0.0/8 + /// - 172.16.0.0/12 + /// - 192.168.0.0/16 + /// + /// [IETF RFC 1918]: https://tools.ietf.org/html/rfc1918 + /// [`true`]: ../../std/primitive.bool.html + /// + /// # Examples + /// + /// ``` + /// use std::net::Ipv4Addr; + /// + /// assert_eq!(Ipv4Addr::new(10, 0, 0, 1).is_private(), true); + /// assert_eq!(Ipv4Addr::new(10, 10, 10, 10).is_private(), true); + /// assert_eq!(Ipv4Addr::new(172, 16, 10, 10).is_private(), true); + /// assert_eq!(Ipv4Addr::new(172, 29, 45, 14).is_private(), true); + /// assert_eq!(Ipv4Addr::new(172, 32, 0, 2).is_private(), false); + /// assert_eq!(Ipv4Addr::new(192, 168, 0, 2).is_private(), true); + /// assert_eq!(Ipv4Addr::new(192, 169, 0, 2).is_private(), false); + /// ``` + /// + /// # Stability guarantees + /// + /// This method's behavior [may by subject to changes][changes] in the + /// future, as new RFCs are published. + /// + /// [changes]: ../net/index.html#stability-guarantees-for-ietf-defined-behavior + #[stable(since = "1.7.0", feature = "ip_17")] + pub fn is_private(&self) -> bool { + match self.octets() { + [10, ..] => true, + [172, b, ..] if b >= 16 && b <= 31 => true, + [192, 168, ..] => true, + _ => false, + } + } + + /// Returns [`true`] if the address is link-local (169.254.0.0/16). + /// + /// This property is defined by [IETF RFC 3927]. + /// + /// [IETF RFC 3927]: https://tools.ietf.org/html/rfc3927 + /// [`true`]: ../../std/primitive.bool.html + /// + /// # Examples + /// + /// ``` + /// use std::net::Ipv4Addr; + /// + /// assert_eq!(Ipv4Addr::new(169, 254, 0, 0).is_link_local(), true); + /// assert_eq!(Ipv4Addr::new(169, 254, 10, 65).is_link_local(), true); + /// assert_eq!(Ipv4Addr::new(16, 89, 10, 65).is_link_local(), false); + /// ``` + /// + /// # Stability guarantees + /// + /// This method's behavior [may by subject to changes][changes] in the + /// future, as new RFCs are published. + /// + /// [changes]: ../net/index.html#stability-guarantees-for-ietf-defined-behavior + #[stable(since = "1.7.0", feature = "ip_17")] + pub fn is_link_local(&self) -> bool { + match self.octets() { + [169, 254, ..] => true, + _ => false, + } + } + + /// Returns [`true`] if the address appears to be globally routable. + /// See [iana-ipv4-special-registry][ipv4-sr]. + /// + /// The following return false: + /// + /// - private addresses (see [`is_private()`](#method.is_private)) + /// - the loopback address (see [`is_loopback()`](#method.is_loopback)) + /// - the link-local address (see [`is_link_local()`](#method.is_link_local)) + /// - the broadcast address (see [`is_broadcast()`](#method.is_broadcast)) + /// - addresses used for documentation (see [`is_documentation()`](#method.is_documentation)) + /// - the unspecified address (see [`is_unspecified()`](#method.is_unspecified)), and the whole + /// 0.0.0.0/8 block + /// - addresses reserved for future protocols (see + /// [`is_ietf_protocol_assignment()`](#method.is_ietf_protocol_assignment), except + /// `192.0.0.9/32` and `192.0.0.10/32` which are globally routable + /// - addresses reserved for future use (see [`is_reserved()`](#method.is_reserved) + /// - addresses reserved for networking devices benchmarking (see + /// [`is_benchmarking`](#method.is_benchmarking)) + /// + /// [ipv4-sr]: https://www.iana.org/assignments/iana-ipv4-special-registry/iana-ipv4-special-registry.xhtml + /// [`true`]: ../../std/primitive.bool.html + /// + /// # Examples + /// + /// ``` + /// use std::net::Ipv4Addr; + /// + /// // private addresses are not global + /// assert_eq!(Ipv4Addr::new(10, 254, 0, 0).is_global(), false); + /// assert_eq!(Ipv4Addr::new(192, 168, 10, 65).is_global(), false); + /// assert_eq!(Ipv4Addr::new(172, 16, 10, 65).is_global(), false); + /// + /// // the 0.0.0.0/8 block is not global + /// assert_eq!(Ipv4Addr::new(0, 1, 2, 3).is_global(), false); + /// // in particular, the unspecified address is not global + /// assert_eq!(Ipv4Addr::new(0, 0, 0, 0).is_global(), false); + /// + /// // the loopback address is not global + /// assert_eq!(Ipv4Addr::new(127, 0, 0, 1).is_global(), false); + /// + /// // link local addresses are not global + /// assert_eq!(Ipv4Addr::new(169, 254, 45, 1).is_global(), false); + /// + /// // the broadcast address is not global + /// assert_eq!(Ipv4Addr::new(255, 255, 255, 255).is_global(), false); + /// + /// // the address space designated for documentation is not global + /// assert_eq!(Ipv4Addr::new(192, 0, 2, 255).is_global(), false); + /// assert_eq!(Ipv4Addr::new(198, 51, 100, 65).is_global(), false); + /// assert_eq!(Ipv4Addr::new(203, 0, 113, 6).is_global(), false); + /// + /// // shared addresses are not global + /// assert_eq!(Ipv4Addr::new(100, 100, 0, 0).is_global(), false); + /// + /// // addresses reserved for protocol assignment are not global + /// assert_eq!(Ipv4Addr::new(192, 0, 0, 0).is_global(), false); + /// assert_eq!(Ipv4Addr::new(192, 0, 0, 255).is_global(), false); + /// + /// // addresses reserved for future use are not global + /// assert_eq!(Ipv4Addr::new(250, 10, 20, 30).is_global(), false); + /// + /// // addresses reserved for network devices benchmarking are not global + /// assert_eq!(Ipv4Addr::new(198, 18, 0, 0).is_global(), false); + /// + /// // All the other addresses are global + /// assert_eq!(Ipv4Addr::new(1, 1, 1, 1).is_global(), true); + /// assert_eq!(Ipv4Addr::new(80, 9, 12, 3).is_global(), true); + /// ``` + /// + /// # Stability guarantees + /// + /// This method's behavior [may by subject to changes][changes] in the + /// future, as new RFCs are published. + /// + /// [changes]: ../net/index.html#stability-guarantees-for-ietf-defined-behavior + #[stable(feature = "ip", since = "1.42.0")] + pub fn is_global(&self) -> bool { + // check if this address is 192.0.0.9 or 192.0.0.10. These addresses are the only two + // globally routable addresses in the 192.0.0.0/24 range. + if u32::from(*self) == 0xc0000009 || u32::from(*self) == 0xc000000a { + return true; + } + !self.is_private() + && !self.is_loopback() + && !self.is_link_local() + && !self.is_broadcast() + && !self.is_documentation() + && !self.is_shared() + && !self.is_ietf_protocol_assignment() + && !self.is_reserved() + && !self.is_benchmarking() + // Make sure the address is not in 0.0.0.0/8 + && self.octets()[0] != 0 + } + + /// Returns [`true`] if this address is part of the Shared Address Space defined in + /// [IETF RFC 6598] (`100.64.0.0/10`). + /// + /// [IETF RFC 6598]: https://tools.ietf.org/html/rfc6598 + /// [`true`]: ../../std/primitive.bool.html + /// + /// # Examples + /// + /// ``` + /// use std::net::Ipv4Addr; + /// + /// assert_eq!(Ipv4Addr::new(100, 64, 0, 0).is_shared(), true); + /// assert_eq!(Ipv4Addr::new(100, 127, 255, 255).is_shared(), true); + /// assert_eq!(Ipv4Addr::new(100, 128, 0, 0).is_shared(), false); + /// ``` + /// + /// # Stability guarantees + /// + /// This method's behavior [may by subject to changes][changes] in the + /// future, as new RFCs are published. + /// + /// [changes]: ../net/index.html#stability-guarantees-for-ietf-defined-behavior + #[stable(feature = "ip", since = "1.42.0")] + pub fn is_shared(&self) -> bool { + self.octets()[0] == 100 && (self.octets()[1] & 0b1100_0000 == 0b0100_0000) + } + + /// Returns [`true`] if this address is part of `192.0.0.0/24`, which is reserved to + /// IANA for IETF protocol assignments, as documented in [IETF RFC 6890]. + /// + /// Note that parts of this block are in use: + /// + /// - `192.0.0.8/32` is the "IPv4 dummy address" (see [IETF RFC 7600]) + /// - `192.0.0.9/32` is the "Port Control Protocol Anycast" (see [IETF RFC 7723]) + /// - `192.0.0.10/32` is used for NAT traversal (see [IETF RFC 8155]) + /// + /// [IETF RFC 6890]: https://tools.ietf.org/html/rfc6890 + /// [IETF RFC 7600]: https://tools.ietf.org/html/rfc7600 + /// [IETF RFC 7723]: https://tools.ietf.org/html/rfc7723 + /// [IETF RFC 8155]: https://tools.ietf.org/html/rfc8155 + /// [`true`]: ../../std/primitive.bool.html + /// + /// # Examples + /// + /// ``` + /// use std::net::Ipv4Addr; + /// + /// assert_eq!(Ipv4Addr::new(192, 0, 0, 0).is_ietf_protocol_assignment(), true); + /// assert_eq!(Ipv4Addr::new(192, 0, 0, 8).is_ietf_protocol_assignment(), true); + /// assert_eq!(Ipv4Addr::new(192, 0, 0, 9).is_ietf_protocol_assignment(), true); + /// assert_eq!(Ipv4Addr::new(192, 0, 0, 255).is_ietf_protocol_assignment(), true); + /// assert_eq!(Ipv4Addr::new(192, 0, 1, 0).is_ietf_protocol_assignment(), false); + /// assert_eq!(Ipv4Addr::new(191, 255, 255, 255).is_ietf_protocol_assignment(), false); + /// ``` + /// + /// # Stability guarantees + /// + /// This method's behavior [may by subject to changes][changes] in the + /// future, as new RFCs are published. + /// + /// [changes]: ../net/index.html#stability-guarantees-for-ietf-defined-behavior + #[stable(feature = "ip", since = "1.42.0")] + pub fn is_ietf_protocol_assignment(&self) -> bool { + self.octets()[0] == 192 && self.octets()[1] == 0 && self.octets()[2] == 0 + } + + /// Returns [`true`] if this address part of the `198.18.0.0/15` range, which is reserved for + /// network devices benchmarking. This range is defined in [IETF RFC 2544] as `192.18.0.0` + /// through `198.19.255.255` but [errata 423] corrects it to `198.18.0.0/15`. + /// + /// [IETF RFC 2544]: https://tools.ietf.org/html/rfc2544 + /// [errata 423]: https://www.rfc-editor.org/errata/eid423 + /// [`true`]: ../../std/primitive.bool.html + /// + /// # Examples + /// + /// ``` + /// use std::net::Ipv4Addr; + /// + /// assert_eq!(Ipv4Addr::new(198, 17, 255, 255).is_benchmarking(), false); + /// assert_eq!(Ipv4Addr::new(198, 18, 0, 0).is_benchmarking(), true); + /// assert_eq!(Ipv4Addr::new(198, 19, 255, 255).is_benchmarking(), true); + /// assert_eq!(Ipv4Addr::new(198, 20, 0, 0).is_benchmarking(), false); + /// ``` + /// + /// # Stability guarantees + /// + /// This method's behavior [may by subject to changes][changes] in the + /// future, as new RFCs are published. + /// + /// [changes]: ../net/index.html#stability-guarantees-for-ietf-defined-behavior + #[stable(feature = "ip", since = "1.42.0")] + pub fn is_benchmarking(&self) -> bool { + self.octets()[0] == 198 && (self.octets()[1] & 0xfe) == 18 + } + + /// Returns [`true`] if this address is reserved by IANA for future use. [IETF RFC 1112] + /// defines the block of reserved addresses as `240.0.0.0/4`. This range normally includes the + /// broadcast address `255.255.255.255`, but this implementation explicitely excludes it, since + /// it is obviously not reserved for future use. + /// + /// [IETF RFC 1112]: https://tools.ietf.org/html/rfc1112 + /// [`true`]: ../../std/primitive.bool.html + /// + /// # Warning + /// + /// As IANA assigns new addresses, this method will be + /// updated. This may result in non-reserved addresses being + /// treated as reserved in code that relies on an outdated version + /// of this method. + /// + /// # Examples + /// + /// ``` + /// use std::net::Ipv4Addr; + /// + /// assert_eq!(Ipv4Addr::new(240, 0, 0, 0).is_reserved(), true); + /// assert_eq!(Ipv4Addr::new(255, 255, 255, 254).is_reserved(), true); + /// + /// assert_eq!(Ipv4Addr::new(239, 255, 255, 255).is_reserved(), false); + /// // The broadcast address is not considered as reserved for future use by this implementation + /// assert_eq!(Ipv4Addr::new(255, 255, 255, 255).is_reserved(), false); + /// ``` + /// + /// # Stability guarantees + /// + /// This method's behavior [may by subject to changes][changes] in the + /// future, as new RFCs are published. + /// + /// [changes]: ../net/index.html#stability-guarantees-for-ietf-defined-behavior + #[stable(feature = "ip", since = "1.42.0")] + pub fn is_reserved(&self) -> bool { + self.octets()[0] & 240 == 240 && !self.is_broadcast() + } + + /// Returns [`true`] if this is a multicast address (224.0.0.0/4). + /// + /// Multicast addresses have a most significant octet between 224 and 239, + /// and is defined by [IETF RFC 5771]. + /// + /// [IETF RFC 5771]: https://tools.ietf.org/html/rfc5771 + /// [`true`]: ../../std/primitive.bool.html + /// + /// # Examples + /// + /// ``` + /// use std::net::Ipv4Addr; + /// + /// assert_eq!(Ipv4Addr::new(224, 254, 0, 0).is_multicast(), true); + /// assert_eq!(Ipv4Addr::new(236, 168, 10, 65).is_multicast(), true); + /// assert_eq!(Ipv4Addr::new(172, 16, 10, 65).is_multicast(), false); + /// ``` + /// + /// # Stability guarantees + /// + /// This method's behavior [may by subject to changes][changes] in the + /// future, as new RFCs are published. + /// + /// [changes]: ../net/index.html#stability-guarantees-for-ietf-defined-behavior + #[stable(since = "1.7.0", feature = "ip_17")] + pub fn is_multicast(&self) -> bool { + self.octets()[0] >= 224 && self.octets()[0] <= 239 + } + + /// Returns [`true`] if this is a broadcast address (255.255.255.255). + /// + /// A broadcast address has all octets set to 255 as defined in [IETF RFC 919]. + /// + /// [IETF RFC 919]: https://tools.ietf.org/html/rfc919 + /// [`true`]: ../../std/primitive.bool.html + /// + /// # Examples + /// + /// ``` + /// use std::net::Ipv4Addr; + /// + /// assert_eq!(Ipv4Addr::new(255, 255, 255, 255).is_broadcast(), true); + /// assert_eq!(Ipv4Addr::new(236, 168, 10, 65).is_broadcast(), false); + /// ``` + /// + /// # Stability guarantees + /// + /// This method's behavior [may by subject to changes][changes] in the + /// future, as new RFCs are published. + /// + /// [changes]: ../net/index.html#stability-guarantees-for-ietf-defined-behavior + #[stable(since = "1.7.0", feature = "ip_17")] + pub fn is_broadcast(&self) -> bool { + self == &Self::BROADCAST + } + + /// Returns [`true`] if this address is in a range designated for documentation. + /// + /// This is defined in [IETF RFC 5737]: + /// + /// - 192.0.2.0/24 (TEST-NET-1) + /// - 198.51.100.0/24 (TEST-NET-2) + /// - 203.0.113.0/24 (TEST-NET-3) + /// + /// [IETF RFC 5737]: https://tools.ietf.org/html/rfc5737 + /// [`true`]: ../../std/primitive.bool.html + /// + /// # Examples + /// + /// ``` + /// use std::net::Ipv4Addr; + /// + /// assert_eq!(Ipv4Addr::new(192, 0, 2, 255).is_documentation(), true); + /// assert_eq!(Ipv4Addr::new(198, 51, 100, 65).is_documentation(), true); + /// assert_eq!(Ipv4Addr::new(203, 0, 113, 6).is_documentation(), true); + /// assert_eq!(Ipv4Addr::new(193, 34, 17, 19).is_documentation(), false); + /// ``` + /// + /// # Stability guarantees + /// + /// This method's behavior [may by subject to changes][changes] in the + /// future, as new RFCs are published. + /// + /// [changes]: ../net/index.html#stability-guarantees-for-ietf-defined-behavior + #[stable(since = "1.7.0", feature = "ip_17")] + pub fn is_documentation(&self) -> bool { + match self.octets() { + [192, 0, 2, _] => true, + [198, 51, 100, _] => true, + [203, 0, 113, _] => true, + _ => false, + } + } + + /// Converts this address to an IPv4-compatible [IPv6 address]. + /// + /// a.b.c.d becomes ::a.b.c.d + /// + /// [IPv6 address]: ../../std/net/struct.Ipv6Addr.html + /// + /// # Examples + /// + /// ``` + /// use std::net::{Ipv4Addr, Ipv6Addr}; + /// + /// assert_eq!( + /// Ipv4Addr::new(192, 0, 2, 255).to_ipv6_compatible(), + /// Ipv6Addr::new(0, 0, 0, 0, 0, 0, 49152, 767) + /// ); + /// ``` + /// + /// # Stability guarantees + /// + /// This method's behavior [may by subject to changes][changes] in the + /// future, as new RFCs are published. + /// + /// [changes]: ../net/index.html#stability-guarantees-for-ietf-defined-behavior + #[stable(feature = "rust1", since = "1.0.0")] + pub fn to_ipv6_compatible(&self) -> Ipv6Addr { + let octets = self.octets(); + Ipv6Addr::from([ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, octets[0], octets[1], octets[2], octets[3], + ]) + } + + /// Converts this address to an IPv4-mapped [IPv6 address]. + /// + /// a.b.c.d becomes ::ffff:a.b.c.d + /// + /// [IPv6 address]: ../../std/net/struct.Ipv6Addr.html + /// + /// # Examples + /// + /// ``` + /// use std::net::{Ipv4Addr, Ipv6Addr}; + /// + /// assert_eq!(Ipv4Addr::new(192, 0, 2, 255).to_ipv6_mapped(), + /// Ipv6Addr::new(0, 0, 0, 0, 0, 65535, 49152, 767)); + /// ``` + /// + /// # Stability guarantees + /// + /// This method's behavior [may by subject to changes][changes] in the + /// future, as new RFCs are published. + /// + /// [changes]: ../net/index.html#stability-guarantees-for-ietf-defined-behavior + #[stable(feature = "rust1", since = "1.0.0")] + pub fn to_ipv6_mapped(&self) -> Ipv6Addr { + let octets = self.octets(); + Ipv6Addr::from([ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xFF, 0xFF, octets[0], octets[1], octets[2], octets[3], + ]) + } +} + +#[stable(feature = "ip_addr", since = "1.7.0")] +impl fmt::Display for IpAddr { + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + IpAddr::V4(ip) => ip.fmt(fmt), + IpAddr::V6(ip) => ip.fmt(fmt), + } + } +} + +#[stable(feature = "ip_from_ip", since = "1.16.0")] +impl From for IpAddr { + fn from(ipv4: Ipv4Addr) -> IpAddr { + IpAddr::V4(ipv4) + } +} + +#[stable(feature = "ip_from_ip", since = "1.16.0")] +impl From for IpAddr { + fn from(ipv6: Ipv6Addr) -> IpAddr { + IpAddr::V6(ipv6) + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl fmt::Display for Ipv4Addr { + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { + const IPV4_BUF_LEN: usize = 15; // Long enough for the longest possible IPv4 address + let mut buf = [0u8; IPV4_BUF_LEN]; + let mut buf_slice = &mut buf[..]; + let octets = self.octets(); + // Note: The call to write should never fail, hence the unwrap + write!(buf_slice, "{}.{}.{}.{}", octets[0], octets[1], octets[2], octets[3]).unwrap(); + let len = IPV4_BUF_LEN - buf_slice.len(); + // This unsafe is OK because we know what is being written to the buffer + let buf = unsafe { crate::str::from_utf8_unchecked(&buf[..len]) }; + fmt.pad(buf) + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl fmt::Debug for Ipv4Addr { + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt::Display::fmt(self, fmt) + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl Clone for Ipv4Addr { + fn clone(&self) -> Ipv4Addr { + *self + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl PartialEq for Ipv4Addr { + fn eq(&self, other: &Ipv4Addr) -> bool { + self.inner.s_addr == other.inner.s_addr + } +} + +#[stable(feature = "ip_cmp", since = "1.16.0")] +impl PartialEq for IpAddr { + fn eq(&self, other: &Ipv4Addr) -> bool { + match self { + IpAddr::V4(v4) => v4 == other, + IpAddr::V6(_) => false, + } + } +} + +#[stable(feature = "ip_cmp", since = "1.16.0")] +impl PartialEq for Ipv4Addr { + fn eq(&self, other: &IpAddr) -> bool { + match other { + IpAddr::V4(v4) => self == v4, + IpAddr::V6(_) => false, + } + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl Eq for Ipv4Addr {} + +#[stable(feature = "rust1", since = "1.0.0")] +impl hash::Hash for Ipv4Addr { + fn hash(&self, s: &mut H) { + // `inner` is #[repr(packed)], so we need to copy `s_addr`. + { self.inner.s_addr }.hash(s) + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl PartialOrd for Ipv4Addr { + fn partial_cmp(&self, other: &Ipv4Addr) -> Option { + Some(self.cmp(other)) + } +} + +#[stable(feature = "ip_cmp", since = "1.16.0")] +impl PartialOrd for IpAddr { + fn partial_cmp(&self, other: &Ipv4Addr) -> Option { + match self { + IpAddr::V4(v4) => v4.partial_cmp(other), + IpAddr::V6(_) => Some(Ordering::Greater), + } + } +} + +#[stable(feature = "ip_cmp", since = "1.16.0")] +impl PartialOrd for Ipv4Addr { + fn partial_cmp(&self, other: &IpAddr) -> Option { + match other { + IpAddr::V4(v4) => self.partial_cmp(v4), + IpAddr::V6(_) => Some(Ordering::Less), + } + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl Ord for Ipv4Addr { + fn cmp(&self, other: &Ipv4Addr) -> Ordering { + u32::from_be(self.inner.s_addr).cmp(&u32::from_be(other.inner.s_addr)) + } +} + +impl AsInner for Ipv4Addr { + fn as_inner(&self) -> &c::in_addr { + &self.inner + } +} +impl FromInner for Ipv4Addr { + fn from_inner(addr: c::in_addr) -> Ipv4Addr { + Ipv4Addr { inner: addr } + } +} + +#[stable(feature = "ip_u32", since = "1.1.0")] +impl From for u32 { + /// Converts an `Ipv4Addr` into a host byte order `u32`. + /// + /// # Examples + /// + /// ``` + /// use std::net::Ipv4Addr; + /// + /// let addr = Ipv4Addr::new(13, 12, 11, 10); + /// assert_eq!(0x0d0c0b0au32, u32::from(addr)); + /// ``` + fn from(ip: Ipv4Addr) -> u32 { + let ip = ip.octets(); + u32::from_be_bytes(ip) + } +} + +#[stable(feature = "ip_u32", since = "1.1.0")] +impl From for Ipv4Addr { + /// Converts a host byte order `u32` into an `Ipv4Addr`. + /// + /// # Examples + /// + /// ``` + /// use std::net::Ipv4Addr; + /// + /// let addr = Ipv4Addr::from(0x0d0c0b0au32); + /// assert_eq!(Ipv4Addr::new(13, 12, 11, 10), addr); + /// ``` + fn from(ip: u32) -> Ipv4Addr { + Ipv4Addr::from(ip.to_be_bytes()) + } +} + +#[stable(feature = "from_slice_v4", since = "1.9.0")] +impl From<[u8; 4]> for Ipv4Addr { + /// # Examples + /// + /// ``` + /// use std::net::Ipv4Addr; + /// + /// let addr = Ipv4Addr::from([13u8, 12u8, 11u8, 10u8]); + /// assert_eq!(Ipv4Addr::new(13, 12, 11, 10), addr); + /// ``` + fn from(octets: [u8; 4]) -> Ipv4Addr { + Ipv4Addr::new(octets[0], octets[1], octets[2], octets[3]) + } +} + +#[stable(feature = "ip_from_slice", since = "1.17.0")] +impl From<[u8; 4]> for IpAddr { + /// Creates an `IpAddr::V4` from a four element byte array. + /// + /// # Examples + /// + /// ``` + /// use std::net::{IpAddr, Ipv4Addr}; + /// + /// let addr = IpAddr::from([13u8, 12u8, 11u8, 10u8]); + /// assert_eq!(IpAddr::V4(Ipv4Addr::new(13, 12, 11, 10)), addr); + /// ``` + fn from(octets: [u8; 4]) -> IpAddr { + IpAddr::V4(Ipv4Addr::from(octets)) + } +} + +impl Ipv6Addr { + /// Creates a new IPv6 address from eight 16-bit segments. + /// + /// The result will represent the IP address `a:b:c:d:e:f:g:h`. + /// + /// # Examples + /// + /// ``` + /// use std::net::Ipv6Addr; + /// + /// let addr = Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_const_stable(feature = "const_ipv6", since = "1.32.0")] + pub const fn new(a: u16, b: u16, c: u16, d: u16, e: u16, f: u16, g: u16, h: u16) -> Ipv6Addr { + Ipv6Addr { + inner: c::in6_addr { + s6_addr: [ + (a >> 8) as u8, + a as u8, + (b >> 8) as u8, + b as u8, + (c >> 8) as u8, + c as u8, + (d >> 8) as u8, + d as u8, + (e >> 8) as u8, + e as u8, + (f >> 8) as u8, + f as u8, + (g >> 8) as u8, + g as u8, + (h >> 8) as u8, + h as u8, + ], + }, + } + } + + /// An IPv6 address representing localhost: `::1`. + /// + /// # Examples + /// + /// ``` + /// use std::net::Ipv6Addr; + /// + /// let addr = Ipv6Addr::LOCALHOST; + /// assert_eq!(addr, Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1)); + /// ``` + #[stable(feature = "ip_constructors", since = "1.30.0")] + pub const LOCALHOST: Self = Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1); + + /// An IPv6 address representing the unspecified address: `::` + /// + /// # Examples + /// + /// ``` + /// use std::net::Ipv6Addr; + /// + /// let addr = Ipv6Addr::UNSPECIFIED; + /// assert_eq!(addr, Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0)); + /// ``` + #[stable(feature = "ip_constructors", since = "1.30.0")] + pub const UNSPECIFIED: Self = Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0); + + /// Returns the eight 16-bit segments that make up this address. + /// + /// # Examples + /// + /// ``` + /// use std::net::Ipv6Addr; + /// + /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff).segments(), + /// [0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff]); + /// ``` + /// + /// # Stability guarantees + /// + /// This method's behavior [may by subject to changes][changes] in the + /// future, as new RFCs are published. + /// + /// [changes]: ../net/index.html#stability-guarantees-for-ietf-defined-behavior + #[stable(feature = "rust1", since = "1.0.0")] + pub fn segments(&self) -> [u16; 8] { + let arr = &self.inner.s6_addr; + [ + u16::from_be_bytes([arr[0], arr[1]]), + u16::from_be_bytes([arr[2], arr[3]]), + u16::from_be_bytes([arr[4], arr[5]]), + u16::from_be_bytes([arr[6], arr[7]]), + u16::from_be_bytes([arr[8], arr[9]]), + u16::from_be_bytes([arr[10], arr[11]]), + u16::from_be_bytes([arr[12], arr[13]]), + u16::from_be_bytes([arr[14], arr[15]]), + ] + } + + /// Returns [`true`] for the special 'unspecified' address (::). + /// + /// This property is defined in [IETF RFC 4291]. + /// + /// [IETF RFC 4291]: https://tools.ietf.org/html/rfc4291 + /// [`true`]: ../../std/primitive.bool.html + /// + /// # Examples + /// + /// ``` + /// use std::net::Ipv6Addr; + /// + /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff).is_unspecified(), false); + /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0).is_unspecified(), true); + /// ``` + /// + /// # Stability guarantees + /// + /// This method's behavior [may by subject to changes][changes] in the + /// future, as new RFCs are published. + /// + /// [changes]: ../net/index.html#stability-guarantees-for-ietf-defined-behavior + #[stable(since = "1.7.0", feature = "ip_17")] + pub fn is_unspecified(&self) -> bool { + self.segments() == [0, 0, 0, 0, 0, 0, 0, 0] + } + + /// Returns [`true`] if this is a loopback address (::1). + /// + /// This property is defined in [IETF RFC 4291]. + /// + /// [IETF RFC 4291]: https://tools.ietf.org/html/rfc4291 + /// [`true`]: ../../std/primitive.bool.html + /// + /// # Examples + /// + /// ``` + /// use std::net::Ipv6Addr; + /// + /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff).is_loopback(), false); + /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0x1).is_loopback(), true); + /// ``` + /// + /// # Stability guarantees + /// + /// This method's behavior [may by subject to changes][changes] in the + /// future, as new RFCs are published. + /// + /// [changes]: ../net/index.html#stability-guarantees-for-ietf-defined-behavior + #[stable(since = "1.7.0", feature = "ip_17")] + pub fn is_loopback(&self) -> bool { + self.segments() == [0, 0, 0, 0, 0, 0, 0, 1] + } + + /// Returns [`true`] if the address appears to be globally routable. + /// + /// The following return [`false`]: + /// + /// - the loopback address + /// - link-local and unique local unicast addresses + /// - interface-, link-, realm-, admin- and site-local multicast addresses + /// + /// [`true`]: ../../std/primitive.bool.html + /// [`false`]: ../../std/primitive.bool.html + /// + /// # Examples + /// + /// ``` + /// use std::net::Ipv6Addr; + /// + /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff).is_global(), true); + /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0x1).is_global(), false); + /// assert_eq!(Ipv6Addr::new(0, 0, 0x1c9, 0, 0, 0xafc8, 0, 0x1).is_global(), true); + /// ``` + /// + /// # Stability guarantees + /// + /// This method's behavior [may by subject to changes][changes] in the + /// future, as new RFCs are published. + /// + /// [changes]: ../net/index.html#stability-guarantees-for-ietf-defined-behavior + #[stable(feature = "ip", since = "1.42.0")] + pub fn is_global(&self) -> bool { + match self.multicast_scope() { + Some(Ipv6MulticastScope::Global) => true, + None => self.is_unicast_global(), + _ => false, + } + } + + /// Returns [`true`] if this is a unique local address (`fc00::/7`). + /// + /// This property is defined in [IETF RFC 4193]. + /// + /// [IETF RFC 4193]: https://tools.ietf.org/html/rfc4193 + /// [`true`]: ../../std/primitive.bool.html + /// + /// # Examples + /// + /// ``` + /// use std::net::Ipv6Addr; + /// + /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff).is_unique_local(), false); + /// assert_eq!(Ipv6Addr::new(0xfc02, 0, 0, 0, 0, 0, 0, 0).is_unique_local(), true); + /// ``` + /// + /// # Stability guarantees + /// + /// This method's behavior [may by subject to changes][changes] in the + /// future, as new RFCs are published. + /// + /// [changes]: ../net/index.html#stability-guarantees-for-ietf-defined-behavior + #[stable(feature = "ip", since = "1.42.0")] + pub fn is_unique_local(&self) -> bool { + (self.segments()[0] & 0xfe00) == 0xfc00 + } + + /// Returns [`true`] if the address is a unicast link-local address (`fe80::/64`). + /// + /// A common mis-conception is to think that "unicast link-local addresses start with + /// `fe80::`", but the [IETF RFC 4291] actually defines a stricter format for these addresses: + /// + /// ```no_rust + /// | 10 | + /// | bits | 54 bits | 64 bits | + /// +----------+-------------------------+----------------------------+ + /// |1111111010| 0 | interface ID | + /// +----------+-------------------------+----------------------------+ + /// ``` + /// + /// This method validates the format defined in the RFC and won't recognize the following + /// addresses such as `fe80:0:0:1::` or `fe81::` as unicast link-local addresses for example. + /// If you need a less strict validation use [`is_unicast_link_local()`] instead. + /// + /// # Examples + /// + /// ``` + /// use std::net::Ipv6Addr; + /// + /// let ip = Ipv6Addr::new(0xfe80, 0, 0, 0, 0, 0, 0, 0); + /// assert!(ip.is_unicast_link_local_strict()); + /// + /// let ip = Ipv6Addr::new(0xfe80, 0, 0, 0, 0xffff, 0xffff, 0xffff, 0xffff); + /// assert!(ip.is_unicast_link_local_strict()); + /// + /// let ip = Ipv6Addr::new(0xfe80, 0, 0, 1, 0, 0, 0, 0); + /// assert!(!ip.is_unicast_link_local_strict()); + /// assert!(ip.is_unicast_link_local()); + /// + /// let ip = Ipv6Addr::new(0xfe81, 0, 0, 0, 0, 0, 0, 0); + /// assert!(!ip.is_unicast_link_local_strict()); + /// assert!(ip.is_unicast_link_local()); + /// ``` + /// + /// # See also + /// + /// - [IETF RFC 4291 section 2.5.6] + /// - [RFC 4291 errata 4406] + /// - [`is_unicast_link_local()`] + /// + /// [IETF RFC 4291]: https://tools.ietf.org/html/rfc4291 + /// [IETF RFC 4291 section 2.5.6]: https://tools.ietf.org/html/rfc4291#section-2.5.6 + /// [`true`]: ../../std/primitive.bool.html + /// [RFC 4291 errata 4406]: https://www.rfc-editor.org/errata/eid4406 + /// [`is_unicast_link_local()`]: ../../std/net/struct.Ipv6Addr.html#method.is_unicast_link_local + /// + /// # Stability guarantees + /// + /// This method's behavior [may by subject to changes][changes] in the + /// future, as new RFCs are published. + /// + /// [changes]: ../net/index.html#stability-guarantees-for-ietf-defined-behavior + #[stable(feature = "ip", since = "1.42.0")] + pub fn is_unicast_link_local_strict(&self) -> bool { + (self.segments()[0] & 0xffff) == 0xfe80 + && (self.segments()[1] & 0xffff) == 0 + && (self.segments()[2] & 0xffff) == 0 + && (self.segments()[3] & 0xffff) == 0 + } + + /// Returns [`true`] if the address is a unicast link-local address (`fe80::/10`). + /// + /// This method returns [`true`] for addresses in the range reserved by [RFC 4291 section 2.4], + /// i.e. addresses with the following format: + /// + /// ```no_rust + /// | 10 | + /// | bits | 54 bits | 64 bits | + /// +----------+-------------------------+----------------------------+ + /// |1111111010| arbitratry value | interface ID | + /// +----------+-------------------------+----------------------------+ + /// ``` + /// + /// As a result, this method consider addresses such as `fe80:0:0:1::` or `fe81::` to be + /// unicast link-local addresses, whereas [`is_unicast_link_local_strict()`] does not. If you + /// need a strict validation fully compliant with the RFC, use + /// [`is_unicast_link_local_strict()`]. + /// + /// # Examples + /// + /// ``` + /// use std::net::Ipv6Addr; + /// + /// let ip = Ipv6Addr::new(0xfe80, 0, 0, 0, 0, 0, 0, 0); + /// assert!(ip.is_unicast_link_local()); + /// + /// let ip = Ipv6Addr::new(0xfe80, 0, 0, 0, 0xffff, 0xffff, 0xffff, 0xffff); + /// assert!(ip.is_unicast_link_local()); + /// + /// let ip = Ipv6Addr::new(0xfe80, 0, 0, 1, 0, 0, 0, 0); + /// assert!(ip.is_unicast_link_local()); + /// assert!(!ip.is_unicast_link_local_strict()); + /// + /// let ip = Ipv6Addr::new(0xfe81, 0, 0, 0, 0, 0, 0, 0); + /// assert!(ip.is_unicast_link_local()); + /// assert!(!ip.is_unicast_link_local_strict()); + /// ``` + /// + /// # See also + /// + /// - [IETF RFC 4291 section 2.4] + /// - [RFC 4291 errata 4406] + /// + /// [IETF RFC 4291 section 2.4]: https://tools.ietf.org/html/rfc4291#section-2.4 + /// [`true`]: ../../std/primitive.bool.html + /// [RFC 4291 errata 4406]: https://www.rfc-editor.org/errata/eid4406 + /// [`is_unicast_link_local_strict()`]: ../../std/net/struct.Ipv6Addr.html#method.is_unicast_link_local_strict + /// + /// # Stability guarantees + /// + /// This method's behavior [may by subject to changes][changes] in the + /// future, as new RFCs are published. + /// + /// [changes]: ../net/index.html#stability-guarantees-for-ietf-defined-behavior + #[stable(feature = "ip", since = "1.42.0")] + pub fn is_unicast_link_local(&self) -> bool { + (self.segments()[0] & 0xffc0) == 0xfe80 + } + + /// Returns [`true`] if this is a deprecated unicast site-local address (fec0::/10). The + /// unicast site-local address format is defined in [RFC 4291 section 2.5.7] as: + /// + /// ```no_rust + /// | 10 | + /// | bits | 54 bits | 64 bits | + /// +----------+-------------------------+----------------------------+ + /// |1111111011| subnet ID | interface ID | + /// +----------+-------------------------+----------------------------+ + /// ``` + /// + /// [`true`]: ../../std/primitive.bool.html + /// [RFC 4291 section 2.5.7]: https://tools.ietf.org/html/rfc4291#section-2.5.7 + /// + /// # Examples + /// + /// ``` + /// use std::net::Ipv6Addr; + /// + /// assert_eq!( + /// Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff).is_unicast_site_local(), + /// false + /// ); + /// assert_eq!(Ipv6Addr::new(0xfec2, 0, 0, 0, 0, 0, 0, 0).is_unicast_site_local(), true); + /// ``` + /// + /// # Warning + /// + /// As per [RFC 3879], the whole `FEC0::/10` prefix is + /// deprecated. New software must not support site-local + /// addresses. + /// + /// [RFC 3879]: https://tools.ietf.org/html/rfc3879 + /// + /// # Stability guarantees + /// + /// This method's behavior [may by subject to changes][changes] in the + /// future, as new RFCs are published. + /// + /// [changes]: ../net/index.html#stability-guarantees-for-ietf-defined-behavior + #[stable(feature = "ip", since = "1.42.0")] + pub fn is_unicast_site_local(&self) -> bool { + (self.segments()[0] & 0xffc0) == 0xfec0 + } + + /// Returns [`true`] if this is an address reserved for documentation + /// (2001:db8::/32). + /// + /// This property is defined in [IETF RFC 3849]. + /// + /// [IETF RFC 3849]: https://tools.ietf.org/html/rfc3849 + /// [`true`]: ../../std/primitive.bool.html + /// + /// # Examples + /// + /// ``` + /// use std::net::Ipv6Addr; + /// + /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff).is_documentation(), false); + /// assert_eq!(Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 0).is_documentation(), true); + /// ``` + /// + /// # Stability guarantees + /// + /// This method's behavior [may by subject to changes][changes] in the + /// future, as new RFCs are published. + /// + /// [changes]: ../net/index.html#stability-guarantees-for-ietf-defined-behavior + #[stable(feature = "ip", since = "1.42.0")] + pub fn is_documentation(&self) -> bool { + (self.segments()[0] == 0x2001) && (self.segments()[1] == 0xdb8) + } + + /// Returns [`true`] if the address is a globally routable unicast address. + /// + /// The following return false: + /// + /// - the loopback address + /// - the link-local addresses + /// - unique local addresses + /// - the unspecified address + /// - the address range reserved for documentation + /// + /// This method returns [`true`] for site-local addresses as per [RFC 4291 section 2.5.7] + /// + /// ```no_rust + /// The special behavior of [the site-local unicast] prefix defined in [RFC3513] must no longer + /// be supported in new implementations (i.e., new implementations must treat this prefix as + /// Global Unicast). + /// ``` + /// + /// [`true`]: ../../std/primitive.bool.html + /// [RFC 4291 section 2.5.7]: https://tools.ietf.org/html/rfc4291#section-2.5.7 + /// + /// # Examples + /// + /// ``` + /// use std::net::Ipv6Addr; + /// + /// assert_eq!(Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 0).is_unicast_global(), false); + /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff).is_unicast_global(), true); + /// ``` + /// + /// # Stability guarantees + /// + /// This method's behavior [may by subject to changes][changes] in the + /// future, as new RFCs are published. + /// + /// [changes]: ../net/index.html#stability-guarantees-for-ietf-defined-behavior + #[stable(feature = "ip", since = "1.42.0")] + pub fn is_unicast_global(&self) -> bool { + !self.is_multicast() + && !self.is_loopback() + && !self.is_unicast_link_local() + && !self.is_unique_local() + && !self.is_unspecified() + && !self.is_documentation() + } + + /// Returns the address's multicast scope if the address is multicast. + /// + /// # Examples + /// + /// ``` + /// use std::net::{Ipv6Addr, Ipv6MulticastScope}; + /// + /// assert_eq!( + /// Ipv6Addr::new(0xff0e, 0, 0, 0, 0, 0, 0, 0).multicast_scope(), + /// Some(Ipv6MulticastScope::Global) + /// ); + /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff).multicast_scope(), None); + /// ``` + /// + /// # Stability guarantees + /// + /// This method's behavior [may by subject to changes][changes] in the + /// future, as new RFCs are published. + /// + /// [changes]: ../net/index.html#stability-guarantees-for-ietf-defined-behavior + #[stable(feature = "ip", since = "1.42.0")] + pub fn multicast_scope(&self) -> Option { + 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 + } + } + + /// Returns [`true`] if this is a multicast address (ff00::/8). + /// + /// This property is defined by [IETF RFC 4291]. + /// + /// [IETF RFC 4291]: https://tools.ietf.org/html/rfc4291 + /// [`true`]: ../../std/primitive.bool.html + /// + /// # Examples + /// + /// ``` + /// use std::net::Ipv6Addr; + /// + /// assert_eq!(Ipv6Addr::new(0xff00, 0, 0, 0, 0, 0, 0, 0).is_multicast(), true); + /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff).is_multicast(), false); + /// ``` + /// + /// # Stability guarantees + /// + /// This method's behavior [may by subject to changes][changes] in the + /// future, as new RFCs are published. + /// + /// [changes]: ../net/index.html#stability-guarantees-for-ietf-defined-behavior + #[stable(since = "1.7.0", feature = "ip_17")] + pub fn is_multicast(&self) -> bool { + (self.segments()[0] & 0xff00) == 0xff00 + } + + /// Converts this address to an [IPv4 address]. Returns [`None`] if this address is + /// neither IPv4-compatible or IPv4-mapped. + /// + /// ::a.b.c.d and ::ffff:a.b.c.d become a.b.c.d + /// + /// [IPv4 address]: ../../std/net/struct.Ipv4Addr.html + /// [`None`]: ../../std/option/enum.Option.html#variant.None + /// + /// # Examples + /// + /// ``` + /// use std::net::{Ipv4Addr, Ipv6Addr}; + /// + /// assert_eq!(Ipv6Addr::new(0xff00, 0, 0, 0, 0, 0, 0, 0).to_ipv4(), None); + /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff).to_ipv4(), + /// Some(Ipv4Addr::new(192, 10, 2, 255))); + /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1).to_ipv4(), + /// Some(Ipv4Addr::new(0, 0, 0, 1))); + /// ``` + /// + /// # Stability guarantees + /// + /// This method's behavior [may by subject to changes][changes] in the + /// future, as new RFCs are published. + /// + /// [changes]: ../net/index.html#stability-guarantees-for-ietf-defined-behavior + #[stable(feature = "rust1", since = "1.0.0")] + pub fn to_ipv4(&self) -> Option { + match self.segments() { + [0, 0, 0, 0, 0, f, g, h] if f == 0 || f == 0xffff => { + Some(Ipv4Addr::new((g >> 8) as u8, g as u8, (h >> 8) as u8, h as u8)) + } + _ => None, + } + } + + /// Returns the sixteen eight-bit integers the IPv6 address consists of. + /// + /// ``` + /// use std::net::Ipv6Addr; + /// + /// assert_eq!(Ipv6Addr::new(0xff00, 0, 0, 0, 0, 0, 0, 0).octets(), + /// [255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]); + /// ``` + #[stable(feature = "ipv6_to_octets", since = "1.12.0")] + #[rustc_const_stable(feature = "const_ipv6", since = "1.32.0")] + pub const fn octets(&self) -> [u8; 16] { + self.inner.s6_addr + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl fmt::Display for Ipv6Addr { + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { + // Note: The calls to write should never fail, hence the unwraps in the function + // Long enough for the longest possible IPv6: 39 + const IPV6_BUF_LEN: usize = 39; + let mut buf = [0u8; IPV6_BUF_LEN]; + let mut buf_slice = &mut buf[..]; + + match self.segments() { + // We need special cases for :: and ::1, otherwise they're formatted + // as ::0.0.0.[01] + [0, 0, 0, 0, 0, 0, 0, 0] => write!(buf_slice, "::").unwrap(), + [0, 0, 0, 0, 0, 0, 0, 1] => write!(buf_slice, "::1").unwrap(), + // Ipv4 Compatible address + [0, 0, 0, 0, 0, 0, g, h] => { + write!( + buf_slice, + "::{}.{}.{}.{}", + (g >> 8) as u8, + g as u8, + (h >> 8) as u8, + h as u8 + ) + .unwrap(); + } + // Ipv4-Mapped address + [0, 0, 0, 0, 0, 0xffff, g, h] => { + write!( + buf_slice, + "::ffff:{}.{}.{}.{}", + (g >> 8) as u8, + g as u8, + (h >> 8) as u8, + h as u8 + ) + .unwrap(); + } + _ => { + fn find_zero_slice(segments: &[u16; 8]) -> (usize, usize) { + let mut longest_span_len = 0; + let mut longest_span_at = 0; + let mut cur_span_len = 0; + let mut cur_span_at = 0; + + for i in 0..8 { + if segments[i] == 0 { + if cur_span_len == 0 { + cur_span_at = i; + } + + cur_span_len += 1; + + if cur_span_len > longest_span_len { + longest_span_len = cur_span_len; + longest_span_at = cur_span_at; + } + } else { + cur_span_len = 0; + cur_span_at = 0; + } + } + + (longest_span_at, longest_span_len) + } + + let (zeros_at, zeros_len) = find_zero_slice(&self.segments()); + + if zeros_len > 1 { + fn fmt_subslice(segments: &[u16], buf: &mut &mut [u8]) { + if !segments.is_empty() { + write!(*buf, "{:x}", segments[0]).unwrap(); + for &seg in &segments[1..] { + write!(*buf, ":{:x}", seg).unwrap(); + } + } + } + + fmt_subslice(&self.segments()[..zeros_at], &mut buf_slice); + write!(buf_slice, "::").unwrap(); + fmt_subslice(&self.segments()[zeros_at + zeros_len..], &mut buf_slice); + } else { + let &[a, b, c, d, e, f, g, h] = &self.segments(); + write!( + buf_slice, + "{:x}:{:x}:{:x}:{:x}:{:x}:{:x}:{:x}:{:x}", + a, b, c, d, e, f, g, h + ) + .unwrap(); + } + } + } + let len = IPV6_BUF_LEN - buf_slice.len(); + // This is safe because we know exactly what can be in this buffer + let buf = unsafe { crate::str::from_utf8_unchecked(&buf[..len]) }; + fmt.pad(buf) + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl fmt::Debug for Ipv6Addr { + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt::Display::fmt(self, fmt) + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl Clone for Ipv6Addr { + fn clone(&self) -> Ipv6Addr { + *self + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl PartialEq for Ipv6Addr { + fn eq(&self, other: &Ipv6Addr) -> bool { + self.inner.s6_addr == other.inner.s6_addr + } +} + +#[stable(feature = "ip_cmp", since = "1.16.0")] +impl PartialEq for Ipv6Addr { + fn eq(&self, other: &IpAddr) -> bool { + match other { + IpAddr::V4(_) => false, + IpAddr::V6(v6) => self == v6, + } + } +} + +#[stable(feature = "ip_cmp", since = "1.16.0")] +impl PartialEq for IpAddr { + fn eq(&self, other: &Ipv6Addr) -> bool { + match self { + IpAddr::V4(_) => false, + IpAddr::V6(v6) => v6 == other, + } + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl Eq for Ipv6Addr {} + +#[stable(feature = "rust1", since = "1.0.0")] +impl hash::Hash for Ipv6Addr { + fn hash(&self, s: &mut H) { + self.inner.s6_addr.hash(s) + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl PartialOrd for Ipv6Addr { + fn partial_cmp(&self, other: &Ipv6Addr) -> Option { + Some(self.cmp(other)) + } +} + +#[stable(feature = "ip_cmp", since = "1.16.0")] +impl PartialOrd for IpAddr { + fn partial_cmp(&self, other: &Ipv6Addr) -> Option { + match self { + IpAddr::V4(_) => Some(Ordering::Less), + IpAddr::V6(v6) => v6.partial_cmp(other), + } + } +} + +#[stable(feature = "ip_cmp", since = "1.16.0")] +impl PartialOrd for Ipv6Addr { + fn partial_cmp(&self, other: &IpAddr) -> Option { + match other { + IpAddr::V4(_) => Some(Ordering::Greater), + IpAddr::V6(v6) => self.partial_cmp(v6), + } + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl Ord for Ipv6Addr { + fn cmp(&self, other: &Ipv6Addr) -> Ordering { + self.segments().cmp(&other.segments()) + } +} + +impl AsInner for Ipv6Addr { + fn as_inner(&self) -> &c::in6_addr { + &self.inner + } +} +impl FromInner for Ipv6Addr { + fn from_inner(addr: c::in6_addr) -> Ipv6Addr { + Ipv6Addr { inner: addr } + } +} + +#[stable(feature = "i128", since = "1.26.0")] +impl From for u128 { + /// Convert an `Ipv6Addr` into a host byte order `u128`. + /// + /// # Examples + /// + /// ``` + /// use std::net::Ipv6Addr; + /// + /// let addr = Ipv6Addr::new( + /// 0x1020, 0x3040, 0x5060, 0x7080, + /// 0x90A0, 0xB0C0, 0xD0E0, 0xF00D, + /// ); + /// assert_eq!(0x102030405060708090A0B0C0D0E0F00D_u128, u128::from(addr)); + /// ``` + fn from(ip: Ipv6Addr) -> u128 { + let ip = ip.octets(); + u128::from_be_bytes(ip) + } +} +#[stable(feature = "i128", since = "1.26.0")] +impl From for Ipv6Addr { + /// Convert a host byte order `u128` into an `Ipv6Addr`. + /// + /// # Examples + /// + /// ``` + /// use std::net::Ipv6Addr; + /// + /// let addr = Ipv6Addr::from(0x102030405060708090A0B0C0D0E0F00D_u128); + /// assert_eq!( + /// Ipv6Addr::new( + /// 0x1020, 0x3040, 0x5060, 0x7080, + /// 0x90A0, 0xB0C0, 0xD0E0, 0xF00D, + /// ), + /// addr); + /// ``` + fn from(ip: u128) -> Ipv6Addr { + Ipv6Addr::from(ip.to_be_bytes()) + } +} + +#[stable(feature = "ipv6_from_octets", since = "1.9.0")] +impl From<[u8; 16]> for Ipv6Addr { + fn from(octets: [u8; 16]) -> Ipv6Addr { + let inner = c::in6_addr { s6_addr: octets }; + Ipv6Addr::from_inner(inner) + } +} + +#[stable(feature = "ipv6_from_segments", since = "1.16.0")] +impl From<[u16; 8]> for Ipv6Addr { + 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) + } +} + +#[stable(feature = "ip_from_slice", since = "1.17.0")] +impl From<[u8; 16]> for IpAddr { + /// Creates an `IpAddr::V6` from a sixteen element byte array. + /// + /// # Examples + /// + /// ``` + /// use std::net::{IpAddr, Ipv6Addr}; + /// + /// let addr = IpAddr::from([ + /// 25u8, 24u8, 23u8, 22u8, 21u8, 20u8, 19u8, 18u8, + /// 17u8, 16u8, 15u8, 14u8, 13u8, 12u8, 11u8, 10u8, + /// ]); + /// assert_eq!( + /// IpAddr::V6(Ipv6Addr::new( + /// 0x1918, 0x1716, + /// 0x1514, 0x1312, + /// 0x1110, 0x0f0e, + /// 0x0d0c, 0x0b0a + /// )), + /// addr + /// ); + /// ``` + fn from(octets: [u8; 16]) -> IpAddr { + IpAddr::V6(Ipv6Addr::from(octets)) + } +} + +#[stable(feature = "ip_from_slice", since = "1.17.0")] +impl From<[u16; 8]> for IpAddr { + /// Creates an `IpAddr::V6` from an eight element 16-bit array. + /// + /// # Examples + /// + /// ``` + /// use std::net::{IpAddr, Ipv6Addr}; + /// + /// let addr = IpAddr::from([ + /// 525u16, 524u16, 523u16, 522u16, + /// 521u16, 520u16, 519u16, 518u16, + /// ]); + /// assert_eq!( + /// IpAddr::V6(Ipv6Addr::new( + /// 0x20d, 0x20c, + /// 0x20b, 0x20a, + /// 0x209, 0x208, + /// 0x207, 0x206 + /// )), + /// addr + /// ); + /// ``` + fn from(segments: [u16; 8]) -> IpAddr { + IpAddr::V6(Ipv6Addr::from(segments)) + } +} + +// Tests for this module +#[cfg(all(test, not(target_os = "emscripten")))] +mod tests { + use crate::net::test::{sa4, sa6, tsa}; + use crate::net::*; + use crate::str::FromStr; + + #[test] + fn test_from_str_ipv4() { + assert_eq!(Ok(Ipv4Addr::new(127, 0, 0, 1)), "127.0.0.1".parse()); + assert_eq!(Ok(Ipv4Addr::new(255, 255, 255, 255)), "255.255.255.255".parse()); + assert_eq!(Ok(Ipv4Addr::new(0, 0, 0, 0)), "0.0.0.0".parse()); + + // out of range + let none: Option = "256.0.0.1".parse().ok(); + assert_eq!(None, none); + // too short + let none: Option = "255.0.0".parse().ok(); + assert_eq!(None, none); + // too long + let none: Option = "255.0.0.1.2".parse().ok(); + assert_eq!(None, none); + // no number between dots + let none: Option = "255.0..1".parse().ok(); + assert_eq!(None, none); + } + + #[test] + fn test_from_str_ipv6() { + assert_eq!(Ok(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0)), "0:0:0:0:0:0:0:0".parse()); + assert_eq!(Ok(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1)), "0:0:0:0:0:0:0:1".parse()); + + assert_eq!(Ok(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1)), "::1".parse()); + assert_eq!(Ok(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0)), "::".parse()); + + assert_eq!( + Ok(Ipv6Addr::new(0x2a02, 0x6b8, 0, 0, 0, 0, 0x11, 0x11)), + "2a02:6b8::11:11".parse() + ); + + // too long group + let none: Option = "::00000".parse().ok(); + assert_eq!(None, none); + // too short + let none: Option = "1:2:3:4:5:6:7".parse().ok(); + assert_eq!(None, none); + // too long + let none: Option = "1:2:3:4:5:6:7:8:9".parse().ok(); + assert_eq!(None, none); + // triple colon + let none: Option = "1:2:::6:7:8".parse().ok(); + assert_eq!(None, none); + // two double colons + let none: Option = "1:2::6::8".parse().ok(); + assert_eq!(None, none); + // `::` indicating zero groups of zeros + let none: Option = "1:2:3:4::5:6:7:8".parse().ok(); + assert_eq!(None, none); + } + + #[test] + fn test_from_str_ipv4_in_ipv6() { + assert_eq!(Ok(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 49152, 545)), "::192.0.2.33".parse()); + assert_eq!( + Ok(Ipv6Addr::new(0, 0, 0, 0, 0, 0xFFFF, 49152, 545)), + "::FFFF:192.0.2.33".parse() + ); + assert_eq!( + Ok(Ipv6Addr::new(0x64, 0xff9b, 0, 0, 0, 0, 49152, 545)), + "64:ff9b::192.0.2.33".parse() + ); + assert_eq!( + Ok(Ipv6Addr::new(0x2001, 0xdb8, 0x122, 0xc000, 0x2, 0x2100, 49152, 545)), + "2001:db8:122:c000:2:2100:192.0.2.33".parse() + ); + + // colon after v4 + let none: Option = "::127.0.0.1:".parse().ok(); + assert_eq!(None, none); + // not enough groups + let none: Option = "1.2.3.4.5:127.0.0.1".parse().ok(); + assert_eq!(None, none); + // too many groups + let none: Option = "1.2.3.4.5:6:7:127.0.0.1".parse().ok(); + assert_eq!(None, none); + } + + #[test] + fn test_from_str_socket_addr() { + assert_eq!(Ok(sa4(Ipv4Addr::new(77, 88, 21, 11), 80)), "77.88.21.11:80".parse()); + assert_eq!( + Ok(SocketAddrV4::new(Ipv4Addr::new(77, 88, 21, 11), 80)), + "77.88.21.11:80".parse() + ); + assert_eq!( + Ok(sa6(Ipv6Addr::new(0x2a02, 0x6b8, 0, 1, 0, 0, 0, 1), 53)), + "[2a02:6b8:0:1::1]:53".parse() + ); + assert_eq!( + Ok(SocketAddrV6::new(Ipv6Addr::new(0x2a02, 0x6b8, 0, 1, 0, 0, 0, 1), 53, 0, 0)), + "[2a02:6b8:0:1::1]:53".parse() + ); + assert_eq!( + Ok(sa6(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0x7F00, 1), 22)), + "[::127.0.0.1]:22".parse() + ); + assert_eq!( + Ok(SocketAddrV6::new(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0x7F00, 1), 22, 0, 0)), + "[::127.0.0.1]:22".parse() + ); + + // without port + let none: Option = "127.0.0.1".parse().ok(); + assert_eq!(None, none); + // without port + let none: Option = "127.0.0.1:".parse().ok(); + assert_eq!(None, none); + // wrong brackets around v4 + let none: Option = "[127.0.0.1]:22".parse().ok(); + assert_eq!(None, none); + // port out of range + let none: Option = "127.0.0.1:123456".parse().ok(); + assert_eq!(None, none); + } + + #[test] + fn ipv4_addr_to_string() { + // Short address + assert_eq!(Ipv4Addr::new(1, 1, 1, 1).to_string(), "1.1.1.1"); + // Long address + assert_eq!(Ipv4Addr::new(127, 127, 127, 127).to_string(), "127.127.127.127"); + + // Test padding + assert_eq!(&format!("{:16}", Ipv4Addr::new(1, 1, 1, 1)), "1.1.1.1 "); + assert_eq!(&format!("{:>16}", Ipv4Addr::new(1, 1, 1, 1)), " 1.1.1.1"); + } + + #[test] + fn ipv6_addr_to_string() { + // ipv4-mapped address + let a1 = Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc000, 0x280); + assert_eq!(a1.to_string(), "::ffff:192.0.2.128"); + + // ipv4-compatible address + let a1 = Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0xc000, 0x280); + assert_eq!(a1.to_string(), "::192.0.2.128"); + + // v6 address with no zero segments + assert_eq!(Ipv6Addr::new(8, 9, 10, 11, 12, 13, 14, 15).to_string(), "8:9:a:b:c:d:e:f"); + + // longest possible IPv6 length + assert_eq!( + Ipv6Addr::new(0x1111, 0x2222, 0x3333, 0x4444, 0x5555, 0x6666, 0x7777, 0x8888) + .to_string(), + "1111:2222:3333:4444:5555:6666:7777:8888" + ); + // padding + assert_eq!( + &format!("{:20}", Ipv6Addr::new(1, 2, 3, 4, 5, 6, 7, 8)), + "1:2:3:4:5:6:7:8 " + ); + assert_eq!( + &format!("{:>20}", Ipv6Addr::new(1, 2, 3, 4, 5, 6, 7, 8)), + " 1:2:3:4:5:6:7:8" + ); + + // reduce a single run of zeros + assert_eq!( + "ae::ffff:102:304", + Ipv6Addr::new(0xae, 0, 0, 0, 0, 0xffff, 0x0102, 0x0304).to_string() + ); + + // don't reduce just a single zero segment + assert_eq!("1:2:3:4:5:6:0:8", Ipv6Addr::new(1, 2, 3, 4, 5, 6, 0, 8).to_string()); + + // 'any' address + assert_eq!("::", Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0).to_string()); + + // loopback address + assert_eq!("::1", Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1).to_string()); + + // ends in zeros + assert_eq!("1::", Ipv6Addr::new(1, 0, 0, 0, 0, 0, 0, 0).to_string()); + + // two runs of zeros, second one is longer + assert_eq!("1:0:0:4::8", Ipv6Addr::new(1, 0, 0, 4, 0, 0, 0, 8).to_string()); + + // two runs of zeros, equal length + assert_eq!("1::4:5:0:0:8", Ipv6Addr::new(1, 0, 0, 4, 5, 0, 0, 8).to_string()); + } + + #[test] + fn ipv4_to_ipv6() { + assert_eq!( + Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0x1234, 0x5678), + Ipv4Addr::new(0x12, 0x34, 0x56, 0x78).to_ipv6_mapped() + ); + assert_eq!( + Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0x1234, 0x5678), + Ipv4Addr::new(0x12, 0x34, 0x56, 0x78).to_ipv6_compatible() + ); + } + + #[test] + fn ipv6_to_ipv4() { + assert_eq!( + Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0x1234, 0x5678).to_ipv4(), + Some(Ipv4Addr::new(0x12, 0x34, 0x56, 0x78)) + ); + assert_eq!( + Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0x1234, 0x5678).to_ipv4(), + Some(Ipv4Addr::new(0x12, 0x34, 0x56, 0x78)) + ); + assert_eq!(Ipv6Addr::new(0, 0, 1, 0, 0, 0, 0x1234, 0x5678).to_ipv4(), None); + } + + #[test] + fn ip_properties() { + macro_rules! ip { + ($s:expr) => { + IpAddr::from_str($s).unwrap() + }; + } + + macro_rules! check { + ($s:expr) => { + check!($s, 0); + }; + + ($s:expr, $mask:expr) => {{ + let unspec: u8 = 1 << 0; + let loopback: u8 = 1 << 1; + let global: u8 = 1 << 2; + let multicast: u8 = 1 << 3; + let doc: u8 = 1 << 4; + + if ($mask & unspec) == unspec { + assert!(ip!($s).is_unspecified()); + } else { + assert!(!ip!($s).is_unspecified()); + } + + if ($mask & loopback) == loopback { + assert!(ip!($s).is_loopback()); + } else { + assert!(!ip!($s).is_loopback()); + } + + if ($mask & global) == global { + assert!(ip!($s).is_global()); + } else { + assert!(!ip!($s).is_global()); + } + + if ($mask & multicast) == multicast { + assert!(ip!($s).is_multicast()); + } else { + assert!(!ip!($s).is_multicast()); + } + + if ($mask & doc) == doc { + assert!(ip!($s).is_documentation()); + } else { + assert!(!ip!($s).is_documentation()); + } + }}; + } + + let unspec: u8 = 1 << 0; + let loopback: u8 = 1 << 1; + let global: u8 = 1 << 2; + let multicast: u8 = 1 << 3; + let doc: u8 = 1 << 4; + + check!("0.0.0.0", unspec); + check!("0.0.0.1"); + check!("0.1.0.0"); + check!("10.9.8.7"); + check!("127.1.2.3", loopback); + check!("172.31.254.253"); + check!("169.254.253.242"); + check!("192.0.2.183", doc); + check!("192.1.2.183", global); + check!("192.168.254.253"); + check!("198.51.100.0", doc); + check!("203.0.113.0", doc); + check!("203.2.113.0", global); + check!("224.0.0.0", global | multicast); + check!("239.255.255.255", global | multicast); + check!("255.255.255.255"); + // make sure benchmarking addresses are not global + check!("198.18.0.0"); + check!("198.18.54.2"); + check!("198.19.255.255"); + // make sure addresses reserved for protocol assignment are not global + check!("192.0.0.0"); + check!("192.0.0.255"); + check!("192.0.0.100"); + // make sure reserved addresses are not global + check!("240.0.0.0"); + check!("251.54.1.76"); + check!("254.255.255.255"); + // make sure shared addresses are not global + check!("100.64.0.0"); + check!("100.127.255.255"); + check!("100.100.100.0"); + + check!("::", unspec); + check!("::1", loopback); + check!("::0.0.0.2", global); + check!("1::", global); + check!("fc00::"); + check!("fdff:ffff::"); + check!("fe80:ffff::"); + check!("febf:ffff::"); + check!("fec0::", global); + check!("ff01::", multicast); + check!("ff02::", multicast); + check!("ff03::", multicast); + check!("ff04::", multicast); + check!("ff05::", multicast); + check!("ff08::", multicast); + check!("ff0e::", global | multicast); + check!("2001:db8:85a3::8a2e:370:7334", doc); + check!("102:304:506:708:90a:b0c:d0e:f10", global); + } + + #[test] + fn ipv4_properties() { + macro_rules! ip { + ($s:expr) => { + Ipv4Addr::from_str($s).unwrap() + }; + } + + macro_rules! check { + ($s:expr) => { + check!($s, 0); + }; + + ($s:expr, $mask:expr) => {{ + let unspec: u16 = 1 << 0; + let loopback: u16 = 1 << 1; + let private: u16 = 1 << 2; + let link_local: u16 = 1 << 3; + let global: u16 = 1 << 4; + let multicast: u16 = 1 << 5; + let broadcast: u16 = 1 << 6; + let documentation: u16 = 1 << 7; + let benchmarking: u16 = 1 << 8; + let ietf_protocol_assignment: u16 = 1 << 9; + let reserved: u16 = 1 << 10; + let shared: u16 = 1 << 11; + + if ($mask & unspec) == unspec { + assert!(ip!($s).is_unspecified()); + } else { + assert!(!ip!($s).is_unspecified()); + } + + if ($mask & loopback) == loopback { + assert!(ip!($s).is_loopback()); + } else { + assert!(!ip!($s).is_loopback()); + } + + if ($mask & private) == private { + assert!(ip!($s).is_private()); + } else { + assert!(!ip!($s).is_private()); + } + + if ($mask & link_local) == link_local { + assert!(ip!($s).is_link_local()); + } else { + assert!(!ip!($s).is_link_local()); + } + + if ($mask & global) == global { + assert!(ip!($s).is_global()); + } else { + assert!(!ip!($s).is_global()); + } + + if ($mask & multicast) == multicast { + assert!(ip!($s).is_multicast()); + } else { + assert!(!ip!($s).is_multicast()); + } + + if ($mask & broadcast) == broadcast { + assert!(ip!($s).is_broadcast()); + } else { + assert!(!ip!($s).is_broadcast()); + } + + if ($mask & documentation) == documentation { + assert!(ip!($s).is_documentation()); + } else { + assert!(!ip!($s).is_documentation()); + } + + if ($mask & benchmarking) == benchmarking { + assert!(ip!($s).is_benchmarking()); + } else { + assert!(!ip!($s).is_benchmarking()); + } + + if ($mask & ietf_protocol_assignment) == ietf_protocol_assignment { + assert!(ip!($s).is_ietf_protocol_assignment()); + } else { + assert!(!ip!($s).is_ietf_protocol_assignment()); + } + + if ($mask & reserved) == reserved { + assert!(ip!($s).is_reserved()); + } else { + assert!(!ip!($s).is_reserved()); + } + + if ($mask & shared) == shared { + assert!(ip!($s).is_shared()); + } else { + assert!(!ip!($s).is_shared()); + } + }}; + } + + let unspec: u16 = 1 << 0; + let loopback: u16 = 1 << 1; + let private: u16 = 1 << 2; + let link_local: u16 = 1 << 3; + let global: u16 = 1 << 4; + let multicast: u16 = 1 << 5; + let broadcast: u16 = 1 << 6; + let documentation: u16 = 1 << 7; + let benchmarking: u16 = 1 << 8; + let ietf_protocol_assignment: u16 = 1 << 9; + let reserved: u16 = 1 << 10; + let shared: u16 = 1 << 11; + + check!("0.0.0.0", unspec); + check!("0.0.0.1"); + check!("0.1.0.0"); + check!("10.9.8.7", private); + check!("127.1.2.3", loopback); + check!("172.31.254.253", private); + check!("169.254.253.242", link_local); + check!("192.0.2.183", documentation); + check!("192.1.2.183", global); + check!("192.168.254.253", private); + check!("198.51.100.0", documentation); + check!("203.0.113.0", documentation); + check!("203.2.113.0", global); + check!("224.0.0.0", global | multicast); + check!("239.255.255.255", global | multicast); + check!("255.255.255.255", broadcast); + check!("198.18.0.0", benchmarking); + check!("198.18.54.2", benchmarking); + check!("198.19.255.255", benchmarking); + check!("192.0.0.0", ietf_protocol_assignment); + check!("192.0.0.255", ietf_protocol_assignment); + check!("192.0.0.100", ietf_protocol_assignment); + check!("240.0.0.0", reserved); + check!("251.54.1.76", reserved); + check!("254.255.255.255", reserved); + check!("100.64.0.0", shared); + check!("100.127.255.255", shared); + check!("100.100.100.0", shared); + } + + #[test] + fn ipv6_properties() { + macro_rules! ip { + ($s:expr) => { + Ipv6Addr::from_str($s).unwrap() + }; + } + + macro_rules! check { + ($s:expr, &[$($octet:expr),*], $mask:expr) => { + assert_eq!($s, ip!($s).to_string()); + let octets = &[$($octet),*]; + assert_eq!(&ip!($s).octets(), octets); + assert_eq!(Ipv6Addr::from(*octets), ip!($s)); + + let unspecified: u16 = 1 << 0; + let loopback: u16 = 1 << 1; + let unique_local: u16 = 1 << 2; + let global: u16 = 1 << 3; + let unicast_link_local: u16 = 1 << 4; + let unicast_link_local_strict: u16 = 1 << 5; + let unicast_site_local: u16 = 1 << 6; + let unicast_global: u16 = 1 << 7; + let documentation: u16 = 1 << 8; + let multicast_interface_local: u16 = 1 << 9; + let multicast_link_local: u16 = 1 << 10; + let multicast_realm_local: u16 = 1 << 11; + let multicast_admin_local: u16 = 1 << 12; + let multicast_site_local: u16 = 1 << 13; + let multicast_organization_local: u16 = 1 << 14; + let multicast_global: u16 = 1 << 15; + let multicast: u16 = multicast_interface_local + | multicast_admin_local + | multicast_global + | multicast_link_local + | multicast_realm_local + | multicast_site_local + | multicast_organization_local; + + if ($mask & unspecified) == unspecified { + assert!(ip!($s).is_unspecified()); + } else { + assert!(!ip!($s).is_unspecified()); + } + if ($mask & loopback) == loopback { + assert!(ip!($s).is_loopback()); + } else { + assert!(!ip!($s).is_loopback()); + } + if ($mask & unique_local) == unique_local { + assert!(ip!($s).is_unique_local()); + } else { + assert!(!ip!($s).is_unique_local()); + } + if ($mask & global) == global { + assert!(ip!($s).is_global()); + } else { + assert!(!ip!($s).is_global()); + } + if ($mask & unicast_link_local) == unicast_link_local { + assert!(ip!($s).is_unicast_link_local()); + } else { + assert!(!ip!($s).is_unicast_link_local()); + } + if ($mask & unicast_link_local_strict) == unicast_link_local_strict { + assert!(ip!($s).is_unicast_link_local_strict()); + } else { + assert!(!ip!($s).is_unicast_link_local_strict()); + } + if ($mask & unicast_site_local) == unicast_site_local { + assert!(ip!($s).is_unicast_site_local()); + } else { + assert!(!ip!($s).is_unicast_site_local()); + } + if ($mask & unicast_global) == unicast_global { + assert!(ip!($s).is_unicast_global()); + } else { + assert!(!ip!($s).is_unicast_global()); + } + if ($mask & documentation) == documentation { + assert!(ip!($s).is_documentation()); + } else { + assert!(!ip!($s).is_documentation()); + } + if ($mask & multicast) != 0 { + assert!(ip!($s).multicast_scope().is_some()); + assert!(ip!($s).is_multicast()); + } else { + assert!(ip!($s).multicast_scope().is_none()); + assert!(!ip!($s).is_multicast()); + } + if ($mask & multicast_interface_local) == multicast_interface_local { + assert_eq!(ip!($s).multicast_scope().unwrap(), + Ipv6MulticastScope::InterfaceLocal); + } + if ($mask & multicast_link_local) == multicast_link_local { + assert_eq!(ip!($s).multicast_scope().unwrap(), + Ipv6MulticastScope::LinkLocal); + } + if ($mask & multicast_realm_local) == multicast_realm_local { + assert_eq!(ip!($s).multicast_scope().unwrap(), + Ipv6MulticastScope::RealmLocal); + } + if ($mask & multicast_admin_local) == multicast_admin_local { + assert_eq!(ip!($s).multicast_scope().unwrap(), + Ipv6MulticastScope::AdminLocal); + } + if ($mask & multicast_site_local) == multicast_site_local { + assert_eq!(ip!($s).multicast_scope().unwrap(), + Ipv6MulticastScope::SiteLocal); + } + if ($mask & multicast_organization_local) == multicast_organization_local { + assert_eq!(ip!($s).multicast_scope().unwrap(), + Ipv6MulticastScope::OrganizationLocal); + } + if ($mask & multicast_global) == multicast_global { + assert_eq!(ip!($s).multicast_scope().unwrap(), + Ipv6MulticastScope::Global); + } + } + } + + let unspecified: u16 = 1 << 0; + let loopback: u16 = 1 << 1; + let unique_local: u16 = 1 << 2; + let global: u16 = 1 << 3; + let unicast_link_local: u16 = 1 << 4; + let unicast_link_local_strict: u16 = 1 << 5; + let unicast_site_local: u16 = 1 << 6; + let unicast_global: u16 = 1 << 7; + let documentation: u16 = 1 << 8; + let multicast_interface_local: u16 = 1 << 9; + let multicast_link_local: u16 = 1 << 10; + let multicast_realm_local: u16 = 1 << 11; + let multicast_admin_local: u16 = 1 << 12; + let multicast_site_local: u16 = 1 << 13; + let multicast_organization_local: u16 = 1 << 14; + let multicast_global: u16 = 1 << 15; + + check!("::", &[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], unspecified); + + check!("::1", &[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1], loopback); + + check!( + "::0.0.0.2", + &[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2], + global | unicast_global + ); + + check!("1::", &[0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], global | unicast_global); + + check!("fc00::", &[0xfc, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], unique_local); + + check!( + "fdff:ffff::", + &[0xfd, 0xff, 0xff, 0xff, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], + unique_local + ); + + check!( + "fe80:ffff::", + &[0xfe, 0x80, 0xff, 0xff, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], + unicast_link_local + ); + + check!( + "fe80::", + &[0xfe, 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], + unicast_link_local | unicast_link_local_strict + ); + + check!( + "febf:ffff::", + &[0xfe, 0xbf, 0xff, 0xff, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], + unicast_link_local + ); + + check!( + "febf::", + &[0xfe, 0xbf, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], + unicast_link_local + ); + + check!( + "febf:ffff:ffff:ffff:ffff:ffff:ffff:ffff", + &[ + 0xfe, 0xbf, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff + ], + unicast_link_local + ); + + check!( + "fe80::ffff:ffff:ffff:ffff", + &[ + 0xfe, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff + ], + unicast_link_local | unicast_link_local_strict + ); + + check!( + "fe80:0:0:1::", + &[0xfe, 0x80, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0], + unicast_link_local + ); + + check!( + "fec0::", + &[0xfe, 0xc0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], + unicast_site_local | unicast_global | global + ); + + check!( + "ff01::", + &[0xff, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], + multicast_interface_local + ); + + check!( + "ff02::", + &[0xff, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], + multicast_link_local + ); + + check!( + "ff03::", + &[0xff, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], + multicast_realm_local + ); + + check!( + "ff04::", + &[0xff, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], + multicast_admin_local + ); + + check!( + "ff05::", + &[0xff, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], + multicast_site_local + ); + + check!( + "ff08::", + &[0xff, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], + multicast_organization_local + ); + + check!( + "ff0e::", + &[0xff, 0xe, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], + multicast_global | global + ); + + check!( + "2001:db8:85a3::8a2e:370:7334", + &[0x20, 1, 0xd, 0xb8, 0x85, 0xa3, 0, 0, 0, 0, 0x8a, 0x2e, 3, 0x70, 0x73, 0x34], + documentation + ); + + check!( + "102:304:506:708:90a:b0c:d0e:f10", + &[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16], + global | unicast_global + ); + } + + #[test] + fn to_socket_addr_socketaddr() { + let a = sa4(Ipv4Addr::new(77, 88, 21, 11), 12345); + assert_eq!(Ok(vec![a]), tsa(a)); + } + + #[test] + fn test_ipv4_to_int() { + let a = Ipv4Addr::new(0x11, 0x22, 0x33, 0x44); + assert_eq!(u32::from(a), 0x11223344); + } + + #[test] + fn test_int_to_ipv4() { + let a = Ipv4Addr::new(0x11, 0x22, 0x33, 0x44); + assert_eq!(Ipv4Addr::from(0x11223344), a); + } + + #[test] + fn test_ipv6_to_int() { + let a = Ipv6Addr::new(0x1122, 0x3344, 0x5566, 0x7788, 0x99aa, 0xbbcc, 0xddee, 0xff11); + assert_eq!(u128::from(a), 0x112233445566778899aabbccddeeff11u128); + } + + #[test] + fn test_int_to_ipv6() { + let a = Ipv6Addr::new(0x1122, 0x3344, 0x5566, 0x7788, 0x99aa, 0xbbcc, 0xddee, 0xff11); + assert_eq!(Ipv6Addr::from(0x112233445566778899aabbccddeeff11u128), a); + } + + #[test] + fn ipv4_from_constructors() { + assert_eq!(Ipv4Addr::LOCALHOST, Ipv4Addr::new(127, 0, 0, 1)); + assert!(Ipv4Addr::LOCALHOST.is_loopback()); + assert_eq!(Ipv4Addr::UNSPECIFIED, Ipv4Addr::new(0, 0, 0, 0)); + assert!(Ipv4Addr::UNSPECIFIED.is_unspecified()); + assert_eq!(Ipv4Addr::BROADCAST, Ipv4Addr::new(255, 255, 255, 255)); + assert!(Ipv4Addr::BROADCAST.is_broadcast()); + } + + #[test] + fn ipv6_from_contructors() { + assert_eq!(Ipv6Addr::LOCALHOST, Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1)); + assert!(Ipv6Addr::LOCALHOST.is_loopback()); + assert_eq!(Ipv6Addr::UNSPECIFIED, Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0)); + assert!(Ipv6Addr::UNSPECIFIED.is_unspecified()); + } + + #[test] + fn ipv4_from_octets() { + assert_eq!(Ipv4Addr::from([127, 0, 0, 1]), Ipv4Addr::new(127, 0, 0, 1)) + } + + #[test] + fn ipv6_from_segments() { + let from_u16s = + Ipv6Addr::from([0x0011, 0x2233, 0x4455, 0x6677, 0x8899, 0xaabb, 0xccdd, 0xeeff]); + let new = Ipv6Addr::new(0x0011, 0x2233, 0x4455, 0x6677, 0x8899, 0xaabb, 0xccdd, 0xeeff); + assert_eq!(new, from_u16s); + } + + #[test] + fn ipv6_from_octets() { + let from_u16s = + Ipv6Addr::from([0x0011, 0x2233, 0x4455, 0x6677, 0x8899, 0xaabb, 0xccdd, 0xeeff]); + let from_u8s = Ipv6Addr::from([ + 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, + 0xee, 0xff, + ]); + assert_eq!(from_u16s, from_u8s); + } + + #[test] + fn cmp() { + let v41 = Ipv4Addr::new(100, 64, 3, 3); + let v42 = Ipv4Addr::new(192, 0, 2, 2); + let v61 = "2001:db8:f00::1002".parse::().unwrap(); + let v62 = "2001:db8:f00::2001".parse::().unwrap(); + assert!(v41 < v42); + assert!(v61 < v62); + + assert_eq!(v41, IpAddr::V4(v41)); + assert_eq!(v61, IpAddr::V6(v61)); + assert!(v41 != IpAddr::V4(v42)); + assert!(v61 != IpAddr::V6(v62)); + + assert!(v41 < IpAddr::V4(v42)); + assert!(v61 < IpAddr::V6(v62)); + assert!(IpAddr::V4(v41) < v42); + assert!(IpAddr::V6(v61) < v62); + + assert!(v41 < IpAddr::V6(v61)); + assert!(IpAddr::V4(v41) < v61); + } + + #[test] + fn is_v4() { + let ip = IpAddr::V4(Ipv4Addr::new(100, 64, 3, 3)); + assert!(ip.is_ipv4()); + assert!(!ip.is_ipv6()); + } + + #[test] + fn is_v6() { + let ip = IpAddr::V6(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0x1234, 0x5678)); + assert!(!ip.is_ipv4()); + assert!(ip.is_ipv6()); + } +} diff --git a/src/libstd/net/mod.rs b/src/libstd/net/mod.rs new file mode 100644 index 0000000000000..86060f73b014b --- /dev/null +++ b/src/libstd/net/mod.rs @@ -0,0 +1,132 @@ +//! Networking primitives for TCP/UDP communication. +//! +//! This module provides networking functionality for the Transmission Control and User +//! Datagram Protocols, as well as types for IP and socket addresses. +//! +//! # Organization +//! +//! * [`TcpListener`] and [`TcpStream`] provide functionality for communication over TCP +//! * [`UdpSocket`] provides functionality for communication over UDP +//! * [`IpAddr`] represents IP addresses of either IPv4 or IPv6; [`Ipv4Addr`] and +//! [`Ipv6Addr`] are respectively IPv4 and IPv6 addresses +//! * [`SocketAddr`] represents socket addresses of either IPv4 or IPv6; [`SocketAddrV4`] +//! and [`SocketAddrV6`] are respectively IPv4 and IPv6 socket addresses +//! * [`ToSocketAddrs`] is a trait that used for generic address resolution when interacting +//! with networking objects like [`TcpListener`], [`TcpStream`] or [`UdpSocket`] +//! * Other types are return or parameter types for various methods in this module +//! +//! # Stability guarantees for IETF-defined behavior +//! +//! [`IpAddr`], [`Ipv4Addr`] and [`Ipv6Addr`] offer helper methods that provide information about +//! an address, for instance whether it is globally routable (see [`IpAddr::is_global()`]), or if +//! it is a multicast address (see [`IpAddr::is_multicast()`]). These methods are compliant with +//! the [IETF RFCs]. As erratas and new RFCs are published, these methods behavior may be subject +//! to changes. +//! +//! For instance, the `240/4` IPv4 block is currently reserved for "future use". If it is made +//! globally routable by an RFC, then in a future release [`Ipv4Addr::is_reserved()`] will return +//! `false` for such addresses, while [`Ipv4Addr::is_global`] will return true. +//! +//! [`IpAddr`]: ../../std/net/enum.IpAddr.html +//! [`Ipv4Addr`]: ../../std/net/struct.Ipv4Addr.html +//! [`IpAddr::is_global()`]: ../../std/net/enum.IpAddr.html#method.is_global +//! [`IpAddr::is_multicast()`]: ../../std/net/enum.IpAddr.html#method.is_multicast +//! [`Ipv4Addr::is_reserved()`]: ../../std/net/struct.Ipv4Addr.html#method.is_reserved +//! [`Ipv4Addr::is_global()`]: ../../std/net/struct.Ipv4Addr.html#method.is_global +//! [`Ipv6Addr`]: ../../std/net/struct.Ipv6Addr.html +//! [`SocketAddr`]: ../../std/net/enum.SocketAddr.html +//! [`SocketAddrV4`]: ../../std/net/struct.SocketAddrV4.html +//! [`SocketAddrV6`]: ../../std/net/struct.SocketAddrV6.html +//! [`TcpListener`]: ../../std/net/struct.TcpListener.html +//! [`TcpStream`]: ../../std/net/struct.TcpStream.html +//! [`ToSocketAddrs`]: ../../std/net/trait.ToSocketAddrs.html +//! [`UdpSocket`]: ../../std/net/struct.UdpSocket.html +//! [IETF RFCs]: https://tools.ietf.org/rfc/index + +#![stable(feature = "rust1", since = "1.0.0")] + +use crate::io::{self, Error, ErrorKind}; + +#[stable(feature = "rust1", since = "1.0.0")] +pub use self::addr::{SocketAddr, SocketAddrV4, SocketAddrV6, ToSocketAddrs}; +#[stable(feature = "rust1", since = "1.0.0")] +pub use self::ip::{IpAddr, Ipv4Addr, Ipv6Addr, Ipv6MulticastScope}; +#[stable(feature = "rust1", since = "1.0.0")] +pub use self::parser::AddrParseError; +#[stable(feature = "rust1", since = "1.0.0")] +pub use self::tcp::{Incoming, TcpListener, TcpStream}; +#[stable(feature = "rust1", since = "1.0.0")] +pub use self::udp::UdpSocket; + +mod addr; +mod ip; +mod parser; +mod tcp; +#[cfg(test)] +mod test; +mod udp; + +/// Possible values which can be passed to the [`shutdown`] method of +/// [`TcpStream`]. +/// +/// [`shutdown`]: struct.TcpStream.html#method.shutdown +/// [`TcpStream`]: struct.TcpStream.html +#[derive(Copy, Clone, PartialEq, Eq, Debug)] +#[stable(feature = "rust1", since = "1.0.0")] +pub enum Shutdown { + /// The reading portion of the [`TcpStream`] should be shut down. + /// + /// All currently blocked and future [reads] will return [`Ok(0)`]. + /// + /// [`TcpStream`]: ../../std/net/struct.TcpStream.html + /// [reads]: ../../std/io/trait.Read.html + /// [`Ok(0)`]: ../../std/result/enum.Result.html#variant.Ok + #[stable(feature = "rust1", since = "1.0.0")] + Read, + /// The writing portion of the [`TcpStream`] should be shut down. + /// + /// All currently blocked and future [writes] will return an error. + /// + /// [`TcpStream`]: ../../std/net/struct.TcpStream.html + /// [writes]: ../../std/io/trait.Write.html + #[stable(feature = "rust1", since = "1.0.0")] + Write, + /// Both the reading and the writing portions of the [`TcpStream`] should be shut down. + /// + /// See [`Shutdown::Read`] and [`Shutdown::Write`] for more information. + /// + /// [`TcpStream`]: ../../std/net/struct.TcpStream.html + /// [`Shutdown::Read`]: #variant.Read + /// [`Shutdown::Write`]: #variant.Write + #[stable(feature = "rust1", since = "1.0.0")] + Both, +} + +#[inline] +const fn htons(i: u16) -> u16 { + i.to_be() +} +#[inline] +const fn ntohs(i: u16) -> u16 { + u16::from_be(i) +} + +fn each_addr(addr: A, mut f: F) -> io::Result +where + F: FnMut(io::Result<&SocketAddr>) -> io::Result, +{ + let addrs = match addr.to_socket_addrs() { + Ok(addrs) => addrs, + Err(e) => return f(Err(e)), + }; + let mut last_err = None; + for addr in addrs { + match f(Ok(&addr)) { + Ok(l) => return Ok(l), + Err(e) => last_err = Some(e), + } + } + Err(last_err.unwrap_or_else(|| { + Error::new(ErrorKind::InvalidInput, "could not resolve to any addresses") + })) +} From 7b7ca5dda7772ff36938c6858e28f1e15d613a8f Mon Sep 17 00:00:00 2001 From: Corentin Henry Date: Sun, 12 Jan 2020 18:56:34 +0100 Subject: [PATCH 02/24] std::net: add Ipv6Multicastscope variants Add variants for the currently reserved and un-assigned scopes. Since variants may be added in the future as new RFCs get published, we also make this enum #[non_exhaustive]. Ref: https://github.com/rust-lang/rust/pull/66584#discussion_r365546460 --- src/libstd/net/ip.rs | 147 ++++++++++++++++++++++++++++++------------- 1 file changed, 102 insertions(+), 45 deletions(-) diff --git a/src/libstd/net/ip.rs b/src/libstd/net/ip.rs index 60b613cfd8c32..6a4ea4ec4f6ec 100644 --- a/src/libstd/net/ip.rs +++ b/src/libstd/net/ip.rs @@ -116,8 +116,15 @@ pub struct Ipv6Addr { /// Scope of an IPv6 address as defined in [section 2 of IETF RFC 7346] /// +/// # Stability guarantees +/// +/// This enum may [may by subject to changes][changes] in the +/// future, as new RFCs are published. +/// +/// [changes]: ../net/index.html#stability-guarantees-for-ietf-defined-behavior /// [section 2 of IETF RFC 7346]: https://tools.ietf.org/html/rfc7346#section-2 #[derive(Copy, PartialEq, Eq, Clone, Hash, Debug)] +#[non_exhaustive] #[stable(feature = "ip", since = "1.42.0")] pub enum Ipv6MulticastScope { /// Interface-Local scope. See [RFC 4291] and [RFC 7346] @@ -168,6 +175,20 @@ pub enum Ipv6MulticastScope { /// [RFC 7346]: https://tools.ietf.org/html/rfc7346#section-2 #[stable(feature = "ip", since = "1.42.0")] Global, + + /// Reserved scope. See [RFC 4291] and [RFC 7346] + /// + /// [RFC 4291]: https://tools.ietf.org/html/rfc4291#section-2.7 + /// [RFC 7346]: https://tools.ietf.org/html/rfc7346#section-2 + #[stable(feature = "ip", since = "1.42.0")] + Reserved, + + /// Un-assigned scope. See [RFC 4291] and [RFC 7346] + /// + /// [RFC 4291]: https://tools.ietf.org/html/rfc4291#section-2.7 + /// [RFC 7346]: https://tools.ietf.org/html/rfc7346#section-2 + #[stable(feature = "ip", since = "1.42.0")] + Unassigned, } impl IpAddr { @@ -1640,7 +1661,7 @@ impl Ipv6Addr { && !self.is_documentation() } - /// Returns the address's multicast scope if the address is multicast. + /// Return the address's multicast scope if the address is multicast. /// /// # Examples /// @@ -1662,17 +1683,19 @@ impl Ipv6Addr { /// [changes]: ../net/index.html#stability-guarantees-for-ietf-defined-behavior #[stable(feature = "ip", since = "1.42.0")] pub fn multicast_scope(&self) -> Option { + use 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, - } + Some(match self.segments()[0] & 0x000f { + 0 | 15 => Reserved, + 1 => InterfaceLocal, + 2 => LinkLocal, + 3 => RealmLocal, + 4 => AdminLocal, + 5 => SiteLocal, + 8 => OrganizationLocal, + 14 => Global, + _ => Unassigned, + }) } else { None } @@ -2551,29 +2574,33 @@ mod tests { assert_eq!(&ip!($s).octets(), octets); assert_eq!(Ipv6Addr::from(*octets), ip!($s)); - let unspecified: u16 = 1 << 0; - let loopback: u16 = 1 << 1; - let unique_local: u16 = 1 << 2; - let global: u16 = 1 << 3; - let unicast_link_local: u16 = 1 << 4; - let unicast_link_local_strict: u16 = 1 << 5; - let unicast_site_local: u16 = 1 << 6; - let unicast_global: u16 = 1 << 7; - let documentation: u16 = 1 << 8; - let multicast_interface_local: u16 = 1 << 9; - let multicast_link_local: u16 = 1 << 10; - let multicast_realm_local: u16 = 1 << 11; - let multicast_admin_local: u16 = 1 << 12; - let multicast_site_local: u16 = 1 << 13; - let multicast_organization_local: u16 = 1 << 14; - let multicast_global: u16 = 1 << 15; - let multicast: u16 = multicast_interface_local + let unspecified: u32 = 1 << 0; + let loopback: u32 = 1 << 1; + let unique_local: u32 = 1 << 2; + let global: u32 = 1 << 3; + let unicast_link_local: u32 = 1 << 4; + let unicast_link_local_strict: u32 = 1 << 5; + let unicast_site_local: u32 = 1 << 6; + let unicast_global: u32 = 1 << 7; + let documentation: u32 = 1 << 8; + let multicast_interface_local: u32 = 1 << 9; + let multicast_link_local: u32 = 1 << 10; + let multicast_realm_local: u32 = 1 << 11; + let multicast_admin_local: u32 = 1 << 12; + let multicast_site_local: u32 = 1 << 13; + let multicast_organization_local: u32 = 1 << 14; + let multicast_global: u32 = 1 << 15; + let multicast_reserved: u32 = 1 << 16; + let multicast_unassigned: u32 = 1 << 17; + let multicast: u32 = multicast_interface_local | multicast_admin_local | multicast_global | multicast_link_local | multicast_realm_local | multicast_site_local - | multicast_organization_local; + | multicast_organization_local + | multicast_reserved + | multicast_unassigned; if ($mask & unspecified) == unspecified { assert!(ip!($s).is_unspecified()); @@ -2655,25 +2682,35 @@ mod tests { assert_eq!(ip!($s).multicast_scope().unwrap(), Ipv6MulticastScope::Global); } + if ($mask & multicast_reserved) == multicast_reserved { + assert_eq!(ip!($s).multicast_scope().unwrap(), + Ipv6MulticastScope::Reserved); + } + if ($mask & multicast_unassigned) == multicast_unassigned { + assert_eq!(ip!($s).multicast_scope().unwrap(), + Ipv6MulticastScope::Unassigned); + } } } - let unspecified: u16 = 1 << 0; - let loopback: u16 = 1 << 1; - let unique_local: u16 = 1 << 2; - let global: u16 = 1 << 3; - let unicast_link_local: u16 = 1 << 4; - let unicast_link_local_strict: u16 = 1 << 5; - let unicast_site_local: u16 = 1 << 6; - let unicast_global: u16 = 1 << 7; - let documentation: u16 = 1 << 8; - let multicast_interface_local: u16 = 1 << 9; - let multicast_link_local: u16 = 1 << 10; - let multicast_realm_local: u16 = 1 << 11; - let multicast_admin_local: u16 = 1 << 12; - let multicast_site_local: u16 = 1 << 13; - let multicast_organization_local: u16 = 1 << 14; - let multicast_global: u16 = 1 << 15; + let unspecified: u32 = 1 << 0; + let loopback: u32 = 1 << 1; + let unique_local: u32 = 1 << 2; + let global: u32 = 1 << 3; + let unicast_link_local: u32 = 1 << 4; + let unicast_link_local_strict: u32 = 1 << 5; + let unicast_site_local: u32 = 1 << 6; + let unicast_global: u32 = 1 << 7; + let documentation: u32 = 1 << 8; + let multicast_interface_local: u32 = 1 << 9; + let multicast_link_local: u32 = 1 << 10; + let multicast_realm_local: u32 = 1 << 11; + let multicast_admin_local: u32 = 1 << 12; + let multicast_site_local: u32 = 1 << 13; + let multicast_organization_local: u32 = 1 << 14; + let multicast_global: u32 = 1 << 15; + let multicast_reserved: u32 = 1 << 16; + let multicast_unassigned: u32 = 1 << 17; check!("::", &[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], unspecified); @@ -2749,6 +2786,8 @@ mod tests { unicast_site_local | unicast_global | global ); + check!("ff00::", &[0xff, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], multicast_reserved); + check!( "ff01::", &[0xff, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], @@ -2779,18 +2818,36 @@ mod tests { multicast_site_local ); + check!( + "ff06::", + &[0xff, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], + multicast_unassigned + ); + check!( "ff08::", &[0xff, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], multicast_organization_local ); + check!( + "ff0a::", + &[0xff, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], + multicast_unassigned + ); + check!( "ff0e::", &[0xff, 0xe, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], multicast_global | global ); + check!( + "ff0f::", + &[0xff, 0xf, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], + multicast_reserved + ); + check!( "2001:db8:85a3::8a2e:370:7334", &[0x20, 1, 0xd, 0xb8, 0x85, 0xa3, 0, 0, 0, 0, 0x8a, 0x2e, 3, 0x70, 0x73, 0x34], From f33f9457e3330b662d58c38dda61610760c1f26b Mon Sep 17 00:00:00 2001 From: Cassandra Fridkin Date: Thu, 3 Sep 2020 20:08:30 -0400 Subject: [PATCH 03/24] Update feature gates --- library/std/src/net/ip.rs | 251 ++++++++++++++++++++++++++++++-------- 1 file changed, 201 insertions(+), 50 deletions(-) diff --git a/library/std/src/net/ip.rs b/library/std/src/net/ip.rs index 9b629e19be53d..45881a52b0dc7 100644 --- a/library/std/src/net/ip.rs +++ b/library/std/src/net/ip.rs @@ -126,14 +126,71 @@ pub struct Ipv6Addr { #[allow(missing_docs)] #[derive(Copy, PartialEq, Eq, Clone, Hash, Debug)] +#[non_exhaustive] +#[stable(feature = "ip", since = "1.47.0")] pub enum Ipv6MulticastScope { + /// Interface-Local scope. See [RFC 4291] and [RFC 7346] + /// + /// [RFC 4291]: https://tools.ietf.org/html/rfc4291#section-2.7 + /// [RFC 7346]: https://tools.ietf.org/html/rfc7346#section-2 + #[stable(feature = "ip", since = "1.47.0")] InterfaceLocal, + + /// Link-Local scope. See [RFC 4291] and [RFC 7346] + /// + /// [RFC 4291]: https://tools.ietf.org/html/rfc4291#section-2.7 + /// [RFC 7346]: https://tools.ietf.org/html/rfc7346#section-2 + #[stable(feature = "ip", since = "1.47.0")] LinkLocal, + + /// Realm-Local scope. See [RFC 4291] and [RFC 7346] + /// + /// [RFC 4291]: https://tools.ietf.org/html/rfc4291#section-2.7 + /// [RFC 7346]: https://tools.ietf.org/html/rfc7346#section-2 + #[stable(feature = "ip", since = "1.47.0")] RealmLocal, + + /// Admin-Local scope. See [RFC 4291] and [RFC 7346] + /// + /// [RFC 4291]: https://tools.ietf.org/html/rfc4291#section-2.7 + /// [RFC 7346]: https://tools.ietf.org/html/rfc7346#section-2 + #[stable(feature = "ip", since = "1.47.0")] AdminLocal, + + /// Site-Local scope. See [RFC 4291] and [RFC 7346] + /// + /// [RFC 4291]: https://tools.ietf.org/html/rfc4291#section-2.7 + /// [RFC 7346]: https://tools.ietf.org/html/rfc7346#section-2 + #[stable(feature = "ip", since = "1.47.0")] SiteLocal, + + /// Organization-Local scope. See [RFC 4291] and [RFC 7346] + /// + /// [RFC 4291]: https://tools.ietf.org/html/rfc4291#section-2.7 + /// [RFC 7346]: https://tools.ietf.org/html/rfc7346#section-2 + #[stable(feature = "ip", since = "1.47.0")] OrganizationLocal, + + /// Global scope. See [RFC 4291] and [RFC 7346] + /// + /// [RFC 4291]: https://tools.ietf.org/html/rfc4291#section-2.7 + /// [RFC 7346]: https://tools.ietf.org/html/rfc7346#section-2 + #[stable(feature = "ip", since = "1.47.0")] Global, + + /// Reserved scope. See [RFC 4291] and [RFC 7346] + /// + /// [RFC 4291]: https://tools.ietf.org/html/rfc4291#section-2.7 + /// [RFC 7346]: https://tools.ietf.org/html/rfc7346#section-2 + #[stable(feature = "ip", since = "1.47.0")] + Reserved, + + /// Un-assigned scope. See [RFC 4291] and [RFC 7346] + /// + /// [RFC 4291]: https://tools.ietf.org/html/rfc4291#section-2.7 + /// [RFC 7346]: https://tools.ietf.org/html/rfc7346#section-2 + #[stable(feature = "ip", since = "1.47.0")] + Unassigned, } impl IpAddr { @@ -198,9 +255,15 @@ impl IpAddr { /// assert_eq!(IpAddr::V4(Ipv4Addr::new(80, 9, 12, 3)).is_global(), true); /// assert_eq!(IpAddr::V6(Ipv6Addr::new(0, 0, 0x1c9, 0, 0, 0xafc8, 0, 0x1)).is_global(), true); /// ``` - #[rustc_const_unstable(feature = "const_ip", issue = "76205")] - #[inline] - pub const fn is_global(&self) -> bool { + /// + /// # Stability guarantees + /// + /// This method's behavior [may by subject to changes][changes] in the + /// future, as new RFCs are published. + /// + /// [changes]: ../net/index.html#stability-guarantees-for-ietf-defined-behavior + #[stable(feature = "ip", since = "1.47.0")] + pub fn is_global(&self) -> bool { match self { IpAddr::V4(ip) => ip.is_global(), IpAddr::V6(ip) => ip.is_global(), @@ -248,9 +311,15 @@ impl IpAddr { /// true /// ); /// ``` - #[rustc_const_unstable(feature = "const_ip", issue = "76205")] - #[inline] - pub const fn is_documentation(&self) -> bool { + /// + /// # Stability guarantees + /// + /// This method's behavior [may by subject to changes][changes] in the + /// future, as new RFCs are published. + /// + /// [changes]: ../net/index.html#stability-guarantees-for-ietf-defined-behavior + #[stable(feature = "ip", since = "1.47.0")] + pub fn is_documentation(&self) -> bool { match self { IpAddr::V4(ip) => ip.is_documentation(), IpAddr::V6(ip) => ip.is_documentation(), @@ -548,9 +617,15 @@ impl Ipv4Addr { /// assert_eq!(Ipv4Addr::new(1, 1, 1, 1).is_global(), true); /// assert_eq!(Ipv4Addr::new(80, 9, 12, 3).is_global(), true); /// ``` - #[rustc_const_unstable(feature = "const_ipv4", issue = "76205")] - #[inline] - pub const fn is_global(&self) -> bool { + /// + /// # Stability guarantees + /// + /// This method's behavior [may by subject to changes][changes] in the + /// future, as new RFCs are published. + /// + /// [changes]: ../net/index.html#stability-guarantees-for-ietf-defined-behavior + #[stable(feature = "ip", since = "1.47.0")] + pub fn is_global(&self) -> bool { // check if this address is 192.0.0.9 or 192.0.0.10. These addresses are the only two // globally routable addresses in the 192.0.0.0/24 range. if u32::from_be_bytes(self.octets()) == 0xc0000009 @@ -586,9 +661,15 @@ impl Ipv4Addr { /// assert_eq!(Ipv4Addr::new(100, 127, 255, 255).is_shared(), true); /// assert_eq!(Ipv4Addr::new(100, 128, 0, 0).is_shared(), false); /// ``` - #[rustc_const_unstable(feature = "const_ipv4", issue = "76205")] - #[inline] - pub const fn is_shared(&self) -> bool { + /// + /// # Stability guarantees + /// + /// This method's behavior [may by subject to changes][changes] in the + /// future, as new RFCs are published. + /// + /// [changes]: ../net/index.html#stability-guarantees-for-ietf-defined-behavior + #[stable(feature = "ip", since = "1.47.0")] + pub fn is_shared(&self) -> bool { self.octets()[0] == 100 && (self.octets()[1] & 0b1100_0000 == 0b0100_0000) } @@ -619,9 +700,15 @@ impl Ipv4Addr { /// assert_eq!(Ipv4Addr::new(192, 0, 1, 0).is_ietf_protocol_assignment(), false); /// assert_eq!(Ipv4Addr::new(191, 255, 255, 255).is_ietf_protocol_assignment(), false); /// ``` - #[rustc_const_unstable(feature = "const_ipv4", issue = "76205")] - #[inline] - pub const fn is_ietf_protocol_assignment(&self) -> bool { + /// + /// # Stability guarantees + /// + /// This method's behavior [may by subject to changes][changes] in the + /// future, as new RFCs are published. + /// + /// [changes]: ../net/index.html#stability-guarantees-for-ietf-defined-behavior + #[stable(feature = "ip", since = "1.47.0")] + pub fn is_ietf_protocol_assignment(&self) -> bool { self.octets()[0] == 192 && self.octets()[1] == 0 && self.octets()[2] == 0 } @@ -643,9 +730,15 @@ impl Ipv4Addr { /// assert_eq!(Ipv4Addr::new(198, 19, 255, 255).is_benchmarking(), true); /// assert_eq!(Ipv4Addr::new(198, 20, 0, 0).is_benchmarking(), false); /// ``` - #[rustc_const_unstable(feature = "const_ipv4", issue = "76205")] - #[inline] - pub const fn is_benchmarking(&self) -> bool { + /// + /// # Stability guarantees + /// + /// This method's behavior [may by subject to changes][changes] in the + /// future, as new RFCs are published. + /// + /// [changes]: ../net/index.html#stability-guarantees-for-ietf-defined-behavior + #[stable(feature = "ip", since = "1.47.0")] + pub fn is_benchmarking(&self) -> bool { self.octets()[0] == 198 && (self.octets()[1] & 0xfe) == 18 } @@ -676,9 +769,15 @@ impl Ipv4Addr { /// // The broadcast address is not considered as reserved for future use by this implementation /// assert_eq!(Ipv4Addr::new(255, 255, 255, 255).is_reserved(), false); /// ``` - #[rustc_const_unstable(feature = "const_ipv4", issue = "76205")] - #[inline] - pub const fn is_reserved(&self) -> bool { + /// + /// # Stability guarantees + /// + /// This method's behavior [may by subject to changes][changes] in the + /// future, as new RFCs are published. + /// + /// [changes]: ../net/index.html#stability-guarantees-for-ietf-defined-behavior + #[stable(feature = "ip", since = "1.47.0")] + pub fn is_reserved(&self) -> bool { self.octets()[0] & 240 == 240 && !self.is_broadcast() } @@ -1233,9 +1332,15 @@ impl Ipv6Addr { /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0x1).is_global(), false); /// assert_eq!(Ipv6Addr::new(0, 0, 0x1c9, 0, 0, 0xafc8, 0, 0x1).is_global(), true); /// ``` - #[rustc_const_unstable(feature = "const_ipv6", issue = "76205")] - #[inline] - pub const fn is_global(&self) -> bool { + /// + /// # Stability guarantees + /// + /// This method's behavior [may by subject to changes][changes] in the + /// future, as new RFCs are published. + /// + /// [changes]: ../net/index.html#stability-guarantees-for-ietf-defined-behavior + #[stable(feature = "ip", since = "1.47.0")] + pub fn is_global(&self) -> bool { match self.multicast_scope() { Some(Ipv6MulticastScope::Global) => true, None => self.is_unicast_global(), @@ -1259,9 +1364,15 @@ impl Ipv6Addr { /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff).is_unique_local(), false); /// assert_eq!(Ipv6Addr::new(0xfc02, 0, 0, 0, 0, 0, 0, 0).is_unique_local(), true); /// ``` - #[rustc_const_unstable(feature = "const_ipv6", issue = "76205")] - #[inline] - pub const fn is_unique_local(&self) -> bool { + /// + /// # Stability guarantees + /// + /// This method's behavior [may by subject to changes][changes] in the + /// future, as new RFCs are published. + /// + /// [changes]: ../net/index.html#stability-guarantees-for-ietf-defined-behavior + #[stable(feature = "ip", since = "1.47.0")] + pub fn is_unique_local(&self) -> bool { (self.segments()[0] & 0xfe00) == 0xfc00 } @@ -1314,10 +1425,20 @@ impl Ipv6Addr { /// [IETF RFC 4291]: https://tools.ietf.org/html/rfc4291 /// [IETF RFC 4291 section 2.5.6]: https://tools.ietf.org/html/rfc4291#section-2.5.6 /// [RFC 4291 errata 4406]: https://www.rfc-editor.org/errata/eid4406 - #[rustc_const_unstable(feature = "const_ipv6", issue = "76205")] - #[inline] - pub const fn is_unicast_link_local_strict(&self) -> bool { - matches!(self.segments(), [0xfe80, 0, 0, 0, ..]) + /// [`is_unicast_link_local()`]: ../../std/net/struct.Ipv6Addr.html#method.is_unicast_link_local + /// + /// # Stability guarantees + /// + /// This method's behavior [may by subject to changes][changes] in the + /// future, as new RFCs are published. + /// + /// [changes]: ../net/index.html#stability-guarantees-for-ietf-defined-behavior + #[stable(feature = "ip", since = "1.47.0")] + pub fn is_unicast_link_local_strict(&self) -> bool { + (self.segments()[0] & 0xffff) == 0xfe80 + && (self.segments()[1] & 0xffff) == 0 + && (self.segments()[2] & 0xffff) == 0 + && (self.segments()[3] & 0xffff) == 0 } /// Returns [`true`] if the address is a unicast link-local address (`fe80::/10`). @@ -1368,9 +1489,16 @@ impl Ipv6Addr { /// /// [IETF RFC 4291 section 2.4]: https://tools.ietf.org/html/rfc4291#section-2.4 /// [RFC 4291 errata 4406]: https://www.rfc-editor.org/errata/eid4406 - #[rustc_const_unstable(feature = "const_ipv6", issue = "76205")] - #[inline] - pub const fn is_unicast_link_local(&self) -> bool { + /// [`is_unicast_link_local_strict()`]: ../../std/net/struct.Ipv6Addr.html#method.is_unicast_link_local_strict + /// + /// # Stability guarantees + /// + /// This method's behavior [may by subject to changes][changes] in the + /// future, as new RFCs are published. + /// + /// [changes]: ../net/index.html#stability-guarantees-for-ietf-defined-behavior + #[stable(feature = "ip", since = "1.47.0")] + pub fn is_unicast_link_local(&self) -> bool { (self.segments()[0] & 0xffc0) == 0xfe80 } @@ -1408,9 +1536,15 @@ impl Ipv6Addr { /// addresses. /// /// [RFC 3879]: https://tools.ietf.org/html/rfc3879 - #[rustc_const_unstable(feature = "const_ipv6", issue = "76205")] - #[inline] - pub const fn is_unicast_site_local(&self) -> bool { + /// + /// # Stability guarantees + /// + /// This method's behavior [may by subject to changes][changes] in the + /// future, as new RFCs are published. + /// + /// [changes]: ../net/index.html#stability-guarantees-for-ietf-defined-behavior + #[stable(feature = "ip", since = "1.47.0")] + pub fn is_unicast_site_local(&self) -> bool { (self.segments()[0] & 0xffc0) == 0xfec0 } @@ -1431,9 +1565,15 @@ impl Ipv6Addr { /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff).is_documentation(), false); /// assert_eq!(Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 0).is_documentation(), true); /// ``` - #[rustc_const_unstable(feature = "const_ipv6", issue = "76205")] - #[inline] - pub const fn is_documentation(&self) -> bool { + /// + /// # Stability guarantees + /// + /// This method's behavior [may by subject to changes][changes] in the + /// future, as new RFCs are published. + /// + /// [changes]: ../net/index.html#stability-guarantees-for-ietf-defined-behavior + #[stable(feature = "ip", since = "1.47.0")] + pub fn is_documentation(&self) -> bool { (self.segments()[0] == 0x2001) && (self.segments()[1] == 0xdb8) } @@ -1467,9 +1607,15 @@ impl Ipv6Addr { /// assert_eq!(Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 0).is_unicast_global(), false); /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff).is_unicast_global(), true); /// ``` - #[rustc_const_unstable(feature = "const_ipv6", issue = "76205")] - #[inline] - pub const fn is_unicast_global(&self) -> bool { + /// + /// # Stability guarantees + /// + /// This method's behavior [may by subject to changes][changes] in the + /// future, as new RFCs are published. + /// + /// [changes]: ../net/index.html#stability-guarantees-for-ietf-defined-behavior + #[stable(feature = "ip", since = "1.47.0")] + pub fn is_unicast_global(&self) -> bool { !self.is_multicast() && !self.is_loopback() && !self.is_unicast_link_local() @@ -1493,9 +1639,16 @@ impl Ipv6Addr { /// ); /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff).multicast_scope(), None); /// ``` - #[rustc_const_unstable(feature = "const_ipv6", issue = "76205")] - #[inline] - pub const fn multicast_scope(&self) -> Option { + /// + /// # Stability guarantees + /// + /// This method's behavior [may by subject to changes][changes] in the + /// future, as new RFCs are published. + /// + /// [changes]: ../net/index.html#stability-guarantees-for-ietf-defined-behavior + #[stable(feature = "ip", since = "1.47.0")] + pub fn multicast_scope(&self) -> Option { + use Ipv6MulticastScope::*; if self.is_multicast() { match self.segments()[0] & 0x000f { 1 => Some(Ipv6MulticastScope::InterfaceLocal), @@ -1545,7 +1698,6 @@ impl Ipv6Addr { /// # Examples /// /// ``` - /// #![feature(ip)] /// /// use std::net::{Ipv4Addr, Ipv6Addr}; /// @@ -1554,9 +1706,8 @@ impl Ipv6Addr { /// Some(Ipv4Addr::new(192, 10, 2, 255))); /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1).to_ipv4_mapped(), None); /// ``` - #[rustc_const_unstable(feature = "const_ipv6", issue = "76205")] - #[inline] - pub const fn to_ipv4_mapped(&self) -> Option { + #[stable(feature = "ip", since = "1.47.0")] + pub fn to_ipv4_mapped(&self) -> Option { 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)) From 86e9b37cde6cd021021e7d62c9bbd72340400c5d Mon Sep 17 00:00:00 2001 From: Cass Date: Fri, 4 Sep 2020 01:07:58 -0400 Subject: [PATCH 04/24] Apply suggestions from code review Thanks again for the help with understanding the attributes! Co-authored-by: Ashley Mannix --- library/std/src/net/ip.rs | 120 ++++++++++++++++++-------------------- 1 file changed, 57 insertions(+), 63 deletions(-) diff --git a/library/std/src/net/ip.rs b/library/std/src/net/ip.rs index 45881a52b0dc7..35103311fa69b 100644 --- a/library/std/src/net/ip.rs +++ b/library/std/src/net/ip.rs @@ -1,11 +1,3 @@ -#![unstable( - feature = "ip", - reason = "extra functionality has not been \ - scrutinized to the level that it should \ - be to be stable", - issue = "27709" -)] - // Tests for this module #[cfg(all(test, not(target_os = "emscripten")))] mod tests; @@ -124,7 +116,15 @@ pub struct Ipv6Addr { inner: c::in6_addr, } -#[allow(missing_docs)] +/// Scope of an IPv6 address as defined in [section 2 of IETF RFC 7346] +/// +/// # Stability guarantees +/// +/// This enum [may by subject to changes][changes] in the +/// future, as new RFCs are published. +/// +/// [changes]: ../net/index.html#stability-guarantees-for-ietf-defined-behavior +/// [section 2 of IETF RFC 7346]: https://tools.ietf.org/html/rfc7346#section-2 #[derive(Copy, PartialEq, Eq, Clone, Hash, Debug)] #[non_exhaustive] #[stable(feature = "ip", since = "1.47.0")] @@ -248,8 +248,6 @@ impl IpAddr { /// # Examples /// /// ``` - /// #![feature(ip)] - /// /// use std::net::{IpAddr, Ipv4Addr, Ipv6Addr}; /// /// assert_eq!(IpAddr::V4(Ipv4Addr::new(80, 9, 12, 3)).is_global(), true); @@ -262,7 +260,7 @@ impl IpAddr { /// future, as new RFCs are published. /// /// [changes]: ../net/index.html#stability-guarantees-for-ietf-defined-behavior - #[stable(feature = "ip", since = "1.47.0")] +#[stable(feature = "ip", since = "1.47.0")] pub fn is_global(&self) -> bool { match self { IpAddr::V4(ip) => ip.is_global(), @@ -301,8 +299,6 @@ impl IpAddr { /// # Examples /// /// ``` - /// #![feature(ip)] - /// /// use std::net::{IpAddr, Ipv4Addr, Ipv6Addr}; /// /// assert_eq!(IpAddr::V4(Ipv4Addr::new(203, 0, 113, 6)).is_documentation(), true); @@ -318,7 +314,7 @@ impl IpAddr { /// future, as new RFCs are published. /// /// [changes]: ../net/index.html#stability-guarantees-for-ietf-defined-behavior - #[stable(feature = "ip", since = "1.47.0")] +#[stable(feature = "ip", since = "1.47.0")] pub fn is_documentation(&self) -> bool { match self { IpAddr::V4(ip) => ip.is_documentation(), @@ -572,8 +568,6 @@ impl Ipv4Addr { /// # Examples /// /// ``` - /// #![feature(ip)] - /// /// use std::net::Ipv4Addr; /// /// // private addresses are not global @@ -624,8 +618,9 @@ impl Ipv4Addr { /// future, as new RFCs are published. /// /// [changes]: ../net/index.html#stability-guarantees-for-ietf-defined-behavior - #[stable(feature = "ip", since = "1.47.0")] - pub fn is_global(&self) -> bool { +#[stable(feature = "ip", since = "1.47.0")] + #[rustc_const_unstable(feature = "const_ipv4", issue = "76205")] + pub const fn is_global(&self) -> bool { // check if this address is 192.0.0.9 or 192.0.0.10. These addresses are the only two // globally routable addresses in the 192.0.0.0/24 range. if u32::from_be_bytes(self.octets()) == 0xc0000009 @@ -668,8 +663,9 @@ impl Ipv4Addr { /// future, as new RFCs are published. /// /// [changes]: ../net/index.html#stability-guarantees-for-ietf-defined-behavior - #[stable(feature = "ip", since = "1.47.0")] - pub fn is_shared(&self) -> bool { +#[stable(feature = "ip", since = "1.47.0")] + #[rustc_const_unstable(feature = "const_ipv4", issue = "76205")] + pub const fn is_shared(&self) -> bool { self.octets()[0] == 100 && (self.octets()[1] & 0b1100_0000 == 0b0100_0000) } @@ -707,8 +703,9 @@ impl Ipv4Addr { /// future, as new RFCs are published. /// /// [changes]: ../net/index.html#stability-guarantees-for-ietf-defined-behavior - #[stable(feature = "ip", since = "1.47.0")] - pub fn is_ietf_protocol_assignment(&self) -> bool { +#[stable(feature = "ip", since = "1.47.0")] + #[rustc_const_unstable(feature = "const_ipv4", issue = "76205")] + pub const fn is_ietf_protocol_assignment(&self) -> bool { self.octets()[0] == 192 && self.octets()[1] == 0 && self.octets()[2] == 0 } @@ -737,8 +734,9 @@ impl Ipv4Addr { /// future, as new RFCs are published. /// /// [changes]: ../net/index.html#stability-guarantees-for-ietf-defined-behavior - #[stable(feature = "ip", since = "1.47.0")] - pub fn is_benchmarking(&self) -> bool { +#[stable(feature = "ip", since = "1.47.0")] + #[rustc_const_unstable(feature = "const_ipv4", issue = "76205")] + pub const fn is_benchmarking(&self) -> bool { self.octets()[0] == 198 && (self.octets()[1] & 0xfe) == 18 } @@ -776,8 +774,9 @@ impl Ipv4Addr { /// future, as new RFCs are published. /// /// [changes]: ../net/index.html#stability-guarantees-for-ietf-defined-behavior - #[stable(feature = "ip", since = "1.47.0")] - pub fn is_reserved(&self) -> bool { +#[stable(feature = "ip", since = "1.47.0")] + #[rustc_const_unstable(feature = "const_ipv4", issue = "76205")] + pub const fn is_reserved(&self) -> bool { self.octets()[0] & 240 == 240 && !self.is_broadcast() } @@ -1324,8 +1323,6 @@ impl Ipv6Addr { /// # Examples /// /// ``` - /// #![feature(ip)] - /// /// use std::net::Ipv6Addr; /// /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff).is_global(), true); @@ -1339,8 +1336,9 @@ impl Ipv6Addr { /// future, as new RFCs are published. /// /// [changes]: ../net/index.html#stability-guarantees-for-ietf-defined-behavior - #[stable(feature = "ip", since = "1.47.0")] - pub fn is_global(&self) -> bool { +#[stable(feature = "ip", since = "1.47.0")] + #[rustc_const_unstable(feature = "const_ipv6", issue = "76205")] + pub const fn is_global(&self) -> bool { match self.multicast_scope() { Some(Ipv6MulticastScope::Global) => true, None => self.is_unicast_global(), @@ -1357,8 +1355,6 @@ impl Ipv6Addr { /// # Examples /// /// ``` - /// #![feature(ip)] - /// /// use std::net::Ipv6Addr; /// /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff).is_unique_local(), false); @@ -1371,8 +1367,9 @@ impl Ipv6Addr { /// future, as new RFCs are published. /// /// [changes]: ../net/index.html#stability-guarantees-for-ietf-defined-behavior - #[stable(feature = "ip", since = "1.47.0")] - pub fn is_unique_local(&self) -> bool { +#[stable(feature = "ip", since = "1.47.0")] + #[rustc_const_unstable(feature = "const_ipv6", issue = "76205")] + pub const fn is_unique_local(&self) -> bool { (self.segments()[0] & 0xfe00) == 0xfc00 } @@ -1396,8 +1393,6 @@ impl Ipv6Addr { /// # Examples /// /// ``` - /// #![feature(ip)] - /// /// use std::net::Ipv6Addr; /// /// let ip = Ipv6Addr::new(0xfe80, 0, 0, 0, 0, 0, 0, 0); @@ -1433,8 +1428,9 @@ impl Ipv6Addr { /// future, as new RFCs are published. /// /// [changes]: ../net/index.html#stability-guarantees-for-ietf-defined-behavior - #[stable(feature = "ip", since = "1.47.0")] - pub fn is_unicast_link_local_strict(&self) -> bool { +#[stable(feature = "ip", since = "1.47.0")] + #[rustc_const_unstable(feature = "const_ipv6", issue = "76205")] + pub const fn is_unicast_link_local_strict(&self) -> bool { (self.segments()[0] & 0xffff) == 0xfe80 && (self.segments()[1] & 0xffff) == 0 && (self.segments()[2] & 0xffff) == 0 @@ -1462,8 +1458,6 @@ impl Ipv6Addr { /// # Examples /// /// ``` - /// #![feature(ip)] - /// /// use std::net::Ipv6Addr; /// /// let ip = Ipv6Addr::new(0xfe80, 0, 0, 0, 0, 0, 0, 0); @@ -1497,8 +1491,9 @@ impl Ipv6Addr { /// future, as new RFCs are published. /// /// [changes]: ../net/index.html#stability-guarantees-for-ietf-defined-behavior - #[stable(feature = "ip", since = "1.47.0")] - pub fn is_unicast_link_local(&self) -> bool { +#[stable(feature = "ip", since = "1.47.0")] + #[rustc_const_unstable(feature = "const_ipv6", issue = "76205")] + pub const fn is_unicast_link_local(&self) -> bool { (self.segments()[0] & 0xffc0) == 0xfe80 } @@ -1518,8 +1513,6 @@ impl Ipv6Addr { /// # Examples /// /// ``` - /// #![feature(ip)] - /// /// use std::net::Ipv6Addr; /// /// assert_eq!( @@ -1543,8 +1536,9 @@ impl Ipv6Addr { /// future, as new RFCs are published. /// /// [changes]: ../net/index.html#stability-guarantees-for-ietf-defined-behavior - #[stable(feature = "ip", since = "1.47.0")] - pub fn is_unicast_site_local(&self) -> bool { +#[stable(feature = "ip", since = "1.47.0")] + #[rustc_const_unstable(feature = "const_ipv6", issue = "76205")] + pub const fn is_unicast_site_local(&self) -> bool { (self.segments()[0] & 0xffc0) == 0xfec0 } @@ -1558,8 +1552,6 @@ impl Ipv6Addr { /// # Examples /// /// ``` - /// #![feature(ip)] - /// /// use std::net::Ipv6Addr; /// /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff).is_documentation(), false); @@ -1572,8 +1564,9 @@ impl Ipv6Addr { /// future, as new RFCs are published. /// /// [changes]: ../net/index.html#stability-guarantees-for-ietf-defined-behavior - #[stable(feature = "ip", since = "1.47.0")] - pub fn is_documentation(&self) -> bool { +#[stable(feature = "ip", since = "1.47.0")] + #[rustc_const_unstable(feature = "const_ipv6", issue = "76205")] + pub const fn is_documentation(&self) -> bool { (self.segments()[0] == 0x2001) && (self.segments()[1] == 0xdb8) } @@ -1600,8 +1593,6 @@ impl Ipv6Addr { /// # Examples /// /// ``` - /// #![feature(ip)] - /// /// use std::net::Ipv6Addr; /// /// assert_eq!(Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 0).is_unicast_global(), false); @@ -1614,8 +1605,9 @@ impl Ipv6Addr { /// future, as new RFCs are published. /// /// [changes]: ../net/index.html#stability-guarantees-for-ietf-defined-behavior - #[stable(feature = "ip", since = "1.47.0")] - pub fn is_unicast_global(&self) -> bool { +#[stable(feature = "ip", since = "1.47.0")] + #[rustc_const_unstable(feature = "const_ipv6", issue = "76205")] + pub const fn is_unicast_global(&self) -> bool { !self.is_multicast() && !self.is_loopback() && !self.is_unicast_link_local() @@ -1629,8 +1621,6 @@ impl Ipv6Addr { /// # Examples /// /// ``` - /// #![feature(ip)] - /// /// use std::net::{Ipv6Addr, Ipv6MulticastScope}; /// /// assert_eq!( @@ -1646,9 +1636,13 @@ impl Ipv6Addr { /// future, as new RFCs are published. /// /// [changes]: ../net/index.html#stability-guarantees-for-ietf-defined-behavior - #[stable(feature = "ip", since = "1.47.0")] - pub fn multicast_scope(&self) -> Option { - use Ipv6MulticastScope::*; +#[stable(feature = "ip", since = "1.47.0")] + #[rustc_const_unstable(feature = "const_ipv6", issue = "76205")] + pub const fn multicast_scope(&self) -> Option { + use crate::net::Ipv6MulticastScope::{ + AdminLocal, Global, InterfaceLocal, LinkLocal, OrganizationLocal, RealmLocal, Reserved, + SiteLocal, Unassigned, + }; if self.is_multicast() { match self.segments()[0] & 0x000f { 1 => Some(Ipv6MulticastScope::InterfaceLocal), @@ -1698,7 +1692,6 @@ impl Ipv6Addr { /// # Examples /// /// ``` - /// /// use std::net::{Ipv4Addr, Ipv6Addr}; /// /// assert_eq!(Ipv6Addr::new(0xff00, 0, 0, 0, 0, 0, 0, 0).to_ipv4_mapped(), None); @@ -1706,8 +1699,9 @@ impl Ipv6Addr { /// Some(Ipv4Addr::new(192, 10, 2, 255))); /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1).to_ipv4_mapped(), None); /// ``` - #[stable(feature = "ip", since = "1.47.0")] - pub fn to_ipv4_mapped(&self) -> Option { +#[stable(feature = "ip", since = "1.47.0")] + #[rustc_const_unstable(feature = "const_ipv6", issue = "76205")] + pub const fn to_ipv4_mapped(&self) -> Option { 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)) From f91cb146050a0ba056b3dfcd18179ce3c4cf5ae8 Mon Sep 17 00:00:00 2001 From: Cassandra Fridkin Date: Fri, 4 Sep 2020 01:59:16 -0400 Subject: [PATCH 05/24] `is_unicast_link_local_strict` --> `is_unicast_link_local` Remove the looser `is_unicast_link_local` and rename `is_unicast_link_local_strict` as i suggested :blush: See https://github.com/rust-lang/rust/pull/76098#issuecomment-686901980 --- library/std/src/net/ip.rs | 108 ++++++++------------------------------ 1 file changed, 22 insertions(+), 86 deletions(-) diff --git a/library/std/src/net/ip.rs b/library/std/src/net/ip.rs index 35103311fa69b..44d43e1a9f7da 100644 --- a/library/std/src/net/ip.rs +++ b/library/std/src/net/ip.rs @@ -260,7 +260,7 @@ impl IpAddr { /// future, as new RFCs are published. /// /// [changes]: ../net/index.html#stability-guarantees-for-ietf-defined-behavior -#[stable(feature = "ip", since = "1.47.0")] + #[stable(feature = "ip", since = "1.47.0")] pub fn is_global(&self) -> bool { match self { IpAddr::V4(ip) => ip.is_global(), @@ -314,7 +314,7 @@ impl IpAddr { /// future, as new RFCs are published. /// /// [changes]: ../net/index.html#stability-guarantees-for-ietf-defined-behavior -#[stable(feature = "ip", since = "1.47.0")] + #[stable(feature = "ip", since = "1.47.0")] pub fn is_documentation(&self) -> bool { match self { IpAddr::V4(ip) => ip.is_documentation(), @@ -618,7 +618,7 @@ impl Ipv4Addr { /// future, as new RFCs are published. /// /// [changes]: ../net/index.html#stability-guarantees-for-ietf-defined-behavior -#[stable(feature = "ip", since = "1.47.0")] + #[stable(feature = "ip", since = "1.47.0")] #[rustc_const_unstable(feature = "const_ipv4", issue = "76205")] pub const fn is_global(&self) -> bool { // check if this address is 192.0.0.9 or 192.0.0.10. These addresses are the only two @@ -663,7 +663,7 @@ impl Ipv4Addr { /// future, as new RFCs are published. /// /// [changes]: ../net/index.html#stability-guarantees-for-ietf-defined-behavior -#[stable(feature = "ip", since = "1.47.0")] + #[stable(feature = "ip", since = "1.47.0")] #[rustc_const_unstable(feature = "const_ipv4", issue = "76205")] pub const fn is_shared(&self) -> bool { self.octets()[0] == 100 && (self.octets()[1] & 0b1100_0000 == 0b0100_0000) @@ -703,7 +703,7 @@ impl Ipv4Addr { /// future, as new RFCs are published. /// /// [changes]: ../net/index.html#stability-guarantees-for-ietf-defined-behavior -#[stable(feature = "ip", since = "1.47.0")] + #[stable(feature = "ip", since = "1.47.0")] #[rustc_const_unstable(feature = "const_ipv4", issue = "76205")] pub const fn is_ietf_protocol_assignment(&self) -> bool { self.octets()[0] == 192 && self.octets()[1] == 0 && self.octets()[2] == 0 @@ -734,7 +734,7 @@ impl Ipv4Addr { /// future, as new RFCs are published. /// /// [changes]: ../net/index.html#stability-guarantees-for-ietf-defined-behavior -#[stable(feature = "ip", since = "1.47.0")] + #[stable(feature = "ip", since = "1.47.0")] #[rustc_const_unstable(feature = "const_ipv4", issue = "76205")] pub const fn is_benchmarking(&self) -> bool { self.octets()[0] == 198 && (self.octets()[1] & 0xfe) == 18 @@ -774,7 +774,7 @@ impl Ipv4Addr { /// future, as new RFCs are published. /// /// [changes]: ../net/index.html#stability-guarantees-for-ietf-defined-behavior -#[stable(feature = "ip", since = "1.47.0")] + #[stable(feature = "ip", since = "1.47.0")] #[rustc_const_unstable(feature = "const_ipv4", issue = "76205")] pub const fn is_reserved(&self) -> bool { self.octets()[0] & 240 == 240 && !self.is_broadcast() @@ -1336,7 +1336,7 @@ impl Ipv6Addr { /// future, as new RFCs are published. /// /// [changes]: ../net/index.html#stability-guarantees-for-ietf-defined-behavior -#[stable(feature = "ip", since = "1.47.0")] + #[stable(feature = "ip", since = "1.47.0")] #[rustc_const_unstable(feature = "const_ipv6", issue = "76205")] pub const fn is_global(&self) -> bool { match self.multicast_scope() { @@ -1367,7 +1367,7 @@ impl Ipv6Addr { /// future, as new RFCs are published. /// /// [changes]: ../net/index.html#stability-guarantees-for-ietf-defined-behavior -#[stable(feature = "ip", since = "1.47.0")] + #[stable(feature = "ip", since = "1.47.0")] #[rustc_const_unstable(feature = "const_ipv6", issue = "76205")] pub const fn is_unique_local(&self) -> bool { (self.segments()[0] & 0xfe00) == 0xfc00 @@ -1386,9 +1386,8 @@ impl Ipv6Addr { /// +----------+-------------------------+----------------------------+ /// ``` /// - /// This method validates the format defined in the RFC and won't recognize addresses - /// like `fe80:0:0:1::` or `fe81::` as unicast link-local addresses. - /// If you need a less strict validation, use [`Ipv6Addr::is_unicast_link_local()`] instead. + /// This method validates the format defined in the RFC and won't recognize the following + /// addresses such as `fe80:0:0:1::` or `fe81::` as unicast link-local addresses for example. /// /// # Examples /// @@ -1396,18 +1395,17 @@ impl Ipv6Addr { /// use std::net::Ipv6Addr; /// /// let ip = Ipv6Addr::new(0xfe80, 0, 0, 0, 0, 0, 0, 0); - /// assert!(ip.is_unicast_link_local_strict()); + /// assert!(ip.is_unicast_link_local()); /// /// let ip = Ipv6Addr::new(0xfe80, 0, 0, 0, 0xffff, 0xffff, 0xffff, 0xffff); - /// assert!(ip.is_unicast_link_local_strict()); + /// assert!(ip.is_unicast_link_local()); /// /// let ip = Ipv6Addr::new(0xfe80, 0, 0, 1, 0, 0, 0, 0); - /// assert!(!ip.is_unicast_link_local_strict()); + /// assert!(!ip.is_unicast_link_local()); /// assert!(ip.is_unicast_link_local()); /// /// let ip = Ipv6Addr::new(0xfe81, 0, 0, 0, 0, 0, 0, 0); - /// assert!(!ip.is_unicast_link_local_strict()); - /// assert!(ip.is_unicast_link_local()); + /// assert!(!ip.is_unicast_link_local()); /// ``` /// /// # See also @@ -1415,12 +1413,10 @@ impl Ipv6Addr { /// - [IETF RFC 4291 section 2.5.6] /// - [RFC 4291 errata 4406] (which has been rejected but provides useful /// insight) - /// - [`Ipv6Addr::is_unicast_link_local()`] /// /// [IETF RFC 4291]: https://tools.ietf.org/html/rfc4291 /// [IETF RFC 4291 section 2.5.6]: https://tools.ietf.org/html/rfc4291#section-2.5.6 /// [RFC 4291 errata 4406]: https://www.rfc-editor.org/errata/eid4406 - /// [`is_unicast_link_local()`]: ../../std/net/struct.Ipv6Addr.html#method.is_unicast_link_local /// /// # Stability guarantees /// @@ -1428,75 +1424,15 @@ impl Ipv6Addr { /// future, as new RFCs are published. /// /// [changes]: ../net/index.html#stability-guarantees-for-ietf-defined-behavior -#[stable(feature = "ip", since = "1.47.0")] + #[stable(feature = "ip", since = "1.47.0")] #[rustc_const_unstable(feature = "const_ipv6", issue = "76205")] - pub const fn is_unicast_link_local_strict(&self) -> bool { + pub const fn is_unicast_link_local(&self) -> bool { (self.segments()[0] & 0xffff) == 0xfe80 && (self.segments()[1] & 0xffff) == 0 && (self.segments()[2] & 0xffff) == 0 && (self.segments()[3] & 0xffff) == 0 } - /// Returns [`true`] if the address is a unicast link-local address (`fe80::/10`). - /// - /// This method returns [`true`] for addresses in the range reserved by [RFC 4291 section 2.4], - /// i.e. addresses with the following format: - /// - /// ```no_rust - /// | 10 | - /// | bits | 54 bits | 64 bits | - /// +----------+-------------------------+----------------------------+ - /// |1111111010| arbitratry value | interface ID | - /// +----------+-------------------------+----------------------------+ - /// ``` - /// - /// As a result, this method considers addresses such as `fe80:0:0:1::` or `fe81::` to be - /// unicast link-local addresses, whereas [`Ipv6Addr::is_unicast_link_local_strict()`] does not. - /// If you need a strict validation fully compliant with the RFC, use - /// [`Ipv6Addr::is_unicast_link_local_strict()`] instead. - /// - /// # Examples - /// - /// ``` - /// use std::net::Ipv6Addr; - /// - /// let ip = Ipv6Addr::new(0xfe80, 0, 0, 0, 0, 0, 0, 0); - /// assert!(ip.is_unicast_link_local()); - /// - /// let ip = Ipv6Addr::new(0xfe80, 0, 0, 0, 0xffff, 0xffff, 0xffff, 0xffff); - /// assert!(ip.is_unicast_link_local()); - /// - /// let ip = Ipv6Addr::new(0xfe80, 0, 0, 1, 0, 0, 0, 0); - /// assert!(ip.is_unicast_link_local()); - /// assert!(!ip.is_unicast_link_local_strict()); - /// - /// let ip = Ipv6Addr::new(0xfe81, 0, 0, 0, 0, 0, 0, 0); - /// assert!(ip.is_unicast_link_local()); - /// assert!(!ip.is_unicast_link_local_strict()); - /// ``` - /// - /// # See also - /// - /// - [IETF RFC 4291 section 2.4] - /// - [RFC 4291 errata 4406] (which has been rejected but provides useful - /// insight) - /// - /// [IETF RFC 4291 section 2.4]: https://tools.ietf.org/html/rfc4291#section-2.4 - /// [RFC 4291 errata 4406]: https://www.rfc-editor.org/errata/eid4406 - /// [`is_unicast_link_local_strict()`]: ../../std/net/struct.Ipv6Addr.html#method.is_unicast_link_local_strict - /// - /// # Stability guarantees - /// - /// This method's behavior [may by subject to changes][changes] in the - /// future, as new RFCs are published. - /// - /// [changes]: ../net/index.html#stability-guarantees-for-ietf-defined-behavior -#[stable(feature = "ip", since = "1.47.0")] - #[rustc_const_unstable(feature = "const_ipv6", issue = "76205")] - pub const fn is_unicast_link_local(&self) -> bool { - (self.segments()[0] & 0xffc0) == 0xfe80 - } - /// Returns [`true`] if this is a deprecated unicast site-local address (fec0::/10). The /// unicast site-local address format is defined in [RFC 4291 section 2.5.7] as: /// @@ -1536,7 +1472,7 @@ impl Ipv6Addr { /// future, as new RFCs are published. /// /// [changes]: ../net/index.html#stability-guarantees-for-ietf-defined-behavior -#[stable(feature = "ip", since = "1.47.0")] + #[stable(feature = "ip", since = "1.47.0")] #[rustc_const_unstable(feature = "const_ipv6", issue = "76205")] pub const fn is_unicast_site_local(&self) -> bool { (self.segments()[0] & 0xffc0) == 0xfec0 @@ -1564,7 +1500,7 @@ impl Ipv6Addr { /// future, as new RFCs are published. /// /// [changes]: ../net/index.html#stability-guarantees-for-ietf-defined-behavior -#[stable(feature = "ip", since = "1.47.0")] + #[stable(feature = "ip", since = "1.47.0")] #[rustc_const_unstable(feature = "const_ipv6", issue = "76205")] pub const fn is_documentation(&self) -> bool { (self.segments()[0] == 0x2001) && (self.segments()[1] == 0xdb8) @@ -1605,7 +1541,7 @@ impl Ipv6Addr { /// future, as new RFCs are published. /// /// [changes]: ../net/index.html#stability-guarantees-for-ietf-defined-behavior -#[stable(feature = "ip", since = "1.47.0")] + #[stable(feature = "ip", since = "1.47.0")] #[rustc_const_unstable(feature = "const_ipv6", issue = "76205")] pub const fn is_unicast_global(&self) -> bool { !self.is_multicast() @@ -1636,7 +1572,7 @@ impl Ipv6Addr { /// future, as new RFCs are published. /// /// [changes]: ../net/index.html#stability-guarantees-for-ietf-defined-behavior -#[stable(feature = "ip", since = "1.47.0")] + #[stable(feature = "ip", since = "1.47.0")] #[rustc_const_unstable(feature = "const_ipv6", issue = "76205")] pub const fn multicast_scope(&self) -> Option { use crate::net::Ipv6MulticastScope::{ @@ -1699,7 +1635,7 @@ impl Ipv6Addr { /// Some(Ipv4Addr::new(192, 10, 2, 255))); /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1).to_ipv4_mapped(), None); /// ``` -#[stable(feature = "ip", since = "1.47.0")] + #[stable(feature = "ip", since = "1.47.0")] #[rustc_const_unstable(feature = "const_ipv6", issue = "76205")] pub const fn to_ipv4_mapped(&self) -> Option { match self.octets() { From 259ada12d34464bb55883afeca70c3aadb3ad28d Mon Sep 17 00:00:00 2001 From: Cassandra Fridkin Date: Fri, 4 Sep 2020 02:12:48 -0400 Subject: [PATCH 06/24] Add checking for ipv4-(mapped | compatible) addresses See https://github.com/rust-lang/rust/pull/66584#issuecomment-597543156 --- library/std/src/net/ip.rs | 49 +++++++++++++++++++++++++++++---------- 1 file changed, 37 insertions(+), 12 deletions(-) diff --git a/library/std/src/net/ip.rs b/library/std/src/net/ip.rs index 44d43e1a9f7da..3f1146552b115 100644 --- a/library/std/src/net/ip.rs +++ b/library/std/src/net/ip.rs @@ -1288,7 +1288,12 @@ impl Ipv6Addr { #[stable(since = "1.7.0", feature = "ip_17")] #[inline] pub const fn is_unspecified(&self) -> bool { - u128::from_be_bytes(self.octets()) == u128::from_be_bytes(Ipv6Addr::UNSPECIFIED.octets()) + if let Some(v4_addr) = self.to_ipv4() { + v4_addr.is_unspecified() + } else { + u128::from_be_bytes(self.octets()) + == u128::from_be_bytes(Ipv6Addr::UNSPECIFIED.octets()) + } } /// Returns [`true`] if this is a loopback address (::1). @@ -1309,7 +1314,11 @@ impl Ipv6Addr { #[stable(since = "1.7.0", feature = "ip_17")] #[inline] pub const fn is_loopback(&self) -> bool { - u128::from_be_bytes(self.octets()) == u128::from_be_bytes(Ipv6Addr::LOCALHOST.octets()) + if let Some(v4_addr) = self.to_ipv4() { + v4_addr.is_loopback() + } else { + u128::from_be_bytes(self.octets()) == u128::from_be_bytes(Ipv6Addr::LOCALHOST.octets()) + } } /// Returns [`true`] if the address appears to be globally routable. @@ -1339,10 +1348,14 @@ impl Ipv6Addr { #[stable(feature = "ip", since = "1.47.0")] #[rustc_const_unstable(feature = "const_ipv6", issue = "76205")] pub const fn is_global(&self) -> bool { - match self.multicast_scope() { - Some(Ipv6MulticastScope::Global) => true, - None => self.is_unicast_global(), - _ => false, + if let Some(v4_addr) = self.to_ipv4() { + v4_addr.is_global() + } else { + match self.multicast_scope() { + Some(Ipv6MulticastScope::Global) => true, + None => self.is_unicast_global(), + _ => false, + } } } @@ -1427,10 +1440,14 @@ impl Ipv6Addr { #[stable(feature = "ip", since = "1.47.0")] #[rustc_const_unstable(feature = "const_ipv6", issue = "76205")] pub const fn is_unicast_link_local(&self) -> bool { - (self.segments()[0] & 0xffff) == 0xfe80 - && (self.segments()[1] & 0xffff) == 0 - && (self.segments()[2] & 0xffff) == 0 - && (self.segments()[3] & 0xffff) == 0 + if let Some(v4_addr) = self.to_ipv4() { + v4_addr.is_link_local() + } else { + (self.segments()[0] & 0xffff) == 0xfe80 + && (self.segments()[1] & 0xffff) == 0 + && (self.segments()[2] & 0xffff) == 0 + && (self.segments()[3] & 0xffff) == 0 + } } /// Returns [`true`] if this is a deprecated unicast site-local address (fec0::/10). The @@ -1503,7 +1520,11 @@ impl Ipv6Addr { #[stable(feature = "ip", since = "1.47.0")] #[rustc_const_unstable(feature = "const_ipv6", issue = "76205")] pub const fn is_documentation(&self) -> bool { - (self.segments()[0] == 0x2001) && (self.segments()[1] == 0xdb8) + if let Some(v4_addr) = self.to_ipv4() { + v4_addr.is_documentation() + } else { + (self.segments()[0] == 0x2001) && (self.segments()[1] == 0xdb8) + } } /// Returns [`true`] if the address is a globally routable unicast address. @@ -1613,7 +1634,11 @@ impl Ipv6Addr { #[stable(since = "1.7.0", feature = "ip_17")] #[inline] pub const fn is_multicast(&self) -> bool { - (self.segments()[0] & 0xff00) == 0xff00 + if let Some(v4_addr) = self.to_ipv4() { + v4_addr.is_multicast() + } else { + (self.segments()[0] & 0xff00) == 0xff00 + } } /// Converts this address to an [`IPv4` address] if it's an "IPv4-mapped IPv6 address" From f15098fc55a508e80e426a54eb5fdb399022f8f5 Mon Sep 17 00:00:00 2001 From: Cassandra Fridkin Date: Fri, 4 Sep 2020 02:19:56 -0400 Subject: [PATCH 07/24] Add stability attributes to Ipv6MulticastScope --- library/std/src/net/ip.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/library/std/src/net/ip.rs b/library/std/src/net/ip.rs index 3f1146552b115..12f227d57d378 100644 --- a/library/std/src/net/ip.rs +++ b/library/std/src/net/ip.rs @@ -126,6 +126,7 @@ pub struct Ipv6Addr { /// [changes]: ../net/index.html#stability-guarantees-for-ietf-defined-behavior /// [section 2 of IETF RFC 7346]: https://tools.ietf.org/html/rfc7346#section-2 #[derive(Copy, PartialEq, Eq, Clone, Hash, Debug)] +#[stable(feature = "ip", since = "1.47.0")] #[non_exhaustive] #[stable(feature = "ip", since = "1.47.0")] pub enum Ipv6MulticastScope { From c8ca75728cc8f41e0615f49a2a4c955b6483ecd9 Mon Sep 17 00:00:00 2001 From: Cassandra Fridkin Date: Fri, 4 Sep 2020 02:41:52 -0400 Subject: [PATCH 08/24] remove `/// #![feature(ip)]` tags from doc tests --- library/std/src/net/ip.rs | 4 ---- 1 file changed, 4 deletions(-) diff --git a/library/std/src/net/ip.rs b/library/std/src/net/ip.rs index 12f227d57d378..1f89c4ba637b9 100644 --- a/library/std/src/net/ip.rs +++ b/library/std/src/net/ip.rs @@ -650,7 +650,6 @@ impl Ipv4Addr { /// # Examples /// /// ``` - /// #![feature(ip)] /// use std::net::Ipv4Addr; /// /// assert_eq!(Ipv4Addr::new(100, 64, 0, 0).is_shared(), true); @@ -687,7 +686,6 @@ impl Ipv4Addr { /// # Examples /// /// ``` - /// #![feature(ip)] /// use std::net::Ipv4Addr; /// /// assert_eq!(Ipv4Addr::new(192, 0, 0, 0).is_ietf_protocol_assignment(), true); @@ -720,7 +718,6 @@ impl Ipv4Addr { /// # Examples /// /// ``` - /// #![feature(ip)] /// use std::net::Ipv4Addr; /// /// assert_eq!(Ipv4Addr::new(198, 17, 255, 255).is_benchmarking(), false); @@ -758,7 +755,6 @@ impl Ipv4Addr { /// # Examples /// /// ``` - /// #![feature(ip)] /// use std::net::Ipv4Addr; /// /// assert_eq!(Ipv4Addr::new(240, 0, 0, 0).is_reserved(), true); From 392a21bfc8c726d05823e0a2ade7604bcdb19d7b Mon Sep 17 00:00:00 2001 From: Cassandra Fridkin Date: Fri, 4 Sep 2020 03:02:28 -0400 Subject: [PATCH 09/24] Remove some more #![feature(ip)] stuff Getting kind of extremely out of my comfort zone here and modifying quite a few different files...i hope this is all ok... --- src/test/ui/consts/std/net/ipv4.rs | 57 ++++++++++++++++++++++++++++++ src/test/ui/consts/std/net/ipv6.rs | 52 +++++++++++++++++++++++++++ 2 files changed, 109 insertions(+) create mode 100644 src/test/ui/consts/std/net/ipv4.rs create mode 100644 src/test/ui/consts/std/net/ipv6.rs diff --git a/src/test/ui/consts/std/net/ipv4.rs b/src/test/ui/consts/std/net/ipv4.rs new file mode 100644 index 0000000000000..58f45c99c336e --- /dev/null +++ b/src/test/ui/consts/std/net/ipv4.rs @@ -0,0 +1,57 @@ +// run-pass + +#![feature(const_ipv4)] + +use std::net::{Ipv4Addr, Ipv6Addr}; + +fn main() { + const IP_ADDRESS: Ipv4Addr = Ipv4Addr::new(127, 0, 0, 1); + assert_eq!(IP_ADDRESS, Ipv4Addr::LOCALHOST); + + const OCTETS: [u8; 4] = IP_ADDRESS.octets(); + assert_eq!(OCTETS, [127, 0, 0, 1]); + + const IS_UNSPECIFIED : bool = IP_ADDRESS.is_unspecified(); + assert!(!IS_UNSPECIFIED); + + const IS_LOOPBACK : bool = IP_ADDRESS.is_loopback(); + assert!(IS_LOOPBACK); + + const IS_PRIVATE : bool = IP_ADDRESS.is_private(); + assert!(!IS_PRIVATE); + + const IS_LINK_LOCAL : bool = IP_ADDRESS.is_link_local(); + assert!(!IS_LINK_LOCAL); + + const IS_GLOBAL : bool = IP_ADDRESS.is_global(); + assert!(!IS_GLOBAL); + + const IS_SHARED : bool = IP_ADDRESS.is_shared(); + assert!(!IS_SHARED); + + const IS_IETF_PROTOCOL_ASSIGNMENT : bool = IP_ADDRESS.is_ietf_protocol_assignment(); + assert!(!IS_IETF_PROTOCOL_ASSIGNMENT); + + const IS_BENCHMARKING : bool = IP_ADDRESS.is_benchmarking(); + assert!(!IS_BENCHMARKING); + + const IS_RESERVED : bool = IP_ADDRESS.is_reserved(); + assert!(!IS_RESERVED); + + const IS_MULTICAST : bool = IP_ADDRESS.is_multicast(); + assert!(!IS_MULTICAST); + + const IS_BROADCAST : bool = IP_ADDRESS.is_broadcast(); + assert!(!IS_BROADCAST); + + const IS_DOCUMENTATION : bool = IP_ADDRESS.is_documentation(); + assert!(!IS_DOCUMENTATION); + + const IP_V6_COMPATIBLE : Ipv6Addr = IP_ADDRESS.to_ipv6_compatible(); + assert_eq!(IP_V6_COMPATIBLE, + Ipv6Addr::from([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 127, 0, 0, 1])); + + const IP_V6_MAPPED : Ipv6Addr = IP_ADDRESS.to_ipv6_mapped(); + assert_eq!(IP_V6_MAPPED, + Ipv6Addr::from([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 127, 0, 0, 1])); +} diff --git a/src/test/ui/consts/std/net/ipv6.rs b/src/test/ui/consts/std/net/ipv6.rs new file mode 100644 index 0000000000000..e3766fedc70ed --- /dev/null +++ b/src/test/ui/consts/std/net/ipv6.rs @@ -0,0 +1,52 @@ +// run-pass + +#![feature(const_ipv6)] + +use std::net::{Ipv4Addr, Ipv6Addr, Ipv6MulticastScope}; + +fn main() { + const IP_ADDRESS : Ipv6Addr = Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1); + assert_eq!(IP_ADDRESS, Ipv6Addr::LOCALHOST); + + const SEGMENTS : [u16; 8] = IP_ADDRESS.segments(); + assert_eq!(SEGMENTS, [0 ,0 ,0 ,0 ,0 ,0 ,0, 1]); + + const OCTETS : [u8; 16] = IP_ADDRESS.octets(); + assert_eq!(OCTETS, [0 ,0 ,0 ,0 ,0 ,0 ,0, 0 ,0 ,0 ,0 ,0 ,0 ,0, 0, 1]); + + const IS_UNSPECIFIED : bool = IP_ADDRESS.is_unspecified(); + assert!(!IS_UNSPECIFIED); + + const IS_LOOPBACK : bool = IP_ADDRESS.is_loopback(); + assert!(IS_LOOPBACK); + + const IS_GLOBAL : bool = IP_ADDRESS.is_global(); + assert!(!IS_GLOBAL); + + const IS_UNIQUE_LOCAL : bool = IP_ADDRESS.is_unique_local(); + assert!(!IS_UNIQUE_LOCAL); + + const IS_UNICAST_LINK_LOCAL_STRICT : bool = IP_ADDRESS.is_unicast_link_local_strict(); + assert!(!IS_UNICAST_LINK_LOCAL_STRICT); + + const IS_UNICAST_LINK_LOCAL : bool = IP_ADDRESS.is_unicast_link_local(); + assert!(!IS_UNICAST_LINK_LOCAL); + + const IS_UNICAST_SITE_LOCAL : bool = IP_ADDRESS.is_unicast_site_local(); + assert!(!IS_UNICAST_SITE_LOCAL); + + const IS_DOCUMENTATION : bool = IP_ADDRESS.is_documentation(); + assert!(!IS_DOCUMENTATION); + + const IS_UNICAST_GLOBAL : bool = IP_ADDRESS.is_unicast_global(); + assert!(!IS_UNICAST_GLOBAL); + + const MULTICAST_SCOPE : Option = IP_ADDRESS.multicast_scope(); + assert_eq!(MULTICAST_SCOPE, None); + + const IS_MULTICAST : bool = IP_ADDRESS.is_multicast(); + assert!(!IS_MULTICAST); + + const IP_V4 : Option = IP_ADDRESS.to_ipv4(); + assert_eq!(IP_V4.unwrap(), Ipv4Addr::new(0, 0, 0, 1)); +} From f5694dc4dc8cdb56ca39548e6b93a76068cd91d3 Mon Sep 17 00:00:00 2001 From: Cassandra Fridkin Date: Fri, 4 Sep 2020 03:38:36 -0400 Subject: [PATCH 10/24] Remove some code having to do with link-local strict --- library/std/src/net/ip/tests.rs | 5 ----- src/test/ui/consts/std/net/ipv6.rs | 3 --- 2 files changed, 8 deletions(-) diff --git a/library/std/src/net/ip/tests.rs b/library/std/src/net/ip/tests.rs index ef0d4edc43473..9dda1c8c93116 100644 --- a/library/std/src/net/ip/tests.rs +++ b/library/std/src/net/ip/tests.rs @@ -524,11 +524,6 @@ fn ipv6_properties() { } else { assert!(!ip!($s).is_unicast_link_local()); } - if ($mask & unicast_link_local_strict) == unicast_link_local_strict { - assert!(ip!($s).is_unicast_link_local_strict()); - } else { - assert!(!ip!($s).is_unicast_link_local_strict()); - } if ($mask & unicast_site_local) == unicast_site_local { assert!(ip!($s).is_unicast_site_local()); } else { diff --git a/src/test/ui/consts/std/net/ipv6.rs b/src/test/ui/consts/std/net/ipv6.rs index e3766fedc70ed..71cc934f6de40 100644 --- a/src/test/ui/consts/std/net/ipv6.rs +++ b/src/test/ui/consts/std/net/ipv6.rs @@ -26,9 +26,6 @@ fn main() { const IS_UNIQUE_LOCAL : bool = IP_ADDRESS.is_unique_local(); assert!(!IS_UNIQUE_LOCAL); - const IS_UNICAST_LINK_LOCAL_STRICT : bool = IP_ADDRESS.is_unicast_link_local_strict(); - assert!(!IS_UNICAST_LINK_LOCAL_STRICT); - const IS_UNICAST_LINK_LOCAL : bool = IP_ADDRESS.is_unicast_link_local(); assert!(!IS_UNICAST_LINK_LOCAL); From 8de3caf15b5cf8cf11bd9b645a02483d1ae146fa Mon Sep 17 00:00:00 2001 From: Cassandra Fridkin Date: Tue, 6 Oct 2020 10:52:50 -0400 Subject: [PATCH 11/24] Change checks for is_unicast_link_local_strict to is_unicast_link_local I really...i'm terrified i'm breaking something here --- library/std/src/net/ip/tests.rs | 17 ++++------------- 1 file changed, 4 insertions(+), 13 deletions(-) diff --git a/library/std/src/net/ip/tests.rs b/library/std/src/net/ip/tests.rs index 9dda1c8c93116..203713d671512 100644 --- a/library/std/src/net/ip/tests.rs +++ b/library/std/src/net/ip/tests.rs @@ -479,8 +479,7 @@ fn ipv6_properties() { let loopback: u16 = 1 << 1; let unique_local: u16 = 1 << 2; let global: u16 = 1 << 3; - let unicast_link_local: u16 = 1 << 4; - let unicast_link_local_strict: u16 = 1 << 5; + let unicast_link_local: u16 = 1 << 5; let unicast_site_local: u16 = 1 << 6; let unicast_global: u16 = 1 << 7; let documentation: u16 = 1 << 8; @@ -581,8 +580,7 @@ fn ipv6_properties() { let loopback: u16 = 1 << 1; let unique_local: u16 = 1 << 2; let global: u16 = 1 << 3; - let unicast_link_local: u16 = 1 << 4; - let unicast_link_local_strict: u16 = 1 << 5; + let unicast_link_local: u16 = 1 << 5; let unicast_site_local: u16 = 1 << 6; let unicast_global: u16 = 1 << 7; let documentation: u16 = 1 << 8; @@ -616,11 +614,7 @@ fn ipv6_properties() { unicast_link_local ); - check!( - "fe80::", - &[0xfe, 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], - unicast_link_local | unicast_link_local_strict - ); + check!("fe80::", &[0xfe, 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], unicast_link_local); check!( "febf:ffff::", @@ -645,7 +639,7 @@ fn ipv6_properties() { 0xfe, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff ], - unicast_link_local | unicast_link_local_strict + unicast_link_local ); check!( @@ -892,9 +886,6 @@ fn ipv6_const() { const IS_UNIQUE_LOCAL: bool = IP_ADDRESS.is_unique_local(); assert!(!IS_UNIQUE_LOCAL); - const IS_UNICAST_LINK_LOCAL_STRICT: bool = IP_ADDRESS.is_unicast_link_local_strict(); - assert!(!IS_UNICAST_LINK_LOCAL_STRICT); - const IS_UNICAST_LINK_LOCAL: bool = IP_ADDRESS.is_unicast_link_local(); assert!(!IS_UNICAST_LINK_LOCAL); From f2245515efdc2f57aa4b9e29510dff62faa0dc02 Mon Sep 17 00:00:00 2001 From: Cassandra Fridkin Date: Tue, 6 Oct 2020 19:04:42 -0400 Subject: [PATCH 12/24] Rewrite ipv4 checks to check ipv6 stuff first --- library/std/src/net/ip.rs | 56 +++++++++++++-------------------------- 1 file changed, 18 insertions(+), 38 deletions(-) diff --git a/library/std/src/net/ip.rs b/library/std/src/net/ip.rs index 1f89c4ba637b9..4ebdd813defb3 100644 --- a/library/std/src/net/ip.rs +++ b/library/std/src/net/ip.rs @@ -1285,12 +1285,8 @@ impl Ipv6Addr { #[stable(since = "1.7.0", feature = "ip_17")] #[inline] pub const fn is_unspecified(&self) -> bool { - if let Some(v4_addr) = self.to_ipv4() { - v4_addr.is_unspecified() - } else { - u128::from_be_bytes(self.octets()) - == u128::from_be_bytes(Ipv6Addr::UNSPECIFIED.octets()) - } + u128::from_be_bytes(self.octets()) == u128::from_be_bytes(Ipv6Addr::UNSPECIFIED.octets()) + || if let Some(v4_addr) = self.to_ipv4() { v4_addr.is_unspecified() } else { false } } /// Returns [`true`] if this is a loopback address (::1). @@ -1311,11 +1307,8 @@ impl Ipv6Addr { #[stable(since = "1.7.0", feature = "ip_17")] #[inline] pub const fn is_loopback(&self) -> bool { - if let Some(v4_addr) = self.to_ipv4() { - v4_addr.is_loopback() - } else { - u128::from_be_bytes(self.octets()) == u128::from_be_bytes(Ipv6Addr::LOCALHOST.octets()) - } + u128::from_be_bytes(self.octets()) == u128::from_be_bytes(Ipv6Addr::LOCALHOST.octets()) + || if let Some(v4_addr) = self.to_ipv4() { v4_addr.is_loopback() } else { false } } /// Returns [`true`] if the address appears to be globally routable. @@ -1345,15 +1338,11 @@ impl Ipv6Addr { #[stable(feature = "ip", since = "1.47.0")] #[rustc_const_unstable(feature = "const_ipv6", issue = "76205")] pub const fn is_global(&self) -> bool { - if let Some(v4_addr) = self.to_ipv4() { - v4_addr.is_global() - } else { - match self.multicast_scope() { - Some(Ipv6MulticastScope::Global) => true, - None => self.is_unicast_global(), - _ => false, - } - } + (match self.multicast_scope() { + Some(Ipv6MulticastScope::Global) => true, + None => self.is_unicast_global(), + _ => false, + }) || if let Some(v4_addr) = self.to_ipv4() { v4_addr.is_global() } else { false } } /// Returns [`true`] if this is a unique local address (`fc00::/7`). @@ -1437,14 +1426,11 @@ impl Ipv6Addr { #[stable(feature = "ip", since = "1.47.0")] #[rustc_const_unstable(feature = "const_ipv6", issue = "76205")] pub const fn is_unicast_link_local(&self) -> bool { - if let Some(v4_addr) = self.to_ipv4() { - v4_addr.is_link_local() - } else { - (self.segments()[0] & 0xffff) == 0xfe80 - && (self.segments()[1] & 0xffff) == 0 - && (self.segments()[2] & 0xffff) == 0 - && (self.segments()[3] & 0xffff) == 0 - } + ((self.segments()[0] & 0xffff) == 0xfe80 + && (self.segments()[1] & 0xffff) == 0 + && (self.segments()[2] & 0xffff) == 0 + && (self.segments()[3] & 0xffff) == 0) + || if let Some(v4_addr) = self.to_ipv4() { v4_addr.is_link_local() } else { false } } /// Returns [`true`] if this is a deprecated unicast site-local address (fec0::/10). The @@ -1517,11 +1503,8 @@ impl Ipv6Addr { #[stable(feature = "ip", since = "1.47.0")] #[rustc_const_unstable(feature = "const_ipv6", issue = "76205")] pub const fn is_documentation(&self) -> bool { - if let Some(v4_addr) = self.to_ipv4() { - v4_addr.is_documentation() - } else { - (self.segments()[0] == 0x2001) && (self.segments()[1] == 0xdb8) - } + ((self.segments()[0] == 0x2001) && (self.segments()[1] == 0xdb8)) + || if let Some(v4_addr) = self.to_ipv4() { v4_addr.is_documentation() } else { false } } /// Returns [`true`] if the address is a globally routable unicast address. @@ -1631,11 +1614,8 @@ impl Ipv6Addr { #[stable(since = "1.7.0", feature = "ip_17")] #[inline] pub const fn is_multicast(&self) -> bool { - if let Some(v4_addr) = self.to_ipv4() { - v4_addr.is_multicast() - } else { - (self.segments()[0] & 0xff00) == 0xff00 - } + (self.segments()[0] & 0xff00) == 0xff00 + || if let Some(v4_addr) = self.to_ipv4() { v4_addr.is_multicast() } else { false } } /// Converts this address to an [`IPv4` address] if it's an "IPv4-mapped IPv6 address" From 2db2b5d599e9a0f2affe8fa0116125ed54b99bee Mon Sep 17 00:00:00 2001 From: Cassandra Fridkin Date: Wed, 7 Oct 2020 11:40:10 -0400 Subject: [PATCH 13/24] Fix test cases that checked for relaxed behavior Because of the changes made due to the discussion [here](https://github.com/rust-lang/rust/pull/76098#issuecomment-686901980), the checks for the more relaxed behavior of the old `is_unicast_link_local` method failed when they were tuned to the new, stricter checking behavior. These test cases have been modified to check that a given IPv6 address *is not* unicast link local, using a bitwise or'ing strategy that was already present in other test cases. Further discussion [here](https://rust-lang.zulipchat.com/#narrow/stream/212497-t-compiler.2Fhelp-wanted/topic/fix.20tests.20for.20.2376098). --- library/std/src/net/ip.rs | 1 - library/std/src/net/ip/tests.rs | 24 +++++++++++++++++------- 2 files changed, 17 insertions(+), 8 deletions(-) diff --git a/library/std/src/net/ip.rs b/library/std/src/net/ip.rs index 4ebdd813defb3..da4799b2ccb2a 100644 --- a/library/std/src/net/ip.rs +++ b/library/std/src/net/ip.rs @@ -1401,7 +1401,6 @@ impl Ipv6Addr { /// /// let ip = Ipv6Addr::new(0xfe80, 0, 0, 1, 0, 0, 0, 0); /// assert!(!ip.is_unicast_link_local()); - /// assert!(ip.is_unicast_link_local()); /// /// let ip = Ipv6Addr::new(0xfe81, 0, 0, 0, 0, 0, 0, 0); /// assert!(!ip.is_unicast_link_local()); diff --git a/library/std/src/net/ip/tests.rs b/library/std/src/net/ip/tests.rs index 203713d671512..74bfc3a1be58b 100644 --- a/library/std/src/net/ip/tests.rs +++ b/library/std/src/net/ip/tests.rs @@ -302,8 +302,14 @@ fn ip_properties() { check!("1::", global); check!("fc00::"); check!("fdff:ffff::"); - check!("fe80:ffff::"); - check!("febf:ffff::"); + + // see [`is_unicast_link_local`] + // fe80:ffff:: is *not* unicast_link_local + check!("fe80:ffff::", global); + // fe80:: *is* unicast_link_local + check!("fe80::"); + + check!("febf:ffff::", global); check!("fec0::", global); check!("ff01::", multicast); check!("ff02::", multicast); @@ -611,7 +617,7 @@ fn ipv6_properties() { check!( "fe80:ffff::", &[0xfe, 0x80, 0xff, 0xff, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], - unicast_link_local + global | unicast_global ); check!("fe80::", &[0xfe, 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], unicast_link_local); @@ -619,10 +625,14 @@ fn ipv6_properties() { check!( "febf:ffff::", &[0xfe, 0xbf, 0xff, 0xff, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], - unicast_link_local + global | unicast_global ); - check!("febf::", &[0xfe, 0xbf, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], unicast_link_local); + check!( + "febf::", + &[0xfe, 0xbf, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], + global | unicast_global + ); check!( "febf:ffff:ffff:ffff:ffff:ffff:ffff:ffff", @@ -630,7 +640,7 @@ fn ipv6_properties() { 0xfe, 0xbf, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff ], - unicast_link_local + global | unicast_global ); check!( @@ -645,7 +655,7 @@ fn ipv6_properties() { check!( "fe80:0:0:1::", &[0xfe, 0x80, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0], - unicast_link_local + global | unicast_global ); check!( From c72ea141da6f3a9c24ce50996a0cd6d9eb4bb8a9 Mon Sep 17 00:00:00 2001 From: Cassandra Fridkin Date: Tue, 20 Oct 2020 20:48:38 -0400 Subject: [PATCH 14/24] Restore the relaxed behavior of `is_unicast_link_local` This brings the behavior more in line with Go, Python, Linux, and C. I know, this should have been a `git revert` but honestly I don't trust myself with that and I just had a big mishap trying to merge upstream Rust anyway so forgive me :crying: --- library/std/src/net/ip.rs | 84 +++++++++++++++++++-------------------- 1 file changed, 42 insertions(+), 42 deletions(-) diff --git a/library/std/src/net/ip.rs b/library/std/src/net/ip.rs index da4799b2ccb2a..8b2a5fadbe571 100644 --- a/library/std/src/net/ip.rs +++ b/library/std/src/net/ip.rs @@ -126,7 +126,7 @@ pub struct Ipv6Addr { /// [changes]: ../net/index.html#stability-guarantees-for-ietf-defined-behavior /// [section 2 of IETF RFC 7346]: https://tools.ietf.org/html/rfc7346#section-2 #[derive(Copy, PartialEq, Eq, Clone, Hash, Debug)] -#[stable(feature = "ip", since = "1.47.0")] +#[stable(feature = "ip", since = "1.48.0")] #[non_exhaustive] #[stable(feature = "ip", since = "1.47.0")] pub enum Ipv6MulticastScope { @@ -134,63 +134,63 @@ pub enum Ipv6MulticastScope { /// /// [RFC 4291]: https://tools.ietf.org/html/rfc4291#section-2.7 /// [RFC 7346]: https://tools.ietf.org/html/rfc7346#section-2 - #[stable(feature = "ip", since = "1.47.0")] + #[stable(feature = "ip", since = "1.48.0")] InterfaceLocal, /// Link-Local scope. See [RFC 4291] and [RFC 7346] /// /// [RFC 4291]: https://tools.ietf.org/html/rfc4291#section-2.7 /// [RFC 7346]: https://tools.ietf.org/html/rfc7346#section-2 - #[stable(feature = "ip", since = "1.47.0")] + #[stable(feature = "ip", since = "1.48.0")] LinkLocal, /// Realm-Local scope. See [RFC 4291] and [RFC 7346] /// /// [RFC 4291]: https://tools.ietf.org/html/rfc4291#section-2.7 /// [RFC 7346]: https://tools.ietf.org/html/rfc7346#section-2 - #[stable(feature = "ip", since = "1.47.0")] + #[stable(feature = "ip", since = "1.48.0")] RealmLocal, /// Admin-Local scope. See [RFC 4291] and [RFC 7346] /// /// [RFC 4291]: https://tools.ietf.org/html/rfc4291#section-2.7 /// [RFC 7346]: https://tools.ietf.org/html/rfc7346#section-2 - #[stable(feature = "ip", since = "1.47.0")] + #[stable(feature = "ip", since = "1.48.0")] AdminLocal, /// Site-Local scope. See [RFC 4291] and [RFC 7346] /// /// [RFC 4291]: https://tools.ietf.org/html/rfc4291#section-2.7 /// [RFC 7346]: https://tools.ietf.org/html/rfc7346#section-2 - #[stable(feature = "ip", since = "1.47.0")] + #[stable(feature = "ip", since = "1.48.0")] SiteLocal, /// Organization-Local scope. See [RFC 4291] and [RFC 7346] /// /// [RFC 4291]: https://tools.ietf.org/html/rfc4291#section-2.7 /// [RFC 7346]: https://tools.ietf.org/html/rfc7346#section-2 - #[stable(feature = "ip", since = "1.47.0")] + #[stable(feature = "ip", since = "1.48.0")] OrganizationLocal, /// Global scope. See [RFC 4291] and [RFC 7346] /// /// [RFC 4291]: https://tools.ietf.org/html/rfc4291#section-2.7 /// [RFC 7346]: https://tools.ietf.org/html/rfc7346#section-2 - #[stable(feature = "ip", since = "1.47.0")] + #[stable(feature = "ip", since = "1.48.0")] Global, /// Reserved scope. See [RFC 4291] and [RFC 7346] /// /// [RFC 4291]: https://tools.ietf.org/html/rfc4291#section-2.7 /// [RFC 7346]: https://tools.ietf.org/html/rfc7346#section-2 - #[stable(feature = "ip", since = "1.47.0")] + #[stable(feature = "ip", since = "1.48.0")] Reserved, /// Un-assigned scope. See [RFC 4291] and [RFC 7346] /// /// [RFC 4291]: https://tools.ietf.org/html/rfc4291#section-2.7 /// [RFC 7346]: https://tools.ietf.org/html/rfc7346#section-2 - #[stable(feature = "ip", since = "1.47.0")] + #[stable(feature = "ip", since = "1.48.0")] Unassigned, } @@ -261,8 +261,9 @@ impl IpAddr { /// future, as new RFCs are published. /// /// [changes]: ../net/index.html#stability-guarantees-for-ietf-defined-behavior - #[stable(feature = "ip", since = "1.47.0")] - pub fn is_global(&self) -> bool { + #[stable(feature = "ip", since = "1.48.0")] + #[rustc_const_unstable(feature = "const_ip", issue = "76205")] + pub const fn is_global(&self) -> bool { match self { IpAddr::V4(ip) => ip.is_global(), IpAddr::V6(ip) => ip.is_global(), @@ -315,8 +316,9 @@ impl IpAddr { /// future, as new RFCs are published. /// /// [changes]: ../net/index.html#stability-guarantees-for-ietf-defined-behavior - #[stable(feature = "ip", since = "1.47.0")] - pub fn is_documentation(&self) -> bool { + #[stable(feature = "ip", since = "1.48.0")] + #[rustc_const_unstable(feature = "const_ip", issue = "76205")] + pub const fn is_documentation(&self) -> bool { match self { IpAddr::V4(ip) => ip.is_documentation(), IpAddr::V6(ip) => ip.is_documentation(), @@ -619,7 +621,7 @@ impl Ipv4Addr { /// future, as new RFCs are published. /// /// [changes]: ../net/index.html#stability-guarantees-for-ietf-defined-behavior - #[stable(feature = "ip", since = "1.47.0")] + #[stable(feature = "ip", since = "1.48.0")] #[rustc_const_unstable(feature = "const_ipv4", issue = "76205")] pub const fn is_global(&self) -> bool { // check if this address is 192.0.0.9 or 192.0.0.10. These addresses are the only two @@ -663,7 +665,7 @@ impl Ipv4Addr { /// future, as new RFCs are published. /// /// [changes]: ../net/index.html#stability-guarantees-for-ietf-defined-behavior - #[stable(feature = "ip", since = "1.47.0")] + #[stable(feature = "ip", since = "1.48.0")] #[rustc_const_unstable(feature = "const_ipv4", issue = "76205")] pub const fn is_shared(&self) -> bool { self.octets()[0] == 100 && (self.octets()[1] & 0b1100_0000 == 0b0100_0000) @@ -702,7 +704,7 @@ impl Ipv4Addr { /// future, as new RFCs are published. /// /// [changes]: ../net/index.html#stability-guarantees-for-ietf-defined-behavior - #[stable(feature = "ip", since = "1.47.0")] + #[stable(feature = "ip", since = "1.48.0")] #[rustc_const_unstable(feature = "const_ipv4", issue = "76205")] pub const fn is_ietf_protocol_assignment(&self) -> bool { self.octets()[0] == 192 && self.octets()[1] == 0 && self.octets()[2] == 0 @@ -732,7 +734,7 @@ impl Ipv4Addr { /// future, as new RFCs are published. /// /// [changes]: ../net/index.html#stability-guarantees-for-ietf-defined-behavior - #[stable(feature = "ip", since = "1.47.0")] + #[stable(feature = "ip", since = "1.48.0")] #[rustc_const_unstable(feature = "const_ipv4", issue = "76205")] pub const fn is_benchmarking(&self) -> bool { self.octets()[0] == 198 && (self.octets()[1] & 0xfe) == 18 @@ -771,7 +773,7 @@ impl Ipv4Addr { /// future, as new RFCs are published. /// /// [changes]: ../net/index.html#stability-guarantees-for-ietf-defined-behavior - #[stable(feature = "ip", since = "1.47.0")] + #[stable(feature = "ip", since = "1.48.0")] #[rustc_const_unstable(feature = "const_ipv4", issue = "76205")] pub const fn is_reserved(&self) -> bool { self.octets()[0] & 240 == 240 && !self.is_broadcast() @@ -1335,7 +1337,7 @@ impl Ipv6Addr { /// future, as new RFCs are published. /// /// [changes]: ../net/index.html#stability-guarantees-for-ietf-defined-behavior - #[stable(feature = "ip", since = "1.47.0")] + #[stable(feature = "ip", since = "1.48.0")] #[rustc_const_unstable(feature = "const_ipv6", issue = "76205")] pub const fn is_global(&self) -> bool { (match self.multicast_scope() { @@ -1366,31 +1368,33 @@ impl Ipv6Addr { /// future, as new RFCs are published. /// /// [changes]: ../net/index.html#stability-guarantees-for-ietf-defined-behavior - #[stable(feature = "ip", since = "1.47.0")] + #[stable(feature = "ip", since = "1.48.0")] #[rustc_const_unstable(feature = "const_ipv6", issue = "76205")] pub const fn is_unique_local(&self) -> bool { (self.segments()[0] & 0xfe00) == 0xfc00 } - /// Returns [`true`] if the address is a unicast link-local address (`fe80::/64`). + /// Returns [`true`] if the address is a unicast link-local address (`fe80::/10`). /// - /// A common misconception is to think that "unicast link-local addresses start with - /// `fe80::`", but [IETF RFC 4291] actually defines a stricter format for these addresses: + /// This method returns [`true`] for addresses in the range reserved by [RFC 4291 section 2.4], + /// i.e. addresses with the following format: /// /// ```no_rust /// | 10 | /// | bits | 54 bits | 64 bits | /// +----------+-------------------------+----------------------------+ - /// |1111111010| 0 | interface ID | + /// |1111111010| arbitrary value | interface ID | /// +----------+-------------------------+----------------------------+ /// ``` /// - /// This method validates the format defined in the RFC and won't recognize the following - /// addresses such as `fe80:0:0:1::` or `fe81::` as unicast link-local addresses for example. + /// As a result, this method consider addresses such as `fe80:0:0:1::` or `fe81::` to be + /// unicast link-local addresses. /// /// # Examples /// /// ``` + /// #![feature(ip)] + /// /// use std::net::Ipv6Addr; /// /// let ip = Ipv6Addr::new(0xfe80, 0, 0, 0, 0, 0, 0, 0); @@ -1400,20 +1404,19 @@ impl Ipv6Addr { /// assert!(ip.is_unicast_link_local()); /// /// let ip = Ipv6Addr::new(0xfe80, 0, 0, 1, 0, 0, 0, 0); - /// assert!(!ip.is_unicast_link_local()); + /// assert!(ip.is_unicast_link_local()); /// /// let ip = Ipv6Addr::new(0xfe81, 0, 0, 0, 0, 0, 0, 0); - /// assert!(!ip.is_unicast_link_local()); + /// assert!(ip.is_unicast_link_local()); /// ``` /// /// # See also /// - /// - [IETF RFC 4291 section 2.5.6] + /// - [IETF RFC 4291 section 2.4] /// - [RFC 4291 errata 4406] (which has been rejected but provides useful /// insight) /// - /// [IETF RFC 4291]: https://tools.ietf.org/html/rfc4291 - /// [IETF RFC 4291 section 2.5.6]: https://tools.ietf.org/html/rfc4291#section-2.5.6 + /// [IETF RFC 4291 section 2.4]: https://tools.ietf.org/html/rfc4291#section-2.4 /// [RFC 4291 errata 4406]: https://www.rfc-editor.org/errata/eid4406 /// /// # Stability guarantees @@ -1422,13 +1425,10 @@ impl Ipv6Addr { /// future, as new RFCs are published. /// /// [changes]: ../net/index.html#stability-guarantees-for-ietf-defined-behavior - #[stable(feature = "ip", since = "1.47.0")] + #[stable(feature = "ip", since = "1.48.0")] #[rustc_const_unstable(feature = "const_ipv6", issue = "76205")] pub const fn is_unicast_link_local(&self) -> bool { - ((self.segments()[0] & 0xffff) == 0xfe80 - && (self.segments()[1] & 0xffff) == 0 - && (self.segments()[2] & 0xffff) == 0 - && (self.segments()[3] & 0xffff) == 0) + (self.segments()[0] & 0xffc0) == 0xfe80 || if let Some(v4_addr) = self.to_ipv4() { v4_addr.is_link_local() } else { false } } @@ -1471,7 +1471,7 @@ impl Ipv6Addr { /// future, as new RFCs are published. /// /// [changes]: ../net/index.html#stability-guarantees-for-ietf-defined-behavior - #[stable(feature = "ip", since = "1.47.0")] + #[stable(feature = "ip", since = "1.48.0")] #[rustc_const_unstable(feature = "const_ipv6", issue = "76205")] pub const fn is_unicast_site_local(&self) -> bool { (self.segments()[0] & 0xffc0) == 0xfec0 @@ -1499,7 +1499,7 @@ impl Ipv6Addr { /// future, as new RFCs are published. /// /// [changes]: ../net/index.html#stability-guarantees-for-ietf-defined-behavior - #[stable(feature = "ip", since = "1.47.0")] + #[stable(feature = "ip", since = "1.48.0")] #[rustc_const_unstable(feature = "const_ipv6", issue = "76205")] pub const fn is_documentation(&self) -> bool { ((self.segments()[0] == 0x2001) && (self.segments()[1] == 0xdb8)) @@ -1541,7 +1541,7 @@ impl Ipv6Addr { /// future, as new RFCs are published. /// /// [changes]: ../net/index.html#stability-guarantees-for-ietf-defined-behavior - #[stable(feature = "ip", since = "1.47.0")] + #[stable(feature = "ip", since = "1.48.0")] #[rustc_const_unstable(feature = "const_ipv6", issue = "76205")] pub const fn is_unicast_global(&self) -> bool { !self.is_multicast() @@ -1572,7 +1572,7 @@ impl Ipv6Addr { /// future, as new RFCs are published. /// /// [changes]: ../net/index.html#stability-guarantees-for-ietf-defined-behavior - #[stable(feature = "ip", since = "1.47.0")] + #[stable(feature = "ip", since = "1.48.0")] #[rustc_const_unstable(feature = "const_ipv6", issue = "76205")] pub const fn multicast_scope(&self) -> Option { use crate::net::Ipv6MulticastScope::{ @@ -1636,7 +1636,7 @@ impl Ipv6Addr { /// Some(Ipv4Addr::new(192, 10, 2, 255))); /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1).to_ipv4_mapped(), None); /// ``` - #[stable(feature = "ip", since = "1.47.0")] + #[stable(feature = "ip", since = "1.48.0")] #[rustc_const_unstable(feature = "const_ipv6", issue = "76205")] pub const fn to_ipv4_mapped(&self) -> Option { match self.octets() { From 179d37680c87600b46ca4404b831b6543ddf562e Mon Sep 17 00:00:00 2001 From: Cassandra Fridkin Date: Tue, 20 Oct 2020 20:51:46 -0400 Subject: [PATCH 15/24] Revert "Fix test cases that checked for relaxed behavior" This reverts commit e0f66e43da61d8fe8aadc6bcdc2545de51607332. --- library/std/src/net/ip/tests.rs | 24 +++++++----------------- 1 file changed, 7 insertions(+), 17 deletions(-) diff --git a/library/std/src/net/ip/tests.rs b/library/std/src/net/ip/tests.rs index 74bfc3a1be58b..203713d671512 100644 --- a/library/std/src/net/ip/tests.rs +++ b/library/std/src/net/ip/tests.rs @@ -302,14 +302,8 @@ fn ip_properties() { check!("1::", global); check!("fc00::"); check!("fdff:ffff::"); - - // see [`is_unicast_link_local`] - // fe80:ffff:: is *not* unicast_link_local - check!("fe80:ffff::", global); - // fe80:: *is* unicast_link_local - check!("fe80::"); - - check!("febf:ffff::", global); + check!("fe80:ffff::"); + check!("febf:ffff::"); check!("fec0::", global); check!("ff01::", multicast); check!("ff02::", multicast); @@ -617,7 +611,7 @@ fn ipv6_properties() { check!( "fe80:ffff::", &[0xfe, 0x80, 0xff, 0xff, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], - global | unicast_global + unicast_link_local ); check!("fe80::", &[0xfe, 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], unicast_link_local); @@ -625,14 +619,10 @@ fn ipv6_properties() { check!( "febf:ffff::", &[0xfe, 0xbf, 0xff, 0xff, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], - global | unicast_global + unicast_link_local ); - check!( - "febf::", - &[0xfe, 0xbf, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], - global | unicast_global - ); + check!("febf::", &[0xfe, 0xbf, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], unicast_link_local); check!( "febf:ffff:ffff:ffff:ffff:ffff:ffff:ffff", @@ -640,7 +630,7 @@ fn ipv6_properties() { 0xfe, 0xbf, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff ], - global | unicast_global + unicast_link_local ); check!( @@ -655,7 +645,7 @@ fn ipv6_properties() { check!( "fe80:0:0:1::", &[0xfe, 0x80, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0], - global | unicast_global + unicast_link_local ); check!( From 4f77918200df5d97eb37d6f48e0501c87b79206b Mon Sep 17 00:00:00 2001 From: Cassandra Fridkin Date: Tue, 20 Oct 2020 21:07:05 -0400 Subject: [PATCH 16/24] Remove IP feature gate --- library/std/src/net/ip.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/library/std/src/net/ip.rs b/library/std/src/net/ip.rs index 8b2a5fadbe571..315caad2f86e3 100644 --- a/library/std/src/net/ip.rs +++ b/library/std/src/net/ip.rs @@ -1393,8 +1393,6 @@ impl Ipv6Addr { /// # Examples /// /// ``` - /// #![feature(ip)] - /// /// use std::net::Ipv6Addr; /// /// let ip = Ipv6Addr::new(0xfe80, 0, 0, 0, 0, 0, 0, 0); From 2f1078d7473727ad24826cd9eb0553873976a900 Mon Sep 17 00:00:00 2001 From: Cassandra Fridkin Date: Tue, 24 Nov 2020 17:30:41 -0500 Subject: [PATCH 17/24] Remove duplicate UI tests as per @CDirkx's suggestions --- src/test/ui/consts/std/net/ipv4.rs | 57 ------------------------------ src/test/ui/consts/std/net/ipv6.rs | 49 ------------------------- 2 files changed, 106 deletions(-) delete mode 100644 src/test/ui/consts/std/net/ipv4.rs delete mode 100644 src/test/ui/consts/std/net/ipv6.rs diff --git a/src/test/ui/consts/std/net/ipv4.rs b/src/test/ui/consts/std/net/ipv4.rs deleted file mode 100644 index 58f45c99c336e..0000000000000 --- a/src/test/ui/consts/std/net/ipv4.rs +++ /dev/null @@ -1,57 +0,0 @@ -// run-pass - -#![feature(const_ipv4)] - -use std::net::{Ipv4Addr, Ipv6Addr}; - -fn main() { - const IP_ADDRESS: Ipv4Addr = Ipv4Addr::new(127, 0, 0, 1); - assert_eq!(IP_ADDRESS, Ipv4Addr::LOCALHOST); - - const OCTETS: [u8; 4] = IP_ADDRESS.octets(); - assert_eq!(OCTETS, [127, 0, 0, 1]); - - const IS_UNSPECIFIED : bool = IP_ADDRESS.is_unspecified(); - assert!(!IS_UNSPECIFIED); - - const IS_LOOPBACK : bool = IP_ADDRESS.is_loopback(); - assert!(IS_LOOPBACK); - - const IS_PRIVATE : bool = IP_ADDRESS.is_private(); - assert!(!IS_PRIVATE); - - const IS_LINK_LOCAL : bool = IP_ADDRESS.is_link_local(); - assert!(!IS_LINK_LOCAL); - - const IS_GLOBAL : bool = IP_ADDRESS.is_global(); - assert!(!IS_GLOBAL); - - const IS_SHARED : bool = IP_ADDRESS.is_shared(); - assert!(!IS_SHARED); - - const IS_IETF_PROTOCOL_ASSIGNMENT : bool = IP_ADDRESS.is_ietf_protocol_assignment(); - assert!(!IS_IETF_PROTOCOL_ASSIGNMENT); - - const IS_BENCHMARKING : bool = IP_ADDRESS.is_benchmarking(); - assert!(!IS_BENCHMARKING); - - const IS_RESERVED : bool = IP_ADDRESS.is_reserved(); - assert!(!IS_RESERVED); - - const IS_MULTICAST : bool = IP_ADDRESS.is_multicast(); - assert!(!IS_MULTICAST); - - const IS_BROADCAST : bool = IP_ADDRESS.is_broadcast(); - assert!(!IS_BROADCAST); - - const IS_DOCUMENTATION : bool = IP_ADDRESS.is_documentation(); - assert!(!IS_DOCUMENTATION); - - const IP_V6_COMPATIBLE : Ipv6Addr = IP_ADDRESS.to_ipv6_compatible(); - assert_eq!(IP_V6_COMPATIBLE, - Ipv6Addr::from([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 127, 0, 0, 1])); - - const IP_V6_MAPPED : Ipv6Addr = IP_ADDRESS.to_ipv6_mapped(); - assert_eq!(IP_V6_MAPPED, - Ipv6Addr::from([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 127, 0, 0, 1])); -} diff --git a/src/test/ui/consts/std/net/ipv6.rs b/src/test/ui/consts/std/net/ipv6.rs deleted file mode 100644 index 71cc934f6de40..0000000000000 --- a/src/test/ui/consts/std/net/ipv6.rs +++ /dev/null @@ -1,49 +0,0 @@ -// run-pass - -#![feature(const_ipv6)] - -use std::net::{Ipv4Addr, Ipv6Addr, Ipv6MulticastScope}; - -fn main() { - const IP_ADDRESS : Ipv6Addr = Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1); - assert_eq!(IP_ADDRESS, Ipv6Addr::LOCALHOST); - - const SEGMENTS : [u16; 8] = IP_ADDRESS.segments(); - assert_eq!(SEGMENTS, [0 ,0 ,0 ,0 ,0 ,0 ,0, 1]); - - const OCTETS : [u8; 16] = IP_ADDRESS.octets(); - assert_eq!(OCTETS, [0 ,0 ,0 ,0 ,0 ,0 ,0, 0 ,0 ,0 ,0 ,0 ,0 ,0, 0, 1]); - - const IS_UNSPECIFIED : bool = IP_ADDRESS.is_unspecified(); - assert!(!IS_UNSPECIFIED); - - const IS_LOOPBACK : bool = IP_ADDRESS.is_loopback(); - assert!(IS_LOOPBACK); - - const IS_GLOBAL : bool = IP_ADDRESS.is_global(); - assert!(!IS_GLOBAL); - - const IS_UNIQUE_LOCAL : bool = IP_ADDRESS.is_unique_local(); - assert!(!IS_UNIQUE_LOCAL); - - const IS_UNICAST_LINK_LOCAL : bool = IP_ADDRESS.is_unicast_link_local(); - assert!(!IS_UNICAST_LINK_LOCAL); - - const IS_UNICAST_SITE_LOCAL : bool = IP_ADDRESS.is_unicast_site_local(); - assert!(!IS_UNICAST_SITE_LOCAL); - - const IS_DOCUMENTATION : bool = IP_ADDRESS.is_documentation(); - assert!(!IS_DOCUMENTATION); - - const IS_UNICAST_GLOBAL : bool = IP_ADDRESS.is_unicast_global(); - assert!(!IS_UNICAST_GLOBAL); - - const MULTICAST_SCOPE : Option = IP_ADDRESS.multicast_scope(); - assert_eq!(MULTICAST_SCOPE, None); - - const IS_MULTICAST : bool = IP_ADDRESS.is_multicast(); - assert!(!IS_MULTICAST); - - const IP_V4 : Option = IP_ADDRESS.to_ipv4(); - assert_eq!(IP_V4.unwrap(), Ipv4Addr::new(0, 0, 0, 1)); -} From 0348e5e7bc28755422d7b1d7ceaf26991361bd1f Mon Sep 17 00:00:00 2001 From: Cassandra Fridkin Date: Tue, 24 Nov 2020 17:46:18 -0500 Subject: [PATCH 18/24] Rewrite using new rustdoc comments!!!! --- library/std/src/net/mod.rs | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/library/std/src/net/mod.rs b/library/std/src/net/mod.rs index d814e9b25ba9a..1e7c842eb2f94 100644 --- a/library/std/src/net/mod.rs +++ b/library/std/src/net/mod.rs @@ -14,6 +14,34 @@ //! * [`ToSocketAddrs`] is a trait that used for generic address resolution when interacting //! with networking objects like [`TcpListener`], [`TcpStream`] or [`UdpSocket`] //! * Other types are return or parameter types for various methods in this module +//! +//! # Stability guarantees for IETF-defined behavior +//! +//! [`IpAddr`], [`Ipv4Addr`] and [`Ipv6Addr`] offer helper methods that provide information about +//! an address, for instance whether it is globally routable (see [`IpAddr::is_global()`]), or if +//! it is a multicast address (see [`IpAddr::is_multicast()`]). These methods are compliant with +//! the [IETF RFCs]. As erratas and new RFCs are published, these methods behavior may be subject +//! to changes. +//! +//! For instance, the `240/4` IPv4 block is currently reserved for "future use". If it is made +//! globally routable by an RFC, then in a future release [`Ipv4Addr::is_reserved()`] will return +//! `false` for such addresses, while [`Ipv4Addr::is_global`] will return true. +//! +//! [`IpAddr`]: crate::net::IpAddr +//! [`Ipv4Addr`]: crate::net::Ipv4Addr +//! [`IpAddr::is_global()`]: crate::net::IpAddr::is_global() +//! [`IpAddr::is_multicast()`]: crate::net::IpAddr::is_multicast() +//! [`Ipv4Addr::is_reserved()`]: crate::net::Ipv4Addr::is_reserved() +//! [`Ipv4Addr::is_global()`]: crate::net::Ipv4Addr::is_global() +//! [`Ipv6Addr`]: crate::net::Ipv6Addr +//! [`SocketAddr`]: crate::net::SocketAddr +//! [`SocketAddrV4`]: crate::net::SocketAddrV4 +//! [`SocketAddrV6`]: crate::net::SocketAddrV6 +//! [`TcpListener`]: crate::net::TcpListener +//! [`TcpStream`]: crate::net::TcpStream +//! [`ToSocketAddrs`]: crate::net::ToSocketAddrs +//! [`UdpSocket`]: crate::net::UdpSocket +//! [IETF RFCs]: https://tools.ietf.org/rfc/index #![stable(feature = "rust1", since = "1.0.0")] From 36792e8dc5129cc2381662159c2288a9e67f7032 Mon Sep 17 00:00:00 2001 From: Cassandra Fridkin Date: Tue, 24 Nov 2020 21:47:23 -0500 Subject: [PATCH 19/24] Adjust Ipv4-in-Ipv6 checking to ignore Ipv4-compatible addresses Per [RFC 4291](https://tools.ietf.org/html/rfc4291#section-2.5.5.1), IPv6-Compatible IPv4 Addresses are deprecated and may be ignored, so let's ignore them! Also add some tests indicating that IPv6-Mapped addresses are treated specially, but IPv6-Compatible addresses are not. --- library/std/src/net/ip.rs | 69 ++++++++++----------------- library/std/src/net/ip/tests.rs | 83 +++++++++++++++++++++++++++++---- 2 files changed, 98 insertions(+), 54 deletions(-) diff --git a/library/std/src/net/ip.rs b/library/std/src/net/ip.rs index 315caad2f86e3..d680eb1bb5244 100644 --- a/library/std/src/net/ip.rs +++ b/library/std/src/net/ip.rs @@ -1288,7 +1288,11 @@ impl Ipv6Addr { #[inline] pub const fn is_unspecified(&self) -> bool { u128::from_be_bytes(self.octets()) == u128::from_be_bytes(Ipv6Addr::UNSPECIFIED.octets()) - || if let Some(v4_addr) = self.to_ipv4() { v4_addr.is_unspecified() } else { false } + || if let Some(v4_addr) = self.to_ipv4_mapped() { + v4_addr.is_unspecified() + } else { + false + } } /// Returns [`true`] if this is a loopback address (::1). @@ -1310,7 +1314,7 @@ impl Ipv6Addr { #[inline] pub const fn is_loopback(&self) -> bool { u128::from_be_bytes(self.octets()) == u128::from_be_bytes(Ipv6Addr::LOCALHOST.octets()) - || if let Some(v4_addr) = self.to_ipv4() { v4_addr.is_loopback() } else { false } + || if let Some(v4_addr) = self.to_ipv4_mapped() { v4_addr.is_loopback() } else { false } } /// Returns [`true`] if the address appears to be globally routable. @@ -1344,7 +1348,7 @@ impl Ipv6Addr { Some(Ipv6MulticastScope::Global) => true, None => self.is_unicast_global(), _ => false, - }) || if let Some(v4_addr) = self.to_ipv4() { v4_addr.is_global() } else { false } + }) || if let Some(v4_addr) = self.to_ipv4_mapped() { v4_addr.is_global() } else { false } } /// Returns [`true`] if this is a unique local address (`fc00::/7`). @@ -1427,7 +1431,11 @@ impl Ipv6Addr { #[rustc_const_unstable(feature = "const_ipv6", issue = "76205")] pub const fn is_unicast_link_local(&self) -> bool { (self.segments()[0] & 0xffc0) == 0xfe80 - || if let Some(v4_addr) = self.to_ipv4() { v4_addr.is_link_local() } else { false } + || if let Some(v4_addr) = self.to_ipv4_mapped() { + v4_addr.is_link_local() + } else { + false + } } /// Returns [`true`] if this is a deprecated unicast site-local address (fec0::/10). The @@ -1501,7 +1509,11 @@ impl Ipv6Addr { #[rustc_const_unstable(feature = "const_ipv6", issue = "76205")] pub const fn is_documentation(&self) -> bool { ((self.segments()[0] == 0x2001) && (self.segments()[1] == 0xdb8)) - || if let Some(v4_addr) = self.to_ipv4() { v4_addr.is_documentation() } else { false } + || if let Some(v4_addr) = self.to_ipv4_mapped() { + v4_addr.is_documentation() + } else { + false + } } /// Returns [`true`] if the address is a globally routable unicast address. @@ -1612,7 +1624,11 @@ impl Ipv6Addr { #[inline] pub const fn is_multicast(&self) -> bool { (self.segments()[0] & 0xff00) == 0xff00 - || if let Some(v4_addr) = self.to_ipv4() { v4_addr.is_multicast() } else { false } + || if let Some(v4_addr) = self.to_ipv4_mapped() { + v4_addr.is_multicast() + } else { + false + } } /// Converts this address to an [`IPv4` address] if it's an "IPv4-mapped IPv6 address" @@ -1645,37 +1661,6 @@ impl Ipv6Addr { } } - /// Converts this address to an [`IPv4` address]. Returns [`None`] if this address is - /// neither IPv4-compatible or IPv4-mapped. - /// - /// ::a.b.c.d and ::ffff:a.b.c.d become a.b.c.d - /// - /// [`IPv4` address]: Ipv4Addr - /// - /// # Examples - /// - /// ``` - /// use std::net::{Ipv4Addr, Ipv6Addr}; - /// - /// assert_eq!(Ipv6Addr::new(0xff00, 0, 0, 0, 0, 0, 0, 0).to_ipv4(), None); - /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff).to_ipv4(), - /// Some(Ipv4Addr::new(192, 10, 2, 255))); - /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1).to_ipv4(), - /// Some(Ipv4Addr::new(0, 0, 0, 1))); - /// ``` - #[rustc_const_stable(feature = "const_ipv6", since = "1.50.0")] - #[stable(feature = "rust1", since = "1.0.0")] - #[inline] - pub const fn to_ipv4(&self) -> Option { - 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 - } - } - /// Returns the sixteen eight-bit integers the IPv6 address consists of. /// /// ``` @@ -1708,14 +1693,8 @@ impl fmt::Display for Ipv6Addr { f.write_str("::") } else if self.is_loopback() { f.write_str("::1") - } else if let Some(ipv4) = self.to_ipv4() { - match segments[5] { - // IPv4 Compatible address - 0 => write!(f, "::{}", ipv4), - // IPv4 Mapped address - 0xffff => write!(f, "::ffff:{}", ipv4), - _ => unreachable!(), - } + } else if let Some(ipv4) = self.to_ipv4_mapped() { + write!(f, "::ffff:{}", ipv4) } else { #[derive(Copy, Clone, Default)] struct Span { diff --git a/library/std/src/net/ip/tests.rs b/library/std/src/net/ip/tests.rs index 203713d671512..70874073a2923 100644 --- a/library/std/src/net/ip/tests.rs +++ b/library/std/src/net/ip/tests.rs @@ -128,8 +128,10 @@ fn ipv6_addr_to_string() { assert_eq!(a1.to_string(), "::ffff:192.0.2.128"); // ipv4-compatible address + // not recognized as special by rust let a1 = Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0xc000, 0x280); - assert_eq!(a1.to_string(), "::192.0.2.128"); + assert_ne!(a1.to_string(), "::192.0.2.128"); + assert_eq!(a1.to_string(), "::c000:280"); // v6 address with no zero segments assert_eq!(Ipv6Addr::new(8, 9, 10, 11, 12, 13, 14, 15).to_string(), "8:9:a:b:c:d:e:f"); @@ -195,14 +197,16 @@ fn ipv6_to_ipv4_mapped() { #[test] fn ipv6_to_ipv4() { assert_eq!( - Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0x1234, 0x5678).to_ipv4(), + Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0x1234, 0x5678).to_ipv4_mapped(), Some(Ipv4Addr::new(0x12, 0x34, 0x56, 0x78)) ); assert_eq!( - Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0x1234, 0x5678).to_ipv4(), - Some(Ipv4Addr::new(0x12, 0x34, 0x56, 0x78)) + Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0x1234, 0x5678).to_ipv4_mapped(), + // IPv4-Compatible IPv6 addresses are unrecognized + // Some(Ipv4Addr::new(0x12, 0x34, 0x56, 0x78)) + None ); - assert_eq!(Ipv6Addr::new(0, 0, 1, 0, 0, 0, 0x1234, 0x5678).to_ipv4(), None); + assert_eq!(Ipv6Addr::new(0, 0, 1, 0, 0, 0, 0x1234, 0x5678).to_ipv4_mapped(), None); } #[test] @@ -596,10 +600,15 @@ fn ipv6_properties() { check!("::1", &[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1], loopback); - check!("::0.0.0.2", &[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2], global | unicast_global); - check!("1::", &[0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], global | unicast_global); + // all methods work on ipv4-mapped addresses as well + check!( + "::ffff:0.0.0.2", + &[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xff, 0xff, 0, 0, 0, 2], + global | unicast_global + ); + check!("fc00::", &[0xfc, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], unique_local); check!( @@ -693,6 +702,62 @@ fn ipv6_properties() { ); } +#[test] +fn ipv4_mapped() { + // assert that IPv4-mapped addresses are correctly identified and methods apply to them, + // and that IPv4-compatible addresses are treated as standard IPv6 addresses + + let v4_unspecified = Ipv4Addr::new(0, 0, 0, 0); + let mapped_unspecified = v4_unspecified.to_ipv6_mapped(); + let compatible_unspecified = v4_unspecified.to_ipv6_compatible(); + + assert!(v4_unspecified.is_unspecified()); + assert!(mapped_unspecified.is_unspecified()); + // this one just happens to meet the criteria, but not because it is treated specially! + assert!(compatible_unspecified.is_unspecified()); + + let v4_loopback = Ipv4Addr::LOCALHOST; + let mapped_loopback = v4_loopback.to_ipv6_mapped(); + let compatible_loopback = v4_loopback.to_ipv6_compatible(); + + assert!(v4_loopback.is_loopback()); + assert!(mapped_loopback.is_loopback()); + assert!(!compatible_loopback.is_loopback()); + + let v4_global = Ipv4Addr::new(192, 1, 2, 183); + let mapped_global = v4_global.to_ipv6_mapped(); + let compatible_global = v4_global.to_ipv6_compatible(); + + assert!(v4_global.is_global()); + assert!(mapped_global.is_global()); + // this one just happens to meet the criteria, but not because it is treated specially! + assert!(compatible_global.is_global()); + + let v4_link_local = Ipv4Addr::new(169, 254, 253, 242); + let mapped_link_local = v4_link_local.to_ipv6_mapped(); + let compatible_link_local = v4_link_local.to_ipv6_compatible(); + + assert!(v4_link_local.is_link_local()); + assert!(mapped_link_local.is_unicast_link_local()); + assert!(!compatible_link_local.is_unicast_link_local()); + + let v4_documentation = Ipv4Addr::new(203, 0, 113, 0); + let mapped_documentation = v4_documentation.to_ipv6_mapped(); + let compatible_documentation = v4_documentation.to_ipv6_compatible(); + + assert!(v4_documentation.is_documentation()); + assert!(mapped_documentation.is_documentation()); + assert!(!compatible_documentation.is_documentation()); + + let v4_multicast = Ipv4Addr::new(224, 0, 0, 0); + let mapped_multicast = v4_multicast.to_ipv6_mapped(); + let compatible_multicast = v4_multicast.to_ipv6_compatible(); + + assert!(v4_multicast.is_multicast()); + assert!(mapped_multicast.is_multicast()); + assert!(!compatible_multicast.is_multicast()); +} + #[test] fn to_socket_addr_socketaddr() { let a = sa4(Ipv4Addr::new(77, 88, 21, 11), 12345); @@ -904,8 +969,8 @@ fn ipv6_const() { const IS_MULTICAST: bool = IP_ADDRESS.is_multicast(); assert!(!IS_MULTICAST); - const IP_V4: Option = IP_ADDRESS.to_ipv4(); - assert_eq!(IP_V4.unwrap(), Ipv4Addr::new(0, 0, 0, 1)); + const IP_V4: Option = IP_ADDRESS.to_ipv4_mapped(); + assert!(IP_V4.is_none()); } #[test] From 42b9a3808402dde9949f4698fb2e1c3f01802768 Mon Sep 17 00:00:00 2001 From: Cassandra Fridkin Date: Wed, 25 Nov 2020 10:35:52 -0500 Subject: [PATCH 20/24] Revert "Adjust Ipv4-in-Ipv6 checking to ignore Ipv4-compatible addresses" This reverts commit 63329f9eadbba6da75a04cbf613f5701b06f71e5. Also, change the behavior of `to_ipv4` to ignore Ipv4-compatible addresses instead of adding another method `to_ipv4_mapped` and never ever using `to_ipv4` instead. Since this method is in stable. --- library/std/src/net/ip.rs | 48 +++++++++++++-------------------- library/std/src/net/ip/tests.rs | 19 +++++++------ 2 files changed, 28 insertions(+), 39 deletions(-) diff --git a/library/std/src/net/ip.rs b/library/std/src/net/ip.rs index d680eb1bb5244..1403abc33d099 100644 --- a/library/std/src/net/ip.rs +++ b/library/std/src/net/ip.rs @@ -1288,11 +1288,7 @@ impl Ipv6Addr { #[inline] pub const fn is_unspecified(&self) -> bool { u128::from_be_bytes(self.octets()) == u128::from_be_bytes(Ipv6Addr::UNSPECIFIED.octets()) - || if let Some(v4_addr) = self.to_ipv4_mapped() { - v4_addr.is_unspecified() - } else { - false - } + || if let Some(v4_addr) = self.to_ipv4() { v4_addr.is_unspecified() } else { false } } /// Returns [`true`] if this is a loopback address (::1). @@ -1314,7 +1310,7 @@ impl Ipv6Addr { #[inline] pub const fn is_loopback(&self) -> bool { u128::from_be_bytes(self.octets()) == u128::from_be_bytes(Ipv6Addr::LOCALHOST.octets()) - || if let Some(v4_addr) = self.to_ipv4_mapped() { v4_addr.is_loopback() } else { false } + || if let Some(v4_addr) = self.to_ipv4() { v4_addr.is_loopback() } else { false } } /// Returns [`true`] if the address appears to be globally routable. @@ -1348,7 +1344,7 @@ impl Ipv6Addr { Some(Ipv6MulticastScope::Global) => true, None => self.is_unicast_global(), _ => false, - }) || if let Some(v4_addr) = self.to_ipv4_mapped() { v4_addr.is_global() } else { false } + }) || if let Some(v4_addr) = self.to_ipv4() { v4_addr.is_global() } else { false } } /// Returns [`true`] if this is a unique local address (`fc00::/7`). @@ -1431,11 +1427,7 @@ impl Ipv6Addr { #[rustc_const_unstable(feature = "const_ipv6", issue = "76205")] pub const fn is_unicast_link_local(&self) -> bool { (self.segments()[0] & 0xffc0) == 0xfe80 - || if let Some(v4_addr) = self.to_ipv4_mapped() { - v4_addr.is_link_local() - } else { - false - } + || if let Some(v4_addr) = self.to_ipv4() { v4_addr.is_link_local() } else { false } } /// Returns [`true`] if this is a deprecated unicast site-local address (fec0::/10). The @@ -1509,11 +1501,7 @@ impl Ipv6Addr { #[rustc_const_unstable(feature = "const_ipv6", issue = "76205")] pub const fn is_documentation(&self) -> bool { ((self.segments()[0] == 0x2001) && (self.segments()[1] == 0xdb8)) - || if let Some(v4_addr) = self.to_ipv4_mapped() { - v4_addr.is_documentation() - } else { - false - } + || if let Some(v4_addr) = self.to_ipv4() { v4_addr.is_documentation() } else { false } } /// Returns [`true`] if the address is a globally routable unicast address. @@ -1624,11 +1612,7 @@ impl Ipv6Addr { #[inline] pub const fn is_multicast(&self) -> bool { (self.segments()[0] & 0xff00) == 0xff00 - || if let Some(v4_addr) = self.to_ipv4_mapped() { - v4_addr.is_multicast() - } else { - false - } + || if let Some(v4_addr) = self.to_ipv4() { v4_addr.is_multicast() } else { false } } /// Converts this address to an [`IPv4` address] if it's an "IPv4-mapped IPv6 address" @@ -1645,14 +1629,14 @@ impl Ipv6Addr { /// ``` /// use std::net::{Ipv4Addr, Ipv6Addr}; /// - /// assert_eq!(Ipv6Addr::new(0xff00, 0, 0, 0, 0, 0, 0, 0).to_ipv4_mapped(), None); - /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff).to_ipv4_mapped(), + /// assert_eq!(Ipv6Addr::new(0xff00, 0, 0, 0, 0, 0, 0, 0).to_ipv4(), None); + /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff).to_ipv4(), /// Some(Ipv4Addr::new(192, 10, 2, 255))); - /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1).to_ipv4_mapped(), None); + /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1).to_ipv4(), None); /// ``` - #[stable(feature = "ip", since = "1.48.0")] #[rustc_const_unstable(feature = "const_ipv6", issue = "76205")] - pub const fn to_ipv4_mapped(&self) -> Option { + #[stable(feature = "rust1", since = "1.0.0")] + pub const fn to_ipv4(&self) -> Option { 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)) @@ -1693,8 +1677,14 @@ impl fmt::Display for Ipv6Addr { f.write_str("::") } else if self.is_loopback() { f.write_str("::1") - } else if let Some(ipv4) = self.to_ipv4_mapped() { - write!(f, "::ffff:{}", ipv4) + } else if let Some(ipv4) = self.to_ipv4() { + match segments[5] { + // IPv4 Compatible address + 0 => write!(f, "::{}", ipv4), + // IPv4 Mapped address + 0xffff => write!(f, "::ffff:{}", ipv4), + _ => unreachable!(), + } } else { #[derive(Copy, Clone, Default)] struct Span { diff --git a/library/std/src/net/ip/tests.rs b/library/std/src/net/ip/tests.rs index 70874073a2923..b51d7f4858b6e 100644 --- a/library/std/src/net/ip/tests.rs +++ b/library/std/src/net/ip/tests.rs @@ -186,27 +186,26 @@ fn ipv4_to_ipv6() { } #[test] -fn ipv6_to_ipv4_mapped() { +fn ipv6_to_ipv4() { assert_eq!( - Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0x1234, 0x5678).to_ipv4_mapped(), + Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0x1234, 0x5678).to_ipv4(), Some(Ipv4Addr::new(0x12, 0x34, 0x56, 0x78)) ); - assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0x1234, 0x5678).to_ipv4_mapped(), None); -} -#[test] -fn ipv6_to_ipv4() { + assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0x1234, 0x5678).to_ipv4(), None); + assert_eq!( - Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0x1234, 0x5678).to_ipv4_mapped(), + Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0x1234, 0x5678).to_ipv4(), Some(Ipv4Addr::new(0x12, 0x34, 0x56, 0x78)) ); + assert_eq!( - Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0x1234, 0x5678).to_ipv4_mapped(), + Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0x1234, 0x5678).to_ipv4(), // IPv4-Compatible IPv6 addresses are unrecognized // Some(Ipv4Addr::new(0x12, 0x34, 0x56, 0x78)) None ); - assert_eq!(Ipv6Addr::new(0, 0, 1, 0, 0, 0, 0x1234, 0x5678).to_ipv4_mapped(), None); + assert_eq!(Ipv6Addr::new(0, 0, 1, 0, 0, 0, 0x1234, 0x5678).to_ipv4(), None); } #[test] @@ -969,7 +968,7 @@ fn ipv6_const() { const IS_MULTICAST: bool = IP_ADDRESS.is_multicast(); assert!(!IS_MULTICAST); - const IP_V4: Option = IP_ADDRESS.to_ipv4_mapped(); + const IP_V4: Option = IP_ADDRESS.to_ipv4(); assert!(IP_V4.is_none()); } From e6b76f0baea5f8674a3fd3cda70d138df601561d Mon Sep 17 00:00:00 2001 From: Cassandra Fridkin Date: Wed, 25 Nov 2020 13:22:25 -0500 Subject: [PATCH 21/24] Update doc comments - Use new intra-doc linking - Clarify that the RFC's are IETF RFC's --- library/std/src/net/ip.rs | 219 ++++++++++++++++++++++++++++++-------- 1 file changed, 172 insertions(+), 47 deletions(-) diff --git a/library/std/src/net/ip.rs b/library/std/src/net/ip.rs index 1403abc33d099..ef76b2cfe6224 100644 --- a/library/std/src/net/ip.rs +++ b/library/std/src/net/ip.rs @@ -121,9 +121,9 @@ pub struct Ipv6Addr { /// # Stability guarantees /// /// This enum [may by subject to changes][changes] in the -/// future, as new RFCs are published. +/// future, as new IETF RFCs are published. /// -/// [changes]: ../net/index.html#stability-guarantees-for-ietf-defined-behavior +/// [changes]: super#stability-guarantees-for-ietf-defined-behavior /// [section 2 of IETF RFC 7346]: https://tools.ietf.org/html/rfc7346#section-2 #[derive(Copy, PartialEq, Eq, Clone, Hash, Debug)] #[stable(feature = "ip", since = "1.48.0")] @@ -208,7 +208,14 @@ impl IpAddr { /// assert_eq!(IpAddr::V4(Ipv4Addr::new(0, 0, 0, 0)).is_unspecified(), true); /// assert_eq!(IpAddr::V6(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0)).is_unspecified(), true); /// ``` - #[rustc_const_stable(feature = "const_ip", since = "1.50.0")] + /// + /// # Stability guarantees + /// + /// This method's behavior [may by subject to changes][changes] in the + /// future, as new IETF RFCs are published. + /// + /// [changes]: super#stability-guarantees-for-ietf-defined-behavior + #[rustc_const_unstable(feature = "const_ip", issue = "76205")] #[stable(feature = "ip_shared", since = "1.12.0")] #[inline] pub const fn is_unspecified(&self) -> bool { @@ -231,7 +238,14 @@ impl IpAddr { /// assert_eq!(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)).is_loopback(), true); /// assert_eq!(IpAddr::V6(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0x1)).is_loopback(), true); /// ``` - #[rustc_const_stable(feature = "const_ip", since = "1.50.0")] + /// + /// # Stability guarantees + /// + /// This method's behavior [may by subject to changes][changes] in the + /// future, as new IETF RFCs are published. + /// + /// [changes]: super#stability-guarantees-for-ietf-defined-behavior + #[rustc_const_unstable(feature = "const_ip", issue = "76205")] #[stable(feature = "ip_shared", since = "1.12.0")] #[inline] pub const fn is_loopback(&self) -> bool { @@ -258,9 +272,9 @@ impl IpAddr { /// # Stability guarantees /// /// This method's behavior [may by subject to changes][changes] in the - /// future, as new RFCs are published. + /// future, as new IETF RFCs are published. /// - /// [changes]: ../net/index.html#stability-guarantees-for-ietf-defined-behavior + /// [changes]: super#stability-guarantees-for-ietf-defined-behavior #[stable(feature = "ip", since = "1.48.0")] #[rustc_const_unstable(feature = "const_ip", issue = "76205")] pub const fn is_global(&self) -> bool { @@ -283,7 +297,14 @@ impl IpAddr { /// assert_eq!(IpAddr::V4(Ipv4Addr::new(224, 254, 0, 0)).is_multicast(), true); /// assert_eq!(IpAddr::V6(Ipv6Addr::new(0xff00, 0, 0, 0, 0, 0, 0, 0)).is_multicast(), true); /// ``` - #[rustc_const_stable(feature = "const_ip", since = "1.50.0")] + /// + /// # Stability guarantees + /// + /// This method's behavior [may by subject to changes][changes] in the + /// future, as new IETF RFCs are published. + /// + /// [changes]: super#stability-guarantees-for-ietf-defined-behavior + #[rustc_const_unstable(feature = "const_ip", issue = "76205")] #[stable(feature = "ip_shared", since = "1.12.0")] #[inline] pub const fn is_multicast(&self) -> bool { @@ -313,9 +334,9 @@ impl IpAddr { /// # Stability guarantees /// /// This method's behavior [may by subject to changes][changes] in the - /// future, as new RFCs are published. + /// future, as new IETF RFCs are published. /// - /// [changes]: ../net/index.html#stability-guarantees-for-ietf-defined-behavior + /// [changes]: super#stability-guarantees-for-ietf-defined-behavior #[stable(feature = "ip", since = "1.48.0")] #[rustc_const_unstable(feature = "const_ip", issue = "76205")] pub const fn is_documentation(&self) -> bool { @@ -338,6 +359,13 @@ impl IpAddr { /// assert_eq!(IpAddr::V4(Ipv4Addr::new(203, 0, 113, 6)).is_ipv4(), true); /// assert_eq!(IpAddr::V6(Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 0)).is_ipv4(), false); /// ``` + /// + /// # Stability guarantees + /// + /// This method's behavior [may by subject to changes][changes] in the + /// future, as new IETF RFCs are published. + /// + /// [changes]: super#stability-guarantees-for-ietf-defined-behavior #[rustc_const_stable(feature = "const_ip", since = "1.50.0")] #[stable(feature = "ipaddr_checker", since = "1.16.0")] #[inline] @@ -358,6 +386,13 @@ impl IpAddr { /// assert_eq!(IpAddr::V4(Ipv4Addr::new(203, 0, 113, 6)).is_ipv6(), false); /// assert_eq!(IpAddr::V6(Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 0)).is_ipv6(), true); /// ``` + /// + /// # Stability guarantees + /// + /// This method's behavior [may by subject to changes][changes] in the + /// future, as new IETF RFCs are published. + /// + /// [changes]: super#stability-guarantees-for-ietf-defined-behavior #[rustc_const_stable(feature = "const_ip", since = "1.50.0")] #[stable(feature = "ipaddr_checker", since = "1.16.0")] #[inline] @@ -439,7 +474,14 @@ impl Ipv4Addr { /// let addr = Ipv4Addr::new(127, 0, 0, 1); /// assert_eq!(addr.octets(), [127, 0, 0, 1]); /// ``` - #[rustc_const_stable(feature = "const_ipv4", since = "1.50.0")] + /// + /// # Stability guarantees + /// + /// This method's behavior [may by subject to changes][changes] in the + /// future, as new IETF RFCs are published. + /// + /// [changes]: super#stability-guarantees-for-ietf-defined-behavior + #[rustc_const_unstable(feature = "const_ipv4", issue = "76205")] #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub const fn octets(&self) -> [u8; 4] { @@ -483,7 +525,14 @@ impl Ipv4Addr { /// assert_eq!(Ipv4Addr::new(127, 0, 0, 1).is_loopback(), true); /// assert_eq!(Ipv4Addr::new(45, 22, 13, 197).is_loopback(), false); /// ``` - #[rustc_const_stable(feature = "const_ipv4", since = "1.50.0")] + /// + /// # Stability guarantees + /// + /// This method's behavior [may by subject to changes][changes] in the + /// future, as new IETF RFCs are published. + /// + /// [changes]: super#stability-guarantees-for-ietf-defined-behavior + #[rustc_const_unstable(feature = "const_ipv4", issue = "76205")] #[stable(since = "1.7.0", feature = "ip_17")] #[inline] pub const fn is_loopback(&self) -> bool { @@ -513,7 +562,14 @@ impl Ipv4Addr { /// assert_eq!(Ipv4Addr::new(192, 168, 0, 2).is_private(), true); /// assert_eq!(Ipv4Addr::new(192, 169, 0, 2).is_private(), false); /// ``` - #[rustc_const_stable(feature = "const_ipv4", since = "1.50.0")] + /// + /// # Stability guarantees + /// + /// This method's behavior [may by subject to changes][changes] in the + /// future, as new IETF RFCs are published. + /// + /// [changes]: super#stability-guarantees-for-ietf-defined-behavior + #[rustc_const_unstable(feature = "const_ipv4", issue = "76205")] #[stable(since = "1.7.0", feature = "ip_17")] #[inline] pub const fn is_private(&self) -> bool { @@ -540,7 +596,14 @@ impl Ipv4Addr { /// assert_eq!(Ipv4Addr::new(169, 254, 10, 65).is_link_local(), true); /// assert_eq!(Ipv4Addr::new(16, 89, 10, 65).is_link_local(), false); /// ``` - #[rustc_const_stable(feature = "const_ipv4", since = "1.50.0")] + /// + /// # Stability guarantees + /// + /// This method's behavior [may by subject to changes][changes] in the + /// future, as new IETF RFCs are published. + /// + /// [changes]: super#stability-guarantees-for-ietf-defined-behavior + #[rustc_const_unstable(feature = "const_ipv4", issue = "76205")] #[stable(since = "1.7.0", feature = "ip_17")] #[inline] pub const fn is_link_local(&self) -> bool { @@ -618,9 +681,9 @@ impl Ipv4Addr { /// # Stability guarantees /// /// This method's behavior [may by subject to changes][changes] in the - /// future, as new RFCs are published. + /// future, as new IETF RFCs are published. /// - /// [changes]: ../net/index.html#stability-guarantees-for-ietf-defined-behavior + /// [changes]: super#stability-guarantees-for-ietf-defined-behavior #[stable(feature = "ip", since = "1.48.0")] #[rustc_const_unstable(feature = "const_ipv4", issue = "76205")] pub const fn is_global(&self) -> bool { @@ -662,9 +725,9 @@ impl Ipv4Addr { /// # Stability guarantees /// /// This method's behavior [may by subject to changes][changes] in the - /// future, as new RFCs are published. + /// future, as new IETF RFCs are published. /// - /// [changes]: ../net/index.html#stability-guarantees-for-ietf-defined-behavior + /// [changes]: super#stability-guarantees-for-ietf-defined-behavior #[stable(feature = "ip", since = "1.48.0")] #[rustc_const_unstable(feature = "const_ipv4", issue = "76205")] pub const fn is_shared(&self) -> bool { @@ -701,9 +764,9 @@ impl Ipv4Addr { /// # Stability guarantees /// /// This method's behavior [may by subject to changes][changes] in the - /// future, as new RFCs are published. + /// future, as new IETF RFCs are published. /// - /// [changes]: ../net/index.html#stability-guarantees-for-ietf-defined-behavior + /// [changes]: super#stability-guarantees-for-ietf-defined-behavior #[stable(feature = "ip", since = "1.48.0")] #[rustc_const_unstable(feature = "const_ipv4", issue = "76205")] pub const fn is_ietf_protocol_assignment(&self) -> bool { @@ -731,9 +794,9 @@ impl Ipv4Addr { /// # Stability guarantees /// /// This method's behavior [may by subject to changes][changes] in the - /// future, as new RFCs are published. + /// future, as new IETF RFCs are published. /// - /// [changes]: ../net/index.html#stability-guarantees-for-ietf-defined-behavior + /// [changes]: super#stability-guarantees-for-ietf-defined-behavior #[stable(feature = "ip", since = "1.48.0")] #[rustc_const_unstable(feature = "const_ipv4", issue = "76205")] pub const fn is_benchmarking(&self) -> bool { @@ -770,9 +833,9 @@ impl Ipv4Addr { /// # Stability guarantees /// /// This method's behavior [may by subject to changes][changes] in the - /// future, as new RFCs are published. + /// future, as new IETF RFCs are published. /// - /// [changes]: ../net/index.html#stability-guarantees-for-ietf-defined-behavior + /// [changes]: super#stability-guarantees-for-ietf-defined-behavior #[stable(feature = "ip", since = "1.48.0")] #[rustc_const_unstable(feature = "const_ipv4", issue = "76205")] pub const fn is_reserved(&self) -> bool { @@ -795,7 +858,14 @@ impl Ipv4Addr { /// assert_eq!(Ipv4Addr::new(236, 168, 10, 65).is_multicast(), true); /// assert_eq!(Ipv4Addr::new(172, 16, 10, 65).is_multicast(), false); /// ``` - #[rustc_const_stable(feature = "const_ipv4", since = "1.50.0")] + /// + /// # Stability guarantees + /// + /// This method's behavior [may by subject to changes][changes] in the + /// future, as new IETF RFCs are published. + /// + /// [changes]: super#stability-guarantees-for-ietf-defined-behavior + #[rustc_const_unstable(feature = "const_ipv4", issue = "76205")] #[stable(since = "1.7.0", feature = "ip_17")] #[inline] pub const fn is_multicast(&self) -> bool { @@ -816,7 +886,14 @@ impl Ipv4Addr { /// assert_eq!(Ipv4Addr::new(255, 255, 255, 255).is_broadcast(), true); /// assert_eq!(Ipv4Addr::new(236, 168, 10, 65).is_broadcast(), false); /// ``` - #[rustc_const_stable(feature = "const_ipv4", since = "1.50.0")] + /// + /// # Stability guarantees + /// + /// This method's behavior [may by subject to changes][changes] in the + /// future, as new IETF RFCs are published. + /// + /// [changes]: super#stability-guarantees-for-ietf-defined-behavior + #[rustc_const_unstable(feature = "const_ipv4", issue = "76205")] #[stable(since = "1.7.0", feature = "ip_17")] #[inline] pub const fn is_broadcast(&self) -> bool { @@ -843,7 +920,14 @@ impl Ipv4Addr { /// assert_eq!(Ipv4Addr::new(203, 0, 113, 6).is_documentation(), true); /// assert_eq!(Ipv4Addr::new(193, 34, 17, 19).is_documentation(), false); /// ``` - #[rustc_const_stable(feature = "const_ipv4", since = "1.50.0")] + /// + /// # Stability guarantees + /// + /// This method's behavior [may by subject to changes][changes] in the + /// future, as new IETF RFCs are published. + /// + /// [changes]: super#stability-guarantees-for-ietf-defined-behavior + #[rustc_const_unstable(feature = "const_ipv4", issue = "76205")] #[stable(since = "1.7.0", feature = "ip_17")] #[inline] pub const fn is_documentation(&self) -> bool { @@ -874,7 +958,14 @@ impl Ipv4Addr { /// Ipv6Addr::new(0, 0, 0, 0, 0, 0, 49152, 767) /// ); /// ``` - #[rustc_const_stable(feature = "const_ipv4", since = "1.50.0")] + /// + /// # Stability guarantees + /// + /// This method's behavior [may by subject to changes][changes] in the + /// future, as new IETF RFCs are published. + /// + /// [changes]: super#stability-guarantees-for-ietf-defined-behavior + #[rustc_const_unstable(feature = "const_ipv4", issue = "76205")] #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub const fn to_ipv6_compatible(&self) -> Ipv6Addr { @@ -898,7 +989,14 @@ impl Ipv4Addr { /// assert_eq!(Ipv4Addr::new(192, 0, 2, 255).to_ipv6_mapped(), /// Ipv6Addr::new(0, 0, 0, 0, 0, 65535, 49152, 767)); /// ``` - #[rustc_const_stable(feature = "const_ipv4", since = "1.50.0")] + /// + /// # Stability guarantees + /// + /// This method's behavior [may by subject to changes][changes] in the + /// future, as new IETF RFCs are published. + /// + /// [changes]: super#stability-guarantees-for-ietf-defined-behavior + #[rustc_const_unstable(feature = "const_ipv4", issue = "76205")] #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub const fn to_ipv6_mapped(&self) -> Ipv6Addr { @@ -1246,8 +1344,14 @@ impl Ipv6Addr { /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff).segments(), /// [0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff]); /// ``` - #[rustc_allow_const_fn_unstable(const_fn_transmute)] - #[rustc_const_stable(feature = "const_ipv6", since = "1.50.0")] + /// + /// # Stability guarantees + /// + /// This method's behavior [may by subject to changes][changes] in the + /// future, as new IETF RFCs are published. + /// + /// [changes]: super#stability-guarantees-for-ietf-defined-behavior + #[rustc_const_unstable(feature = "const_ipv6", issue = "76205")] #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub const fn segments(&self) -> [u16; 8] { @@ -1283,7 +1387,14 @@ impl Ipv6Addr { /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff).is_unspecified(), false); /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0).is_unspecified(), true); /// ``` - #[rustc_const_stable(feature = "const_ipv6", since = "1.50.0")] + /// + /// # Stability guarantees + /// + /// This method's behavior [may by subject to changes][changes] in the + /// future, as new IETF RFCs are published. + /// + /// [changes]: super#stability-guarantees-for-ietf-defined-behavior + #[rustc_const_unstable(feature = "const_ipv6", issue = "76205")] #[stable(since = "1.7.0", feature = "ip_17")] #[inline] pub const fn is_unspecified(&self) -> bool { @@ -1305,7 +1416,14 @@ impl Ipv6Addr { /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff).is_loopback(), false); /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0x1).is_loopback(), true); /// ``` - #[rustc_const_stable(feature = "const_ipv6", since = "1.50.0")] + /// + /// # Stability guarantees + /// + /// This method's behavior [may by subject to changes][changes] in the + /// future, as new IETF RFCs are published. + /// + /// [changes]: super#stability-guarantees-for-ietf-defined-behavior + #[rustc_const_unstable(feature = "const_ipv6", issue = "76205")] #[stable(since = "1.7.0", feature = "ip_17")] #[inline] pub const fn is_loopback(&self) -> bool { @@ -1334,9 +1452,9 @@ impl Ipv6Addr { /// # Stability guarantees /// /// This method's behavior [may by subject to changes][changes] in the - /// future, as new RFCs are published. + /// future, as new IETF RFCs are published. /// - /// [changes]: ../net/index.html#stability-guarantees-for-ietf-defined-behavior + /// [changes]: super#stability-guarantees-for-ietf-defined-behavior #[stable(feature = "ip", since = "1.48.0")] #[rustc_const_unstable(feature = "const_ipv6", issue = "76205")] pub const fn is_global(&self) -> bool { @@ -1365,9 +1483,9 @@ impl Ipv6Addr { /// # Stability guarantees /// /// This method's behavior [may by subject to changes][changes] in the - /// future, as new RFCs are published. + /// future, as new IETF RFCs are published. /// - /// [changes]: ../net/index.html#stability-guarantees-for-ietf-defined-behavior + /// [changes]: super#stability-guarantees-for-ietf-defined-behavior #[stable(feature = "ip", since = "1.48.0")] #[rustc_const_unstable(feature = "const_ipv6", issue = "76205")] pub const fn is_unique_local(&self) -> bool { @@ -1420,9 +1538,9 @@ impl Ipv6Addr { /// # Stability guarantees /// /// This method's behavior [may by subject to changes][changes] in the - /// future, as new RFCs are published. + /// future, as new IETF RFCs are published. /// - /// [changes]: ../net/index.html#stability-guarantees-for-ietf-defined-behavior + /// [changes]: super#stability-guarantees-for-ietf-defined-behavior #[stable(feature = "ip", since = "1.48.0")] #[rustc_const_unstable(feature = "const_ipv6", issue = "76205")] pub const fn is_unicast_link_local(&self) -> bool { @@ -1466,9 +1584,9 @@ impl Ipv6Addr { /// # Stability guarantees /// /// This method's behavior [may by subject to changes][changes] in the - /// future, as new RFCs are published. + /// future, as new IETF RFCs are published. /// - /// [changes]: ../net/index.html#stability-guarantees-for-ietf-defined-behavior + /// [changes]: super#stability-guarantees-for-ietf-defined-behavior #[stable(feature = "ip", since = "1.48.0")] #[rustc_const_unstable(feature = "const_ipv6", issue = "76205")] pub const fn is_unicast_site_local(&self) -> bool { @@ -1494,9 +1612,9 @@ impl Ipv6Addr { /// # Stability guarantees /// /// This method's behavior [may by subject to changes][changes] in the - /// future, as new RFCs are published. + /// future, as new IETF RFCs are published. /// - /// [changes]: ../net/index.html#stability-guarantees-for-ietf-defined-behavior + /// [changes]: super#stability-guarantees-for-ietf-defined-behavior #[stable(feature = "ip", since = "1.48.0")] #[rustc_const_unstable(feature = "const_ipv6", issue = "76205")] pub const fn is_documentation(&self) -> bool { @@ -1536,9 +1654,9 @@ impl Ipv6Addr { /// # Stability guarantees /// /// This method's behavior [may by subject to changes][changes] in the - /// future, as new RFCs are published. + /// future, as new IETF RFCs are published. /// - /// [changes]: ../net/index.html#stability-guarantees-for-ietf-defined-behavior + /// [changes]: super#stability-guarantees-for-ietf-defined-behavior #[stable(feature = "ip", since = "1.48.0")] #[rustc_const_unstable(feature = "const_ipv6", issue = "76205")] pub const fn is_unicast_global(&self) -> bool { @@ -1567,9 +1685,9 @@ impl Ipv6Addr { /// # Stability guarantees /// /// This method's behavior [may by subject to changes][changes] in the - /// future, as new RFCs are published. + /// future, as new IETF RFCs are published. /// - /// [changes]: ../net/index.html#stability-guarantees-for-ietf-defined-behavior + /// [changes]: super#stability-guarantees-for-ietf-defined-behavior #[stable(feature = "ip", since = "1.48.0")] #[rustc_const_unstable(feature = "const_ipv6", issue = "76205")] pub const fn multicast_scope(&self) -> Option { @@ -1607,7 +1725,14 @@ impl Ipv6Addr { /// assert_eq!(Ipv6Addr::new(0xff00, 0, 0, 0, 0, 0, 0, 0).is_multicast(), true); /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff).is_multicast(), false); /// ``` - #[rustc_const_stable(feature = "const_ipv6", since = "1.50.0")] + /// + /// # Stability guarantees + /// + /// This method's behavior [may by subject to changes][changes] in the + /// future, as new IETF RFCs are published. + /// + /// [changes]: super#stability-guarantees-for-ietf-defined-behavior + #[rustc_const_unstable(feature = "const_ipv6", issue = "76205")] #[stable(since = "1.7.0", feature = "ip_17")] #[inline] pub const fn is_multicast(&self) -> bool { From f469444bc81784080628aaf18f184e4cd17e2778 Mon Sep 17 00:00:00 2001 From: Cass Fridkin Date: Sat, 6 Feb 2021 15:08:52 -0500 Subject: [PATCH 22/24] stop treating `::ffff:0.0.0.0` as unspecified https://github.com/rust-lang/rust/pull/76098#discussion_r558679462 --- library/std/src/net/ip.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/library/std/src/net/ip.rs b/library/std/src/net/ip.rs index ef76b2cfe6224..6bb093f57b05a 100644 --- a/library/std/src/net/ip.rs +++ b/library/std/src/net/ip.rs @@ -1399,7 +1399,6 @@ impl Ipv6Addr { #[inline] pub const fn is_unspecified(&self) -> bool { u128::from_be_bytes(self.octets()) == u128::from_be_bytes(Ipv6Addr::UNSPECIFIED.octets()) - || if let Some(v4_addr) = self.to_ipv4() { v4_addr.is_unspecified() } else { false } } /// Returns [`true`] if this is a loopback address (::1). From 240a913a8f2cdf2cb49f06d880f49505b287be39 Mon Sep 17 00:00:00 2001 From: Cass Fridkin Date: Sun, 28 Feb 2021 10:46:08 -0500 Subject: [PATCH 23/24] wow i hope i didn't mess something up just did a really big rebase and i'm slightly concerned that i somehow tanked this whole branch but i guess we'll see --- library/std/src/net/ip.rs | 5 ----- 1 file changed, 5 deletions(-) diff --git a/library/std/src/net/ip.rs b/library/std/src/net/ip.rs index 6bb093f57b05a..a2800aa710fed 100644 --- a/library/std/src/net/ip.rs +++ b/library/std/src/net/ip.rs @@ -128,7 +128,6 @@ pub struct Ipv6Addr { #[derive(Copy, PartialEq, Eq, Clone, Hash, Debug)] #[stable(feature = "ip", since = "1.48.0")] #[non_exhaustive] -#[stable(feature = "ip", since = "1.47.0")] pub enum Ipv6MulticastScope { /// Interface-Local scope. See [RFC 4291] and [RFC 7346] /// @@ -1690,10 +1689,6 @@ impl Ipv6Addr { #[stable(feature = "ip", since = "1.48.0")] #[rustc_const_unstable(feature = "const_ipv6", issue = "76205")] pub const fn multicast_scope(&self) -> Option { - use crate::net::Ipv6MulticastScope::{ - AdminLocal, Global, InterfaceLocal, LinkLocal, OrganizationLocal, RealmLocal, Reserved, - SiteLocal, Unassigned, - }; if self.is_multicast() { match self.segments()[0] & 0x000f { 1 => Some(Ipv6MulticastScope::InterfaceLocal), From 6c42f4a91fbb1e4deaeafd11cbeaf3003b1f7407 Mon Sep 17 00:00:00 2001 From: Ben Kimock Date: Sat, 22 May 2021 13:04:58 -0400 Subject: [PATCH 24/24] Fix tests * Move libstd ip tests to their own module * Delete failing test; mapped addresses are never unspecified --- library/std/src/net/ip/tests.rs | 2 - src/libstd/net/ip.rs | 883 -------------------------------- src/libstd/net/mod.rs | 2 +- src/libstd/net/tests.rs | 823 +++++++++++++++++++++++++++++ 4 files changed, 824 insertions(+), 886 deletions(-) create mode 100644 src/libstd/net/tests.rs diff --git a/library/std/src/net/ip/tests.rs b/library/std/src/net/ip/tests.rs index b51d7f4858b6e..5e194d97c2d43 100644 --- a/library/std/src/net/ip/tests.rs +++ b/library/std/src/net/ip/tests.rs @@ -707,11 +707,9 @@ fn ipv4_mapped() { // and that IPv4-compatible addresses are treated as standard IPv6 addresses let v4_unspecified = Ipv4Addr::new(0, 0, 0, 0); - let mapped_unspecified = v4_unspecified.to_ipv6_mapped(); let compatible_unspecified = v4_unspecified.to_ipv6_compatible(); assert!(v4_unspecified.is_unspecified()); - assert!(mapped_unspecified.is_unspecified()); // this one just happens to meet the criteria, but not because it is treated specially! assert!(compatible_unspecified.is_unspecified()); diff --git a/src/libstd/net/ip.rs b/src/libstd/net/ip.rs index 6a4ea4ec4f6ec..3843401e48020 100644 --- a/src/libstd/net/ip.rs +++ b/src/libstd/net/ip.rs @@ -2087,886 +2087,3 @@ impl From<[u16; 8]> for IpAddr { IpAddr::V6(Ipv6Addr::from(segments)) } } - -// Tests for this module -#[cfg(all(test, not(target_os = "emscripten")))] -mod tests { - use crate::net::test::{sa4, sa6, tsa}; - use crate::net::*; - use crate::str::FromStr; - - #[test] - fn test_from_str_ipv4() { - assert_eq!(Ok(Ipv4Addr::new(127, 0, 0, 1)), "127.0.0.1".parse()); - assert_eq!(Ok(Ipv4Addr::new(255, 255, 255, 255)), "255.255.255.255".parse()); - assert_eq!(Ok(Ipv4Addr::new(0, 0, 0, 0)), "0.0.0.0".parse()); - - // out of range - let none: Option = "256.0.0.1".parse().ok(); - assert_eq!(None, none); - // too short - let none: Option = "255.0.0".parse().ok(); - assert_eq!(None, none); - // too long - let none: Option = "255.0.0.1.2".parse().ok(); - assert_eq!(None, none); - // no number between dots - let none: Option = "255.0..1".parse().ok(); - assert_eq!(None, none); - } - - #[test] - fn test_from_str_ipv6() { - assert_eq!(Ok(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0)), "0:0:0:0:0:0:0:0".parse()); - assert_eq!(Ok(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1)), "0:0:0:0:0:0:0:1".parse()); - - assert_eq!(Ok(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1)), "::1".parse()); - assert_eq!(Ok(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0)), "::".parse()); - - assert_eq!( - Ok(Ipv6Addr::new(0x2a02, 0x6b8, 0, 0, 0, 0, 0x11, 0x11)), - "2a02:6b8::11:11".parse() - ); - - // too long group - let none: Option = "::00000".parse().ok(); - assert_eq!(None, none); - // too short - let none: Option = "1:2:3:4:5:6:7".parse().ok(); - assert_eq!(None, none); - // too long - let none: Option = "1:2:3:4:5:6:7:8:9".parse().ok(); - assert_eq!(None, none); - // triple colon - let none: Option = "1:2:::6:7:8".parse().ok(); - assert_eq!(None, none); - // two double colons - let none: Option = "1:2::6::8".parse().ok(); - assert_eq!(None, none); - // `::` indicating zero groups of zeros - let none: Option = "1:2:3:4::5:6:7:8".parse().ok(); - assert_eq!(None, none); - } - - #[test] - fn test_from_str_ipv4_in_ipv6() { - assert_eq!(Ok(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 49152, 545)), "::192.0.2.33".parse()); - assert_eq!( - Ok(Ipv6Addr::new(0, 0, 0, 0, 0, 0xFFFF, 49152, 545)), - "::FFFF:192.0.2.33".parse() - ); - assert_eq!( - Ok(Ipv6Addr::new(0x64, 0xff9b, 0, 0, 0, 0, 49152, 545)), - "64:ff9b::192.0.2.33".parse() - ); - assert_eq!( - Ok(Ipv6Addr::new(0x2001, 0xdb8, 0x122, 0xc000, 0x2, 0x2100, 49152, 545)), - "2001:db8:122:c000:2:2100:192.0.2.33".parse() - ); - - // colon after v4 - let none: Option = "::127.0.0.1:".parse().ok(); - assert_eq!(None, none); - // not enough groups - let none: Option = "1.2.3.4.5:127.0.0.1".parse().ok(); - assert_eq!(None, none); - // too many groups - let none: Option = "1.2.3.4.5:6:7:127.0.0.1".parse().ok(); - assert_eq!(None, none); - } - - #[test] - fn test_from_str_socket_addr() { - assert_eq!(Ok(sa4(Ipv4Addr::new(77, 88, 21, 11), 80)), "77.88.21.11:80".parse()); - assert_eq!( - Ok(SocketAddrV4::new(Ipv4Addr::new(77, 88, 21, 11), 80)), - "77.88.21.11:80".parse() - ); - assert_eq!( - Ok(sa6(Ipv6Addr::new(0x2a02, 0x6b8, 0, 1, 0, 0, 0, 1), 53)), - "[2a02:6b8:0:1::1]:53".parse() - ); - assert_eq!( - Ok(SocketAddrV6::new(Ipv6Addr::new(0x2a02, 0x6b8, 0, 1, 0, 0, 0, 1), 53, 0, 0)), - "[2a02:6b8:0:1::1]:53".parse() - ); - assert_eq!( - Ok(sa6(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0x7F00, 1), 22)), - "[::127.0.0.1]:22".parse() - ); - assert_eq!( - Ok(SocketAddrV6::new(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0x7F00, 1), 22, 0, 0)), - "[::127.0.0.1]:22".parse() - ); - - // without port - let none: Option = "127.0.0.1".parse().ok(); - assert_eq!(None, none); - // without port - let none: Option = "127.0.0.1:".parse().ok(); - assert_eq!(None, none); - // wrong brackets around v4 - let none: Option = "[127.0.0.1]:22".parse().ok(); - assert_eq!(None, none); - // port out of range - let none: Option = "127.0.0.1:123456".parse().ok(); - assert_eq!(None, none); - } - - #[test] - fn ipv4_addr_to_string() { - // Short address - assert_eq!(Ipv4Addr::new(1, 1, 1, 1).to_string(), "1.1.1.1"); - // Long address - assert_eq!(Ipv4Addr::new(127, 127, 127, 127).to_string(), "127.127.127.127"); - - // Test padding - assert_eq!(&format!("{:16}", Ipv4Addr::new(1, 1, 1, 1)), "1.1.1.1 "); - assert_eq!(&format!("{:>16}", Ipv4Addr::new(1, 1, 1, 1)), " 1.1.1.1"); - } - - #[test] - fn ipv6_addr_to_string() { - // ipv4-mapped address - let a1 = Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc000, 0x280); - assert_eq!(a1.to_string(), "::ffff:192.0.2.128"); - - // ipv4-compatible address - let a1 = Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0xc000, 0x280); - assert_eq!(a1.to_string(), "::192.0.2.128"); - - // v6 address with no zero segments - assert_eq!(Ipv6Addr::new(8, 9, 10, 11, 12, 13, 14, 15).to_string(), "8:9:a:b:c:d:e:f"); - - // longest possible IPv6 length - assert_eq!( - Ipv6Addr::new(0x1111, 0x2222, 0x3333, 0x4444, 0x5555, 0x6666, 0x7777, 0x8888) - .to_string(), - "1111:2222:3333:4444:5555:6666:7777:8888" - ); - // padding - assert_eq!( - &format!("{:20}", Ipv6Addr::new(1, 2, 3, 4, 5, 6, 7, 8)), - "1:2:3:4:5:6:7:8 " - ); - assert_eq!( - &format!("{:>20}", Ipv6Addr::new(1, 2, 3, 4, 5, 6, 7, 8)), - " 1:2:3:4:5:6:7:8" - ); - - // reduce a single run of zeros - assert_eq!( - "ae::ffff:102:304", - Ipv6Addr::new(0xae, 0, 0, 0, 0, 0xffff, 0x0102, 0x0304).to_string() - ); - - // don't reduce just a single zero segment - assert_eq!("1:2:3:4:5:6:0:8", Ipv6Addr::new(1, 2, 3, 4, 5, 6, 0, 8).to_string()); - - // 'any' address - assert_eq!("::", Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0).to_string()); - - // loopback address - assert_eq!("::1", Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1).to_string()); - - // ends in zeros - assert_eq!("1::", Ipv6Addr::new(1, 0, 0, 0, 0, 0, 0, 0).to_string()); - - // two runs of zeros, second one is longer - assert_eq!("1:0:0:4::8", Ipv6Addr::new(1, 0, 0, 4, 0, 0, 0, 8).to_string()); - - // two runs of zeros, equal length - assert_eq!("1::4:5:0:0:8", Ipv6Addr::new(1, 0, 0, 4, 5, 0, 0, 8).to_string()); - } - - #[test] - fn ipv4_to_ipv6() { - assert_eq!( - Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0x1234, 0x5678), - Ipv4Addr::new(0x12, 0x34, 0x56, 0x78).to_ipv6_mapped() - ); - assert_eq!( - Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0x1234, 0x5678), - Ipv4Addr::new(0x12, 0x34, 0x56, 0x78).to_ipv6_compatible() - ); - } - - #[test] - fn ipv6_to_ipv4() { - assert_eq!( - Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0x1234, 0x5678).to_ipv4(), - Some(Ipv4Addr::new(0x12, 0x34, 0x56, 0x78)) - ); - assert_eq!( - Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0x1234, 0x5678).to_ipv4(), - Some(Ipv4Addr::new(0x12, 0x34, 0x56, 0x78)) - ); - assert_eq!(Ipv6Addr::new(0, 0, 1, 0, 0, 0, 0x1234, 0x5678).to_ipv4(), None); - } - - #[test] - fn ip_properties() { - macro_rules! ip { - ($s:expr) => { - IpAddr::from_str($s).unwrap() - }; - } - - macro_rules! check { - ($s:expr) => { - check!($s, 0); - }; - - ($s:expr, $mask:expr) => {{ - let unspec: u8 = 1 << 0; - let loopback: u8 = 1 << 1; - let global: u8 = 1 << 2; - let multicast: u8 = 1 << 3; - let doc: u8 = 1 << 4; - - if ($mask & unspec) == unspec { - assert!(ip!($s).is_unspecified()); - } else { - assert!(!ip!($s).is_unspecified()); - } - - if ($mask & loopback) == loopback { - assert!(ip!($s).is_loopback()); - } else { - assert!(!ip!($s).is_loopback()); - } - - if ($mask & global) == global { - assert!(ip!($s).is_global()); - } else { - assert!(!ip!($s).is_global()); - } - - if ($mask & multicast) == multicast { - assert!(ip!($s).is_multicast()); - } else { - assert!(!ip!($s).is_multicast()); - } - - if ($mask & doc) == doc { - assert!(ip!($s).is_documentation()); - } else { - assert!(!ip!($s).is_documentation()); - } - }}; - } - - let unspec: u8 = 1 << 0; - let loopback: u8 = 1 << 1; - let global: u8 = 1 << 2; - let multicast: u8 = 1 << 3; - let doc: u8 = 1 << 4; - - check!("0.0.0.0", unspec); - check!("0.0.0.1"); - check!("0.1.0.0"); - check!("10.9.8.7"); - check!("127.1.2.3", loopback); - check!("172.31.254.253"); - check!("169.254.253.242"); - check!("192.0.2.183", doc); - check!("192.1.2.183", global); - check!("192.168.254.253"); - check!("198.51.100.0", doc); - check!("203.0.113.0", doc); - check!("203.2.113.0", global); - check!("224.0.0.0", global | multicast); - check!("239.255.255.255", global | multicast); - check!("255.255.255.255"); - // make sure benchmarking addresses are not global - check!("198.18.0.0"); - check!("198.18.54.2"); - check!("198.19.255.255"); - // make sure addresses reserved for protocol assignment are not global - check!("192.0.0.0"); - check!("192.0.0.255"); - check!("192.0.0.100"); - // make sure reserved addresses are not global - check!("240.0.0.0"); - check!("251.54.1.76"); - check!("254.255.255.255"); - // make sure shared addresses are not global - check!("100.64.0.0"); - check!("100.127.255.255"); - check!("100.100.100.0"); - - check!("::", unspec); - check!("::1", loopback); - check!("::0.0.0.2", global); - check!("1::", global); - check!("fc00::"); - check!("fdff:ffff::"); - check!("fe80:ffff::"); - check!("febf:ffff::"); - check!("fec0::", global); - check!("ff01::", multicast); - check!("ff02::", multicast); - check!("ff03::", multicast); - check!("ff04::", multicast); - check!("ff05::", multicast); - check!("ff08::", multicast); - check!("ff0e::", global | multicast); - check!("2001:db8:85a3::8a2e:370:7334", doc); - check!("102:304:506:708:90a:b0c:d0e:f10", global); - } - - #[test] - fn ipv4_properties() { - macro_rules! ip { - ($s:expr) => { - Ipv4Addr::from_str($s).unwrap() - }; - } - - macro_rules! check { - ($s:expr) => { - check!($s, 0); - }; - - ($s:expr, $mask:expr) => {{ - let unspec: u16 = 1 << 0; - let loopback: u16 = 1 << 1; - let private: u16 = 1 << 2; - let link_local: u16 = 1 << 3; - let global: u16 = 1 << 4; - let multicast: u16 = 1 << 5; - let broadcast: u16 = 1 << 6; - let documentation: u16 = 1 << 7; - let benchmarking: u16 = 1 << 8; - let ietf_protocol_assignment: u16 = 1 << 9; - let reserved: u16 = 1 << 10; - let shared: u16 = 1 << 11; - - if ($mask & unspec) == unspec { - assert!(ip!($s).is_unspecified()); - } else { - assert!(!ip!($s).is_unspecified()); - } - - if ($mask & loopback) == loopback { - assert!(ip!($s).is_loopback()); - } else { - assert!(!ip!($s).is_loopback()); - } - - if ($mask & private) == private { - assert!(ip!($s).is_private()); - } else { - assert!(!ip!($s).is_private()); - } - - if ($mask & link_local) == link_local { - assert!(ip!($s).is_link_local()); - } else { - assert!(!ip!($s).is_link_local()); - } - - if ($mask & global) == global { - assert!(ip!($s).is_global()); - } else { - assert!(!ip!($s).is_global()); - } - - if ($mask & multicast) == multicast { - assert!(ip!($s).is_multicast()); - } else { - assert!(!ip!($s).is_multicast()); - } - - if ($mask & broadcast) == broadcast { - assert!(ip!($s).is_broadcast()); - } else { - assert!(!ip!($s).is_broadcast()); - } - - if ($mask & documentation) == documentation { - assert!(ip!($s).is_documentation()); - } else { - assert!(!ip!($s).is_documentation()); - } - - if ($mask & benchmarking) == benchmarking { - assert!(ip!($s).is_benchmarking()); - } else { - assert!(!ip!($s).is_benchmarking()); - } - - if ($mask & ietf_protocol_assignment) == ietf_protocol_assignment { - assert!(ip!($s).is_ietf_protocol_assignment()); - } else { - assert!(!ip!($s).is_ietf_protocol_assignment()); - } - - if ($mask & reserved) == reserved { - assert!(ip!($s).is_reserved()); - } else { - assert!(!ip!($s).is_reserved()); - } - - if ($mask & shared) == shared { - assert!(ip!($s).is_shared()); - } else { - assert!(!ip!($s).is_shared()); - } - }}; - } - - let unspec: u16 = 1 << 0; - let loopback: u16 = 1 << 1; - let private: u16 = 1 << 2; - let link_local: u16 = 1 << 3; - let global: u16 = 1 << 4; - let multicast: u16 = 1 << 5; - let broadcast: u16 = 1 << 6; - let documentation: u16 = 1 << 7; - let benchmarking: u16 = 1 << 8; - let ietf_protocol_assignment: u16 = 1 << 9; - let reserved: u16 = 1 << 10; - let shared: u16 = 1 << 11; - - check!("0.0.0.0", unspec); - check!("0.0.0.1"); - check!("0.1.0.0"); - check!("10.9.8.7", private); - check!("127.1.2.3", loopback); - check!("172.31.254.253", private); - check!("169.254.253.242", link_local); - check!("192.0.2.183", documentation); - check!("192.1.2.183", global); - check!("192.168.254.253", private); - check!("198.51.100.0", documentation); - check!("203.0.113.0", documentation); - check!("203.2.113.0", global); - check!("224.0.0.0", global | multicast); - check!("239.255.255.255", global | multicast); - check!("255.255.255.255", broadcast); - check!("198.18.0.0", benchmarking); - check!("198.18.54.2", benchmarking); - check!("198.19.255.255", benchmarking); - check!("192.0.0.0", ietf_protocol_assignment); - check!("192.0.0.255", ietf_protocol_assignment); - check!("192.0.0.100", ietf_protocol_assignment); - check!("240.0.0.0", reserved); - check!("251.54.1.76", reserved); - check!("254.255.255.255", reserved); - check!("100.64.0.0", shared); - check!("100.127.255.255", shared); - check!("100.100.100.0", shared); - } - - #[test] - fn ipv6_properties() { - macro_rules! ip { - ($s:expr) => { - Ipv6Addr::from_str($s).unwrap() - }; - } - - macro_rules! check { - ($s:expr, &[$($octet:expr),*], $mask:expr) => { - assert_eq!($s, ip!($s).to_string()); - let octets = &[$($octet),*]; - assert_eq!(&ip!($s).octets(), octets); - assert_eq!(Ipv6Addr::from(*octets), ip!($s)); - - let unspecified: u32 = 1 << 0; - let loopback: u32 = 1 << 1; - let unique_local: u32 = 1 << 2; - let global: u32 = 1 << 3; - let unicast_link_local: u32 = 1 << 4; - let unicast_link_local_strict: u32 = 1 << 5; - let unicast_site_local: u32 = 1 << 6; - let unicast_global: u32 = 1 << 7; - let documentation: u32 = 1 << 8; - let multicast_interface_local: u32 = 1 << 9; - let multicast_link_local: u32 = 1 << 10; - let multicast_realm_local: u32 = 1 << 11; - let multicast_admin_local: u32 = 1 << 12; - let multicast_site_local: u32 = 1 << 13; - let multicast_organization_local: u32 = 1 << 14; - let multicast_global: u32 = 1 << 15; - let multicast_reserved: u32 = 1 << 16; - let multicast_unassigned: u32 = 1 << 17; - let multicast: u32 = multicast_interface_local - | multicast_admin_local - | multicast_global - | multicast_link_local - | multicast_realm_local - | multicast_site_local - | multicast_organization_local - | multicast_reserved - | multicast_unassigned; - - if ($mask & unspecified) == unspecified { - assert!(ip!($s).is_unspecified()); - } else { - assert!(!ip!($s).is_unspecified()); - } - if ($mask & loopback) == loopback { - assert!(ip!($s).is_loopback()); - } else { - assert!(!ip!($s).is_loopback()); - } - if ($mask & unique_local) == unique_local { - assert!(ip!($s).is_unique_local()); - } else { - assert!(!ip!($s).is_unique_local()); - } - if ($mask & global) == global { - assert!(ip!($s).is_global()); - } else { - assert!(!ip!($s).is_global()); - } - if ($mask & unicast_link_local) == unicast_link_local { - assert!(ip!($s).is_unicast_link_local()); - } else { - assert!(!ip!($s).is_unicast_link_local()); - } - if ($mask & unicast_link_local_strict) == unicast_link_local_strict { - assert!(ip!($s).is_unicast_link_local_strict()); - } else { - assert!(!ip!($s).is_unicast_link_local_strict()); - } - if ($mask & unicast_site_local) == unicast_site_local { - assert!(ip!($s).is_unicast_site_local()); - } else { - assert!(!ip!($s).is_unicast_site_local()); - } - if ($mask & unicast_global) == unicast_global { - assert!(ip!($s).is_unicast_global()); - } else { - assert!(!ip!($s).is_unicast_global()); - } - if ($mask & documentation) == documentation { - assert!(ip!($s).is_documentation()); - } else { - assert!(!ip!($s).is_documentation()); - } - if ($mask & multicast) != 0 { - assert!(ip!($s).multicast_scope().is_some()); - assert!(ip!($s).is_multicast()); - } else { - assert!(ip!($s).multicast_scope().is_none()); - assert!(!ip!($s).is_multicast()); - } - if ($mask & multicast_interface_local) == multicast_interface_local { - assert_eq!(ip!($s).multicast_scope().unwrap(), - Ipv6MulticastScope::InterfaceLocal); - } - if ($mask & multicast_link_local) == multicast_link_local { - assert_eq!(ip!($s).multicast_scope().unwrap(), - Ipv6MulticastScope::LinkLocal); - } - if ($mask & multicast_realm_local) == multicast_realm_local { - assert_eq!(ip!($s).multicast_scope().unwrap(), - Ipv6MulticastScope::RealmLocal); - } - if ($mask & multicast_admin_local) == multicast_admin_local { - assert_eq!(ip!($s).multicast_scope().unwrap(), - Ipv6MulticastScope::AdminLocal); - } - if ($mask & multicast_site_local) == multicast_site_local { - assert_eq!(ip!($s).multicast_scope().unwrap(), - Ipv6MulticastScope::SiteLocal); - } - if ($mask & multicast_organization_local) == multicast_organization_local { - assert_eq!(ip!($s).multicast_scope().unwrap(), - Ipv6MulticastScope::OrganizationLocal); - } - if ($mask & multicast_global) == multicast_global { - assert_eq!(ip!($s).multicast_scope().unwrap(), - Ipv6MulticastScope::Global); - } - if ($mask & multicast_reserved) == multicast_reserved { - assert_eq!(ip!($s).multicast_scope().unwrap(), - Ipv6MulticastScope::Reserved); - } - if ($mask & multicast_unassigned) == multicast_unassigned { - assert_eq!(ip!($s).multicast_scope().unwrap(), - Ipv6MulticastScope::Unassigned); - } - } - } - - let unspecified: u32 = 1 << 0; - let loopback: u32 = 1 << 1; - let unique_local: u32 = 1 << 2; - let global: u32 = 1 << 3; - let unicast_link_local: u32 = 1 << 4; - let unicast_link_local_strict: u32 = 1 << 5; - let unicast_site_local: u32 = 1 << 6; - let unicast_global: u32 = 1 << 7; - let documentation: u32 = 1 << 8; - let multicast_interface_local: u32 = 1 << 9; - let multicast_link_local: u32 = 1 << 10; - let multicast_realm_local: u32 = 1 << 11; - let multicast_admin_local: u32 = 1 << 12; - let multicast_site_local: u32 = 1 << 13; - let multicast_organization_local: u32 = 1 << 14; - let multicast_global: u32 = 1 << 15; - let multicast_reserved: u32 = 1 << 16; - let multicast_unassigned: u32 = 1 << 17; - - check!("::", &[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], unspecified); - - check!("::1", &[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1], loopback); - - check!( - "::0.0.0.2", - &[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2], - global | unicast_global - ); - - check!("1::", &[0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], global | unicast_global); - - check!("fc00::", &[0xfc, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], unique_local); - - check!( - "fdff:ffff::", - &[0xfd, 0xff, 0xff, 0xff, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], - unique_local - ); - - check!( - "fe80:ffff::", - &[0xfe, 0x80, 0xff, 0xff, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], - unicast_link_local - ); - - check!( - "fe80::", - &[0xfe, 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], - unicast_link_local | unicast_link_local_strict - ); - - check!( - "febf:ffff::", - &[0xfe, 0xbf, 0xff, 0xff, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], - unicast_link_local - ); - - check!( - "febf::", - &[0xfe, 0xbf, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], - unicast_link_local - ); - - check!( - "febf:ffff:ffff:ffff:ffff:ffff:ffff:ffff", - &[ - 0xfe, 0xbf, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff - ], - unicast_link_local - ); - - check!( - "fe80::ffff:ffff:ffff:ffff", - &[ - 0xfe, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff - ], - unicast_link_local | unicast_link_local_strict - ); - - check!( - "fe80:0:0:1::", - &[0xfe, 0x80, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0], - unicast_link_local - ); - - check!( - "fec0::", - &[0xfe, 0xc0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], - unicast_site_local | unicast_global | global - ); - - check!("ff00::", &[0xff, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], multicast_reserved); - - check!( - "ff01::", - &[0xff, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], - multicast_interface_local - ); - - check!( - "ff02::", - &[0xff, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], - multicast_link_local - ); - - check!( - "ff03::", - &[0xff, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], - multicast_realm_local - ); - - check!( - "ff04::", - &[0xff, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], - multicast_admin_local - ); - - check!( - "ff05::", - &[0xff, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], - multicast_site_local - ); - - check!( - "ff06::", - &[0xff, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], - multicast_unassigned - ); - - check!( - "ff08::", - &[0xff, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], - multicast_organization_local - ); - - check!( - "ff0a::", - &[0xff, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], - multicast_unassigned - ); - - check!( - "ff0e::", - &[0xff, 0xe, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], - multicast_global | global - ); - - check!( - "ff0f::", - &[0xff, 0xf, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], - multicast_reserved - ); - - check!( - "2001:db8:85a3::8a2e:370:7334", - &[0x20, 1, 0xd, 0xb8, 0x85, 0xa3, 0, 0, 0, 0, 0x8a, 0x2e, 3, 0x70, 0x73, 0x34], - documentation - ); - - check!( - "102:304:506:708:90a:b0c:d0e:f10", - &[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16], - global | unicast_global - ); - } - - #[test] - fn to_socket_addr_socketaddr() { - let a = sa4(Ipv4Addr::new(77, 88, 21, 11), 12345); - assert_eq!(Ok(vec![a]), tsa(a)); - } - - #[test] - fn test_ipv4_to_int() { - let a = Ipv4Addr::new(0x11, 0x22, 0x33, 0x44); - assert_eq!(u32::from(a), 0x11223344); - } - - #[test] - fn test_int_to_ipv4() { - let a = Ipv4Addr::new(0x11, 0x22, 0x33, 0x44); - assert_eq!(Ipv4Addr::from(0x11223344), a); - } - - #[test] - fn test_ipv6_to_int() { - let a = Ipv6Addr::new(0x1122, 0x3344, 0x5566, 0x7788, 0x99aa, 0xbbcc, 0xddee, 0xff11); - assert_eq!(u128::from(a), 0x112233445566778899aabbccddeeff11u128); - } - - #[test] - fn test_int_to_ipv6() { - let a = Ipv6Addr::new(0x1122, 0x3344, 0x5566, 0x7788, 0x99aa, 0xbbcc, 0xddee, 0xff11); - assert_eq!(Ipv6Addr::from(0x112233445566778899aabbccddeeff11u128), a); - } - - #[test] - fn ipv4_from_constructors() { - assert_eq!(Ipv4Addr::LOCALHOST, Ipv4Addr::new(127, 0, 0, 1)); - assert!(Ipv4Addr::LOCALHOST.is_loopback()); - assert_eq!(Ipv4Addr::UNSPECIFIED, Ipv4Addr::new(0, 0, 0, 0)); - assert!(Ipv4Addr::UNSPECIFIED.is_unspecified()); - assert_eq!(Ipv4Addr::BROADCAST, Ipv4Addr::new(255, 255, 255, 255)); - assert!(Ipv4Addr::BROADCAST.is_broadcast()); - } - - #[test] - fn ipv6_from_contructors() { - assert_eq!(Ipv6Addr::LOCALHOST, Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1)); - assert!(Ipv6Addr::LOCALHOST.is_loopback()); - assert_eq!(Ipv6Addr::UNSPECIFIED, Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0)); - assert!(Ipv6Addr::UNSPECIFIED.is_unspecified()); - } - - #[test] - fn ipv4_from_octets() { - assert_eq!(Ipv4Addr::from([127, 0, 0, 1]), Ipv4Addr::new(127, 0, 0, 1)) - } - - #[test] - fn ipv6_from_segments() { - let from_u16s = - Ipv6Addr::from([0x0011, 0x2233, 0x4455, 0x6677, 0x8899, 0xaabb, 0xccdd, 0xeeff]); - let new = Ipv6Addr::new(0x0011, 0x2233, 0x4455, 0x6677, 0x8899, 0xaabb, 0xccdd, 0xeeff); - assert_eq!(new, from_u16s); - } - - #[test] - fn ipv6_from_octets() { - let from_u16s = - Ipv6Addr::from([0x0011, 0x2233, 0x4455, 0x6677, 0x8899, 0xaabb, 0xccdd, 0xeeff]); - let from_u8s = Ipv6Addr::from([ - 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, - 0xee, 0xff, - ]); - assert_eq!(from_u16s, from_u8s); - } - - #[test] - fn cmp() { - let v41 = Ipv4Addr::new(100, 64, 3, 3); - let v42 = Ipv4Addr::new(192, 0, 2, 2); - let v61 = "2001:db8:f00::1002".parse::().unwrap(); - let v62 = "2001:db8:f00::2001".parse::().unwrap(); - assert!(v41 < v42); - assert!(v61 < v62); - - assert_eq!(v41, IpAddr::V4(v41)); - assert_eq!(v61, IpAddr::V6(v61)); - assert!(v41 != IpAddr::V4(v42)); - assert!(v61 != IpAddr::V6(v62)); - - assert!(v41 < IpAddr::V4(v42)); - assert!(v61 < IpAddr::V6(v62)); - assert!(IpAddr::V4(v41) < v42); - assert!(IpAddr::V6(v61) < v62); - - assert!(v41 < IpAddr::V6(v61)); - assert!(IpAddr::V4(v41) < v61); - } - - #[test] - fn is_v4() { - let ip = IpAddr::V4(Ipv4Addr::new(100, 64, 3, 3)); - assert!(ip.is_ipv4()); - assert!(!ip.is_ipv6()); - } - - #[test] - fn is_v6() { - let ip = IpAddr::V6(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0x1234, 0x5678)); - assert!(!ip.is_ipv4()); - assert!(ip.is_ipv6()); - } -} diff --git a/src/libstd/net/mod.rs b/src/libstd/net/mod.rs index 86060f73b014b..643b7fa9ad745 100644 --- a/src/libstd/net/mod.rs +++ b/src/libstd/net/mod.rs @@ -63,7 +63,7 @@ mod ip; mod parser; mod tcp; #[cfg(test)] -mod test; +mod tests; mod udp; /// Possible values which can be passed to the [`shutdown`] method of diff --git a/src/libstd/net/tests.rs b/src/libstd/net/tests.rs new file mode 100644 index 0000000000000..ba806f7052d6f --- /dev/null +++ b/src/libstd/net/tests.rs @@ -0,0 +1,823 @@ +use crate::net::test::{sa4, sa6, tsa}; +use crate::net::*; +use crate::str::FromStr; + +#[test] +fn test_from_str_ipv4() { + assert_eq!(Ok(Ipv4Addr::new(127, 0, 0, 1)), "127.0.0.1".parse()); + assert_eq!(Ok(Ipv4Addr::new(255, 255, 255, 255)), "255.255.255.255".parse()); + assert_eq!(Ok(Ipv4Addr::new(0, 0, 0, 0)), "0.0.0.0".parse()); + + // out of range + let none: Option = "256.0.0.1".parse().ok(); + assert_eq!(None, none); + // too short + let none: Option = "255.0.0".parse().ok(); + assert_eq!(None, none); + // too long + let none: Option = "255.0.0.1.2".parse().ok(); + assert_eq!(None, none); + // no number between dots + let none: Option = "255.0..1".parse().ok(); + assert_eq!(None, none); +} + +#[test] +fn test_from_str_ipv6() { + assert_eq!(Ok(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0)), "0:0:0:0:0:0:0:0".parse()); + assert_eq!(Ok(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1)), "0:0:0:0:0:0:0:1".parse()); + + assert_eq!(Ok(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1)), "::1".parse()); + assert_eq!(Ok(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0)), "::".parse()); + + assert_eq!(Ok(Ipv6Addr::new(0x2a02, 0x6b8, 0, 0, 0, 0, 0x11, 0x11)), "2a02:6b8::11:11".parse()); + + // too long group + let none: Option = "::00000".parse().ok(); + assert_eq!(None, none); + // too short + let none: Option = "1:2:3:4:5:6:7".parse().ok(); + assert_eq!(None, none); + // too long + let none: Option = "1:2:3:4:5:6:7:8:9".parse().ok(); + assert_eq!(None, none); + // triple colon + let none: Option = "1:2:::6:7:8".parse().ok(); + assert_eq!(None, none); + // two double colons + let none: Option = "1:2::6::8".parse().ok(); + assert_eq!(None, none); + // `::` indicating zero groups of zeros + let none: Option = "1:2:3:4::5:6:7:8".parse().ok(); + assert_eq!(None, none); +} + +#[test] +fn test_from_str_ipv4_in_ipv6() { + assert_eq!(Ok(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 49152, 545)), "::192.0.2.33".parse()); + assert_eq!(Ok(Ipv6Addr::new(0, 0, 0, 0, 0, 0xFFFF, 49152, 545)), "::FFFF:192.0.2.33".parse()); + assert_eq!( + Ok(Ipv6Addr::new(0x64, 0xff9b, 0, 0, 0, 0, 49152, 545)), + "64:ff9b::192.0.2.33".parse() + ); + assert_eq!( + Ok(Ipv6Addr::new(0x2001, 0xdb8, 0x122, 0xc000, 0x2, 0x2100, 49152, 545)), + "2001:db8:122:c000:2:2100:192.0.2.33".parse() + ); + + // colon after v4 + let none: Option = "::127.0.0.1:".parse().ok(); + assert_eq!(None, none); + // not enough groups + let none: Option = "1.2.3.4.5:127.0.0.1".parse().ok(); + assert_eq!(None, none); + // too many groups + let none: Option = "1.2.3.4.5:6:7:127.0.0.1".parse().ok(); + assert_eq!(None, none); +} + +#[test] +fn test_from_str_socket_addr() { + assert_eq!(Ok(sa4(Ipv4Addr::new(77, 88, 21, 11), 80)), "77.88.21.11:80".parse()); + assert_eq!(Ok(SocketAddrV4::new(Ipv4Addr::new(77, 88, 21, 11), 80)), "77.88.21.11:80".parse()); + assert_eq!( + Ok(sa6(Ipv6Addr::new(0x2a02, 0x6b8, 0, 1, 0, 0, 0, 1), 53)), + "[2a02:6b8:0:1::1]:53".parse() + ); + assert_eq!( + Ok(SocketAddrV6::new(Ipv6Addr::new(0x2a02, 0x6b8, 0, 1, 0, 0, 0, 1), 53, 0, 0)), + "[2a02:6b8:0:1::1]:53".parse() + ); + assert_eq!(Ok(sa6(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0x7F00, 1), 22)), "[::127.0.0.1]:22".parse()); + assert_eq!( + Ok(SocketAddrV6::new(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0x7F00, 1), 22, 0, 0)), + "[::127.0.0.1]:22".parse() + ); + + // without port + let none: Option = "127.0.0.1".parse().ok(); + assert_eq!(None, none); + // without port + let none: Option = "127.0.0.1:".parse().ok(); + assert_eq!(None, none); + // wrong brackets around v4 + let none: Option = "[127.0.0.1]:22".parse().ok(); + assert_eq!(None, none); + // port out of range + let none: Option = "127.0.0.1:123456".parse().ok(); + assert_eq!(None, none); +} + +#[test] +fn ipv4_addr_to_string() { + // Short address + assert_eq!(Ipv4Addr::new(1, 1, 1, 1).to_string(), "1.1.1.1"); + // Long address + assert_eq!(Ipv4Addr::new(127, 127, 127, 127).to_string(), "127.127.127.127"); + + // Test padding + assert_eq!(&format!("{:16}", Ipv4Addr::new(1, 1, 1, 1)), "1.1.1.1 "); + assert_eq!(&format!("{:>16}", Ipv4Addr::new(1, 1, 1, 1)), " 1.1.1.1"); +} + +#[test] +fn ipv6_addr_to_string() { + // ipv4-mapped address + let a1 = Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc000, 0x280); + assert_eq!(a1.to_string(), "::ffff:192.0.2.128"); + + // ipv4-compatible address + let a1 = Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0xc000, 0x280); + assert_eq!(a1.to_string(), "::192.0.2.128"); + + // v6 address with no zero segments + assert_eq!(Ipv6Addr::new(8, 9, 10, 11, 12, 13, 14, 15).to_string(), "8:9:a:b:c:d:e:f"); + + // longest possible IPv6 length + assert_eq!( + Ipv6Addr::new(0x1111, 0x2222, 0x3333, 0x4444, 0x5555, 0x6666, 0x7777, 0x8888).to_string(), + "1111:2222:3333:4444:5555:6666:7777:8888" + ); + // padding + assert_eq!(&format!("{:20}", Ipv6Addr::new(1, 2, 3, 4, 5, 6, 7, 8)), "1:2:3:4:5:6:7:8 "); + assert_eq!(&format!("{:>20}", Ipv6Addr::new(1, 2, 3, 4, 5, 6, 7, 8)), " 1:2:3:4:5:6:7:8"); + + // reduce a single run of zeros + assert_eq!( + "ae::ffff:102:304", + Ipv6Addr::new(0xae, 0, 0, 0, 0, 0xffff, 0x0102, 0x0304).to_string() + ); + + // don't reduce just a single zero segment + assert_eq!("1:2:3:4:5:6:0:8", Ipv6Addr::new(1, 2, 3, 4, 5, 6, 0, 8).to_string()); + + // 'any' address + assert_eq!("::", Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0).to_string()); + + // loopback address + assert_eq!("::1", Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1).to_string()); + + // ends in zeros + assert_eq!("1::", Ipv6Addr::new(1, 0, 0, 0, 0, 0, 0, 0).to_string()); + + // two runs of zeros, second one is longer + assert_eq!("1:0:0:4::8", Ipv6Addr::new(1, 0, 0, 4, 0, 0, 0, 8).to_string()); + + // two runs of zeros, equal length + assert_eq!("1::4:5:0:0:8", Ipv6Addr::new(1, 0, 0, 4, 5, 0, 0, 8).to_string()); +} + +#[test] +fn ipv4_to_ipv6() { + assert_eq!( + Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0x1234, 0x5678), + Ipv4Addr::new(0x12, 0x34, 0x56, 0x78).to_ipv6_mapped() + ); + assert_eq!( + Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0x1234, 0x5678), + Ipv4Addr::new(0x12, 0x34, 0x56, 0x78).to_ipv6_compatible() + ); +} + +#[test] +fn ipv6_to_ipv4() { + assert_eq!( + Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0x1234, 0x5678).to_ipv4(), + Some(Ipv4Addr::new(0x12, 0x34, 0x56, 0x78)) + ); + assert_eq!( + Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0x1234, 0x5678).to_ipv4(), + Some(Ipv4Addr::new(0x12, 0x34, 0x56, 0x78)) + ); + assert_eq!(Ipv6Addr::new(0, 0, 1, 0, 0, 0, 0x1234, 0x5678).to_ipv4(), None); +} + +#[test] +fn ip_properties() { + macro_rules! ip { + ($s:expr) => { + IpAddr::from_str($s).unwrap() + }; + } + + macro_rules! check { + ($s:expr) => { + check!($s, 0); + }; + + ($s:expr, $mask:expr) => {{ + let unspec: u8 = 1 << 0; + let loopback: u8 = 1 << 1; + let global: u8 = 1 << 2; + let multicast: u8 = 1 << 3; + let doc: u8 = 1 << 4; + + if ($mask & unspec) == unspec { + assert!(ip!($s).is_unspecified()); + } else { + assert!(!ip!($s).is_unspecified()); + } + + if ($mask & loopback) == loopback { + assert!(ip!($s).is_loopback()); + } else { + assert!(!ip!($s).is_loopback()); + } + + if ($mask & global) == global { + assert!(ip!($s).is_global()); + } else { + assert!(!ip!($s).is_global()); + } + + if ($mask & multicast) == multicast { + assert!(ip!($s).is_multicast()); + } else { + assert!(!ip!($s).is_multicast()); + } + + if ($mask & doc) == doc { + assert!(ip!($s).is_documentation()); + } else { + assert!(!ip!($s).is_documentation()); + } + }}; + } + + let unspec: u8 = 1 << 0; + let loopback: u8 = 1 << 1; + let global: u8 = 1 << 2; + let multicast: u8 = 1 << 3; + let doc: u8 = 1 << 4; + + check!("0.0.0.0", unspec); + check!("0.0.0.1"); + check!("0.1.0.0"); + check!("10.9.8.7"); + check!("127.1.2.3", loopback); + check!("172.31.254.253"); + check!("169.254.253.242"); + check!("192.0.2.183", doc); + check!("192.1.2.183", global); + check!("192.168.254.253"); + check!("198.51.100.0", doc); + check!("203.0.113.0", doc); + check!("203.2.113.0", global); + check!("224.0.0.0", global | multicast); + check!("239.255.255.255", global | multicast); + check!("255.255.255.255"); + // make sure benchmarking addresses are not global + check!("198.18.0.0"); + check!("198.18.54.2"); + check!("198.19.255.255"); + // make sure addresses reserved for protocol assignment are not global + check!("192.0.0.0"); + check!("192.0.0.255"); + check!("192.0.0.100"); + // make sure reserved addresses are not global + check!("240.0.0.0"); + check!("251.54.1.76"); + check!("254.255.255.255"); + // make sure shared addresses are not global + check!("100.64.0.0"); + check!("100.127.255.255"); + check!("100.100.100.0"); + + check!("::", unspec); + check!("::1", loopback); + check!("::0.0.0.2", global); + check!("1::", global); + check!("fc00::"); + check!("fdff:ffff::"); + check!("fe80:ffff::"); + check!("febf:ffff::"); + check!("fec0::", global); + check!("ff01::", multicast); + check!("ff02::", multicast); + check!("ff03::", multicast); + check!("ff04::", multicast); + check!("ff05::", multicast); + check!("ff08::", multicast); + check!("ff0e::", global | multicast); + check!("2001:db8:85a3::8a2e:370:7334", doc); + check!("102:304:506:708:90a:b0c:d0e:f10", global); +} + +#[test] +fn ipv4_properties() { + macro_rules! ip { + ($s:expr) => { + Ipv4Addr::from_str($s).unwrap() + }; + } + + macro_rules! check { + ($s:expr) => { + check!($s, 0); + }; + + ($s:expr, $mask:expr) => {{ + let unspec: u16 = 1 << 0; + let loopback: u16 = 1 << 1; + let private: u16 = 1 << 2; + let link_local: u16 = 1 << 3; + let global: u16 = 1 << 4; + let multicast: u16 = 1 << 5; + let broadcast: u16 = 1 << 6; + let documentation: u16 = 1 << 7; + let benchmarking: u16 = 1 << 8; + let ietf_protocol_assignment: u16 = 1 << 9; + let reserved: u16 = 1 << 10; + let shared: u16 = 1 << 11; + + if ($mask & unspec) == unspec { + assert!(ip!($s).is_unspecified()); + } else { + assert!(!ip!($s).is_unspecified()); + } + + if ($mask & loopback) == loopback { + assert!(ip!($s).is_loopback()); + } else { + assert!(!ip!($s).is_loopback()); + } + + if ($mask & private) == private { + assert!(ip!($s).is_private()); + } else { + assert!(!ip!($s).is_private()); + } + + if ($mask & link_local) == link_local { + assert!(ip!($s).is_link_local()); + } else { + assert!(!ip!($s).is_link_local()); + } + + if ($mask & global) == global { + assert!(ip!($s).is_global()); + } else { + assert!(!ip!($s).is_global()); + } + + if ($mask & multicast) == multicast { + assert!(ip!($s).is_multicast()); + } else { + assert!(!ip!($s).is_multicast()); + } + + if ($mask & broadcast) == broadcast { + assert!(ip!($s).is_broadcast()); + } else { + assert!(!ip!($s).is_broadcast()); + } + + if ($mask & documentation) == documentation { + assert!(ip!($s).is_documentation()); + } else { + assert!(!ip!($s).is_documentation()); + } + + if ($mask & benchmarking) == benchmarking { + assert!(ip!($s).is_benchmarking()); + } else { + assert!(!ip!($s).is_benchmarking()); + } + + if ($mask & ietf_protocol_assignment) == ietf_protocol_assignment { + assert!(ip!($s).is_ietf_protocol_assignment()); + } else { + assert!(!ip!($s).is_ietf_protocol_assignment()); + } + + if ($mask & reserved) == reserved { + assert!(ip!($s).is_reserved()); + } else { + assert!(!ip!($s).is_reserved()); + } + + if ($mask & shared) == shared { + assert!(ip!($s).is_shared()); + } else { + assert!(!ip!($s).is_shared()); + } + }}; + } + + let unspec: u16 = 1 << 0; + let loopback: u16 = 1 << 1; + let private: u16 = 1 << 2; + let link_local: u16 = 1 << 3; + let global: u16 = 1 << 4; + let multicast: u16 = 1 << 5; + let broadcast: u16 = 1 << 6; + let documentation: u16 = 1 << 7; + let benchmarking: u16 = 1 << 8; + let ietf_protocol_assignment: u16 = 1 << 9; + let reserved: u16 = 1 << 10; + let shared: u16 = 1 << 11; + + check!("0.0.0.0", unspec); + check!("0.0.0.1"); + check!("0.1.0.0"); + check!("10.9.8.7", private); + check!("127.1.2.3", loopback); + check!("172.31.254.253", private); + check!("169.254.253.242", link_local); + check!("192.0.2.183", documentation); + check!("192.1.2.183", global); + check!("192.168.254.253", private); + check!("198.51.100.0", documentation); + check!("203.0.113.0", documentation); + check!("203.2.113.0", global); + check!("224.0.0.0", global | multicast); + check!("239.255.255.255", global | multicast); + check!("255.255.255.255", broadcast); + check!("198.18.0.0", benchmarking); + check!("198.18.54.2", benchmarking); + check!("198.19.255.255", benchmarking); + check!("192.0.0.0", ietf_protocol_assignment); + check!("192.0.0.255", ietf_protocol_assignment); + check!("192.0.0.100", ietf_protocol_assignment); + check!("240.0.0.0", reserved); + check!("251.54.1.76", reserved); + check!("254.255.255.255", reserved); + check!("100.64.0.0", shared); + check!("100.127.255.255", shared); + check!("100.100.100.0", shared); +} + +#[test] +fn ipv6_properties() { + macro_rules! ip { + ($s:expr) => { + Ipv6Addr::from_str($s).unwrap() + }; + } + + macro_rules! check { + ($s:expr, &[$($octet:expr),*], $mask:expr) => { + assert_eq!($s, ip!($s).to_string()); + let octets = &[$($octet),*]; + assert_eq!(&ip!($s).octets(), octets); + assert_eq!(Ipv6Addr::from(*octets), ip!($s)); + + let unspecified: u32 = 1 << 0; + let loopback: u32 = 1 << 1; + let unique_local: u32 = 1 << 2; + let global: u32 = 1 << 3; + let unicast_link_local: u32 = 1 << 4; + let unicast_link_local_strict: u32 = 1 << 5; + let unicast_site_local: u32 = 1 << 6; + let unicast_global: u32 = 1 << 7; + let documentation: u32 = 1 << 8; + let multicast_interface_local: u32 = 1 << 9; + let multicast_link_local: u32 = 1 << 10; + let multicast_realm_local: u32 = 1 << 11; + let multicast_admin_local: u32 = 1 << 12; + let multicast_site_local: u32 = 1 << 13; + let multicast_organization_local: u32 = 1 << 14; + let multicast_global: u32 = 1 << 15; + let multicast_reserved: u32 = 1 << 16; + let multicast_unassigned: u32 = 1 << 17; + let multicast: u32 = multicast_interface_local + | multicast_admin_local + | multicast_global + | multicast_link_local + | multicast_realm_local + | multicast_site_local + | multicast_organization_local + | multicast_reserved + | multicast_unassigned; + + if ($mask & unspecified) == unspecified { + assert!(ip!($s).is_unspecified()); + } else { + assert!(!ip!($s).is_unspecified()); + } + if ($mask & loopback) == loopback { + assert!(ip!($s).is_loopback()); + } else { + assert!(!ip!($s).is_loopback()); + } + if ($mask & unique_local) == unique_local { + assert!(ip!($s).is_unique_local()); + } else { + assert!(!ip!($s).is_unique_local()); + } + if ($mask & global) == global { + assert!(ip!($s).is_global()); + } else { + assert!(!ip!($s).is_global()); + } + if ($mask & unicast_link_local) == unicast_link_local { + assert!(ip!($s).is_unicast_link_local()); + } else { + assert!(!ip!($s).is_unicast_link_local()); + } + if ($mask & unicast_link_local_strict) == unicast_link_local_strict { + assert!(ip!($s).is_unicast_link_local_strict()); + } else { + assert!(!ip!($s).is_unicast_link_local_strict()); + } + if ($mask & unicast_site_local) == unicast_site_local { + assert!(ip!($s).is_unicast_site_local()); + } else { + assert!(!ip!($s).is_unicast_site_local()); + } + if ($mask & unicast_global) == unicast_global { + assert!(ip!($s).is_unicast_global()); + } else { + assert!(!ip!($s).is_unicast_global()); + } + if ($mask & documentation) == documentation { + assert!(ip!($s).is_documentation()); + } else { + assert!(!ip!($s).is_documentation()); + } + if ($mask & multicast) != 0 { + assert!(ip!($s).multicast_scope().is_some()); + assert!(ip!($s).is_multicast()); + } else { + assert!(ip!($s).multicast_scope().is_none()); + assert!(!ip!($s).is_multicast()); + } + if ($mask & multicast_interface_local) == multicast_interface_local { + assert_eq!(ip!($s).multicast_scope().unwrap(), + Ipv6MulticastScope::InterfaceLocal); + } + if ($mask & multicast_link_local) == multicast_link_local { + assert_eq!(ip!($s).multicast_scope().unwrap(), + Ipv6MulticastScope::LinkLocal); + } + if ($mask & multicast_realm_local) == multicast_realm_local { + assert_eq!(ip!($s).multicast_scope().unwrap(), + Ipv6MulticastScope::RealmLocal); + } + if ($mask & multicast_admin_local) == multicast_admin_local { + assert_eq!(ip!($s).multicast_scope().unwrap(), + Ipv6MulticastScope::AdminLocal); + } + if ($mask & multicast_site_local) == multicast_site_local { + assert_eq!(ip!($s).multicast_scope().unwrap(), + Ipv6MulticastScope::SiteLocal); + } + if ($mask & multicast_organization_local) == multicast_organization_local { + assert_eq!(ip!($s).multicast_scope().unwrap(), + Ipv6MulticastScope::OrganizationLocal); + } + if ($mask & multicast_global) == multicast_global { + assert_eq!(ip!($s).multicast_scope().unwrap(), + Ipv6MulticastScope::Global); + } + if ($mask & multicast_reserved) == multicast_reserved { + assert_eq!(ip!($s).multicast_scope().unwrap(), + Ipv6MulticastScope::Reserved); + } + if ($mask & multicast_unassigned) == multicast_unassigned { + assert_eq!(ip!($s).multicast_scope().unwrap(), + Ipv6MulticastScope::Unassigned); + } + } + } + + let unspecified: u32 = 1 << 0; + let loopback: u32 = 1 << 1; + let unique_local: u32 = 1 << 2; + let global: u32 = 1 << 3; + let unicast_link_local: u32 = 1 << 4; + let unicast_link_local_strict: u32 = 1 << 5; + let unicast_site_local: u32 = 1 << 6; + let unicast_global: u32 = 1 << 7; + let documentation: u32 = 1 << 8; + let multicast_interface_local: u32 = 1 << 9; + let multicast_link_local: u32 = 1 << 10; + let multicast_realm_local: u32 = 1 << 11; + let multicast_admin_local: u32 = 1 << 12; + let multicast_site_local: u32 = 1 << 13; + let multicast_organization_local: u32 = 1 << 14; + let multicast_global: u32 = 1 << 15; + let multicast_reserved: u32 = 1 << 16; + let multicast_unassigned: u32 = 1 << 17; + + check!("::", &[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], unspecified); + + check!("::1", &[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1], loopback); + + check!("::0.0.0.2", &[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2], global | unicast_global); + + check!("1::", &[0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], global | unicast_global); + + check!("fc00::", &[0xfc, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], unique_local); + + check!( + "fdff:ffff::", + &[0xfd, 0xff, 0xff, 0xff, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], + unique_local + ); + + check!( + "fe80:ffff::", + &[0xfe, 0x80, 0xff, 0xff, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], + unicast_link_local + ); + + check!( + "fe80::", + &[0xfe, 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], + unicast_link_local | unicast_link_local_strict + ); + + check!( + "febf:ffff::", + &[0xfe, 0xbf, 0xff, 0xff, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], + unicast_link_local + ); + + check!("febf::", &[0xfe, 0xbf, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], unicast_link_local); + + check!( + "febf:ffff:ffff:ffff:ffff:ffff:ffff:ffff", + &[ + 0xfe, 0xbf, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff + ], + unicast_link_local + ); + + check!( + "fe80::ffff:ffff:ffff:ffff", + &[ + 0xfe, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff + ], + unicast_link_local | unicast_link_local_strict + ); + + check!( + "fe80:0:0:1::", + &[0xfe, 0x80, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0], + unicast_link_local + ); + + check!( + "fec0::", + &[0xfe, 0xc0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], + unicast_site_local | unicast_global | global + ); + + check!("ff00::", &[0xff, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], multicast_reserved); + + check!( + "ff01::", + &[0xff, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], + multicast_interface_local + ); + + check!("ff02::", &[0xff, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], multicast_link_local); + + check!("ff03::", &[0xff, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], multicast_realm_local); + + check!("ff04::", &[0xff, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], multicast_admin_local); + + check!("ff05::", &[0xff, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], multicast_site_local); + + check!("ff06::", &[0xff, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], multicast_unassigned); + + check!( + "ff08::", + &[0xff, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], + multicast_organization_local + ); + + check!("ff0a::", &[0xff, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], multicast_unassigned); + + check!( + "ff0e::", + &[0xff, 0xe, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], + multicast_global | global + ); + + check!("ff0f::", &[0xff, 0xf, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], multicast_reserved); + + check!( + "2001:db8:85a3::8a2e:370:7334", + &[0x20, 1, 0xd, 0xb8, 0x85, 0xa3, 0, 0, 0, 0, 0x8a, 0x2e, 3, 0x70, 0x73, 0x34], + documentation + ); + + check!( + "102:304:506:708:90a:b0c:d0e:f10", + &[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16], + global | unicast_global + ); +} + +#[test] +fn to_socket_addr_socketaddr() { + let a = sa4(Ipv4Addr::new(77, 88, 21, 11), 12345); + assert_eq!(Ok(vec![a]), tsa(a)); +} + +#[test] +fn test_ipv4_to_int() { + let a = Ipv4Addr::new(0x11, 0x22, 0x33, 0x44); + assert_eq!(u32::from(a), 0x11223344); +} + +#[test] +fn test_int_to_ipv4() { + let a = Ipv4Addr::new(0x11, 0x22, 0x33, 0x44); + assert_eq!(Ipv4Addr::from(0x11223344), a); +} + +#[test] +fn test_ipv6_to_int() { + let a = Ipv6Addr::new(0x1122, 0x3344, 0x5566, 0x7788, 0x99aa, 0xbbcc, 0xddee, 0xff11); + assert_eq!(u128::from(a), 0x112233445566778899aabbccddeeff11u128); +} + +#[test] +fn test_int_to_ipv6() { + let a = Ipv6Addr::new(0x1122, 0x3344, 0x5566, 0x7788, 0x99aa, 0xbbcc, 0xddee, 0xff11); + assert_eq!(Ipv6Addr::from(0x112233445566778899aabbccddeeff11u128), a); +} + +#[test] +fn ipv4_from_constructors() { + assert_eq!(Ipv4Addr::LOCALHOST, Ipv4Addr::new(127, 0, 0, 1)); + assert!(Ipv4Addr::LOCALHOST.is_loopback()); + assert_eq!(Ipv4Addr::UNSPECIFIED, Ipv4Addr::new(0, 0, 0, 0)); + assert!(Ipv4Addr::UNSPECIFIED.is_unspecified()); + assert_eq!(Ipv4Addr::BROADCAST, Ipv4Addr::new(255, 255, 255, 255)); + assert!(Ipv4Addr::BROADCAST.is_broadcast()); +} + +#[test] +fn ipv6_from_contructors() { + assert_eq!(Ipv6Addr::LOCALHOST, Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1)); + assert!(Ipv6Addr::LOCALHOST.is_loopback()); + assert_eq!(Ipv6Addr::UNSPECIFIED, Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0)); + assert!(Ipv6Addr::UNSPECIFIED.is_unspecified()); +} + +#[test] +fn ipv4_from_octets() { + assert_eq!(Ipv4Addr::from([127, 0, 0, 1]), Ipv4Addr::new(127, 0, 0, 1)) +} + +#[test] +fn ipv6_from_segments() { + let from_u16s = + Ipv6Addr::from([0x0011, 0x2233, 0x4455, 0x6677, 0x8899, 0xaabb, 0xccdd, 0xeeff]); + let new = Ipv6Addr::new(0x0011, 0x2233, 0x4455, 0x6677, 0x8899, 0xaabb, 0xccdd, 0xeeff); + assert_eq!(new, from_u16s); +} + +#[test] +fn ipv6_from_octets() { + let from_u16s = + Ipv6Addr::from([0x0011, 0x2233, 0x4455, 0x6677, 0x8899, 0xaabb, 0xccdd, 0xeeff]); + let from_u8s = Ipv6Addr::from([ + 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, + 0xff, + ]); + assert_eq!(from_u16s, from_u8s); +} + +#[test] +fn cmp() { + let v41 = Ipv4Addr::new(100, 64, 3, 3); + let v42 = Ipv4Addr::new(192, 0, 2, 2); + let v61 = "2001:db8:f00::1002".parse::().unwrap(); + let v62 = "2001:db8:f00::2001".parse::().unwrap(); + assert!(v41 < v42); + assert!(v61 < v62); + + assert_eq!(v41, IpAddr::V4(v41)); + assert_eq!(v61, IpAddr::V6(v61)); + assert!(v41 != IpAddr::V4(v42)); + assert!(v61 != IpAddr::V6(v62)); + + assert!(v41 < IpAddr::V4(v42)); + assert!(v61 < IpAddr::V6(v62)); + assert!(IpAddr::V4(v41) < v42); + assert!(IpAddr::V6(v61) < v62); + + assert!(v41 < IpAddr::V6(v61)); + assert!(IpAddr::V4(v41) < v61); +} + +#[test] +fn is_v4() { + let ip = IpAddr::V4(Ipv4Addr::new(100, 64, 3, 3)); + assert!(ip.is_ipv4()); + assert!(!ip.is_ipv6()); +} + +#[test] +fn is_v6() { + let ip = IpAddr::V6(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0x1234, 0x5678)); + assert!(!ip.is_ipv4()); + assert!(ip.is_ipv6()); +}