1 //! The following is derived from Rust's 2 //! library/std/src/net/ip_addr.rs at revision 3 //! bd20fc1fd657b32f7aa1d70d8723f04c87f21606. 4 //! 5 //! All code in this file is licensed MIT or Apache 2.0 at your option. 6 //! 7 //! This defines `IpAddr`, `Ipv4Addr`, and `Ipv6Addr`. Ideally, these should be 8 //! defined in `core`. See [RFC 2832]. 9 //! 10 //! [RFC 2832]: https://github.com/rust-lang/rfcs/pull/2832 11 12 #![allow(unsafe_code)] 13 14 use core::cmp::Ordering; 15 use core::mem::transmute; 16 17 /// An IP address, either IPv4 or IPv6. 18 /// 19 /// This enum can contain either an [`Ipv4Addr`] or an [`Ipv6Addr`], see their 20 /// respective documentation for more details. 21 /// 22 /// # Examples 23 /// 24 /// ``` 25 /// use std::net::{IpAddr, Ipv4Addr, Ipv6Addr}; 26 /// 27 /// let localhost_v4 = IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)); 28 /// let localhost_v6 = IpAddr::V6(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1)); 29 /// 30 /// assert_eq!("127.0.0.1".parse(), Ok(localhost_v4)); 31 /// assert_eq!("::1".parse(), Ok(localhost_v6)); 32 /// 33 /// assert_eq!(localhost_v4.is_ipv6(), false); 34 /// assert_eq!(localhost_v4.is_ipv4(), true); 35 /// ``` 36 #[cfg_attr(staged_api, stable(feature = "ip_addr", since = "1.7.0"))] 37 #[derive(Copy, Clone, Eq, PartialEq, Hash, PartialOrd, Ord)] 38 pub enum IpAddr { 39 /// An IPv4 address. 40 #[cfg_attr(staged_api, stable(feature = "ip_addr", since = "1.7.0"))] 41 V4(#[cfg_attr(staged_api, stable(feature = "ip_addr", since = "1.7.0"))] Ipv4Addr), 42 /// An IPv6 address. 43 #[cfg_attr(staged_api, stable(feature = "ip_addr", since = "1.7.0"))] 44 V6(#[cfg_attr(staged_api, stable(feature = "ip_addr", since = "1.7.0"))] Ipv6Addr), 45 } 46 47 /// An IPv4 address. 48 /// 49 /// IPv4 addresses are defined as 32-bit integers in [IETF RFC 791]. 50 /// They are usually represented as four octets. 51 /// 52 /// See [`IpAddr`] for a type encompassing both IPv4 and IPv6 addresses. 53 /// 54 /// [IETF RFC 791]: https://tools.ietf.org/html/rfc791 55 /// 56 /// # Textual representation 57 /// 58 /// `Ipv4Addr` provides a [`FromStr`] implementation. The four octets are in decimal 59 /// notation, divided by `.` (this is called "dot-decimal notation"). 60 /// Notably, octal numbers (which are indicated with a leading `0`) and hexadecimal numbers (which 61 /// are indicated with a leading `0x`) are not allowed per [IETF RFC 6943]. 62 /// 63 /// [IETF RFC 6943]: https://tools.ietf.org/html/rfc6943#section-3.1.1 64 /// [`FromStr`]: core::str::FromStr 65 /// 66 /// # Examples 67 /// 68 /// ``` 69 /// use std::net::Ipv4Addr; 70 /// 71 /// let localhost = Ipv4Addr::new(127, 0, 0, 1); 72 /// assert_eq!("127.0.0.1".parse(), Ok(localhost)); 73 /// assert_eq!(localhost.is_loopback(), true); 74 /// assert!("012.004.002.000".parse::<Ipv4Addr>().is_err()); // all octets are in octal 75 /// assert!("0000000.0.0.0".parse::<Ipv4Addr>().is_err()); // first octet is a zero in octal 76 /// assert!("0xcb.0x0.0x71.0x00".parse::<Ipv4Addr>().is_err()); // all octets are in hex 77 /// ``` 78 #[derive(Copy, Clone, PartialEq, Eq, Hash)] 79 #[cfg_attr(staged_api, stable(feature = "rust1", since = "1.0.0"))] 80 pub struct Ipv4Addr { 81 octets: [u8; 4], 82 } 83 84 /// An IPv6 address. 85 /// 86 /// IPv6 addresses are defined as 128-bit integers in [IETF RFC 4291]. 87 /// They are usually represented as eight 16-bit segments. 88 /// 89 /// [IETF RFC 4291]: https://tools.ietf.org/html/rfc4291 90 /// 91 /// # Embedding IPv4 Addresses 92 /// 93 /// See [`IpAddr`] for a type encompassing both IPv4 and IPv6 addresses. 94 /// 95 /// To assist in the transition from IPv4 to IPv6 two types of IPv6 addresses that embed an IPv4 address were defined: 96 /// IPv4-compatible and IPv4-mapped addresses. Of these IPv4-compatible addresses have been officially deprecated. 97 /// 98 /// Both types of addresses are not assigned any special meaning by this implementation, 99 /// other than what the relevant standards prescribe. This means that an address like `::ffff:127.0.0.1`, 100 /// while representing an IPv4 loopback address, is not itself an IPv6 loopback address; only `::1` is. 101 /// To handle these so called "IPv4-in-IPv6" addresses, they have to first be converted to their canonical IPv4 address. 102 /// 103 /// ### IPv4-Compatible IPv6 Addresses 104 /// 105 /// IPv4-compatible IPv6 addresses are defined in [IETF RFC 4291 Section 2.5.5.1], and have been officially deprecated. 106 /// The RFC describes the format of an "IPv4-Compatible IPv6 address" as follows: 107 /// 108 /// ```text 109 /// | 80 bits | 16 | 32 bits | 110 /// +--------------------------------------+--------------------------+ 111 /// |0000..............................0000|0000| IPv4 address | 112 /// +--------------------------------------+----+---------------------+ 113 /// ``` 114 /// So `::a.b.c.d` would be an IPv4-compatible IPv6 address representing the IPv4 address `a.b.c.d`. 115 /// 116 /// To convert from an IPv4 address to an IPv4-compatible IPv6 address, use [`Ipv4Addr::to_ipv6_compatible`]. 117 /// Use [`Ipv6Addr::to_ipv4`] to convert an IPv4-compatible IPv6 address to the canonical IPv4 address. 118 /// 119 /// [IETF RFC 4291 Section 2.5.5.1]: https://datatracker.ietf.org/doc/html/rfc4291#section-2.5.5.1 120 /// 121 /// ### IPv4-Mapped IPv6 Addresses 122 /// 123 /// IPv4-mapped IPv6 addresses are defined in [IETF RFC 4291 Section 2.5.5.2]. 124 /// The RFC describes the format of an "IPv4-Mapped IPv6 address" as follows: 125 /// 126 /// ```text 127 /// | 80 bits | 16 | 32 bits | 128 /// +--------------------------------------+--------------------------+ 129 /// |0000..............................0000|FFFF| IPv4 address | 130 /// +--------------------------------------+----+---------------------+ 131 /// ``` 132 /// So `::ffff:a.b.c.d` would be an IPv4-mapped IPv6 address representing the IPv4 address `a.b.c.d`. 133 /// 134 /// To convert from an IPv4 address to an IPv4-mapped IPv6 address, use [`Ipv4Addr::to_ipv6_mapped`]. 135 /// Use [`Ipv6Addr::to_ipv4`] to convert an IPv4-mapped IPv6 address to the canonical IPv4 address. 136 /// Note that this will also convert the IPv6 loopback address `::1` to `0.0.0.1`. Use 137 /// [`Ipv6Addr::to_ipv4_mapped`] to avoid this. 138 /// 139 /// [IETF RFC 4291 Section 2.5.5.2]: https://datatracker.ietf.org/doc/html/rfc4291#section-2.5.5.2 140 /// 141 /// # Textual representation 142 /// 143 /// `Ipv6Addr` provides a [`FromStr`] implementation. There are many ways to represent 144 /// an IPv6 address in text, but in general, each segments is written in hexadecimal 145 /// notation, and segments are separated by `:`. For more information, see 146 /// [IETF RFC 5952]. 147 /// 148 /// [`FromStr`]: core::str::FromStr 149 /// [IETF RFC 5952]: https://tools.ietf.org/html/rfc5952 150 /// 151 /// # Examples 152 /// 153 /// ``` 154 /// use std::net::Ipv6Addr; 155 /// 156 /// let localhost = Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1); 157 /// assert_eq!("::1".parse(), Ok(localhost)); 158 /// assert_eq!(localhost.is_loopback(), true); 159 /// ``` 160 #[derive(Copy, Clone, PartialEq, Eq, Hash)] 161 #[cfg_attr(staged_api, stable(feature = "rust1", since = "1.0.0"))] 162 pub struct Ipv6Addr { 163 octets: [u8; 16], 164 } 165 166 /// Scope of an [IPv6 multicast address] as defined in [IETF RFC 7346 section 2]. 167 /// 168 /// # Stability Guarantees 169 /// 170 /// Not all possible values for a multicast scope have been assigned. 171 /// Future RFCs may introduce new scopes, which will be added as variants to this enum; 172 /// because of this the enum is marked as `#[non_exhaustive]`. 173 /// 174 /// # Examples 175 /// ``` 176 /// #![feature(ip)] 177 /// 178 /// use std::net::Ipv6Addr; 179 /// use std::net::Ipv6MulticastScope::*; 180 /// 181 /// // An IPv6 multicast address with global scope (`ff0e::`). 182 /// let address = Ipv6Addr::new(0xff0e, 0, 0, 0, 0, 0, 0, 0); 183 /// 184 /// // Will print "Global scope". 185 /// match address.multicast_scope() { 186 /// Some(InterfaceLocal) => println!("Interface-Local scope"), 187 /// Some(LinkLocal) => println!("Link-Local scope"), 188 /// Some(RealmLocal) => println!("Realm-Local scope"), 189 /// Some(AdminLocal) => println!("Admin-Local scope"), 190 /// Some(SiteLocal) => println!("Site-Local scope"), 191 /// Some(OrganizationLocal) => println!("Organization-Local scope"), 192 /// Some(Global) => println!("Global scope"), 193 /// Some(_) => println!("Unknown scope"), 194 /// None => println!("Not a multicast address!") 195 /// } 196 /// 197 /// ``` 198 /// 199 /// [IPv6 multicast address]: Ipv6Addr 200 /// [IETF RFC 7346 section 2]: https://tools.ietf.org/html/rfc7346#section-2 201 #[derive(Copy, PartialEq, Eq, Clone, Hash, Debug)] 202 #[cfg_attr(staged_api, unstable(feature = "ip", issue = "27709"))] 203 #[non_exhaustive] 204 pub enum Ipv6MulticastScope { 205 /// Interface-Local scope. 206 InterfaceLocal, 207 /// Link-Local scope. 208 LinkLocal, 209 /// Realm-Local scope. 210 RealmLocal, 211 /// Admin-Local scope. 212 AdminLocal, 213 /// Site-Local scope. 214 SiteLocal, 215 /// Organization-Local scope. 216 OrganizationLocal, 217 /// Global scope. 218 Global, 219 } 220 221 impl IpAddr { 222 /// Returns [`true`] for the special 'unspecified' address. 223 /// 224 /// See the documentation for [`Ipv4Addr::is_unspecified()`] and 225 /// [`Ipv6Addr::is_unspecified()`] for more details. 226 /// 227 /// # Examples 228 /// 229 /// ``` 230 /// use std::net::{IpAddr, Ipv4Addr, Ipv6Addr}; 231 /// 232 /// assert_eq!(IpAddr::V4(Ipv4Addr::new(0, 0, 0, 0)).is_unspecified(), true); 233 /// assert_eq!(IpAddr::V6(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0)).is_unspecified(), true); 234 /// ``` 235 #[cfg_attr( 236 staged_api, 237 rustc_const_stable(feature = "const_ip_50", since = "1.50.0") 238 )] 239 #[cfg_attr(staged_api, stable(feature = "ip_shared", since = "1.12.0"))] 240 #[must_use] 241 #[inline] is_unspecified(&self) -> bool242 pub const fn is_unspecified(&self) -> bool { 243 match self { 244 IpAddr::V4(ip) => ip.is_unspecified(), 245 IpAddr::V6(ip) => ip.is_unspecified(), 246 } 247 } 248 249 /// Returns [`true`] if this is a loopback address. 250 /// 251 /// See the documentation for [`Ipv4Addr::is_loopback()`] and 252 /// [`Ipv6Addr::is_loopback()`] for more details. 253 /// 254 /// # Examples 255 /// 256 /// ``` 257 /// use std::net::{IpAddr, Ipv4Addr, Ipv6Addr}; 258 /// 259 /// assert_eq!(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)).is_loopback(), true); 260 /// assert_eq!(IpAddr::V6(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0x1)).is_loopback(), true); 261 /// ``` 262 #[cfg_attr( 263 staged_api, 264 rustc_const_stable(feature = "const_ip_50", since = "1.50.0") 265 )] 266 #[cfg_attr(staged_api, stable(feature = "ip_shared", since = "1.12.0"))] 267 #[must_use] 268 #[inline] is_loopback(&self) -> bool269 pub const fn is_loopback(&self) -> bool { 270 match self { 271 IpAddr::V4(ip) => ip.is_loopback(), 272 IpAddr::V6(ip) => ip.is_loopback(), 273 } 274 } 275 276 /// Returns [`true`] if the address appears to be globally routable. 277 /// 278 /// See the documentation for [`Ipv4Addr::is_global()`] and 279 /// [`Ipv6Addr::is_global()`] for more details. 280 /// 281 /// # Examples 282 /// 283 /// ``` 284 /// #![feature(ip)] 285 /// 286 /// use std::net::{IpAddr, Ipv4Addr, Ipv6Addr}; 287 /// 288 /// assert_eq!(IpAddr::V4(Ipv4Addr::new(80, 9, 12, 3)).is_global(), true); 289 /// assert_eq!(IpAddr::V6(Ipv6Addr::new(0, 0, 0x1c9, 0, 0, 0xafc8, 0, 0x1)).is_global(), true); 290 /// ``` 291 #[cfg_attr( 292 staged_api, 293 rustc_const_unstable(feature = "const_ip", issue = "76205") 294 )] 295 #[cfg_attr(staged_api, unstable(feature = "ip", issue = "27709"))] 296 #[must_use] 297 #[inline] is_global(&self) -> bool298 pub const fn is_global(&self) -> bool { 299 match self { 300 IpAddr::V4(ip) => ip.is_global(), 301 IpAddr::V6(ip) => ip.is_global(), 302 } 303 } 304 305 /// Returns [`true`] if this is a multicast address. 306 /// 307 /// See the documentation for [`Ipv4Addr::is_multicast()`] and 308 /// [`Ipv6Addr::is_multicast()`] for more details. 309 /// 310 /// # Examples 311 /// 312 /// ``` 313 /// use std::net::{IpAddr, Ipv4Addr, Ipv6Addr}; 314 /// 315 /// assert_eq!(IpAddr::V4(Ipv4Addr::new(224, 254, 0, 0)).is_multicast(), true); 316 /// assert_eq!(IpAddr::V6(Ipv6Addr::new(0xff00, 0, 0, 0, 0, 0, 0, 0)).is_multicast(), true); 317 /// ``` 318 #[cfg_attr( 319 staged_api, 320 rustc_const_stable(feature = "const_ip_50", since = "1.50.0") 321 )] 322 #[cfg_attr(staged_api, stable(feature = "ip_shared", since = "1.12.0"))] 323 #[must_use] 324 #[inline] is_multicast(&self) -> bool325 pub const fn is_multicast(&self) -> bool { 326 match self { 327 IpAddr::V4(ip) => ip.is_multicast(), 328 IpAddr::V6(ip) => ip.is_multicast(), 329 } 330 } 331 332 /// Returns [`true`] if this address is in a range designated for documentation. 333 /// 334 /// See the documentation for [`Ipv4Addr::is_documentation()`] and 335 /// [`Ipv6Addr::is_documentation()`] for more details. 336 /// 337 /// # Examples 338 /// 339 /// ``` 340 /// #![feature(ip)] 341 /// 342 /// use std::net::{IpAddr, Ipv4Addr, Ipv6Addr}; 343 /// 344 /// assert_eq!(IpAddr::V4(Ipv4Addr::new(203, 0, 113, 6)).is_documentation(), true); 345 /// assert_eq!( 346 /// IpAddr::V6(Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 0)).is_documentation(), 347 /// true 348 /// ); 349 /// ``` 350 #[cfg_attr( 351 staged_api, 352 rustc_const_unstable(feature = "const_ip", issue = "76205") 353 )] 354 #[cfg_attr(staged_api, unstable(feature = "ip", issue = "27709"))] 355 #[must_use] 356 #[inline] is_documentation(&self) -> bool357 pub const fn is_documentation(&self) -> bool { 358 match self { 359 IpAddr::V4(ip) => ip.is_documentation(), 360 IpAddr::V6(ip) => ip.is_documentation(), 361 } 362 } 363 364 /// Returns [`true`] if this address is in a range designated for benchmarking. 365 /// 366 /// See the documentation for [`Ipv4Addr::is_benchmarking()`] and 367 /// [`Ipv6Addr::is_benchmarking()`] for more details. 368 /// 369 /// # Examples 370 /// 371 /// ``` 372 /// #![feature(ip)] 373 /// 374 /// use std::net::{IpAddr, Ipv4Addr, Ipv6Addr}; 375 /// 376 /// assert_eq!(IpAddr::V4(Ipv4Addr::new(198, 19, 255, 255)).is_benchmarking(), true); 377 /// assert_eq!(IpAddr::V6(Ipv6Addr::new(0x2001, 0x2, 0, 0, 0, 0, 0, 0)).is_benchmarking(), true); 378 /// ``` 379 #[cfg_attr(staged_api, unstable(feature = "ip", issue = "27709"))] 380 #[must_use] 381 #[inline] is_benchmarking(&self) -> bool382 pub const fn is_benchmarking(&self) -> bool { 383 match self { 384 IpAddr::V4(ip) => ip.is_benchmarking(), 385 IpAddr::V6(ip) => ip.is_benchmarking(), 386 } 387 } 388 389 /// Returns [`true`] if this address is an [`IPv4` address], and [`false`] 390 /// otherwise. 391 /// 392 /// [`IPv4` address]: IpAddr::V4 393 /// 394 /// # Examples 395 /// 396 /// ``` 397 /// use std::net::{IpAddr, Ipv4Addr, Ipv6Addr}; 398 /// 399 /// assert_eq!(IpAddr::V4(Ipv4Addr::new(203, 0, 113, 6)).is_ipv4(), true); 400 /// assert_eq!(IpAddr::V6(Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 0)).is_ipv4(), false); 401 /// ``` 402 #[cfg_attr( 403 staged_api, 404 rustc_const_stable(feature = "const_ip_50", since = "1.50.0") 405 )] 406 #[cfg_attr(staged_api, stable(feature = "ipaddr_checker", since = "1.16.0"))] 407 #[must_use] 408 #[inline] is_ipv4(&self) -> bool409 pub const fn is_ipv4(&self) -> bool { 410 matches!(self, IpAddr::V4(_)) 411 } 412 413 /// Returns [`true`] if this address is an [`IPv6` address], and [`false`] 414 /// otherwise. 415 /// 416 /// [`IPv6` address]: IpAddr::V6 417 /// 418 /// # Examples 419 /// 420 /// ``` 421 /// use std::net::{IpAddr, Ipv4Addr, Ipv6Addr}; 422 /// 423 /// assert_eq!(IpAddr::V4(Ipv4Addr::new(203, 0, 113, 6)).is_ipv6(), false); 424 /// assert_eq!(IpAddr::V6(Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 0)).is_ipv6(), true); 425 /// ``` 426 #[cfg_attr( 427 staged_api, 428 rustc_const_stable(feature = "const_ip_50", since = "1.50.0") 429 )] 430 #[cfg_attr(staged_api, stable(feature = "ipaddr_checker", since = "1.16.0"))] 431 #[must_use] 432 #[inline] is_ipv6(&self) -> bool433 pub const fn is_ipv6(&self) -> bool { 434 matches!(self, IpAddr::V6(_)) 435 } 436 437 /// Converts this address to an `IpAddr::V4` if it is an IPv4-mapped IPv6 addresses, otherwise it 438 /// return `self` as-is. 439 /// 440 /// # Examples 441 /// 442 /// ``` 443 /// #![feature(ip)] 444 /// use std::net::{IpAddr, Ipv4Addr, Ipv6Addr}; 445 /// 446 /// assert_eq!(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)).to_canonical().is_loopback(), true); 447 /// assert_eq!(IpAddr::V6(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0x7f00, 0x1)).is_loopback(), false); 448 /// assert_eq!(IpAddr::V6(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0x7f00, 0x1)).to_canonical().is_loopback(), true); 449 /// ``` 450 #[inline] 451 #[must_use = "this returns the result of the operation, \ 452 without modifying the original"] 453 #[cfg_attr( 454 staged_api, 455 rustc_const_unstable(feature = "const_ip", issue = "76205") 456 )] 457 #[cfg_attr(staged_api, unstable(feature = "ip", issue = "27709"))] to_canonical(&self) -> IpAddr458 pub const fn to_canonical(&self) -> IpAddr { 459 match self { 460 &v4 @ IpAddr::V4(_) => v4, 461 IpAddr::V6(v6) => v6.to_canonical(), 462 } 463 } 464 } 465 466 impl Ipv4Addr { 467 /// Creates a new IPv4 address from four eight-bit octets. 468 /// 469 /// The result will represent the IP address `a`.`b`.`c`.`d`. 470 /// 471 /// # Examples 472 /// 473 /// ``` 474 /// use std::net::Ipv4Addr; 475 /// 476 /// let addr = Ipv4Addr::new(127, 0, 0, 1); 477 /// ``` 478 #[cfg_attr( 479 staged_api, 480 rustc_const_stable(feature = "const_ip_32", since = "1.32.0") 481 )] 482 #[cfg_attr(staged_api, stable(feature = "rust1", since = "1.0.0"))] 483 #[must_use] 484 #[inline] new(a: u8, b: u8, c: u8, d: u8) -> Ipv4Addr485 pub const fn new(a: u8, b: u8, c: u8, d: u8) -> Ipv4Addr { 486 Ipv4Addr { 487 octets: [a, b, c, d], 488 } 489 } 490 491 /// An IPv4 address with the address pointing to localhost: `127.0.0.1` 492 /// 493 /// # Examples 494 /// 495 /// ``` 496 /// use std::net::Ipv4Addr; 497 /// 498 /// let addr = Ipv4Addr::LOCALHOST; 499 /// assert_eq!(addr, Ipv4Addr::new(127, 0, 0, 1)); 500 /// ``` 501 #[cfg_attr(staged_api, stable(feature = "ip_constructors", since = "1.30.0"))] 502 pub const LOCALHOST: Self = Ipv4Addr::new(127, 0, 0, 1); 503 504 /// An IPv4 address representing an unspecified address: `0.0.0.0` 505 /// 506 /// This corresponds to the constant `INADDR_ANY` in other languages. 507 /// 508 /// # Examples 509 /// 510 /// ``` 511 /// use std::net::Ipv4Addr; 512 /// 513 /// let addr = Ipv4Addr::UNSPECIFIED; 514 /// assert_eq!(addr, Ipv4Addr::new(0, 0, 0, 0)); 515 /// ``` 516 #[doc(alias = "INADDR_ANY")] 517 #[cfg_attr(staged_api, stable(feature = "ip_constructors", since = "1.30.0"))] 518 pub const UNSPECIFIED: Self = Ipv4Addr::new(0, 0, 0, 0); 519 520 /// An IPv4 address representing the broadcast address: `255.255.255.255` 521 /// 522 /// # Examples 523 /// 524 /// ``` 525 /// use std::net::Ipv4Addr; 526 /// 527 /// let addr = Ipv4Addr::BROADCAST; 528 /// assert_eq!(addr, Ipv4Addr::new(255, 255, 255, 255)); 529 /// ``` 530 #[cfg_attr(staged_api, stable(feature = "ip_constructors", since = "1.30.0"))] 531 pub const BROADCAST: Self = Ipv4Addr::new(255, 255, 255, 255); 532 533 /// Returns the four eight-bit integers that make up this address. 534 /// 535 /// # Examples 536 /// 537 /// ``` 538 /// use std::net::Ipv4Addr; 539 /// 540 /// let addr = Ipv4Addr::new(127, 0, 0, 1); 541 /// assert_eq!(addr.octets(), [127, 0, 0, 1]); 542 /// ``` 543 #[cfg_attr( 544 staged_api, 545 rustc_const_stable(feature = "const_ip_50", since = "1.50.0") 546 )] 547 #[cfg_attr(staged_api, stable(feature = "rust1", since = "1.0.0"))] 548 #[must_use] 549 #[inline] octets(&self) -> [u8; 4]550 pub const fn octets(&self) -> [u8; 4] { 551 self.octets 552 } 553 554 /// Returns [`true`] for the special 'unspecified' address (`0.0.0.0`). 555 /// 556 /// This property is defined in _UNIX Network Programming, Second Edition_, 557 /// W. Richard Stevens, p. 891; see also [ip7]. 558 /// 559 /// [ip7]: https://man7.org/linux/man-pages/man7/ip.7.html 560 /// 561 /// # Examples 562 /// 563 /// ``` 564 /// use std::net::Ipv4Addr; 565 /// 566 /// assert_eq!(Ipv4Addr::new(0, 0, 0, 0).is_unspecified(), true); 567 /// assert_eq!(Ipv4Addr::new(45, 22, 13, 197).is_unspecified(), false); 568 /// ``` 569 #[cfg_attr( 570 staged_api, 571 rustc_const_stable(feature = "const_ip_32", since = "1.32.0") 572 )] 573 #[cfg_attr(staged_api, stable(feature = "ip_shared", since = "1.12.0"))] 574 #[must_use] 575 #[inline] is_unspecified(&self) -> bool576 pub const fn is_unspecified(&self) -> bool { 577 u32::from_be_bytes(self.octets) == 0 578 } 579 580 /// Returns [`true`] if this is a loopback address (`127.0.0.0/8`). 581 /// 582 /// This property is defined by [IETF RFC 1122]. 583 /// 584 /// [IETF RFC 1122]: https://tools.ietf.org/html/rfc1122 585 /// 586 /// # Examples 587 /// 588 /// ``` 589 /// use std::net::Ipv4Addr; 590 /// 591 /// assert_eq!(Ipv4Addr::new(127, 0, 0, 1).is_loopback(), true); 592 /// assert_eq!(Ipv4Addr::new(45, 22, 13, 197).is_loopback(), false); 593 /// ``` 594 #[cfg_attr( 595 staged_api, 596 rustc_const_stable(feature = "const_ip_50", since = "1.50.0") 597 )] 598 #[cfg_attr(staged_api, stable(since = "1.7.0", feature = "ip_17"))] 599 #[must_use] 600 #[inline] is_loopback(&self) -> bool601 pub const fn is_loopback(&self) -> bool { 602 self.octets()[0] == 127 603 } 604 605 /// Returns [`true`] if this is a private address. 606 /// 607 /// The private address ranges are defined in [IETF RFC 1918] and include: 608 /// 609 /// - `10.0.0.0/8` 610 /// - `172.16.0.0/12` 611 /// - `192.168.0.0/16` 612 /// 613 /// [IETF RFC 1918]: https://tools.ietf.org/html/rfc1918 614 /// 615 /// # Examples 616 /// 617 /// ``` 618 /// use std::net::Ipv4Addr; 619 /// 620 /// assert_eq!(Ipv4Addr::new(10, 0, 0, 1).is_private(), true); 621 /// assert_eq!(Ipv4Addr::new(10, 10, 10, 10).is_private(), true); 622 /// assert_eq!(Ipv4Addr::new(172, 16, 10, 10).is_private(), true); 623 /// assert_eq!(Ipv4Addr::new(172, 29, 45, 14).is_private(), true); 624 /// assert_eq!(Ipv4Addr::new(172, 32, 0, 2).is_private(), false); 625 /// assert_eq!(Ipv4Addr::new(192, 168, 0, 2).is_private(), true); 626 /// assert_eq!(Ipv4Addr::new(192, 169, 0, 2).is_private(), false); 627 /// ``` 628 #[cfg_attr( 629 staged_api, 630 rustc_const_stable(feature = "const_ip_50", since = "1.50.0") 631 )] 632 #[cfg_attr(staged_api, stable(since = "1.7.0", feature = "ip_17"))] 633 #[must_use] 634 #[inline] is_private(&self) -> bool635 pub const fn is_private(&self) -> bool { 636 match self.octets() { 637 [10, ..] => true, 638 [172, b, ..] if b >= 16 && b <= 31 => true, 639 [192, 168, ..] => true, 640 _ => false, 641 } 642 } 643 644 /// Returns [`true`] if the address is link-local (`169.254.0.0/16`). 645 /// 646 /// This property is defined by [IETF RFC 3927]. 647 /// 648 /// [IETF RFC 3927]: https://tools.ietf.org/html/rfc3927 649 /// 650 /// # Examples 651 /// 652 /// ``` 653 /// use std::net::Ipv4Addr; 654 /// 655 /// assert_eq!(Ipv4Addr::new(169, 254, 0, 0).is_link_local(), true); 656 /// assert_eq!(Ipv4Addr::new(169, 254, 10, 65).is_link_local(), true); 657 /// assert_eq!(Ipv4Addr::new(16, 89, 10, 65).is_link_local(), false); 658 /// ``` 659 #[cfg_attr( 660 staged_api, 661 rustc_const_stable(feature = "const_ip_50", since = "1.50.0") 662 )] 663 #[cfg_attr(staged_api, stable(since = "1.7.0", feature = "ip_17"))] 664 #[must_use] 665 #[inline] is_link_local(&self) -> bool666 pub const fn is_link_local(&self) -> bool { 667 matches!(self.octets(), [169, 254, ..]) 668 } 669 670 /// Returns [`true`] if the address appears to be globally reachable 671 /// as specified by the [IANA IPv4 Special-Purpose Address Registry]. 672 /// Whether or not an address is practically reachable will depend on your network configuration. 673 /// 674 /// Most IPv4 addresses are globally reachable; 675 /// unless they are specifically defined as *not* globally reachable. 676 /// 677 /// Non-exhaustive list of notable addresses that are not globally reachable: 678 /// 679 /// - The [unspecified address] ([`is_unspecified`](Ipv4Addr::is_unspecified)) 680 /// - Addresses reserved for private use ([`is_private`](Ipv4Addr::is_private)) 681 /// - Addresses in the shared address space ([`is_shared`](Ipv4Addr::is_shared)) 682 /// - Loopback addresses ([`is_loopback`](Ipv4Addr::is_loopback)) 683 /// - Link-local addresses ([`is_link_local`](Ipv4Addr::is_link_local)) 684 /// - Addresses reserved for documentation ([`is_documentation`](Ipv4Addr::is_documentation)) 685 /// - Addresses reserved for benchmarking ([`is_benchmarking`](Ipv4Addr::is_benchmarking)) 686 /// - Reserved addresses ([`is_reserved`](Ipv4Addr::is_reserved)) 687 /// - The [broadcast address] ([`is_broadcast`](Ipv4Addr::is_broadcast)) 688 /// 689 /// For the complete overview of which addresses are globally reachable, see the table at the [IANA IPv4 Special-Purpose Address Registry]. 690 /// 691 /// [IANA IPv4 Special-Purpose Address Registry]: https://www.iana.org/assignments/iana-ipv4-special-registry/iana-ipv4-special-registry.xhtml 692 /// [unspecified address]: Ipv4Addr::UNSPECIFIED 693 /// [broadcast address]: Ipv4Addr::BROADCAST 694 695 /// 696 /// # Examples 697 /// 698 /// ``` 699 /// #![feature(ip)] 700 /// 701 /// use std::net::Ipv4Addr; 702 /// 703 /// // Most IPv4 addresses are globally reachable: 704 /// assert_eq!(Ipv4Addr::new(80, 9, 12, 3).is_global(), true); 705 /// 706 /// // However some addresses have been assigned a special meaning 707 /// // that makes them not globally reachable. Some examples are: 708 /// 709 /// // The unspecified address (`0.0.0.0`) 710 /// assert_eq!(Ipv4Addr::UNSPECIFIED.is_global(), false); 711 /// 712 /// // Addresses reserved for private use (`10.0.0.0/8`, `172.16.0.0/12`, 192.168.0.0/16) 713 /// assert_eq!(Ipv4Addr::new(10, 254, 0, 0).is_global(), false); 714 /// assert_eq!(Ipv4Addr::new(192, 168, 10, 65).is_global(), false); 715 /// assert_eq!(Ipv4Addr::new(172, 16, 10, 65).is_global(), false); 716 /// 717 /// // Addresses in the shared address space (`100.64.0.0/10`) 718 /// assert_eq!(Ipv4Addr::new(100, 100, 0, 0).is_global(), false); 719 /// 720 /// // The loopback addresses (`127.0.0.0/8`) 721 /// assert_eq!(Ipv4Addr::LOCALHOST.is_global(), false); 722 /// 723 /// // Link-local addresses (`169.254.0.0/16`) 724 /// assert_eq!(Ipv4Addr::new(169, 254, 45, 1).is_global(), false); 725 /// 726 /// // Addresses reserved for documentation (`192.0.2.0/24`, `198.51.100.0/24`, `203.0.113.0/24`) 727 /// assert_eq!(Ipv4Addr::new(192, 0, 2, 255).is_global(), false); 728 /// assert_eq!(Ipv4Addr::new(198, 51, 100, 65).is_global(), false); 729 /// assert_eq!(Ipv4Addr::new(203, 0, 113, 6).is_global(), false); 730 /// 731 /// // Addresses reserved for benchmarking (`198.18.0.0/15`) 732 /// assert_eq!(Ipv4Addr::new(198, 18, 0, 0).is_global(), false); 733 /// 734 /// // Reserved addresses (`240.0.0.0/4`) 735 /// assert_eq!(Ipv4Addr::new(250, 10, 20, 30).is_global(), false); 736 /// 737 /// // The broadcast address (`255.255.255.255`) 738 /// assert_eq!(Ipv4Addr::BROADCAST.is_global(), false); 739 /// 740 /// // For a complete overview see the IANA IPv4 Special-Purpose Address Registry. 741 /// ``` 742 #[cfg_attr( 743 staged_api, 744 rustc_const_unstable(feature = "const_ipv4", issue = "76205") 745 )] 746 #[cfg_attr(staged_api, unstable(feature = "ip", issue = "27709"))] 747 #[must_use] 748 #[inline] is_global(&self) -> bool749 pub const fn is_global(&self) -> bool { 750 !(self.octets()[0] == 0 // "This network" 751 || self.is_private() 752 || self.is_shared() 753 || self.is_loopback() 754 || self.is_link_local() 755 // addresses reserved for future protocols (`192.0.0.0/24`) 756 ||(self.octets()[0] == 192 && self.octets()[1] == 0 && self.octets()[2] == 0) 757 || self.is_documentation() 758 || self.is_benchmarking() 759 || self.is_reserved() 760 || self.is_broadcast()) 761 } 762 763 /// Returns [`true`] if this address is part of the Shared Address Space defined in 764 /// [IETF RFC 6598] (`100.64.0.0/10`). 765 /// 766 /// [IETF RFC 6598]: https://tools.ietf.org/html/rfc6598 767 /// 768 /// # Examples 769 /// 770 /// ``` 771 /// #![feature(ip)] 772 /// use std::net::Ipv4Addr; 773 /// 774 /// assert_eq!(Ipv4Addr::new(100, 64, 0, 0).is_shared(), true); 775 /// assert_eq!(Ipv4Addr::new(100, 127, 255, 255).is_shared(), true); 776 /// assert_eq!(Ipv4Addr::new(100, 128, 0, 0).is_shared(), false); 777 /// ``` 778 #[cfg_attr( 779 staged_api, 780 rustc_const_unstable(feature = "const_ipv4", issue = "76205") 781 )] 782 #[cfg_attr(staged_api, unstable(feature = "ip", issue = "27709"))] 783 #[must_use] 784 #[inline] is_shared(&self) -> bool785 pub const fn is_shared(&self) -> bool { 786 self.octets()[0] == 100 && (self.octets()[1] & 0b1100_0000 == 0b0100_0000) 787 } 788 789 /// Returns [`true`] if this address part of the `198.18.0.0/15` range, which is reserved for 790 /// network devices benchmarking. This range is defined in [IETF RFC 2544] as `192.18.0.0` 791 /// through `198.19.255.255` but [errata 423] corrects it to `198.18.0.0/15`. 792 /// 793 /// [IETF RFC 2544]: https://tools.ietf.org/html/rfc2544 794 /// [errata 423]: https://www.rfc-editor.org/errata/eid423 795 /// 796 /// # Examples 797 /// 798 /// ``` 799 /// #![feature(ip)] 800 /// use std::net::Ipv4Addr; 801 /// 802 /// assert_eq!(Ipv4Addr::new(198, 17, 255, 255).is_benchmarking(), false); 803 /// assert_eq!(Ipv4Addr::new(198, 18, 0, 0).is_benchmarking(), true); 804 /// assert_eq!(Ipv4Addr::new(198, 19, 255, 255).is_benchmarking(), true); 805 /// assert_eq!(Ipv4Addr::new(198, 20, 0, 0).is_benchmarking(), false); 806 /// ``` 807 #[cfg_attr( 808 staged_api, 809 rustc_const_unstable(feature = "const_ipv4", issue = "76205") 810 )] 811 #[cfg_attr(staged_api, unstable(feature = "ip", issue = "27709"))] 812 #[must_use] 813 #[inline] is_benchmarking(&self) -> bool814 pub const fn is_benchmarking(&self) -> bool { 815 self.octets()[0] == 198 && (self.octets()[1] & 0xfe) == 18 816 } 817 818 /// Returns [`true`] if this address is reserved by IANA for future use. [IETF RFC 1112] 819 /// defines the block of reserved addresses as `240.0.0.0/4`. This range normally includes the 820 /// broadcast address `255.255.255.255`, but this implementation explicitly excludes it, since 821 /// it is obviously not reserved for future use. 822 /// 823 /// [IETF RFC 1112]: https://tools.ietf.org/html/rfc1112 824 /// 825 /// # Warning 826 /// 827 /// As IANA assigns new addresses, this method will be 828 /// updated. This may result in non-reserved addresses being 829 /// treated as reserved in code that relies on an outdated version 830 /// of this method. 831 /// 832 /// # Examples 833 /// 834 /// ``` 835 /// #![feature(ip)] 836 /// use std::net::Ipv4Addr; 837 /// 838 /// assert_eq!(Ipv4Addr::new(240, 0, 0, 0).is_reserved(), true); 839 /// assert_eq!(Ipv4Addr::new(255, 255, 255, 254).is_reserved(), true); 840 /// 841 /// assert_eq!(Ipv4Addr::new(239, 255, 255, 255).is_reserved(), false); 842 /// // The broadcast address is not considered as reserved for future use by this implementation 843 /// assert_eq!(Ipv4Addr::new(255, 255, 255, 255).is_reserved(), false); 844 /// ``` 845 #[cfg_attr( 846 staged_api, 847 rustc_const_unstable(feature = "const_ipv4", issue = "76205") 848 )] 849 #[cfg_attr(staged_api, unstable(feature = "ip", issue = "27709"))] 850 #[must_use] 851 #[inline] is_reserved(&self) -> bool852 pub const fn is_reserved(&self) -> bool { 853 self.octets()[0] & 240 == 240 && !self.is_broadcast() 854 } 855 856 /// Returns [`true`] if this is a multicast address (`224.0.0.0/4`). 857 /// 858 /// Multicast addresses have a most significant octet between `224` and `239`, 859 /// and is defined by [IETF RFC 5771]. 860 /// 861 /// [IETF RFC 5771]: https://tools.ietf.org/html/rfc5771 862 /// 863 /// # Examples 864 /// 865 /// ``` 866 /// use std::net::Ipv4Addr; 867 /// 868 /// assert_eq!(Ipv4Addr::new(224, 254, 0, 0).is_multicast(), true); 869 /// assert_eq!(Ipv4Addr::new(236, 168, 10, 65).is_multicast(), true); 870 /// assert_eq!(Ipv4Addr::new(172, 16, 10, 65).is_multicast(), false); 871 /// ``` 872 #[cfg_attr( 873 staged_api, 874 rustc_const_stable(feature = "const_ip_50", since = "1.50.0") 875 )] 876 #[cfg_attr(staged_api, stable(since = "1.7.0", feature = "ip_17"))] 877 #[must_use] 878 #[inline] is_multicast(&self) -> bool879 pub const fn is_multicast(&self) -> bool { 880 self.octets()[0] >= 224 && self.octets()[0] <= 239 881 } 882 883 /// Returns [`true`] if this is a broadcast address (`255.255.255.255`). 884 /// 885 /// A broadcast address has all octets set to `255` as defined in [IETF RFC 919]. 886 /// 887 /// [IETF RFC 919]: https://tools.ietf.org/html/rfc919 888 /// 889 /// # Examples 890 /// 891 /// ``` 892 /// use std::net::Ipv4Addr; 893 /// 894 /// assert_eq!(Ipv4Addr::new(255, 255, 255, 255).is_broadcast(), true); 895 /// assert_eq!(Ipv4Addr::new(236, 168, 10, 65).is_broadcast(), false); 896 /// ``` 897 #[cfg_attr( 898 staged_api, 899 rustc_const_stable(feature = "const_ip_50", since = "1.50.0") 900 )] 901 #[cfg_attr(staged_api, stable(since = "1.7.0", feature = "ip_17"))] 902 #[must_use] 903 #[inline] is_broadcast(&self) -> bool904 pub const fn is_broadcast(&self) -> bool { 905 u32::from_be_bytes(self.octets()) == u32::from_be_bytes(Self::BROADCAST.octets()) 906 } 907 908 /// Returns [`true`] if this address is in a range designated for documentation. 909 /// 910 /// This is defined in [IETF RFC 5737]: 911 /// 912 /// - `192.0.2.0/24` (TEST-NET-1) 913 /// - `198.51.100.0/24` (TEST-NET-2) 914 /// - `203.0.113.0/24` (TEST-NET-3) 915 /// 916 /// [IETF RFC 5737]: https://tools.ietf.org/html/rfc5737 917 /// 918 /// # Examples 919 /// 920 /// ``` 921 /// use std::net::Ipv4Addr; 922 /// 923 /// assert_eq!(Ipv4Addr::new(192, 0, 2, 255).is_documentation(), true); 924 /// assert_eq!(Ipv4Addr::new(198, 51, 100, 65).is_documentation(), true); 925 /// assert_eq!(Ipv4Addr::new(203, 0, 113, 6).is_documentation(), true); 926 /// assert_eq!(Ipv4Addr::new(193, 34, 17, 19).is_documentation(), false); 927 /// ``` 928 #[cfg_attr( 929 staged_api, 930 rustc_const_stable(feature = "const_ip_50", since = "1.50.0") 931 )] 932 #[cfg_attr(staged_api, stable(since = "1.7.0", feature = "ip_17"))] 933 #[must_use] 934 #[inline] is_documentation(&self) -> bool935 pub const fn is_documentation(&self) -> bool { 936 matches!( 937 self.octets(), 938 [192, 0, 2, _] | [198, 51, 100, _] | [203, 0, 113, _] 939 ) 940 } 941 942 /// Converts this address to an [IPv4-compatible] [`IPv6` address]. 943 /// 944 /// `a.b.c.d` becomes `::a.b.c.d` 945 /// 946 /// Note that IPv4-compatible addresses have been officially deprecated. 947 /// If you don't explicitly need an IPv4-compatible address for legacy reasons, consider using `to_ipv6_mapped` instead. 948 /// 949 /// [IPv4-compatible]: Ipv6Addr#ipv4-compatible-ipv6-addresses 950 /// [`IPv6` address]: Ipv6Addr 951 /// 952 /// # Examples 953 /// 954 /// ``` 955 /// use std::net::{Ipv4Addr, Ipv6Addr}; 956 /// 957 /// assert_eq!( 958 /// Ipv4Addr::new(192, 0, 2, 255).to_ipv6_compatible(), 959 /// Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0xc000, 0x2ff) 960 /// ); 961 /// ``` 962 #[cfg_attr( 963 staged_api, 964 rustc_const_stable(feature = "const_ip_50", since = "1.50.0") 965 )] 966 #[cfg_attr(staged_api, stable(feature = "rust1", since = "1.0.0"))] 967 #[must_use = "this returns the result of the operation, \ 968 without modifying the original"] 969 #[inline] to_ipv6_compatible(&self) -> Ipv6Addr970 pub const fn to_ipv6_compatible(&self) -> Ipv6Addr { 971 let [a, b, c, d] = self.octets(); 972 Ipv6Addr { 973 octets: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, a, b, c, d], 974 } 975 } 976 977 /// Converts this address to an [IPv4-mapped] [`IPv6` address]. 978 /// 979 /// `a.b.c.d` becomes `::ffff:a.b.c.d` 980 /// 981 /// [IPv4-mapped]: Ipv6Addr#ipv4-mapped-ipv6-addresses 982 /// [`IPv6` address]: Ipv6Addr 983 /// 984 /// # Examples 985 /// 986 /// ``` 987 /// use std::net::{Ipv4Addr, Ipv6Addr}; 988 /// 989 /// assert_eq!(Ipv4Addr::new(192, 0, 2, 255).to_ipv6_mapped(), 990 /// Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc000, 0x2ff)); 991 /// ``` 992 #[cfg_attr( 993 staged_api, 994 rustc_const_stable(feature = "const_ip_50", since = "1.50.0") 995 )] 996 #[cfg_attr(staged_api, stable(feature = "rust1", since = "1.0.0"))] 997 #[must_use = "this returns the result of the operation, \ 998 without modifying the original"] 999 #[inline] to_ipv6_mapped(&self) -> Ipv6Addr1000 pub const fn to_ipv6_mapped(&self) -> Ipv6Addr { 1001 let [a, b, c, d] = self.octets(); 1002 Ipv6Addr { 1003 octets: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xFF, 0xFF, a, b, c, d], 1004 } 1005 } 1006 } 1007 1008 #[cfg_attr(staged_api, stable(feature = "ip_from_ip", since = "1.16.0"))] 1009 impl From<Ipv4Addr> for IpAddr { 1010 /// Copies this address to a new `IpAddr::V4`. 1011 /// 1012 /// # Examples 1013 /// 1014 /// ``` 1015 /// use std::net::{IpAddr, Ipv4Addr}; 1016 /// 1017 /// let addr = Ipv4Addr::new(127, 0, 0, 1); 1018 /// 1019 /// assert_eq!( 1020 /// IpAddr::V4(addr), 1021 /// IpAddr::from(addr) 1022 /// ) 1023 /// ``` 1024 #[inline] from(ipv4: Ipv4Addr) -> IpAddr1025 fn from(ipv4: Ipv4Addr) -> IpAddr { 1026 IpAddr::V4(ipv4) 1027 } 1028 } 1029 1030 #[cfg_attr(staged_api, stable(feature = "ip_from_ip", since = "1.16.0"))] 1031 impl From<Ipv6Addr> for IpAddr { 1032 /// Copies this address to a new `IpAddr::V6`. 1033 /// 1034 /// # Examples 1035 /// 1036 /// ``` 1037 /// use std::net::{IpAddr, Ipv6Addr}; 1038 /// 1039 /// let addr = Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff); 1040 /// 1041 /// assert_eq!( 1042 /// IpAddr::V6(addr), 1043 /// IpAddr::from(addr) 1044 /// ); 1045 /// ``` 1046 #[inline] from(ipv6: Ipv6Addr) -> IpAddr1047 fn from(ipv6: Ipv6Addr) -> IpAddr { 1048 IpAddr::V6(ipv6) 1049 } 1050 } 1051 1052 #[cfg_attr(staged_api, stable(feature = "ip_cmp", since = "1.16.0"))] 1053 impl PartialEq<Ipv4Addr> for IpAddr { 1054 #[inline] eq(&self, other: &Ipv4Addr) -> bool1055 fn eq(&self, other: &Ipv4Addr) -> bool { 1056 match self { 1057 IpAddr::V4(v4) => v4 == other, 1058 IpAddr::V6(_) => false, 1059 } 1060 } 1061 } 1062 1063 #[cfg_attr(staged_api, stable(feature = "ip_cmp", since = "1.16.0"))] 1064 impl PartialEq<IpAddr> for Ipv4Addr { 1065 #[inline] eq(&self, other: &IpAddr) -> bool1066 fn eq(&self, other: &IpAddr) -> bool { 1067 match other { 1068 IpAddr::V4(v4) => self == v4, 1069 IpAddr::V6(_) => false, 1070 } 1071 } 1072 } 1073 1074 #[cfg_attr(staged_api, stable(feature = "rust1", since = "1.0.0"))] 1075 impl PartialOrd for Ipv4Addr { 1076 #[inline] partial_cmp(&self, other: &Ipv4Addr) -> Option<Ordering>1077 fn partial_cmp(&self, other: &Ipv4Addr) -> Option<Ordering> { 1078 Some(self.cmp(other)) 1079 } 1080 } 1081 1082 #[cfg_attr(staged_api, stable(feature = "ip_cmp", since = "1.16.0"))] 1083 impl PartialOrd<Ipv4Addr> for IpAddr { 1084 #[inline] partial_cmp(&self, other: &Ipv4Addr) -> Option<Ordering>1085 fn partial_cmp(&self, other: &Ipv4Addr) -> Option<Ordering> { 1086 match self { 1087 IpAddr::V4(v4) => v4.partial_cmp(other), 1088 IpAddr::V6(_) => Some(Ordering::Greater), 1089 } 1090 } 1091 } 1092 1093 #[cfg_attr(staged_api, stable(feature = "ip_cmp", since = "1.16.0"))] 1094 impl PartialOrd<IpAddr> for Ipv4Addr { 1095 #[inline] partial_cmp(&self, other: &IpAddr) -> Option<Ordering>1096 fn partial_cmp(&self, other: &IpAddr) -> Option<Ordering> { 1097 match other { 1098 IpAddr::V4(v4) => self.partial_cmp(v4), 1099 IpAddr::V6(_) => Some(Ordering::Less), 1100 } 1101 } 1102 } 1103 1104 #[cfg_attr(staged_api, stable(feature = "rust1", since = "1.0.0"))] 1105 impl Ord for Ipv4Addr { 1106 #[inline] cmp(&self, other: &Ipv4Addr) -> Ordering1107 fn cmp(&self, other: &Ipv4Addr) -> Ordering { 1108 self.octets.cmp(&other.octets) 1109 } 1110 } 1111 1112 #[cfg_attr(staged_api, stable(feature = "ip_u32", since = "1.1.0"))] 1113 impl From<Ipv4Addr> for u32 { 1114 /// Converts an `Ipv4Addr` into a host byte order `u32`. 1115 /// 1116 /// # Examples 1117 /// 1118 /// ``` 1119 /// use std::net::Ipv4Addr; 1120 /// 1121 /// let addr = Ipv4Addr::new(0x12, 0x34, 0x56, 0x78); 1122 /// assert_eq!(0x12345678, u32::from(addr)); 1123 /// ``` 1124 #[inline] from(ip: Ipv4Addr) -> u321125 fn from(ip: Ipv4Addr) -> u32 { 1126 u32::from_be_bytes(ip.octets) 1127 } 1128 } 1129 1130 #[cfg_attr(staged_api, stable(feature = "ip_u32", since = "1.1.0"))] 1131 impl From<u32> for Ipv4Addr { 1132 /// Converts a host byte order `u32` into an `Ipv4Addr`. 1133 /// 1134 /// # Examples 1135 /// 1136 /// ``` 1137 /// use std::net::Ipv4Addr; 1138 /// 1139 /// let addr = Ipv4Addr::from(0x12345678); 1140 /// assert_eq!(Ipv4Addr::new(0x12, 0x34, 0x56, 0x78), addr); 1141 /// ``` 1142 #[inline] from(ip: u32) -> Ipv4Addr1143 fn from(ip: u32) -> Ipv4Addr { 1144 Ipv4Addr { 1145 octets: ip.to_be_bytes(), 1146 } 1147 } 1148 } 1149 1150 #[cfg_attr(staged_api, stable(feature = "from_slice_v4", since = "1.9.0"))] 1151 impl From<[u8; 4]> for Ipv4Addr { 1152 /// Creates an `Ipv4Addr` from a four element byte array. 1153 /// 1154 /// # Examples 1155 /// 1156 /// ``` 1157 /// use std::net::Ipv4Addr; 1158 /// 1159 /// let addr = Ipv4Addr::from([13u8, 12u8, 11u8, 10u8]); 1160 /// assert_eq!(Ipv4Addr::new(13, 12, 11, 10), addr); 1161 /// ``` 1162 #[inline] from(octets: [u8; 4]) -> Ipv4Addr1163 fn from(octets: [u8; 4]) -> Ipv4Addr { 1164 Ipv4Addr { octets } 1165 } 1166 } 1167 1168 #[cfg_attr(staged_api, stable(feature = "ip_from_slice", since = "1.17.0"))] 1169 impl From<[u8; 4]> for IpAddr { 1170 /// Creates an `IpAddr::V4` from a four element byte array. 1171 /// 1172 /// # Examples 1173 /// 1174 /// ``` 1175 /// use std::net::{IpAddr, Ipv4Addr}; 1176 /// 1177 /// let addr = IpAddr::from([13u8, 12u8, 11u8, 10u8]); 1178 /// assert_eq!(IpAddr::V4(Ipv4Addr::new(13, 12, 11, 10)), addr); 1179 /// ``` 1180 #[inline] from(octets: [u8; 4]) -> IpAddr1181 fn from(octets: [u8; 4]) -> IpAddr { 1182 IpAddr::V4(Ipv4Addr::from(octets)) 1183 } 1184 } 1185 1186 impl Ipv6Addr { 1187 /// Creates a new IPv6 address from eight 16-bit segments. 1188 /// 1189 /// The result will represent the IP address `a:b:c:d:e:f:g:h`. 1190 /// 1191 /// # Examples 1192 /// 1193 /// ``` 1194 /// use std::net::Ipv6Addr; 1195 /// 1196 /// let addr = Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff); 1197 /// ``` 1198 #[cfg_attr( 1199 staged_api, 1200 rustc_const_stable(feature = "const_ip_32", since = "1.32.0") 1201 )] 1202 #[cfg_attr(staged_api, stable(feature = "rust1", since = "1.0.0"))] 1203 #[allow(clippy::too_many_arguments)] 1204 #[must_use] 1205 #[inline] new(a: u16, b: u16, c: u16, d: u16, e: u16, f: u16, g: u16, h: u16) -> Ipv6Addr1206 pub const fn new(a: u16, b: u16, c: u16, d: u16, e: u16, f: u16, g: u16, h: u16) -> Ipv6Addr { 1207 let addr16 = [ 1208 a.to_be(), 1209 b.to_be(), 1210 c.to_be(), 1211 d.to_be(), 1212 e.to_be(), 1213 f.to_be(), 1214 g.to_be(), 1215 h.to_be(), 1216 ]; 1217 Ipv6Addr { 1218 // All elements in `addr16` are big endian. 1219 // SAFETY: `[u16; 8]` is always safe to transmute to `[u8; 16]`. 1220 octets: unsafe { transmute::<_, [u8; 16]>(addr16) }, 1221 } 1222 } 1223 1224 /// An IPv6 address representing localhost: `::1`. 1225 /// 1226 /// This corresponds to constant `IN6ADDR_LOOPBACK_INIT` or `in6addr_loopback` in other 1227 /// languages. 1228 /// 1229 /// # Examples 1230 /// 1231 /// ``` 1232 /// use std::net::Ipv6Addr; 1233 /// 1234 /// let addr = Ipv6Addr::LOCALHOST; 1235 /// assert_eq!(addr, Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1)); 1236 /// ``` 1237 #[doc(alias = "IN6ADDR_LOOPBACK_INIT")] 1238 #[doc(alias = "in6addr_loopback")] 1239 #[cfg_attr(staged_api, stable(feature = "ip_constructors", since = "1.30.0"))] 1240 pub const LOCALHOST: Self = Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1); 1241 1242 /// An IPv6 address representing the unspecified address: `::` 1243 /// 1244 /// This corresponds to constant `IN6ADDR_ANY_INIT` or `in6addr_any` in other languages. 1245 /// 1246 /// # Examples 1247 /// 1248 /// ``` 1249 /// use std::net::Ipv6Addr; 1250 /// 1251 /// let addr = Ipv6Addr::UNSPECIFIED; 1252 /// assert_eq!(addr, Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0)); 1253 /// ``` 1254 #[doc(alias = "IN6ADDR_ANY_INIT")] 1255 #[doc(alias = "in6addr_any")] 1256 #[cfg_attr(staged_api, stable(feature = "ip_constructors", since = "1.30.0"))] 1257 pub const UNSPECIFIED: Self = Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0); 1258 1259 /// Returns the eight 16-bit segments that make up this address. 1260 /// 1261 /// # Examples 1262 /// 1263 /// ``` 1264 /// use std::net::Ipv6Addr; 1265 /// 1266 /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff).segments(), 1267 /// [0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff]); 1268 /// ``` 1269 #[cfg_attr( 1270 staged_api, 1271 rustc_const_stable(feature = "const_ip_50", since = "1.50.0") 1272 )] 1273 #[cfg_attr(staged_api, stable(feature = "rust1", since = "1.0.0"))] 1274 #[must_use] 1275 #[inline] segments(&self) -> [u16; 8]1276 pub const fn segments(&self) -> [u16; 8] { 1277 // All elements in `self.octets` must be big endian. 1278 // SAFETY: `[u8; 16]` is always safe to transmute to `[u16; 8]`. 1279 let [a, b, c, d, e, f, g, h] = unsafe { transmute::<_, [u16; 8]>(self.octets) }; 1280 // We want native endian u16 1281 [ 1282 u16::from_be(a), 1283 u16::from_be(b), 1284 u16::from_be(c), 1285 u16::from_be(d), 1286 u16::from_be(e), 1287 u16::from_be(f), 1288 u16::from_be(g), 1289 u16::from_be(h), 1290 ] 1291 } 1292 1293 /// Returns [`true`] for the special 'unspecified' address (`::`). 1294 /// 1295 /// This property is defined in [IETF RFC 4291]. 1296 /// 1297 /// [IETF RFC 4291]: https://tools.ietf.org/html/rfc4291 1298 /// 1299 /// # Examples 1300 /// 1301 /// ``` 1302 /// use std::net::Ipv6Addr; 1303 /// 1304 /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff).is_unspecified(), false); 1305 /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0).is_unspecified(), true); 1306 /// ``` 1307 #[cfg_attr( 1308 staged_api, 1309 rustc_const_stable(feature = "const_ip_50", since = "1.50.0") 1310 )] 1311 #[cfg_attr(staged_api, stable(since = "1.7.0", feature = "ip_17"))] 1312 #[must_use] 1313 #[inline] is_unspecified(&self) -> bool1314 pub const fn is_unspecified(&self) -> bool { 1315 u128::from_be_bytes(self.octets()) == u128::from_be_bytes(Ipv6Addr::UNSPECIFIED.octets()) 1316 } 1317 1318 /// Returns [`true`] if this is the [loopback address] (`::1`), 1319 /// as defined in [IETF RFC 4291 section 2.5.3]. 1320 /// 1321 /// Contrary to IPv4, in IPv6 there is only one loopback address. 1322 /// 1323 /// [loopback address]: Ipv6Addr::LOCALHOST 1324 /// [IETF RFC 4291 section 2.5.3]: https://tools.ietf.org/html/rfc4291#section-2.5.3 1325 /// 1326 /// # Examples 1327 /// 1328 /// ``` 1329 /// use std::net::Ipv6Addr; 1330 /// 1331 /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff).is_loopback(), false); 1332 /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0x1).is_loopback(), true); 1333 /// ``` 1334 #[cfg_attr( 1335 staged_api, 1336 rustc_const_stable(feature = "const_ip_50", since = "1.50.0") 1337 )] 1338 #[cfg_attr(staged_api, stable(since = "1.7.0", feature = "ip_17"))] 1339 #[must_use] 1340 #[inline] is_loopback(&self) -> bool1341 pub const fn is_loopback(&self) -> bool { 1342 u128::from_be_bytes(self.octets()) == u128::from_be_bytes(Ipv6Addr::LOCALHOST.octets()) 1343 } 1344 1345 /// Returns [`true`] if the address appears to be globally reachable 1346 /// as specified by the [IANA IPv6 Special-Purpose Address Registry]. 1347 /// Whether or not an address is practically reachable will depend on your network configuration. 1348 /// 1349 /// Most IPv6 addresses are globally reachable; 1350 /// unless they are specifically defined as *not* globally reachable. 1351 /// 1352 /// Non-exhaustive list of notable addresses that are not globally reachable: 1353 /// - The [unspecified address] ([`is_unspecified`](Ipv6Addr::is_unspecified)) 1354 /// - The [loopback address] ([`is_loopback`](Ipv6Addr::is_loopback)) 1355 /// - IPv4-mapped addresses 1356 /// - Addresses reserved for benchmarking 1357 /// - Addresses reserved for documentation ([`is_documentation`](Ipv6Addr::is_documentation)) 1358 /// - Unique local addresses ([`is_unique_local`](Ipv6Addr::is_unique_local)) 1359 /// - Unicast addresses with link-local scope ([`is_unicast_link_local`](Ipv6Addr::is_unicast_link_local)) 1360 /// 1361 /// For the complete overview of which addresses are globally reachable, see the table at the [IANA IPv6 Special-Purpose Address Registry]. 1362 /// 1363 /// Note that an address having global scope is not the same as being globally reachable, 1364 /// and there is no direct relation between the two concepts: There exist addresses with global scope 1365 /// that are not globally reachable (for example unique local addresses), 1366 /// and addresses that are globally reachable without having global scope 1367 /// (multicast addresses with non-global scope). 1368 /// 1369 /// [IANA IPv6 Special-Purpose Address Registry]: https://www.iana.org/assignments/iana-ipv6-special-registry/iana-ipv6-special-registry.xhtml 1370 /// [unspecified address]: Ipv6Addr::UNSPECIFIED 1371 /// [loopback address]: Ipv6Addr::LOCALHOST 1372 /// 1373 /// # Examples 1374 /// 1375 /// ``` 1376 /// #![feature(ip)] 1377 /// 1378 /// use std::net::Ipv6Addr; 1379 /// 1380 /// // Most IPv6 addresses are globally reachable: 1381 /// assert_eq!(Ipv6Addr::new(0x26, 0, 0x1c9, 0, 0, 0xafc8, 0x10, 0x1).is_global(), true); 1382 /// 1383 /// // However some addresses have been assigned a special meaning 1384 /// // that makes them not globally reachable. Some examples are: 1385 /// 1386 /// // The unspecified address (`::`) 1387 /// assert_eq!(Ipv6Addr::UNSPECIFIED.is_global(), false); 1388 /// 1389 /// // The loopback address (`::1`) 1390 /// assert_eq!(Ipv6Addr::LOCALHOST.is_global(), false); 1391 /// 1392 /// // IPv4-mapped addresses (`::ffff:0:0/96`) 1393 /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff).is_global(), false); 1394 /// 1395 /// // Addresses reserved for benchmarking (`2001:2::/48`) 1396 /// assert_eq!(Ipv6Addr::new(0x2001, 2, 0, 0, 0, 0, 0, 1,).is_global(), false); 1397 /// 1398 /// // Addresses reserved for documentation (`2001:db8::/32`) 1399 /// assert_eq!(Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 1).is_global(), false); 1400 /// 1401 /// // Unique local addresses (`fc00::/7`) 1402 /// assert_eq!(Ipv6Addr::new(0xfc02, 0, 0, 0, 0, 0, 0, 1).is_global(), false); 1403 /// 1404 /// // Unicast addresses with link-local scope (`fe80::/10`) 1405 /// assert_eq!(Ipv6Addr::new(0xfe81, 0, 0, 0, 0, 0, 0, 1).is_global(), false); 1406 /// 1407 /// // For a complete overview see the IANA IPv6 Special-Purpose Address Registry. 1408 /// ``` 1409 #[cfg_attr( 1410 staged_api, 1411 rustc_const_unstable(feature = "const_ipv6", issue = "76205") 1412 )] 1413 #[cfg_attr(staged_api, unstable(feature = "ip", issue = "27709"))] 1414 #[must_use] 1415 #[inline] is_global(&self) -> bool1416 pub const fn is_global(&self) -> bool { 1417 !(self.is_unspecified() 1418 || self.is_loopback() 1419 // IPv4-mapped Address (`::ffff:0:0/96`) 1420 || matches!(self.segments(), [0, 0, 0, 0, 0, 0xffff, _, _]) 1421 // IPv4-IPv6 Translat. (`64:ff9b:1::/48`) 1422 || matches!(self.segments(), [0x64, 0xff9b, 1, _, _, _, _, _]) 1423 // Discard-Only Address Block (`100::/64`) 1424 || matches!(self.segments(), [0x100, 0, 0, 0, _, _, _, _]) 1425 // IETF Protocol Assignments (`2001::/23`) 1426 || (matches!(self.segments(), [0x2001, b, _, _, _, _, _, _] if b < 0x200) 1427 && !( 1428 // Port Control Protocol Anycast (`2001:1::1`) 1429 u128::from_be_bytes(self.octets()) == 0x2001_0001_0000_0000_0000_0000_0000_0001 1430 // Traversal Using Relays around NAT Anycast (`2001:1::2`) 1431 || u128::from_be_bytes(self.octets()) == 0x2001_0001_0000_0000_0000_0000_0000_0002 1432 // AMT (`2001:3::/32`) 1433 || matches!(self.segments(), [0x2001, 3, _, _, _, _, _, _]) 1434 // AS112-v6 (`2001:4:112::/48`) 1435 || matches!(self.segments(), [0x2001, 4, 0x112, _, _, _, _, _]) 1436 // ORCHIDv2 (`2001:20::/28`) 1437 || matches!(self.segments(), [0x2001, b, _, _, _, _, _, _] if b >= 0x20 && b <= 0x2F) 1438 )) 1439 || self.is_documentation() 1440 || self.is_unique_local() 1441 || self.is_unicast_link_local()) 1442 } 1443 1444 /// Returns [`true`] if this is a unique local address (`fc00::/7`). 1445 /// 1446 /// This property is defined in [IETF RFC 4193]. 1447 /// 1448 /// [IETF RFC 4193]: https://tools.ietf.org/html/rfc4193 1449 /// 1450 /// # Examples 1451 /// 1452 /// ``` 1453 /// #![feature(ip)] 1454 /// 1455 /// use std::net::Ipv6Addr; 1456 /// 1457 /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff).is_unique_local(), false); 1458 /// assert_eq!(Ipv6Addr::new(0xfc02, 0, 0, 0, 0, 0, 0, 0).is_unique_local(), true); 1459 /// ``` 1460 #[cfg_attr( 1461 staged_api, 1462 rustc_const_unstable(feature = "const_ipv6", issue = "76205") 1463 )] 1464 #[cfg_attr(staged_api, unstable(feature = "ip", issue = "27709"))] 1465 #[must_use] 1466 #[inline] is_unique_local(&self) -> bool1467 pub const fn is_unique_local(&self) -> bool { 1468 (self.segments()[0] & 0xfe00) == 0xfc00 1469 } 1470 1471 /// Returns [`true`] if this is a unicast address, as defined by [IETF RFC 4291]. 1472 /// Any address that is not a [multicast address] (`ff00::/8`) is unicast. 1473 /// 1474 /// [IETF RFC 4291]: https://tools.ietf.org/html/rfc4291 1475 /// [multicast address]: Ipv6Addr::is_multicast 1476 /// 1477 /// # Examples 1478 /// 1479 /// ``` 1480 /// #![feature(ip)] 1481 /// 1482 /// use std::net::Ipv6Addr; 1483 /// 1484 /// // The unspecified and loopback addresses are unicast. 1485 /// assert_eq!(Ipv6Addr::UNSPECIFIED.is_unicast(), true); 1486 /// assert_eq!(Ipv6Addr::LOCALHOST.is_unicast(), true); 1487 /// 1488 /// // Any address that is not a multicast address (`ff00::/8`) is unicast. 1489 /// assert_eq!(Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 0).is_unicast(), true); 1490 /// assert_eq!(Ipv6Addr::new(0xff00, 0, 0, 0, 0, 0, 0, 0).is_unicast(), false); 1491 /// ``` 1492 #[cfg_attr( 1493 staged_api, 1494 rustc_const_unstable(feature = "const_ipv6", issue = "76205") 1495 )] 1496 #[cfg_attr(staged_api, unstable(feature = "ip", issue = "27709"))] 1497 #[must_use] 1498 #[inline] is_unicast(&self) -> bool1499 pub const fn is_unicast(&self) -> bool { 1500 !self.is_multicast() 1501 } 1502 1503 /// Returns `true` if the address is a unicast address with link-local scope, 1504 /// as defined in [RFC 4291]. 1505 /// 1506 /// A unicast address has link-local scope if it has the prefix `fe80::/10`, as per [RFC 4291 section 2.4]. 1507 /// Note that this encompasses more addresses than those defined in [RFC 4291 section 2.5.6], 1508 /// which describes "Link-Local IPv6 Unicast Addresses" as having the following stricter format: 1509 /// 1510 /// ```text 1511 /// | 10 bits | 54 bits | 64 bits | 1512 /// +----------+-------------------------+----------------------------+ 1513 /// |1111111010| 0 | interface ID | 1514 /// +----------+-------------------------+----------------------------+ 1515 /// ``` 1516 /// So while currently the only addresses with link-local scope an application will encounter are all in `fe80::/64`, 1517 /// this might change in the future with the publication of new standards. More addresses in `fe80::/10` could be allocated, 1518 /// and those addresses will have link-local scope. 1519 /// 1520 /// Also note that while [RFC 4291 section 2.5.3] mentions about the [loopback address] (`::1`) that "it is treated as having Link-Local scope", 1521 /// this does not mean that the loopback address actually has link-local scope and this method will return `false` on it. 1522 /// 1523 /// [RFC 4291]: https://tools.ietf.org/html/rfc4291 1524 /// [RFC 4291 section 2.4]: https://tools.ietf.org/html/rfc4291#section-2.4 1525 /// [RFC 4291 section 2.5.3]: https://tools.ietf.org/html/rfc4291#section-2.5.3 1526 /// [RFC 4291 section 2.5.6]: https://tools.ietf.org/html/rfc4291#section-2.5.6 1527 /// [loopback address]: Ipv6Addr::LOCALHOST 1528 /// 1529 /// # Examples 1530 /// 1531 /// ``` 1532 /// #![feature(ip)] 1533 /// 1534 /// use std::net::Ipv6Addr; 1535 /// 1536 /// // The loopback address (`::1`) does not actually have link-local scope. 1537 /// assert_eq!(Ipv6Addr::LOCALHOST.is_unicast_link_local(), false); 1538 /// 1539 /// // Only addresses in `fe80::/10` have link-local scope. 1540 /// assert_eq!(Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 0).is_unicast_link_local(), false); 1541 /// assert_eq!(Ipv6Addr::new(0xfe80, 0, 0, 0, 0, 0, 0, 0).is_unicast_link_local(), true); 1542 /// 1543 /// // Addresses outside the stricter `fe80::/64` also have link-local scope. 1544 /// assert_eq!(Ipv6Addr::new(0xfe80, 0, 0, 1, 0, 0, 0, 0).is_unicast_link_local(), true); 1545 /// assert_eq!(Ipv6Addr::new(0xfe81, 0, 0, 0, 0, 0, 0, 0).is_unicast_link_local(), true); 1546 /// ``` 1547 #[cfg_attr( 1548 staged_api, 1549 rustc_const_unstable(feature = "const_ipv6", issue = "76205") 1550 )] 1551 #[cfg_attr(staged_api, unstable(feature = "ip", issue = "27709"))] 1552 #[must_use] 1553 #[inline] is_unicast_link_local(&self) -> bool1554 pub const fn is_unicast_link_local(&self) -> bool { 1555 (self.segments()[0] & 0xffc0) == 0xfe80 1556 } 1557 1558 /// Returns [`true`] if this is an address reserved for documentation 1559 /// (`2001:db8::/32`). 1560 /// 1561 /// This property is defined in [IETF RFC 3849]. 1562 /// 1563 /// [IETF RFC 3849]: https://tools.ietf.org/html/rfc3849 1564 /// 1565 /// # Examples 1566 /// 1567 /// ``` 1568 /// #![feature(ip)] 1569 /// 1570 /// use std::net::Ipv6Addr; 1571 /// 1572 /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff).is_documentation(), false); 1573 /// assert_eq!(Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 0).is_documentation(), true); 1574 /// ``` 1575 #[cfg_attr( 1576 staged_api, 1577 rustc_const_unstable(feature = "const_ipv6", issue = "76205") 1578 )] 1579 #[cfg_attr(staged_api, unstable(feature = "ip", issue = "27709"))] 1580 #[must_use] 1581 #[inline] is_documentation(&self) -> bool1582 pub const fn is_documentation(&self) -> bool { 1583 (self.segments()[0] == 0x2001) && (self.segments()[1] == 0xdb8) 1584 } 1585 1586 /// Returns [`true`] if this is an address reserved for benchmarking (`2001:2::/48`). 1587 /// 1588 /// This property is defined in [IETF RFC 5180], where it is mistakenly specified as covering the range `2001:0200::/48`. 1589 /// This is corrected in [IETF RFC Errata 1752] to `2001:0002::/48`. 1590 /// 1591 /// [IETF RFC 5180]: https://tools.ietf.org/html/rfc5180 1592 /// [IETF RFC Errata 1752]: https://www.rfc-editor.org/errata_search.php?eid=1752 1593 /// 1594 /// ``` 1595 /// #![feature(ip)] 1596 /// 1597 /// use std::net::Ipv6Addr; 1598 /// 1599 /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc613, 0x0).is_benchmarking(), false); 1600 /// assert_eq!(Ipv6Addr::new(0x2001, 0x2, 0, 0, 0, 0, 0, 0).is_benchmarking(), true); 1601 /// ``` 1602 #[cfg_attr(staged_api, unstable(feature = "ip", issue = "27709"))] 1603 #[must_use] 1604 #[inline] is_benchmarking(&self) -> bool1605 pub const fn is_benchmarking(&self) -> bool { 1606 (self.segments()[0] == 0x2001) && (self.segments()[1] == 0x2) && (self.segments()[2] == 0) 1607 } 1608 1609 /// Returns [`true`] if the address is a globally routable unicast address. 1610 /// 1611 /// The following return false: 1612 /// 1613 /// - the loopback address 1614 /// - the link-local addresses 1615 /// - unique local addresses 1616 /// - the unspecified address 1617 /// - the address range reserved for documentation 1618 /// 1619 /// This method returns [`true`] for site-local addresses as per [RFC 4291 section 2.5.7] 1620 /// 1621 /// ```no_rust 1622 /// The special behavior of [the site-local unicast] prefix defined in [RFC3513] must no longer 1623 /// be supported in new implementations (i.e., new implementations must treat this prefix as 1624 /// Global Unicast). 1625 /// ``` 1626 /// 1627 /// [RFC 4291 section 2.5.7]: https://tools.ietf.org/html/rfc4291#section-2.5.7 1628 /// 1629 /// # Examples 1630 /// 1631 /// ``` 1632 /// #![feature(ip)] 1633 /// 1634 /// use std::net::Ipv6Addr; 1635 /// 1636 /// assert_eq!(Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 0).is_unicast_global(), false); 1637 /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff).is_unicast_global(), true); 1638 /// ``` 1639 #[cfg_attr( 1640 staged_api, 1641 rustc_const_unstable(feature = "const_ipv6", issue = "76205") 1642 )] 1643 #[cfg_attr(staged_api, unstable(feature = "ip", issue = "27709"))] 1644 #[must_use] 1645 #[inline] is_unicast_global(&self) -> bool1646 pub const fn is_unicast_global(&self) -> bool { 1647 self.is_unicast() 1648 && !self.is_loopback() 1649 && !self.is_unicast_link_local() 1650 && !self.is_unique_local() 1651 && !self.is_unspecified() 1652 && !self.is_documentation() 1653 && !self.is_benchmarking() 1654 } 1655 1656 /// Returns the address' multicast scope if the address is multicast. 1657 /// 1658 /// # Examples 1659 /// 1660 /// ``` 1661 /// #![feature(ip)] 1662 /// 1663 /// use std::net::{Ipv6Addr, Ipv6MulticastScope}; 1664 /// 1665 /// assert_eq!( 1666 /// Ipv6Addr::new(0xff0e, 0, 0, 0, 0, 0, 0, 0).multicast_scope(), 1667 /// Some(Ipv6MulticastScope::Global) 1668 /// ); 1669 /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff).multicast_scope(), None); 1670 /// ``` 1671 #[cfg_attr( 1672 staged_api, 1673 rustc_const_unstable(feature = "const_ipv6", issue = "76205") 1674 )] 1675 #[cfg_attr(staged_api, unstable(feature = "ip", issue = "27709"))] 1676 #[must_use] 1677 #[inline] multicast_scope(&self) -> Option<Ipv6MulticastScope>1678 pub const fn multicast_scope(&self) -> Option<Ipv6MulticastScope> { 1679 if self.is_multicast() { 1680 match self.segments()[0] & 0x000f { 1681 1 => Some(Ipv6MulticastScope::InterfaceLocal), 1682 2 => Some(Ipv6MulticastScope::LinkLocal), 1683 3 => Some(Ipv6MulticastScope::RealmLocal), 1684 4 => Some(Ipv6MulticastScope::AdminLocal), 1685 5 => Some(Ipv6MulticastScope::SiteLocal), 1686 8 => Some(Ipv6MulticastScope::OrganizationLocal), 1687 14 => Some(Ipv6MulticastScope::Global), 1688 _ => None, 1689 } 1690 } else { 1691 None 1692 } 1693 } 1694 1695 /// Returns [`true`] if this is a multicast address (`ff00::/8`). 1696 /// 1697 /// This property is defined by [IETF RFC 4291]. 1698 /// 1699 /// [IETF RFC 4291]: https://tools.ietf.org/html/rfc4291 1700 /// 1701 /// # Examples 1702 /// 1703 /// ``` 1704 /// use std::net::Ipv6Addr; 1705 /// 1706 /// assert_eq!(Ipv6Addr::new(0xff00, 0, 0, 0, 0, 0, 0, 0).is_multicast(), true); 1707 /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff).is_multicast(), false); 1708 /// ``` 1709 #[cfg_attr( 1710 staged_api, 1711 rustc_const_stable(feature = "const_ip_50", since = "1.50.0") 1712 )] 1713 #[cfg_attr(staged_api, stable(since = "1.7.0", feature = "ip_17"))] 1714 #[must_use] 1715 #[inline] is_multicast(&self) -> bool1716 pub const fn is_multicast(&self) -> bool { 1717 (self.segments()[0] & 0xff00) == 0xff00 1718 } 1719 1720 /// Converts this address to an [`IPv4` address] if it's an [IPv4-mapped] address, 1721 /// as defined in [IETF RFC 4291 section 2.5.5.2], otherwise returns [`None`]. 1722 /// 1723 /// `::ffff:a.b.c.d` becomes `a.b.c.d`. 1724 /// All addresses *not* starting with `::ffff` will return `None`. 1725 /// 1726 /// [`IPv4` address]: Ipv4Addr 1727 /// [IPv4-mapped]: Ipv6Addr 1728 /// [IETF RFC 4291 section 2.5.5.2]: https://tools.ietf.org/html/rfc4291#section-2.5.5.2 1729 /// 1730 /// # Examples 1731 /// 1732 /// ``` 1733 /// use std::net::{Ipv4Addr, Ipv6Addr}; 1734 /// 1735 /// assert_eq!(Ipv6Addr::new(0xff00, 0, 0, 0, 0, 0, 0, 0).to_ipv4_mapped(), None); 1736 /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff).to_ipv4_mapped(), 1737 /// Some(Ipv4Addr::new(192, 10, 2, 255))); 1738 /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1).to_ipv4_mapped(), None); 1739 /// ``` 1740 #[cfg_attr( 1741 staged_api, 1742 rustc_const_unstable(feature = "const_ipv6", issue = "76205") 1743 )] 1744 #[cfg_attr(staged_api, stable(feature = "ipv6_to_ipv4_mapped", since = "1.63.0"))] 1745 #[must_use = "this returns the result of the operation, \ 1746 without modifying the original"] 1747 #[inline] to_ipv4_mapped(&self) -> Option<Ipv4Addr>1748 pub const fn to_ipv4_mapped(&self) -> Option<Ipv4Addr> { 1749 match self.octets() { 1750 [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xff, 0xff, a, b, c, d] => { 1751 Some(Ipv4Addr::new(a, b, c, d)) 1752 } 1753 _ => None, 1754 } 1755 } 1756 1757 /// Converts this address to an [`IPv4` address] if it is either 1758 /// an [IPv4-compatible] address as defined in [IETF RFC 4291 section 2.5.5.1], 1759 /// or an [IPv4-mapped] address as defined in [IETF RFC 4291 section 2.5.5.2], 1760 /// otherwise returns [`None`]. 1761 /// 1762 /// Note that this will return an [`IPv4` address] for the IPv6 loopback address `::1`. Use 1763 /// [`Ipv6Addr::to_ipv4_mapped`] to avoid this. 1764 /// 1765 /// `::a.b.c.d` and `::ffff:a.b.c.d` become `a.b.c.d`. `::1` becomes `0.0.0.1`. 1766 /// All addresses *not* starting with either all zeroes or `::ffff` will return `None`. 1767 /// 1768 /// [`IPv4` address]: Ipv4Addr 1769 /// [IPv4-compatible]: Ipv6Addr#ipv4-compatible-ipv6-addresses 1770 /// [IPv4-mapped]: Ipv6Addr#ipv4-mapped-ipv6-addresses 1771 /// [IETF RFC 4291 section 2.5.5.1]: https://tools.ietf.org/html/rfc4291#section-2.5.5.1 1772 /// [IETF RFC 4291 section 2.5.5.2]: https://tools.ietf.org/html/rfc4291#section-2.5.5.2 1773 /// 1774 /// # Examples 1775 /// 1776 /// ``` 1777 /// use std::net::{Ipv4Addr, Ipv6Addr}; 1778 /// 1779 /// assert_eq!(Ipv6Addr::new(0xff00, 0, 0, 0, 0, 0, 0, 0).to_ipv4(), None); 1780 /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff).to_ipv4(), 1781 /// Some(Ipv4Addr::new(192, 10, 2, 255))); 1782 /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1).to_ipv4(), 1783 /// Some(Ipv4Addr::new(0, 0, 0, 1))); 1784 /// ``` 1785 #[cfg_attr( 1786 staged_api, 1787 rustc_const_stable(feature = "const_ip_50", since = "1.50.0") 1788 )] 1789 #[cfg_attr(staged_api, stable(feature = "rust1", since = "1.0.0"))] 1790 #[must_use = "this returns the result of the operation, \ 1791 without modifying the original"] 1792 #[inline] to_ipv4(&self) -> Option<Ipv4Addr>1793 pub const fn to_ipv4(&self) -> Option<Ipv4Addr> { 1794 if let [0, 0, 0, 0, 0, 0 | 0xffff, ab, cd] = self.segments() { 1795 let [a, b] = ab.to_be_bytes(); 1796 let [c, d] = cd.to_be_bytes(); 1797 Some(Ipv4Addr::new(a, b, c, d)) 1798 } else { 1799 None 1800 } 1801 } 1802 1803 /// Converts this address to an `IpAddr::V4` if it is an IPv4-mapped addresses, otherwise it 1804 /// returns self wrapped in an `IpAddr::V6`. 1805 /// 1806 /// # Examples 1807 /// 1808 /// ``` 1809 /// #![feature(ip)] 1810 /// use std::net::Ipv6Addr; 1811 /// 1812 /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0x7f00, 0x1).is_loopback(), false); 1813 /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0x7f00, 0x1).to_canonical().is_loopback(), true); 1814 /// ``` 1815 #[cfg_attr( 1816 staged_api, 1817 rustc_const_unstable(feature = "const_ipv6", issue = "76205") 1818 )] 1819 #[cfg_attr(staged_api, unstable(feature = "ip", issue = "27709"))] 1820 #[must_use = "this returns the result of the operation, \ 1821 without modifying the original"] 1822 #[inline] to_canonical(&self) -> IpAddr1823 pub const fn to_canonical(&self) -> IpAddr { 1824 if let Some(mapped) = self.to_ipv4_mapped() { 1825 return IpAddr::V4(mapped); 1826 } 1827 IpAddr::V6(*self) 1828 } 1829 1830 /// Returns the sixteen eight-bit integers the IPv6 address consists of. 1831 /// 1832 /// ``` 1833 /// use std::net::Ipv6Addr; 1834 /// 1835 /// assert_eq!(Ipv6Addr::new(0xff00, 0, 0, 0, 0, 0, 0, 0).octets(), 1836 /// [255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]); 1837 /// ``` 1838 #[cfg_attr( 1839 staged_api, 1840 rustc_const_stable(feature = "const_ip_32", since = "1.32.0") 1841 )] 1842 #[cfg_attr(staged_api, stable(feature = "ipv6_to_octets", since = "1.12.0"))] 1843 #[must_use] 1844 #[inline] octets(&self) -> [u8; 16]1845 pub const fn octets(&self) -> [u8; 16] { 1846 self.octets 1847 } 1848 } 1849 1850 #[cfg_attr(staged_api, stable(feature = "ip_cmp", since = "1.16.0"))] 1851 impl PartialEq<IpAddr> for Ipv6Addr { 1852 #[inline] eq(&self, other: &IpAddr) -> bool1853 fn eq(&self, other: &IpAddr) -> bool { 1854 match other { 1855 IpAddr::V4(_) => false, 1856 IpAddr::V6(v6) => self == v6, 1857 } 1858 } 1859 } 1860 1861 #[cfg_attr(staged_api, stable(feature = "ip_cmp", since = "1.16.0"))] 1862 impl PartialEq<Ipv6Addr> for IpAddr { 1863 #[inline] eq(&self, other: &Ipv6Addr) -> bool1864 fn eq(&self, other: &Ipv6Addr) -> bool { 1865 match self { 1866 IpAddr::V4(_) => false, 1867 IpAddr::V6(v6) => v6 == other, 1868 } 1869 } 1870 } 1871 1872 #[cfg_attr(staged_api, stable(feature = "rust1", since = "1.0.0"))] 1873 impl PartialOrd for Ipv6Addr { 1874 #[inline] partial_cmp(&self, other: &Ipv6Addr) -> Option<Ordering>1875 fn partial_cmp(&self, other: &Ipv6Addr) -> Option<Ordering> { 1876 Some(self.cmp(other)) 1877 } 1878 } 1879 1880 #[cfg_attr(staged_api, stable(feature = "ip_cmp", since = "1.16.0"))] 1881 impl PartialOrd<Ipv6Addr> for IpAddr { 1882 #[inline] partial_cmp(&self, other: &Ipv6Addr) -> Option<Ordering>1883 fn partial_cmp(&self, other: &Ipv6Addr) -> Option<Ordering> { 1884 match self { 1885 IpAddr::V4(_) => Some(Ordering::Less), 1886 IpAddr::V6(v6) => v6.partial_cmp(other), 1887 } 1888 } 1889 } 1890 1891 #[cfg_attr(staged_api, stable(feature = "ip_cmp", since = "1.16.0"))] 1892 impl PartialOrd<IpAddr> for Ipv6Addr { 1893 #[inline] partial_cmp(&self, other: &IpAddr) -> Option<Ordering>1894 fn partial_cmp(&self, other: &IpAddr) -> Option<Ordering> { 1895 match other { 1896 IpAddr::V4(_) => Some(Ordering::Greater), 1897 IpAddr::V6(v6) => self.partial_cmp(v6), 1898 } 1899 } 1900 } 1901 1902 #[cfg_attr(staged_api, stable(feature = "rust1", since = "1.0.0"))] 1903 impl Ord for Ipv6Addr { 1904 #[inline] cmp(&self, other: &Ipv6Addr) -> Ordering1905 fn cmp(&self, other: &Ipv6Addr) -> Ordering { 1906 self.segments().cmp(&other.segments()) 1907 } 1908 } 1909 1910 #[cfg_attr(staged_api, stable(feature = "i128", since = "1.26.0"))] 1911 impl From<Ipv6Addr> for u128 { 1912 /// Convert an `Ipv6Addr` into a host byte order `u128`. 1913 /// 1914 /// # Examples 1915 /// 1916 /// ``` 1917 /// use std::net::Ipv6Addr; 1918 /// 1919 /// let addr = Ipv6Addr::new( 1920 /// 0x1020, 0x3040, 0x5060, 0x7080, 1921 /// 0x90A0, 0xB0C0, 0xD0E0, 0xF00D, 1922 /// ); 1923 /// assert_eq!(0x102030405060708090A0B0C0D0E0F00D_u128, u128::from(addr)); 1924 /// ``` 1925 #[inline] from(ip: Ipv6Addr) -> u1281926 fn from(ip: Ipv6Addr) -> u128 { 1927 u128::from_be_bytes(ip.octets) 1928 } 1929 } 1930 #[cfg_attr(staged_api, stable(feature = "i128", since = "1.26.0"))] 1931 impl From<u128> for Ipv6Addr { 1932 /// Convert a host byte order `u128` into an `Ipv6Addr`. 1933 /// 1934 /// # Examples 1935 /// 1936 /// ``` 1937 /// use std::net::Ipv6Addr; 1938 /// 1939 /// let addr = Ipv6Addr::from(0x102030405060708090A0B0C0D0E0F00D_u128); 1940 /// assert_eq!( 1941 /// Ipv6Addr::new( 1942 /// 0x1020, 0x3040, 0x5060, 0x7080, 1943 /// 0x90A0, 0xB0C0, 0xD0E0, 0xF00D, 1944 /// ), 1945 /// addr); 1946 /// ``` 1947 #[inline] from(ip: u128) -> Ipv6Addr1948 fn from(ip: u128) -> Ipv6Addr { 1949 Ipv6Addr::from(ip.to_be_bytes()) 1950 } 1951 } 1952 1953 #[cfg_attr(staged_api, stable(feature = "ipv6_from_octets", since = "1.9.0"))] 1954 impl From<[u8; 16]> for Ipv6Addr { 1955 /// Creates an `Ipv6Addr` from a sixteen element byte array. 1956 /// 1957 /// # Examples 1958 /// 1959 /// ``` 1960 /// use std::net::Ipv6Addr; 1961 /// 1962 /// let addr = Ipv6Addr::from([ 1963 /// 25u8, 24u8, 23u8, 22u8, 21u8, 20u8, 19u8, 18u8, 1964 /// 17u8, 16u8, 15u8, 14u8, 13u8, 12u8, 11u8, 10u8, 1965 /// ]); 1966 /// assert_eq!( 1967 /// Ipv6Addr::new( 1968 /// 0x1918, 0x1716, 1969 /// 0x1514, 0x1312, 1970 /// 0x1110, 0x0f0e, 1971 /// 0x0d0c, 0x0b0a 1972 /// ), 1973 /// addr 1974 /// ); 1975 /// ``` 1976 #[inline] from(octets: [u8; 16]) -> Ipv6Addr1977 fn from(octets: [u8; 16]) -> Ipv6Addr { 1978 Ipv6Addr { octets } 1979 } 1980 } 1981 1982 #[cfg_attr(staged_api, stable(feature = "ipv6_from_segments", since = "1.16.0"))] 1983 impl From<[u16; 8]> for Ipv6Addr { 1984 /// Creates an `Ipv6Addr` from an eight element 16-bit array. 1985 /// 1986 /// # Examples 1987 /// 1988 /// ``` 1989 /// use std::net::Ipv6Addr; 1990 /// 1991 /// let addr = Ipv6Addr::from([ 1992 /// 525u16, 524u16, 523u16, 522u16, 1993 /// 521u16, 520u16, 519u16, 518u16, 1994 /// ]); 1995 /// assert_eq!( 1996 /// Ipv6Addr::new( 1997 /// 0x20d, 0x20c, 1998 /// 0x20b, 0x20a, 1999 /// 0x209, 0x208, 2000 /// 0x207, 0x206 2001 /// ), 2002 /// addr 2003 /// ); 2004 /// ``` 2005 #[inline] from(segments: [u16; 8]) -> Ipv6Addr2006 fn from(segments: [u16; 8]) -> Ipv6Addr { 2007 let [a, b, c, d, e, f, g, h] = segments; 2008 Ipv6Addr::new(a, b, c, d, e, f, g, h) 2009 } 2010 } 2011 2012 #[cfg_attr(staged_api, stable(feature = "ip_from_slice", since = "1.17.0"))] 2013 impl From<[u8; 16]> for IpAddr { 2014 /// Creates an `IpAddr::V6` from a sixteen element byte array. 2015 /// 2016 /// # Examples 2017 /// 2018 /// ``` 2019 /// use std::net::{IpAddr, Ipv6Addr}; 2020 /// 2021 /// let addr = IpAddr::from([ 2022 /// 25u8, 24u8, 23u8, 22u8, 21u8, 20u8, 19u8, 18u8, 2023 /// 17u8, 16u8, 15u8, 14u8, 13u8, 12u8, 11u8, 10u8, 2024 /// ]); 2025 /// assert_eq!( 2026 /// IpAddr::V6(Ipv6Addr::new( 2027 /// 0x1918, 0x1716, 2028 /// 0x1514, 0x1312, 2029 /// 0x1110, 0x0f0e, 2030 /// 0x0d0c, 0x0b0a 2031 /// )), 2032 /// addr 2033 /// ); 2034 /// ``` 2035 #[inline] from(octets: [u8; 16]) -> IpAddr2036 fn from(octets: [u8; 16]) -> IpAddr { 2037 IpAddr::V6(Ipv6Addr::from(octets)) 2038 } 2039 } 2040 2041 #[cfg_attr(staged_api, stable(feature = "ip_from_slice", since = "1.17.0"))] 2042 impl From<[u16; 8]> for IpAddr { 2043 /// Creates an `IpAddr::V6` from an eight element 16-bit array. 2044 /// 2045 /// # Examples 2046 /// 2047 /// ``` 2048 /// use std::net::{IpAddr, Ipv6Addr}; 2049 /// 2050 /// let addr = IpAddr::from([ 2051 /// 525u16, 524u16, 523u16, 522u16, 2052 /// 521u16, 520u16, 519u16, 518u16, 2053 /// ]); 2054 /// assert_eq!( 2055 /// IpAddr::V6(Ipv6Addr::new( 2056 /// 0x20d, 0x20c, 2057 /// 0x20b, 0x20a, 2058 /// 0x209, 0x208, 2059 /// 0x207, 0x206 2060 /// )), 2061 /// addr 2062 /// ); 2063 /// ``` 2064 #[inline] from(segments: [u16; 8]) -> IpAddr2065 fn from(segments: [u16; 8]) -> IpAddr { 2066 IpAddr::V6(Ipv6Addr::from(segments)) 2067 } 2068 } 2069