]> git.lizzy.rs Git - rust.git/blob - library/std/src/net/ip.rs
Rollup merge of #81966 - deg4uss3r:degausser/aarch64_apple_ios_sim, r=shepmaster
[rust.git] / library / std / src / net / ip.rs
1 #![unstable(
2     feature = "ip",
3     reason = "extra functionality has not been \
4                                       scrutinized to the level that it should \
5                                       be to be stable",
6     issue = "27709"
7 )]
8
9 // Tests for this module
10 #[cfg(all(test, not(target_os = "emscripten")))]
11 mod tests;
12
13 use crate::cmp::Ordering;
14 use crate::fmt::{self, Write as FmtWrite};
15 use crate::hash;
16 use crate::io::Write as IoWrite;
17 use crate::mem::transmute;
18 use crate::sys::net::netc as c;
19 use crate::sys_common::{AsInner, FromInner, IntoInner};
20
21 /// An IP address, either IPv4 or IPv6.
22 ///
23 /// This enum can contain either an [`Ipv4Addr`] or an [`Ipv6Addr`], see their
24 /// respective documentation for more details.
25 ///
26 /// The size of an `IpAddr` instance may vary depending on the target operating
27 /// system.
28 ///
29 /// # Examples
30 ///
31 /// ```
32 /// use std::net::{IpAddr, Ipv4Addr, Ipv6Addr};
33 ///
34 /// let localhost_v4 = IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1));
35 /// let localhost_v6 = IpAddr::V6(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1));
36 ///
37 /// assert_eq!("127.0.0.1".parse(), Ok(localhost_v4));
38 /// assert_eq!("::1".parse(), Ok(localhost_v6));
39 ///
40 /// assert_eq!(localhost_v4.is_ipv6(), false);
41 /// assert_eq!(localhost_v4.is_ipv4(), true);
42 /// ```
43 #[stable(feature = "ip_addr", since = "1.7.0")]
44 #[derive(Copy, Clone, Eq, PartialEq, Hash, PartialOrd, Ord)]
45 pub enum IpAddr {
46     /// An IPv4 address.
47     #[stable(feature = "ip_addr", since = "1.7.0")]
48     V4(#[stable(feature = "ip_addr", since = "1.7.0")] Ipv4Addr),
49     /// An IPv6 address.
50     #[stable(feature = "ip_addr", since = "1.7.0")]
51     V6(#[stable(feature = "ip_addr", since = "1.7.0")] Ipv6Addr),
52 }
53
54 /// An IPv4 address.
55 ///
56 /// IPv4 addresses are defined as 32-bit integers in [IETF RFC 791].
57 /// They are usually represented as four octets.
58 ///
59 /// See [`IpAddr`] for a type encompassing both IPv4 and IPv6 addresses.
60 ///
61 /// The size of an `Ipv4Addr` struct may vary depending on the target operating
62 /// system.
63 ///
64 /// [IETF RFC 791]: https://tools.ietf.org/html/rfc791
65 ///
66 /// # Textual representation
67 ///
68 /// `Ipv4Addr` provides a [`FromStr`] implementation. The four octets are in decimal
69 /// notation, divided by `.` (this is called "dot-decimal notation").
70 ///
71 /// [`FromStr`]: crate::str::FromStr
72 ///
73 /// # Examples
74 ///
75 /// ```
76 /// use std::net::Ipv4Addr;
77 ///
78 /// let localhost = Ipv4Addr::new(127, 0, 0, 1);
79 /// assert_eq!("127.0.0.1".parse(), Ok(localhost));
80 /// assert_eq!(localhost.is_loopback(), true);
81 /// ```
82 #[derive(Copy)]
83 #[stable(feature = "rust1", since = "1.0.0")]
84 pub struct Ipv4Addr {
85     inner: c::in_addr,
86 }
87
88 /// An IPv6 address.
89 ///
90 /// IPv6 addresses are defined as 128-bit integers in [IETF RFC 4291].
91 /// They are usually represented as eight 16-bit segments.
92 ///
93 /// See [`IpAddr`] for a type encompassing both IPv4 and IPv6 addresses.
94 ///
95 /// The size of an `Ipv6Addr` struct may vary depending on the target operating
96 /// system.
97 ///
98 /// [IETF RFC 4291]: https://tools.ietf.org/html/rfc4291
99 ///
100 /// # Textual representation
101 ///
102 /// `Ipv6Addr` provides a [`FromStr`] implementation. There are many ways to represent
103 /// an IPv6 address in text, but in general, each segments is written in hexadecimal
104 /// notation, and segments are separated by `:`. For more information, see
105 /// [IETF RFC 5952].
106 ///
107 /// [`FromStr`]: crate::str::FromStr
108 /// [IETF RFC 5952]: https://tools.ietf.org/html/rfc5952
109 ///
110 /// # Examples
111 ///
112 /// ```
113 /// use std::net::Ipv6Addr;
114 ///
115 /// let localhost = Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1);
116 /// assert_eq!("::1".parse(), Ok(localhost));
117 /// assert_eq!(localhost.is_loopback(), true);
118 /// ```
119 #[derive(Copy)]
120 #[stable(feature = "rust1", since = "1.0.0")]
121 pub struct Ipv6Addr {
122     inner: c::in6_addr,
123 }
124
125 #[allow(missing_docs)]
126 #[derive(Copy, PartialEq, Eq, Clone, Hash, Debug)]
127 pub enum Ipv6MulticastScope {
128     InterfaceLocal,
129     LinkLocal,
130     RealmLocal,
131     AdminLocal,
132     SiteLocal,
133     OrganizationLocal,
134     Global,
135 }
136
137 impl IpAddr {
138     /// Returns [`true`] for the special 'unspecified' address.
139     ///
140     /// See the documentation for [`Ipv4Addr::is_unspecified()`] and
141     /// [`Ipv6Addr::is_unspecified()`] for more details.
142     ///
143     /// # Examples
144     ///
145     /// ```
146     /// use std::net::{IpAddr, Ipv4Addr, Ipv6Addr};
147     ///
148     /// assert_eq!(IpAddr::V4(Ipv4Addr::new(0, 0, 0, 0)).is_unspecified(), true);
149     /// assert_eq!(IpAddr::V6(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0)).is_unspecified(), true);
150     /// ```
151     #[rustc_const_stable(feature = "const_ip", since = "1.50.0")]
152     #[stable(feature = "ip_shared", since = "1.12.0")]
153     #[inline]
154     pub const fn is_unspecified(&self) -> bool {
155         match self {
156             IpAddr::V4(ip) => ip.is_unspecified(),
157             IpAddr::V6(ip) => ip.is_unspecified(),
158         }
159     }
160
161     /// Returns [`true`] if this is a loopback address.
162     ///
163     /// See the documentation for [`Ipv4Addr::is_loopback()`] and
164     /// [`Ipv6Addr::is_loopback()`] for more details.
165     ///
166     /// # Examples
167     ///
168     /// ```
169     /// use std::net::{IpAddr, Ipv4Addr, Ipv6Addr};
170     ///
171     /// assert_eq!(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)).is_loopback(), true);
172     /// assert_eq!(IpAddr::V6(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0x1)).is_loopback(), true);
173     /// ```
174     #[rustc_const_stable(feature = "const_ip", since = "1.50.0")]
175     #[stable(feature = "ip_shared", since = "1.12.0")]
176     #[inline]
177     pub const fn is_loopback(&self) -> bool {
178         match self {
179             IpAddr::V4(ip) => ip.is_loopback(),
180             IpAddr::V6(ip) => ip.is_loopback(),
181         }
182     }
183
184     /// Returns [`true`] if the address appears to be globally routable.
185     ///
186     /// See the documentation for [`Ipv4Addr::is_global()`] and
187     /// [`Ipv6Addr::is_global()`] for more details.
188     ///
189     /// # Examples
190     ///
191     /// ```
192     /// #![feature(ip)]
193     ///
194     /// use std::net::{IpAddr, Ipv4Addr, Ipv6Addr};
195     ///
196     /// assert_eq!(IpAddr::V4(Ipv4Addr::new(80, 9, 12, 3)).is_global(), true);
197     /// assert_eq!(IpAddr::V6(Ipv6Addr::new(0, 0, 0x1c9, 0, 0, 0xafc8, 0, 0x1)).is_global(), true);
198     /// ```
199     #[rustc_const_unstable(feature = "const_ip", issue = "76205")]
200     #[inline]
201     pub const fn is_global(&self) -> bool {
202         match self {
203             IpAddr::V4(ip) => ip.is_global(),
204             IpAddr::V6(ip) => ip.is_global(),
205         }
206     }
207
208     /// Returns [`true`] if this is a multicast address.
209     ///
210     /// See the documentation for [`Ipv4Addr::is_multicast()`] and
211     /// [`Ipv6Addr::is_multicast()`] for more details.
212     ///
213     /// # Examples
214     ///
215     /// ```
216     /// use std::net::{IpAddr, Ipv4Addr, Ipv6Addr};
217     ///
218     /// assert_eq!(IpAddr::V4(Ipv4Addr::new(224, 254, 0, 0)).is_multicast(), true);
219     /// assert_eq!(IpAddr::V6(Ipv6Addr::new(0xff00, 0, 0, 0, 0, 0, 0, 0)).is_multicast(), true);
220     /// ```
221     #[rustc_const_stable(feature = "const_ip", since = "1.50.0")]
222     #[stable(feature = "ip_shared", since = "1.12.0")]
223     #[inline]
224     pub const fn is_multicast(&self) -> bool {
225         match self {
226             IpAddr::V4(ip) => ip.is_multicast(),
227             IpAddr::V6(ip) => ip.is_multicast(),
228         }
229     }
230
231     /// Returns [`true`] if this address is in a range designated for documentation.
232     ///
233     /// See the documentation for [`Ipv4Addr::is_documentation()`] and
234     /// [`Ipv6Addr::is_documentation()`] for more details.
235     ///
236     /// # Examples
237     ///
238     /// ```
239     /// #![feature(ip)]
240     ///
241     /// use std::net::{IpAddr, Ipv4Addr, Ipv6Addr};
242     ///
243     /// assert_eq!(IpAddr::V4(Ipv4Addr::new(203, 0, 113, 6)).is_documentation(), true);
244     /// assert_eq!(
245     ///     IpAddr::V6(Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 0)).is_documentation(),
246     ///     true
247     /// );
248     /// ```
249     #[rustc_const_unstable(feature = "const_ip", issue = "76205")]
250     #[inline]
251     pub const fn is_documentation(&self) -> bool {
252         match self {
253             IpAddr::V4(ip) => ip.is_documentation(),
254             IpAddr::V6(ip) => ip.is_documentation(),
255         }
256     }
257
258     /// Returns [`true`] if this address is an [`IPv4` address], and [`false`]
259     /// otherwise.
260     ///
261     /// [`IPv4` address]: IpAddr::V4
262     ///
263     /// # Examples
264     ///
265     /// ```
266     /// use std::net::{IpAddr, Ipv4Addr, Ipv6Addr};
267     ///
268     /// assert_eq!(IpAddr::V4(Ipv4Addr::new(203, 0, 113, 6)).is_ipv4(), true);
269     /// assert_eq!(IpAddr::V6(Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 0)).is_ipv4(), false);
270     /// ```
271     #[rustc_const_stable(feature = "const_ip", since = "1.50.0")]
272     #[stable(feature = "ipaddr_checker", since = "1.16.0")]
273     #[inline]
274     pub const fn is_ipv4(&self) -> bool {
275         matches!(self, IpAddr::V4(_))
276     }
277
278     /// Returns [`true`] if this address is an [`IPv6` address], and [`false`]
279     /// otherwise.
280     ///
281     /// [`IPv6` address]: IpAddr::V6
282     ///
283     /// # Examples
284     ///
285     /// ```
286     /// use std::net::{IpAddr, Ipv4Addr, Ipv6Addr};
287     ///
288     /// assert_eq!(IpAddr::V4(Ipv4Addr::new(203, 0, 113, 6)).is_ipv6(), false);
289     /// assert_eq!(IpAddr::V6(Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 0)).is_ipv6(), true);
290     /// ```
291     #[rustc_const_stable(feature = "const_ip", since = "1.50.0")]
292     #[stable(feature = "ipaddr_checker", since = "1.16.0")]
293     #[inline]
294     pub const fn is_ipv6(&self) -> bool {
295         matches!(self, IpAddr::V6(_))
296     }
297 }
298
299 impl Ipv4Addr {
300     /// Creates a new IPv4 address from four eight-bit octets.
301     ///
302     /// The result will represent the IP address `a`.`b`.`c`.`d`.
303     ///
304     /// # Examples
305     ///
306     /// ```
307     /// use std::net::Ipv4Addr;
308     ///
309     /// let addr = Ipv4Addr::new(127, 0, 0, 1);
310     /// ```
311     #[rustc_const_stable(feature = "const_ipv4", since = "1.32.0")]
312     #[stable(feature = "rust1", since = "1.0.0")]
313     #[inline]
314     pub const fn new(a: u8, b: u8, c: u8, d: u8) -> Ipv4Addr {
315         // `s_addr` is stored as BE on all machine and the array is in BE order.
316         // So the native endian conversion method is used so that it's never swapped.
317         Ipv4Addr { inner: c::in_addr { s_addr: u32::from_ne_bytes([a, b, c, d]) } }
318     }
319
320     /// An IPv4 address with the address pointing to localhost: 127.0.0.1.
321     ///
322     /// # Examples
323     ///
324     /// ```
325     /// use std::net::Ipv4Addr;
326     ///
327     /// let addr = Ipv4Addr::LOCALHOST;
328     /// assert_eq!(addr, Ipv4Addr::new(127, 0, 0, 1));
329     /// ```
330     #[stable(feature = "ip_constructors", since = "1.30.0")]
331     pub const LOCALHOST: Self = Ipv4Addr::new(127, 0, 0, 1);
332
333     /// An IPv4 address representing an unspecified address: 0.0.0.0
334     ///
335     /// # Examples
336     ///
337     /// ```
338     /// use std::net::Ipv4Addr;
339     ///
340     /// let addr = Ipv4Addr::UNSPECIFIED;
341     /// assert_eq!(addr, Ipv4Addr::new(0, 0, 0, 0));
342     /// ```
343     #[stable(feature = "ip_constructors", since = "1.30.0")]
344     pub const UNSPECIFIED: Self = Ipv4Addr::new(0, 0, 0, 0);
345
346     /// An IPv4 address representing the broadcast address: 255.255.255.255
347     ///
348     /// # Examples
349     ///
350     /// ```
351     /// use std::net::Ipv4Addr;
352     ///
353     /// let addr = Ipv4Addr::BROADCAST;
354     /// assert_eq!(addr, Ipv4Addr::new(255, 255, 255, 255));
355     /// ```
356     #[stable(feature = "ip_constructors", since = "1.30.0")]
357     pub const BROADCAST: Self = Ipv4Addr::new(255, 255, 255, 255);
358
359     /// Returns the four eight-bit integers that make up this address.
360     ///
361     /// # Examples
362     ///
363     /// ```
364     /// use std::net::Ipv4Addr;
365     ///
366     /// let addr = Ipv4Addr::new(127, 0, 0, 1);
367     /// assert_eq!(addr.octets(), [127, 0, 0, 1]);
368     /// ```
369     #[rustc_const_stable(feature = "const_ipv4", since = "1.50.0")]
370     #[stable(feature = "rust1", since = "1.0.0")]
371     #[inline]
372     pub const fn octets(&self) -> [u8; 4] {
373         // This returns the order we want because s_addr is stored in big-endian.
374         self.inner.s_addr.to_ne_bytes()
375     }
376
377     /// Returns [`true`] for the special 'unspecified' address (0.0.0.0).
378     ///
379     /// This property is defined in _UNIX Network Programming, Second Edition_,
380     /// W. Richard Stevens, p. 891; see also [ip7].
381     ///
382     /// [ip7]: http://man7.org/linux/man-pages/man7/ip.7.html
383     ///
384     /// # Examples
385     ///
386     /// ```
387     /// use std::net::Ipv4Addr;
388     ///
389     /// assert_eq!(Ipv4Addr::new(0, 0, 0, 0).is_unspecified(), true);
390     /// assert_eq!(Ipv4Addr::new(45, 22, 13, 197).is_unspecified(), false);
391     /// ```
392     #[rustc_const_stable(feature = "const_ipv4", since = "1.32.0")]
393     #[stable(feature = "ip_shared", since = "1.12.0")]
394     #[inline]
395     pub const fn is_unspecified(&self) -> bool {
396         self.inner.s_addr == 0
397     }
398
399     /// Returns [`true`] if this is a loopback address (127.0.0.0/8).
400     ///
401     /// This property is defined by [IETF RFC 1122].
402     ///
403     /// [IETF RFC 1122]: https://tools.ietf.org/html/rfc1122
404     ///
405     /// # Examples
406     ///
407     /// ```
408     /// use std::net::Ipv4Addr;
409     ///
410     /// assert_eq!(Ipv4Addr::new(127, 0, 0, 1).is_loopback(), true);
411     /// assert_eq!(Ipv4Addr::new(45, 22, 13, 197).is_loopback(), false);
412     /// ```
413     #[rustc_const_stable(feature = "const_ipv4", since = "1.50.0")]
414     #[stable(since = "1.7.0", feature = "ip_17")]
415     #[inline]
416     pub const fn is_loopback(&self) -> bool {
417         self.octets()[0] == 127
418     }
419
420     /// Returns [`true`] if this is a private address.
421     ///
422     /// The private address ranges are defined in [IETF RFC 1918] and include:
423     ///
424     ///  - 10.0.0.0/8
425     ///  - 172.16.0.0/12
426     ///  - 192.168.0.0/16
427     ///
428     /// [IETF RFC 1918]: https://tools.ietf.org/html/rfc1918
429     ///
430     /// # Examples
431     ///
432     /// ```
433     /// use std::net::Ipv4Addr;
434     ///
435     /// assert_eq!(Ipv4Addr::new(10, 0, 0, 1).is_private(), true);
436     /// assert_eq!(Ipv4Addr::new(10, 10, 10, 10).is_private(), true);
437     /// assert_eq!(Ipv4Addr::new(172, 16, 10, 10).is_private(), true);
438     /// assert_eq!(Ipv4Addr::new(172, 29, 45, 14).is_private(), true);
439     /// assert_eq!(Ipv4Addr::new(172, 32, 0, 2).is_private(), false);
440     /// assert_eq!(Ipv4Addr::new(192, 168, 0, 2).is_private(), true);
441     /// assert_eq!(Ipv4Addr::new(192, 169, 0, 2).is_private(), false);
442     /// ```
443     #[rustc_const_stable(feature = "const_ipv4", since = "1.50.0")]
444     #[stable(since = "1.7.0", feature = "ip_17")]
445     #[inline]
446     pub const fn is_private(&self) -> bool {
447         match self.octets() {
448             [10, ..] => true,
449             [172, b, ..] if b >= 16 && b <= 31 => true,
450             [192, 168, ..] => true,
451             _ => false,
452         }
453     }
454
455     /// Returns [`true`] if the address is link-local (169.254.0.0/16).
456     ///
457     /// This property is defined by [IETF RFC 3927].
458     ///
459     /// [IETF RFC 3927]: https://tools.ietf.org/html/rfc3927
460     ///
461     /// # Examples
462     ///
463     /// ```
464     /// use std::net::Ipv4Addr;
465     ///
466     /// assert_eq!(Ipv4Addr::new(169, 254, 0, 0).is_link_local(), true);
467     /// assert_eq!(Ipv4Addr::new(169, 254, 10, 65).is_link_local(), true);
468     /// assert_eq!(Ipv4Addr::new(16, 89, 10, 65).is_link_local(), false);
469     /// ```
470     #[rustc_const_stable(feature = "const_ipv4", since = "1.50.0")]
471     #[stable(since = "1.7.0", feature = "ip_17")]
472     #[inline]
473     pub const fn is_link_local(&self) -> bool {
474         matches!(self.octets(), [169, 254, ..])
475     }
476
477     /// Returns [`true`] if the address appears to be globally routable.
478     /// See [iana-ipv4-special-registry][ipv4-sr].
479     ///
480     /// The following return [`false`]:
481     ///
482     /// - private addresses (see [`Ipv4Addr::is_private()`])
483     /// - the loopback address (see [`Ipv4Addr::is_loopback()`])
484     /// - the link-local address (see [`Ipv4Addr::is_link_local()`])
485     /// - the broadcast address (see [`Ipv4Addr::is_broadcast()`])
486     /// - addresses used for documentation (see [`Ipv4Addr::is_documentation()`])
487     /// - the unspecified address (see [`Ipv4Addr::is_unspecified()`]), and the whole
488     ///   0.0.0.0/8 block
489     /// - addresses reserved for future protocols (see
490     /// [`Ipv4Addr::is_ietf_protocol_assignment()`], except
491     /// `192.0.0.9/32` and `192.0.0.10/32` which are globally routable
492     /// - addresses reserved for future use (see [`Ipv4Addr::is_reserved()`]
493     /// - addresses reserved for networking devices benchmarking (see
494     /// [`Ipv4Addr::is_benchmarking()`])
495     ///
496     /// [ipv4-sr]: https://www.iana.org/assignments/iana-ipv4-special-registry/iana-ipv4-special-registry.xhtml
497     ///
498     /// # Examples
499     ///
500     /// ```
501     /// #![feature(ip)]
502     ///
503     /// use std::net::Ipv4Addr;
504     ///
505     /// // private addresses are not global
506     /// assert_eq!(Ipv4Addr::new(10, 254, 0, 0).is_global(), false);
507     /// assert_eq!(Ipv4Addr::new(192, 168, 10, 65).is_global(), false);
508     /// assert_eq!(Ipv4Addr::new(172, 16, 10, 65).is_global(), false);
509     ///
510     /// // the 0.0.0.0/8 block is not global
511     /// assert_eq!(Ipv4Addr::new(0, 1, 2, 3).is_global(), false);
512     /// // in particular, the unspecified address is not global
513     /// assert_eq!(Ipv4Addr::new(0, 0, 0, 0).is_global(), false);
514     ///
515     /// // the loopback address is not global
516     /// assert_eq!(Ipv4Addr::new(127, 0, 0, 1).is_global(), false);
517     ///
518     /// // link local addresses are not global
519     /// assert_eq!(Ipv4Addr::new(169, 254, 45, 1).is_global(), false);
520     ///
521     /// // the broadcast address is not global
522     /// assert_eq!(Ipv4Addr::new(255, 255, 255, 255).is_global(), false);
523     ///
524     /// // the address space designated for documentation is not global
525     /// assert_eq!(Ipv4Addr::new(192, 0, 2, 255).is_global(), false);
526     /// assert_eq!(Ipv4Addr::new(198, 51, 100, 65).is_global(), false);
527     /// assert_eq!(Ipv4Addr::new(203, 0, 113, 6).is_global(), false);
528     ///
529     /// // shared addresses are not global
530     /// assert_eq!(Ipv4Addr::new(100, 100, 0, 0).is_global(), false);
531     ///
532     /// // addresses reserved for protocol assignment are not global
533     /// assert_eq!(Ipv4Addr::new(192, 0, 0, 0).is_global(), false);
534     /// assert_eq!(Ipv4Addr::new(192, 0, 0, 255).is_global(), false);
535     ///
536     /// // addresses reserved for future use are not global
537     /// assert_eq!(Ipv4Addr::new(250, 10, 20, 30).is_global(), false);
538     ///
539     /// // addresses reserved for network devices benchmarking are not global
540     /// assert_eq!(Ipv4Addr::new(198, 18, 0, 0).is_global(), false);
541     ///
542     /// // All the other addresses are global
543     /// assert_eq!(Ipv4Addr::new(1, 1, 1, 1).is_global(), true);
544     /// assert_eq!(Ipv4Addr::new(80, 9, 12, 3).is_global(), true);
545     /// ```
546     #[rustc_const_unstable(feature = "const_ipv4", issue = "76205")]
547     #[inline]
548     pub const fn is_global(&self) -> bool {
549         // check if this address is 192.0.0.9 or 192.0.0.10. These addresses are the only two
550         // globally routable addresses in the 192.0.0.0/24 range.
551         if u32::from_be_bytes(self.octets()) == 0xc0000009
552             || u32::from_be_bytes(self.octets()) == 0xc000000a
553         {
554             return true;
555         }
556         !self.is_private()
557             && !self.is_loopback()
558             && !self.is_link_local()
559             && !self.is_broadcast()
560             && !self.is_documentation()
561             && !self.is_shared()
562             && !self.is_ietf_protocol_assignment()
563             && !self.is_reserved()
564             && !self.is_benchmarking()
565             // Make sure the address is not in 0.0.0.0/8
566             && self.octets()[0] != 0
567     }
568
569     /// Returns [`true`] if this address is part of the Shared Address Space defined in
570     /// [IETF RFC 6598] (`100.64.0.0/10`).
571     ///
572     /// [IETF RFC 6598]: https://tools.ietf.org/html/rfc6598
573     ///
574     /// # Examples
575     ///
576     /// ```
577     /// #![feature(ip)]
578     /// use std::net::Ipv4Addr;
579     ///
580     /// assert_eq!(Ipv4Addr::new(100, 64, 0, 0).is_shared(), true);
581     /// assert_eq!(Ipv4Addr::new(100, 127, 255, 255).is_shared(), true);
582     /// assert_eq!(Ipv4Addr::new(100, 128, 0, 0).is_shared(), false);
583     /// ```
584     #[rustc_const_unstable(feature = "const_ipv4", issue = "76205")]
585     #[inline]
586     pub const fn is_shared(&self) -> bool {
587         self.octets()[0] == 100 && (self.octets()[1] & 0b1100_0000 == 0b0100_0000)
588     }
589
590     /// Returns [`true`] if this address is part of `192.0.0.0/24`, which is reserved to
591     /// IANA for IETF protocol assignments, as documented in [IETF RFC 6890].
592     ///
593     /// Note that parts of this block are in use:
594     ///
595     /// - `192.0.0.8/32` is the "IPv4 dummy address" (see [IETF RFC 7600])
596     /// - `192.0.0.9/32` is the "Port Control Protocol Anycast" (see [IETF RFC 7723])
597     /// - `192.0.0.10/32` is used for NAT traversal (see [IETF RFC 8155])
598     ///
599     /// [IETF RFC 6890]: https://tools.ietf.org/html/rfc6890
600     /// [IETF RFC 7600]: https://tools.ietf.org/html/rfc7600
601     /// [IETF RFC 7723]: https://tools.ietf.org/html/rfc7723
602     /// [IETF RFC 8155]: https://tools.ietf.org/html/rfc8155
603     ///
604     /// # Examples
605     ///
606     /// ```
607     /// #![feature(ip)]
608     /// use std::net::Ipv4Addr;
609     ///
610     /// assert_eq!(Ipv4Addr::new(192, 0, 0, 0).is_ietf_protocol_assignment(), true);
611     /// assert_eq!(Ipv4Addr::new(192, 0, 0, 8).is_ietf_protocol_assignment(), true);
612     /// assert_eq!(Ipv4Addr::new(192, 0, 0, 9).is_ietf_protocol_assignment(), true);
613     /// assert_eq!(Ipv4Addr::new(192, 0, 0, 255).is_ietf_protocol_assignment(), true);
614     /// assert_eq!(Ipv4Addr::new(192, 0, 1, 0).is_ietf_protocol_assignment(), false);
615     /// assert_eq!(Ipv4Addr::new(191, 255, 255, 255).is_ietf_protocol_assignment(), false);
616     /// ```
617     #[rustc_const_unstable(feature = "const_ipv4", issue = "76205")]
618     #[inline]
619     pub const fn is_ietf_protocol_assignment(&self) -> bool {
620         self.octets()[0] == 192 && self.octets()[1] == 0 && self.octets()[2] == 0
621     }
622
623     /// Returns [`true`] if this address part of the `198.18.0.0/15` range, which is reserved for
624     /// network devices benchmarking. This range is defined in [IETF RFC 2544] as `192.18.0.0`
625     /// through `198.19.255.255` but [errata 423] corrects it to `198.18.0.0/15`.
626     ///
627     /// [IETF RFC 2544]: https://tools.ietf.org/html/rfc2544
628     /// [errata 423]: https://www.rfc-editor.org/errata/eid423
629     ///
630     /// # Examples
631     ///
632     /// ```
633     /// #![feature(ip)]
634     /// use std::net::Ipv4Addr;
635     ///
636     /// assert_eq!(Ipv4Addr::new(198, 17, 255, 255).is_benchmarking(), false);
637     /// assert_eq!(Ipv4Addr::new(198, 18, 0, 0).is_benchmarking(), true);
638     /// assert_eq!(Ipv4Addr::new(198, 19, 255, 255).is_benchmarking(), true);
639     /// assert_eq!(Ipv4Addr::new(198, 20, 0, 0).is_benchmarking(), false);
640     /// ```
641     #[rustc_const_unstable(feature = "const_ipv4", issue = "76205")]
642     #[inline]
643     pub const fn is_benchmarking(&self) -> bool {
644         self.octets()[0] == 198 && (self.octets()[1] & 0xfe) == 18
645     }
646
647     /// Returns [`true`] if this address is reserved by IANA for future use. [IETF RFC 1112]
648     /// defines the block of reserved addresses as `240.0.0.0/4`. This range normally includes the
649     /// broadcast address `255.255.255.255`, but this implementation explicitly excludes it, since
650     /// it is obviously not reserved for future use.
651     ///
652     /// [IETF RFC 1112]: https://tools.ietf.org/html/rfc1112
653     ///
654     /// # Warning
655     ///
656     /// As IANA assigns new addresses, this method will be
657     /// updated. This may result in non-reserved addresses being
658     /// treated as reserved in code that relies on an outdated version
659     /// of this method.
660     ///
661     /// # Examples
662     ///
663     /// ```
664     /// #![feature(ip)]
665     /// use std::net::Ipv4Addr;
666     ///
667     /// assert_eq!(Ipv4Addr::new(240, 0, 0, 0).is_reserved(), true);
668     /// assert_eq!(Ipv4Addr::new(255, 255, 255, 254).is_reserved(), true);
669     ///
670     /// assert_eq!(Ipv4Addr::new(239, 255, 255, 255).is_reserved(), false);
671     /// // The broadcast address is not considered as reserved for future use by this implementation
672     /// assert_eq!(Ipv4Addr::new(255, 255, 255, 255).is_reserved(), false);
673     /// ```
674     #[rustc_const_unstable(feature = "const_ipv4", issue = "76205")]
675     #[inline]
676     pub const fn is_reserved(&self) -> bool {
677         self.octets()[0] & 240 == 240 && !self.is_broadcast()
678     }
679
680     /// Returns [`true`] if this is a multicast address (224.0.0.0/4).
681     ///
682     /// Multicast addresses have a most significant octet between 224 and 239,
683     /// and is defined by [IETF RFC 5771].
684     ///
685     /// [IETF RFC 5771]: https://tools.ietf.org/html/rfc5771
686     ///
687     /// # Examples
688     ///
689     /// ```
690     /// use std::net::Ipv4Addr;
691     ///
692     /// assert_eq!(Ipv4Addr::new(224, 254, 0, 0).is_multicast(), true);
693     /// assert_eq!(Ipv4Addr::new(236, 168, 10, 65).is_multicast(), true);
694     /// assert_eq!(Ipv4Addr::new(172, 16, 10, 65).is_multicast(), false);
695     /// ```
696     #[rustc_const_stable(feature = "const_ipv4", since = "1.50.0")]
697     #[stable(since = "1.7.0", feature = "ip_17")]
698     #[inline]
699     pub const fn is_multicast(&self) -> bool {
700         self.octets()[0] >= 224 && self.octets()[0] <= 239
701     }
702
703     /// Returns [`true`] if this is a broadcast address (255.255.255.255).
704     ///
705     /// A broadcast address has all octets set to 255 as defined in [IETF RFC 919].
706     ///
707     /// [IETF RFC 919]: https://tools.ietf.org/html/rfc919
708     ///
709     /// # Examples
710     ///
711     /// ```
712     /// use std::net::Ipv4Addr;
713     ///
714     /// assert_eq!(Ipv4Addr::new(255, 255, 255, 255).is_broadcast(), true);
715     /// assert_eq!(Ipv4Addr::new(236, 168, 10, 65).is_broadcast(), false);
716     /// ```
717     #[rustc_const_stable(feature = "const_ipv4", since = "1.50.0")]
718     #[stable(since = "1.7.0", feature = "ip_17")]
719     #[inline]
720     pub const fn is_broadcast(&self) -> bool {
721         u32::from_be_bytes(self.octets()) == u32::from_be_bytes(Self::BROADCAST.octets())
722     }
723
724     /// Returns [`true`] if this address is in a range designated for documentation.
725     ///
726     /// This is defined in [IETF RFC 5737]:
727     ///
728     /// - 192.0.2.0/24 (TEST-NET-1)
729     /// - 198.51.100.0/24 (TEST-NET-2)
730     /// - 203.0.113.0/24 (TEST-NET-3)
731     ///
732     /// [IETF RFC 5737]: https://tools.ietf.org/html/rfc5737
733     ///
734     /// # Examples
735     ///
736     /// ```
737     /// use std::net::Ipv4Addr;
738     ///
739     /// assert_eq!(Ipv4Addr::new(192, 0, 2, 255).is_documentation(), true);
740     /// assert_eq!(Ipv4Addr::new(198, 51, 100, 65).is_documentation(), true);
741     /// assert_eq!(Ipv4Addr::new(203, 0, 113, 6).is_documentation(), true);
742     /// assert_eq!(Ipv4Addr::new(193, 34, 17, 19).is_documentation(), false);
743     /// ```
744     #[rustc_const_stable(feature = "const_ipv4", since = "1.50.0")]
745     #[stable(since = "1.7.0", feature = "ip_17")]
746     #[inline]
747     pub const fn is_documentation(&self) -> bool {
748         match self.octets() {
749             [192, 0, 2, _] => true,
750             [198, 51, 100, _] => true,
751             [203, 0, 113, _] => true,
752             _ => false,
753         }
754     }
755
756     /// Converts this address to an IPv4-compatible [`IPv6` address].
757     ///
758     /// a.b.c.d becomes ::a.b.c.d
759     ///
760     /// This isn't typically the method you want; these addresses don't typically
761     /// function on modern systems. Use `to_ipv6_mapped` instead.
762     ///
763     /// [`IPv6` address]: Ipv6Addr
764     ///
765     /// # Examples
766     ///
767     /// ```
768     /// use std::net::{Ipv4Addr, Ipv6Addr};
769     ///
770     /// assert_eq!(
771     ///     Ipv4Addr::new(192, 0, 2, 255).to_ipv6_compatible(),
772     ///     Ipv6Addr::new(0, 0, 0, 0, 0, 0, 49152, 767)
773     /// );
774     /// ```
775     #[rustc_const_stable(feature = "const_ipv4", since = "1.50.0")]
776     #[stable(feature = "rust1", since = "1.0.0")]
777     #[inline]
778     pub const fn to_ipv6_compatible(&self) -> Ipv6Addr {
779         let [a, b, c, d] = self.octets();
780         Ipv6Addr {
781             inner: c::in6_addr { s6_addr: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, a, b, c, d] },
782         }
783     }
784
785     /// Converts this address to an IPv4-mapped [`IPv6` address].
786     ///
787     /// a.b.c.d becomes ::ffff:a.b.c.d
788     ///
789     /// [`IPv6` address]: Ipv6Addr
790     ///
791     /// # Examples
792     ///
793     /// ```
794     /// use std::net::{Ipv4Addr, Ipv6Addr};
795     ///
796     /// assert_eq!(Ipv4Addr::new(192, 0, 2, 255).to_ipv6_mapped(),
797     ///            Ipv6Addr::new(0, 0, 0, 0, 0, 65535, 49152, 767));
798     /// ```
799     #[rustc_const_stable(feature = "const_ipv4", since = "1.50.0")]
800     #[stable(feature = "rust1", since = "1.0.0")]
801     #[inline]
802     pub const fn to_ipv6_mapped(&self) -> Ipv6Addr {
803         let [a, b, c, d] = self.octets();
804         Ipv6Addr {
805             inner: c::in6_addr { s6_addr: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xFF, 0xFF, a, b, c, d] },
806         }
807     }
808 }
809
810 #[stable(feature = "ip_addr", since = "1.7.0")]
811 impl fmt::Display for IpAddr {
812     fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
813         match self {
814             IpAddr::V4(ip) => ip.fmt(fmt),
815             IpAddr::V6(ip) => ip.fmt(fmt),
816         }
817     }
818 }
819
820 #[stable(feature = "ip_addr", since = "1.7.0")]
821 impl fmt::Debug for IpAddr {
822     fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
823         fmt::Display::fmt(self, fmt)
824     }
825 }
826
827 #[stable(feature = "ip_from_ip", since = "1.16.0")]
828 impl From<Ipv4Addr> for IpAddr {
829     /// Copies this address to a new `IpAddr::V4`.
830     ///
831     /// # Examples
832     ///
833     /// ```
834     /// use std::net::{IpAddr, Ipv4Addr};
835     ///
836     /// let addr = Ipv4Addr::new(127, 0, 0, 1);
837     ///
838     /// assert_eq!(
839     ///     IpAddr::V4(addr),
840     ///     IpAddr::from(addr)
841     /// )
842     /// ```
843     #[inline]
844     fn from(ipv4: Ipv4Addr) -> IpAddr {
845         IpAddr::V4(ipv4)
846     }
847 }
848
849 #[stable(feature = "ip_from_ip", since = "1.16.0")]
850 impl From<Ipv6Addr> for IpAddr {
851     /// Copies this address to a new `IpAddr::V6`.
852     ///
853     /// # Examples
854     ///
855     /// ```
856     /// use std::net::{IpAddr, Ipv6Addr};
857     ///
858     /// let addr = Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff);
859     ///
860     /// assert_eq!(
861     ///     IpAddr::V6(addr),
862     ///     IpAddr::from(addr)
863     /// );
864     /// ```
865     #[inline]
866     fn from(ipv6: Ipv6Addr) -> IpAddr {
867         IpAddr::V6(ipv6)
868     }
869 }
870
871 #[stable(feature = "rust1", since = "1.0.0")]
872 impl fmt::Display for Ipv4Addr {
873     fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
874         let octets = self.octets();
875         // Fast Path: if there's no alignment stuff, write directly to the buffer
876         if fmt.precision().is_none() && fmt.width().is_none() {
877             write!(fmt, "{}.{}.{}.{}", octets[0], octets[1], octets[2], octets[3])
878         } else {
879             const IPV4_BUF_LEN: usize = 15; // Long enough for the longest possible IPv4 address
880             let mut buf = [0u8; IPV4_BUF_LEN];
881             let mut buf_slice = &mut buf[..];
882
883             // Note: The call to write should never fail, hence the unwrap
884             write!(buf_slice, "{}.{}.{}.{}", octets[0], octets[1], octets[2], octets[3]).unwrap();
885             let len = IPV4_BUF_LEN - buf_slice.len();
886
887             // This unsafe is OK because we know what is being written to the buffer
888             let buf = unsafe { crate::str::from_utf8_unchecked(&buf[..len]) };
889             fmt.pad(buf)
890         }
891     }
892 }
893
894 #[stable(feature = "rust1", since = "1.0.0")]
895 impl fmt::Debug for Ipv4Addr {
896     fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
897         fmt::Display::fmt(self, fmt)
898     }
899 }
900
901 #[stable(feature = "rust1", since = "1.0.0")]
902 impl Clone for Ipv4Addr {
903     #[inline]
904     fn clone(&self) -> Ipv4Addr {
905         *self
906     }
907 }
908
909 #[stable(feature = "rust1", since = "1.0.0")]
910 impl PartialEq for Ipv4Addr {
911     #[inline]
912     fn eq(&self, other: &Ipv4Addr) -> bool {
913         self.inner.s_addr == other.inner.s_addr
914     }
915 }
916
917 #[stable(feature = "ip_cmp", since = "1.16.0")]
918 impl PartialEq<Ipv4Addr> for IpAddr {
919     #[inline]
920     fn eq(&self, other: &Ipv4Addr) -> bool {
921         match self {
922             IpAddr::V4(v4) => v4 == other,
923             IpAddr::V6(_) => false,
924         }
925     }
926 }
927
928 #[stable(feature = "ip_cmp", since = "1.16.0")]
929 impl PartialEq<IpAddr> for Ipv4Addr {
930     #[inline]
931     fn eq(&self, other: &IpAddr) -> bool {
932         match other {
933             IpAddr::V4(v4) => self == v4,
934             IpAddr::V6(_) => false,
935         }
936     }
937 }
938
939 #[stable(feature = "rust1", since = "1.0.0")]
940 impl Eq for Ipv4Addr {}
941
942 #[stable(feature = "rust1", since = "1.0.0")]
943 impl hash::Hash for Ipv4Addr {
944     #[inline]
945     fn hash<H: hash::Hasher>(&self, s: &mut H) {
946         // NOTE:
947         // * hash in big endian order
948         // * in netbsd, `in_addr` has `repr(packed)`, we need to
949         //   copy `s_addr` to avoid unsafe borrowing
950         { self.inner.s_addr }.hash(s)
951     }
952 }
953
954 #[stable(feature = "rust1", since = "1.0.0")]
955 impl PartialOrd for Ipv4Addr {
956     #[inline]
957     fn partial_cmp(&self, other: &Ipv4Addr) -> Option<Ordering> {
958         Some(self.cmp(other))
959     }
960 }
961
962 #[stable(feature = "ip_cmp", since = "1.16.0")]
963 impl PartialOrd<Ipv4Addr> for IpAddr {
964     #[inline]
965     fn partial_cmp(&self, other: &Ipv4Addr) -> Option<Ordering> {
966         match self {
967             IpAddr::V4(v4) => v4.partial_cmp(other),
968             IpAddr::V6(_) => Some(Ordering::Greater),
969         }
970     }
971 }
972
973 #[stable(feature = "ip_cmp", since = "1.16.0")]
974 impl PartialOrd<IpAddr> for Ipv4Addr {
975     #[inline]
976     fn partial_cmp(&self, other: &IpAddr) -> Option<Ordering> {
977         match other {
978             IpAddr::V4(v4) => self.partial_cmp(v4),
979             IpAddr::V6(_) => Some(Ordering::Less),
980         }
981     }
982 }
983
984 #[stable(feature = "rust1", since = "1.0.0")]
985 impl Ord for Ipv4Addr {
986     #[inline]
987     fn cmp(&self, other: &Ipv4Addr) -> Ordering {
988         // Compare as native endian
989         u32::from_be(self.inner.s_addr).cmp(&u32::from_be(other.inner.s_addr))
990     }
991 }
992
993 impl IntoInner<c::in_addr> for Ipv4Addr {
994     fn into_inner(self) -> c::in_addr {
995         self.inner
996     }
997 }
998
999 #[stable(feature = "ip_u32", since = "1.1.0")]
1000 impl From<Ipv4Addr> for u32 {
1001     /// Converts an `Ipv4Addr` into a host byte order `u32`.
1002     ///
1003     /// # Examples
1004     ///
1005     /// ```
1006     /// use std::net::Ipv4Addr;
1007     ///
1008     /// let addr = Ipv4Addr::new(0xca, 0xfe, 0xba, 0xbe);
1009     /// assert_eq!(0xcafebabe, u32::from(addr));
1010     /// ```
1011     #[inline]
1012     fn from(ip: Ipv4Addr) -> u32 {
1013         let ip = ip.octets();
1014         u32::from_be_bytes(ip)
1015     }
1016 }
1017
1018 #[stable(feature = "ip_u32", since = "1.1.0")]
1019 impl From<u32> for Ipv4Addr {
1020     /// Converts a host byte order `u32` into an `Ipv4Addr`.
1021     ///
1022     /// # Examples
1023     ///
1024     /// ```
1025     /// use std::net::Ipv4Addr;
1026     ///
1027     /// let addr = Ipv4Addr::from(0xcafebabe);
1028     /// assert_eq!(Ipv4Addr::new(0xca, 0xfe, 0xba, 0xbe), addr);
1029     /// ```
1030     #[inline]
1031     fn from(ip: u32) -> Ipv4Addr {
1032         Ipv4Addr::from(ip.to_be_bytes())
1033     }
1034 }
1035
1036 #[stable(feature = "from_slice_v4", since = "1.9.0")]
1037 impl From<[u8; 4]> for Ipv4Addr {
1038     /// Creates an `Ipv4Addr` from a four element byte array.
1039     ///
1040     /// # Examples
1041     ///
1042     /// ```
1043     /// use std::net::Ipv4Addr;
1044     ///
1045     /// let addr = Ipv4Addr::from([13u8, 12u8, 11u8, 10u8]);
1046     /// assert_eq!(Ipv4Addr::new(13, 12, 11, 10), addr);
1047     /// ```
1048     #[inline]
1049     fn from(octets: [u8; 4]) -> Ipv4Addr {
1050         Ipv4Addr::new(octets[0], octets[1], octets[2], octets[3])
1051     }
1052 }
1053
1054 #[stable(feature = "ip_from_slice", since = "1.17.0")]
1055 impl From<[u8; 4]> for IpAddr {
1056     /// Creates an `IpAddr::V4` from a four element byte array.
1057     ///
1058     /// # Examples
1059     ///
1060     /// ```
1061     /// use std::net::{IpAddr, Ipv4Addr};
1062     ///
1063     /// let addr = IpAddr::from([13u8, 12u8, 11u8, 10u8]);
1064     /// assert_eq!(IpAddr::V4(Ipv4Addr::new(13, 12, 11, 10)), addr);
1065     /// ```
1066     #[inline]
1067     fn from(octets: [u8; 4]) -> IpAddr {
1068         IpAddr::V4(Ipv4Addr::from(octets))
1069     }
1070 }
1071
1072 impl Ipv6Addr {
1073     /// Creates a new IPv6 address from eight 16-bit segments.
1074     ///
1075     /// The result will represent the IP address `a:b:c:d:e:f:g:h`.
1076     ///
1077     /// # Examples
1078     ///
1079     /// ```
1080     /// use std::net::Ipv6Addr;
1081     ///
1082     /// let addr = Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff);
1083     /// ```
1084     #[rustc_allow_const_fn_unstable(const_fn_transmute)]
1085     #[rustc_const_stable(feature = "const_ipv6", since = "1.32.0")]
1086     #[stable(feature = "rust1", since = "1.0.0")]
1087     #[inline]
1088     pub const fn new(a: u16, b: u16, c: u16, d: u16, e: u16, f: u16, g: u16, h: u16) -> Ipv6Addr {
1089         let addr16 = [
1090             a.to_be(),
1091             b.to_be(),
1092             c.to_be(),
1093             d.to_be(),
1094             e.to_be(),
1095             f.to_be(),
1096             g.to_be(),
1097             h.to_be(),
1098         ];
1099         Ipv6Addr {
1100             inner: c::in6_addr {
1101                 // All elements in `addr16` are big endian.
1102                 // SAFETY: `[u16; 8]` is always safe to transmute to `[u8; 16]`.
1103                 // rustc_allow_const_fn_unstable: the transmute could be written as stable const
1104                 // code, but that leads to worse code generation (#75085)
1105                 s6_addr: unsafe { transmute::<_, [u8; 16]>(addr16) },
1106             },
1107         }
1108     }
1109
1110     /// An IPv6 address representing localhost: `::1`.
1111     ///
1112     /// # Examples
1113     ///
1114     /// ```
1115     /// use std::net::Ipv6Addr;
1116     ///
1117     /// let addr = Ipv6Addr::LOCALHOST;
1118     /// assert_eq!(addr, Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1));
1119     /// ```
1120     #[stable(feature = "ip_constructors", since = "1.30.0")]
1121     pub const LOCALHOST: Self = Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1);
1122
1123     /// An IPv6 address representing the unspecified address: `::`
1124     ///
1125     /// # Examples
1126     ///
1127     /// ```
1128     /// use std::net::Ipv6Addr;
1129     ///
1130     /// let addr = Ipv6Addr::UNSPECIFIED;
1131     /// assert_eq!(addr, Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0));
1132     /// ```
1133     #[stable(feature = "ip_constructors", since = "1.30.0")]
1134     pub const UNSPECIFIED: Self = Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0);
1135
1136     /// Returns the eight 16-bit segments that make up this address.
1137     ///
1138     /// # Examples
1139     ///
1140     /// ```
1141     /// use std::net::Ipv6Addr;
1142     ///
1143     /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff).segments(),
1144     ///            [0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff]);
1145     /// ```
1146     #[rustc_allow_const_fn_unstable(const_fn_transmute)]
1147     #[rustc_const_stable(feature = "const_ipv6", since = "1.50.0")]
1148     #[stable(feature = "rust1", since = "1.0.0")]
1149     #[inline]
1150     pub const fn segments(&self) -> [u16; 8] {
1151         // All elements in `s6_addr` must be big endian.
1152         // SAFETY: `[u8; 16]` is always safe to transmute to `[u16; 8]`.
1153         // rustc_allow_const_fn_unstable: the transmute could be written as stable const code, but
1154         // that leads to worse code generation (#75085)
1155         let [a, b, c, d, e, f, g, h] = unsafe { transmute::<_, [u16; 8]>(self.inner.s6_addr) };
1156         // We want native endian u16
1157         [
1158             u16::from_be(a),
1159             u16::from_be(b),
1160             u16::from_be(c),
1161             u16::from_be(d),
1162             u16::from_be(e),
1163             u16::from_be(f),
1164             u16::from_be(g),
1165             u16::from_be(h),
1166         ]
1167     }
1168
1169     /// Returns [`true`] for the special 'unspecified' address (::).
1170     ///
1171     /// This property is defined in [IETF RFC 4291].
1172     ///
1173     /// [IETF RFC 4291]: https://tools.ietf.org/html/rfc4291
1174     ///
1175     /// # Examples
1176     ///
1177     /// ```
1178     /// use std::net::Ipv6Addr;
1179     ///
1180     /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff).is_unspecified(), false);
1181     /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0).is_unspecified(), true);
1182     /// ```
1183     #[rustc_const_stable(feature = "const_ipv6", since = "1.50.0")]
1184     #[stable(since = "1.7.0", feature = "ip_17")]
1185     #[inline]
1186     pub const fn is_unspecified(&self) -> bool {
1187         u128::from_be_bytes(self.octets()) == u128::from_be_bytes(Ipv6Addr::UNSPECIFIED.octets())
1188     }
1189
1190     /// Returns [`true`] if this is a loopback address (::1).
1191     ///
1192     /// This property is defined in [IETF RFC 4291].
1193     ///
1194     /// [IETF RFC 4291]: https://tools.ietf.org/html/rfc4291
1195     ///
1196     /// # Examples
1197     ///
1198     /// ```
1199     /// use std::net::Ipv6Addr;
1200     ///
1201     /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff).is_loopback(), false);
1202     /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0x1).is_loopback(), true);
1203     /// ```
1204     #[rustc_const_stable(feature = "const_ipv6", since = "1.50.0")]
1205     #[stable(since = "1.7.0", feature = "ip_17")]
1206     #[inline]
1207     pub const fn is_loopback(&self) -> bool {
1208         u128::from_be_bytes(self.octets()) == u128::from_be_bytes(Ipv6Addr::LOCALHOST.octets())
1209     }
1210
1211     /// Returns [`true`] if the address appears to be globally routable.
1212     ///
1213     /// The following return [`false`]:
1214     ///
1215     /// - the loopback address
1216     /// - link-local and unique local unicast addresses
1217     /// - interface-, link-, realm-, admin- and site-local multicast addresses
1218     ///
1219     /// # Examples
1220     ///
1221     /// ```
1222     /// #![feature(ip)]
1223     ///
1224     /// use std::net::Ipv6Addr;
1225     ///
1226     /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff).is_global(), true);
1227     /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0x1).is_global(), false);
1228     /// assert_eq!(Ipv6Addr::new(0, 0, 0x1c9, 0, 0, 0xafc8, 0, 0x1).is_global(), true);
1229     /// ```
1230     #[rustc_const_unstable(feature = "const_ipv6", issue = "76205")]
1231     #[inline]
1232     pub const fn is_global(&self) -> bool {
1233         match self.multicast_scope() {
1234             Some(Ipv6MulticastScope::Global) => true,
1235             None => self.is_unicast_global(),
1236             _ => false,
1237         }
1238     }
1239
1240     /// Returns [`true`] if this is a unique local address (`fc00::/7`).
1241     ///
1242     /// This property is defined in [IETF RFC 4193].
1243     ///
1244     /// [IETF RFC 4193]: https://tools.ietf.org/html/rfc4193
1245     ///
1246     /// # Examples
1247     ///
1248     /// ```
1249     /// #![feature(ip)]
1250     ///
1251     /// use std::net::Ipv6Addr;
1252     ///
1253     /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff).is_unique_local(), false);
1254     /// assert_eq!(Ipv6Addr::new(0xfc02, 0, 0, 0, 0, 0, 0, 0).is_unique_local(), true);
1255     /// ```
1256     #[rustc_const_unstable(feature = "const_ipv6", issue = "76205")]
1257     #[inline]
1258     pub const fn is_unique_local(&self) -> bool {
1259         (self.segments()[0] & 0xfe00) == 0xfc00
1260     }
1261
1262     /// Returns [`true`] if the address is a unicast link-local address (`fe80::/64`).
1263     ///
1264     /// A common misconception is to think that "unicast link-local addresses start with
1265     /// `fe80::`", but [IETF RFC 4291] actually defines a stricter format for these addresses:
1266     ///
1267     /// ```no_rust
1268     /// |   10     |
1269     /// |  bits    |         54 bits         |          64 bits           |
1270     /// +----------+-------------------------+----------------------------+
1271     /// |1111111010|           0             |       interface ID         |
1272     /// +----------+-------------------------+----------------------------+
1273     /// ```
1274     ///
1275     /// This method validates the format defined in the RFC and won't recognize addresses
1276     /// like `fe80:0:0:1::` or `fe81::` as unicast link-local addresses.
1277     /// If you need a less strict validation, use [`Ipv6Addr::is_unicast_link_local()`] instead.
1278     ///
1279     /// # Examples
1280     ///
1281     /// ```
1282     /// #![feature(ip)]
1283     ///
1284     /// use std::net::Ipv6Addr;
1285     ///
1286     /// let ip = Ipv6Addr::new(0xfe80, 0, 0, 0, 0, 0, 0, 0);
1287     /// assert!(ip.is_unicast_link_local_strict());
1288     ///
1289     /// let ip = Ipv6Addr::new(0xfe80, 0, 0, 0, 0xffff, 0xffff, 0xffff, 0xffff);
1290     /// assert!(ip.is_unicast_link_local_strict());
1291     ///
1292     /// let ip = Ipv6Addr::new(0xfe80, 0, 0, 1, 0, 0, 0, 0);
1293     /// assert!(!ip.is_unicast_link_local_strict());
1294     /// assert!(ip.is_unicast_link_local());
1295     ///
1296     /// let ip = Ipv6Addr::new(0xfe81, 0, 0, 0, 0, 0, 0, 0);
1297     /// assert!(!ip.is_unicast_link_local_strict());
1298     /// assert!(ip.is_unicast_link_local());
1299     /// ```
1300     ///
1301     /// # See also
1302     ///
1303     /// - [IETF RFC 4291 section 2.5.6]
1304     /// - [RFC 4291 errata 4406] (which has been rejected but provides useful
1305     ///   insight)
1306     /// - [`Ipv6Addr::is_unicast_link_local()`]
1307     ///
1308     /// [IETF RFC 4291]: https://tools.ietf.org/html/rfc4291
1309     /// [IETF RFC 4291 section 2.5.6]: https://tools.ietf.org/html/rfc4291#section-2.5.6
1310     /// [RFC 4291 errata 4406]: https://www.rfc-editor.org/errata/eid4406
1311     #[rustc_const_unstable(feature = "const_ipv6", issue = "76205")]
1312     #[inline]
1313     pub const fn is_unicast_link_local_strict(&self) -> bool {
1314         matches!(self.segments(), [0xfe80, 0, 0, 0, ..])
1315     }
1316
1317     /// Returns [`true`] if the address is a unicast link-local address (`fe80::/10`).
1318     ///
1319     /// This method returns [`true`] for addresses in the range reserved by [RFC 4291 section 2.4],
1320     /// i.e. addresses with the following format:
1321     ///
1322     /// ```no_rust
1323     /// |   10     |
1324     /// |  bits    |         54 bits         |          64 bits           |
1325     /// +----------+-------------------------+----------------------------+
1326     /// |1111111010|    arbitratry value     |       interface ID         |
1327     /// +----------+-------------------------+----------------------------+
1328     /// ```
1329     ///
1330     /// As a result, this method considers addresses such as `fe80:0:0:1::` or `fe81::` to be
1331     /// unicast link-local addresses, whereas [`Ipv6Addr::is_unicast_link_local_strict()`] does not.
1332     /// If you need a strict validation fully compliant with the RFC, use
1333     /// [`Ipv6Addr::is_unicast_link_local_strict()`] instead.
1334     ///
1335     /// # Examples
1336     ///
1337     /// ```
1338     /// #![feature(ip)]
1339     ///
1340     /// use std::net::Ipv6Addr;
1341     ///
1342     /// let ip = Ipv6Addr::new(0xfe80, 0, 0, 0, 0, 0, 0, 0);
1343     /// assert!(ip.is_unicast_link_local());
1344     ///
1345     /// let ip = Ipv6Addr::new(0xfe80, 0, 0, 0, 0xffff, 0xffff, 0xffff, 0xffff);
1346     /// assert!(ip.is_unicast_link_local());
1347     ///
1348     /// let ip = Ipv6Addr::new(0xfe80, 0, 0, 1, 0, 0, 0, 0);
1349     /// assert!(ip.is_unicast_link_local());
1350     /// assert!(!ip.is_unicast_link_local_strict());
1351     ///
1352     /// let ip = Ipv6Addr::new(0xfe81, 0, 0, 0, 0, 0, 0, 0);
1353     /// assert!(ip.is_unicast_link_local());
1354     /// assert!(!ip.is_unicast_link_local_strict());
1355     /// ```
1356     ///
1357     /// # See also
1358     ///
1359     /// - [IETF RFC 4291 section 2.4]
1360     /// - [RFC 4291 errata 4406] (which has been rejected but provides useful
1361     ///   insight)
1362     ///
1363     /// [IETF RFC 4291 section 2.4]: https://tools.ietf.org/html/rfc4291#section-2.4
1364     /// [RFC 4291 errata 4406]: https://www.rfc-editor.org/errata/eid4406
1365     #[rustc_const_unstable(feature = "const_ipv6", issue = "76205")]
1366     #[inline]
1367     pub const fn is_unicast_link_local(&self) -> bool {
1368         (self.segments()[0] & 0xffc0) == 0xfe80
1369     }
1370
1371     /// Returns [`true`] if this is a deprecated unicast site-local address (fec0::/10). The
1372     /// unicast site-local address format is defined in [RFC 4291 section 2.5.7] as:
1373     ///
1374     /// ```no_rust
1375     /// |   10     |
1376     /// |  bits    |         54 bits         |         64 bits            |
1377     /// +----------+-------------------------+----------------------------+
1378     /// |1111111011|        subnet ID        |       interface ID         |
1379     /// +----------+-------------------------+----------------------------+
1380     /// ```
1381     ///
1382     /// [RFC 4291 section 2.5.7]: https://tools.ietf.org/html/rfc4291#section-2.5.7
1383     ///
1384     /// # Examples
1385     ///
1386     /// ```
1387     /// #![feature(ip)]
1388     ///
1389     /// use std::net::Ipv6Addr;
1390     ///
1391     /// assert_eq!(
1392     ///     Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff).is_unicast_site_local(),
1393     ///     false
1394     /// );
1395     /// assert_eq!(Ipv6Addr::new(0xfec2, 0, 0, 0, 0, 0, 0, 0).is_unicast_site_local(), true);
1396     /// ```
1397     ///
1398     /// # Warning
1399     ///
1400     /// As per [RFC 3879], the whole `FEC0::/10` prefix is
1401     /// deprecated. New software must not support site-local
1402     /// addresses.
1403     ///
1404     /// [RFC 3879]: https://tools.ietf.org/html/rfc3879
1405     #[rustc_const_unstable(feature = "const_ipv6", issue = "76205")]
1406     #[inline]
1407     pub const fn is_unicast_site_local(&self) -> bool {
1408         (self.segments()[0] & 0xffc0) == 0xfec0
1409     }
1410
1411     /// Returns [`true`] if this is an address reserved for documentation
1412     /// (`2001:db8::/32`).
1413     ///
1414     /// This property is defined in [IETF RFC 3849].
1415     ///
1416     /// [IETF RFC 3849]: https://tools.ietf.org/html/rfc3849
1417     ///
1418     /// # Examples
1419     ///
1420     /// ```
1421     /// #![feature(ip)]
1422     ///
1423     /// use std::net::Ipv6Addr;
1424     ///
1425     /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff).is_documentation(), false);
1426     /// assert_eq!(Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 0).is_documentation(), true);
1427     /// ```
1428     #[rustc_const_unstable(feature = "const_ipv6", issue = "76205")]
1429     #[inline]
1430     pub const fn is_documentation(&self) -> bool {
1431         (self.segments()[0] == 0x2001) && (self.segments()[1] == 0xdb8)
1432     }
1433
1434     /// Returns [`true`] if the address is a globally routable unicast address.
1435     ///
1436     /// The following return false:
1437     ///
1438     /// - the loopback address
1439     /// - the link-local addresses
1440     /// - unique local addresses
1441     /// - the unspecified address
1442     /// - the address range reserved for documentation
1443     ///
1444     /// This method returns [`true`] for site-local addresses as per [RFC 4291 section 2.5.7]
1445     ///
1446     /// ```no_rust
1447     /// The special behavior of [the site-local unicast] prefix defined in [RFC3513] must no longer
1448     /// be supported in new implementations (i.e., new implementations must treat this prefix as
1449     /// Global Unicast).
1450     /// ```
1451     ///
1452     /// [RFC 4291 section 2.5.7]: https://tools.ietf.org/html/rfc4291#section-2.5.7
1453     ///
1454     /// # Examples
1455     ///
1456     /// ```
1457     /// #![feature(ip)]
1458     ///
1459     /// use std::net::Ipv6Addr;
1460     ///
1461     /// assert_eq!(Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 0).is_unicast_global(), false);
1462     /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff).is_unicast_global(), true);
1463     /// ```
1464     #[rustc_const_unstable(feature = "const_ipv6", issue = "76205")]
1465     #[inline]
1466     pub const fn is_unicast_global(&self) -> bool {
1467         !self.is_multicast()
1468             && !self.is_loopback()
1469             && !self.is_unicast_link_local()
1470             && !self.is_unique_local()
1471             && !self.is_unspecified()
1472             && !self.is_documentation()
1473     }
1474
1475     /// Returns the address's multicast scope if the address is multicast.
1476     ///
1477     /// # Examples
1478     ///
1479     /// ```
1480     /// #![feature(ip)]
1481     ///
1482     /// use std::net::{Ipv6Addr, Ipv6MulticastScope};
1483     ///
1484     /// assert_eq!(
1485     ///     Ipv6Addr::new(0xff0e, 0, 0, 0, 0, 0, 0, 0).multicast_scope(),
1486     ///     Some(Ipv6MulticastScope::Global)
1487     /// );
1488     /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff).multicast_scope(), None);
1489     /// ```
1490     #[rustc_const_unstable(feature = "const_ipv6", issue = "76205")]
1491     #[inline]
1492     pub const fn multicast_scope(&self) -> Option<Ipv6MulticastScope> {
1493         if self.is_multicast() {
1494             match self.segments()[0] & 0x000f {
1495                 1 => Some(Ipv6MulticastScope::InterfaceLocal),
1496                 2 => Some(Ipv6MulticastScope::LinkLocal),
1497                 3 => Some(Ipv6MulticastScope::RealmLocal),
1498                 4 => Some(Ipv6MulticastScope::AdminLocal),
1499                 5 => Some(Ipv6MulticastScope::SiteLocal),
1500                 8 => Some(Ipv6MulticastScope::OrganizationLocal),
1501                 14 => Some(Ipv6MulticastScope::Global),
1502                 _ => None,
1503             }
1504         } else {
1505             None
1506         }
1507     }
1508
1509     /// Returns [`true`] if this is a multicast address (ff00::/8).
1510     ///
1511     /// This property is defined by [IETF RFC 4291].
1512     ///
1513     /// [IETF RFC 4291]: https://tools.ietf.org/html/rfc4291
1514     ///
1515     /// # Examples
1516     ///
1517     /// ```
1518     /// use std::net::Ipv6Addr;
1519     ///
1520     /// assert_eq!(Ipv6Addr::new(0xff00, 0, 0, 0, 0, 0, 0, 0).is_multicast(), true);
1521     /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff).is_multicast(), false);
1522     /// ```
1523     #[rustc_const_stable(feature = "const_ipv6", since = "1.50.0")]
1524     #[stable(since = "1.7.0", feature = "ip_17")]
1525     #[inline]
1526     pub const fn is_multicast(&self) -> bool {
1527         (self.segments()[0] & 0xff00) == 0xff00
1528     }
1529
1530     /// Converts this address to an [`IPv4` address] if it's an "IPv4-mapped IPv6 address"
1531     /// defined in [IETF RFC 4291 section 2.5.5.2], otherwise returns [`None`].
1532     ///
1533     /// `::ffff:a.b.c.d` becomes `a.b.c.d`.
1534     /// All addresses *not* starting with `::ffff` will return `None`.
1535     ///
1536     /// [`IPv4` address]: Ipv4Addr
1537     /// [IETF RFC 4291 section 2.5.5.2]: https://tools.ietf.org/html/rfc4291#section-2.5.5.2
1538     ///
1539     /// # Examples
1540     ///
1541     /// ```
1542     /// #![feature(ip)]
1543     ///
1544     /// use std::net::{Ipv4Addr, Ipv6Addr};
1545     ///
1546     /// assert_eq!(Ipv6Addr::new(0xff00, 0, 0, 0, 0, 0, 0, 0).to_ipv4_mapped(), None);
1547     /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff).to_ipv4_mapped(),
1548     ///            Some(Ipv4Addr::new(192, 10, 2, 255)));
1549     /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1).to_ipv4_mapped(), None);
1550     /// ```
1551     #[rustc_const_unstable(feature = "const_ipv6", issue = "76205")]
1552     #[inline]
1553     pub const fn to_ipv4_mapped(&self) -> Option<Ipv4Addr> {
1554         match self.octets() {
1555             [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xff, 0xff, a, b, c, d] => {
1556                 Some(Ipv4Addr::new(a, b, c, d))
1557             }
1558             _ => None,
1559         }
1560     }
1561
1562     /// Converts this address to an [`IPv4` address]. Returns [`None`] if this address is
1563     /// neither IPv4-compatible or IPv4-mapped.
1564     ///
1565     /// ::a.b.c.d and ::ffff:a.b.c.d become a.b.c.d
1566     ///
1567     /// [`IPv4` address]: Ipv4Addr
1568     ///
1569     /// # Examples
1570     ///
1571     /// ```
1572     /// use std::net::{Ipv4Addr, Ipv6Addr};
1573     ///
1574     /// assert_eq!(Ipv6Addr::new(0xff00, 0, 0, 0, 0, 0, 0, 0).to_ipv4(), None);
1575     /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff).to_ipv4(),
1576     ///            Some(Ipv4Addr::new(192, 10, 2, 255)));
1577     /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1).to_ipv4(),
1578     ///            Some(Ipv4Addr::new(0, 0, 0, 1)));
1579     /// ```
1580     #[rustc_const_stable(feature = "const_ipv6", since = "1.50.0")]
1581     #[stable(feature = "rust1", since = "1.0.0")]
1582     #[inline]
1583     pub const fn to_ipv4(&self) -> Option<Ipv4Addr> {
1584         if let [0, 0, 0, 0, 0, 0 | 0xffff, ab, cd] = self.segments() {
1585             let [a, b] = ab.to_be_bytes();
1586             let [c, d] = cd.to_be_bytes();
1587             Some(Ipv4Addr::new(a, b, c, d))
1588         } else {
1589             None
1590         }
1591     }
1592
1593     /// Returns the sixteen eight-bit integers the IPv6 address consists of.
1594     ///
1595     /// ```
1596     /// use std::net::Ipv6Addr;
1597     ///
1598     /// assert_eq!(Ipv6Addr::new(0xff00, 0, 0, 0, 0, 0, 0, 0).octets(),
1599     ///            [255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]);
1600     /// ```
1601     #[rustc_const_stable(feature = "const_ipv6", since = "1.32.0")]
1602     #[stable(feature = "ipv6_to_octets", since = "1.12.0")]
1603     #[inline]
1604     pub const fn octets(&self) -> [u8; 16] {
1605         self.inner.s6_addr
1606     }
1607 }
1608
1609 /// Write an Ipv6Addr, conforming to the canonical style described by
1610 /// [RFC 5952](https://tools.ietf.org/html/rfc5952).
1611 #[stable(feature = "rust1", since = "1.0.0")]
1612 impl fmt::Display for Ipv6Addr {
1613     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1614         // If there are no alignment requirements, write out the IP address to
1615         // f. Otherwise, write it to a local buffer, then use f.pad.
1616         if f.precision().is_none() && f.width().is_none() {
1617             let segments = self.segments();
1618
1619             // Special case for :: and ::1; otherwise they get written with the
1620             // IPv4 formatter
1621             if self.is_unspecified() {
1622                 f.write_str("::")
1623             } else if self.is_loopback() {
1624                 f.write_str("::1")
1625             } else if let Some(ipv4) = self.to_ipv4() {
1626                 match segments[5] {
1627                     // IPv4 Compatible address
1628                     0 => write!(f, "::{}", ipv4),
1629                     // IPv4 Mapped address
1630                     0xffff => write!(f, "::ffff:{}", ipv4),
1631                     _ => unreachable!(),
1632                 }
1633             } else {
1634                 #[derive(Copy, Clone, Default)]
1635                 struct Span {
1636                     start: usize,
1637                     len: usize,
1638                 }
1639
1640                 // Find the inner 0 span
1641                 let zeroes = {
1642                     let mut longest = Span::default();
1643                     let mut current = Span::default();
1644
1645                     for (i, &segment) in segments.iter().enumerate() {
1646                         if segment == 0 {
1647                             if current.len == 0 {
1648                                 current.start = i;
1649                             }
1650
1651                             current.len += 1;
1652
1653                             if current.len > longest.len {
1654                                 longest = current;
1655                             }
1656                         } else {
1657                             current = Span::default();
1658                         }
1659                     }
1660
1661                     longest
1662                 };
1663
1664                 /// Write a colon-separated part of the address
1665                 #[inline]
1666                 fn fmt_subslice(f: &mut fmt::Formatter<'_>, chunk: &[u16]) -> fmt::Result {
1667                     if let Some((first, tail)) = chunk.split_first() {
1668                         write!(f, "{:x}", first)?;
1669                         for segment in tail {
1670                             f.write_char(':')?;
1671                             write!(f, "{:x}", segment)?;
1672                         }
1673                     }
1674                     Ok(())
1675                 }
1676
1677                 if zeroes.len > 1 {
1678                     fmt_subslice(f, &segments[..zeroes.start])?;
1679                     f.write_str("::")?;
1680                     fmt_subslice(f, &segments[zeroes.start + zeroes.len..])
1681                 } else {
1682                     fmt_subslice(f, &segments)
1683                 }
1684             }
1685         } else {
1686             // Slow path: write the address to a local buffer, the use f.pad.
1687             // Defined recursively by using the fast path to write to the
1688             // buffer.
1689
1690             // This is the largest possible size of an IPv6 address
1691             const IPV6_BUF_LEN: usize = (4 * 8) + 7;
1692             let mut buf = [0u8; IPV6_BUF_LEN];
1693             let mut buf_slice = &mut buf[..];
1694
1695             // Note: This call to write should never fail, so unwrap is okay.
1696             write!(buf_slice, "{}", self).unwrap();
1697             let len = IPV6_BUF_LEN - buf_slice.len();
1698
1699             // This is safe because we know exactly what can be in this buffer
1700             let buf = unsafe { crate::str::from_utf8_unchecked(&buf[..len]) };
1701             f.pad(buf)
1702         }
1703     }
1704 }
1705
1706 #[stable(feature = "rust1", since = "1.0.0")]
1707 impl fmt::Debug for Ipv6Addr {
1708     fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
1709         fmt::Display::fmt(self, fmt)
1710     }
1711 }
1712
1713 #[stable(feature = "rust1", since = "1.0.0")]
1714 impl Clone for Ipv6Addr {
1715     #[inline]
1716     fn clone(&self) -> Ipv6Addr {
1717         *self
1718     }
1719 }
1720
1721 #[stable(feature = "rust1", since = "1.0.0")]
1722 impl PartialEq for Ipv6Addr {
1723     #[inline]
1724     fn eq(&self, other: &Ipv6Addr) -> bool {
1725         self.inner.s6_addr == other.inner.s6_addr
1726     }
1727 }
1728
1729 #[stable(feature = "ip_cmp", since = "1.16.0")]
1730 impl PartialEq<IpAddr> for Ipv6Addr {
1731     #[inline]
1732     fn eq(&self, other: &IpAddr) -> bool {
1733         match other {
1734             IpAddr::V4(_) => false,
1735             IpAddr::V6(v6) => self == v6,
1736         }
1737     }
1738 }
1739
1740 #[stable(feature = "ip_cmp", since = "1.16.0")]
1741 impl PartialEq<Ipv6Addr> for IpAddr {
1742     #[inline]
1743     fn eq(&self, other: &Ipv6Addr) -> bool {
1744         match self {
1745             IpAddr::V4(_) => false,
1746             IpAddr::V6(v6) => v6 == other,
1747         }
1748     }
1749 }
1750
1751 #[stable(feature = "rust1", since = "1.0.0")]
1752 impl Eq for Ipv6Addr {}
1753
1754 #[stable(feature = "rust1", since = "1.0.0")]
1755 impl hash::Hash for Ipv6Addr {
1756     #[inline]
1757     fn hash<H: hash::Hasher>(&self, s: &mut H) {
1758         self.inner.s6_addr.hash(s)
1759     }
1760 }
1761
1762 #[stable(feature = "rust1", since = "1.0.0")]
1763 impl PartialOrd for Ipv6Addr {
1764     #[inline]
1765     fn partial_cmp(&self, other: &Ipv6Addr) -> Option<Ordering> {
1766         Some(self.cmp(other))
1767     }
1768 }
1769
1770 #[stable(feature = "ip_cmp", since = "1.16.0")]
1771 impl PartialOrd<Ipv6Addr> for IpAddr {
1772     #[inline]
1773     fn partial_cmp(&self, other: &Ipv6Addr) -> Option<Ordering> {
1774         match self {
1775             IpAddr::V4(_) => Some(Ordering::Less),
1776             IpAddr::V6(v6) => v6.partial_cmp(other),
1777         }
1778     }
1779 }
1780
1781 #[stable(feature = "ip_cmp", since = "1.16.0")]
1782 impl PartialOrd<IpAddr> for Ipv6Addr {
1783     #[inline]
1784     fn partial_cmp(&self, other: &IpAddr) -> Option<Ordering> {
1785         match other {
1786             IpAddr::V4(_) => Some(Ordering::Greater),
1787             IpAddr::V6(v6) => self.partial_cmp(v6),
1788         }
1789     }
1790 }
1791
1792 #[stable(feature = "rust1", since = "1.0.0")]
1793 impl Ord for Ipv6Addr {
1794     #[inline]
1795     fn cmp(&self, other: &Ipv6Addr) -> Ordering {
1796         self.segments().cmp(&other.segments())
1797     }
1798 }
1799
1800 impl AsInner<c::in6_addr> for Ipv6Addr {
1801     fn as_inner(&self) -> &c::in6_addr {
1802         &self.inner
1803     }
1804 }
1805 impl FromInner<c::in6_addr> for Ipv6Addr {
1806     fn from_inner(addr: c::in6_addr) -> Ipv6Addr {
1807         Ipv6Addr { inner: addr }
1808     }
1809 }
1810
1811 #[stable(feature = "i128", since = "1.26.0")]
1812 impl From<Ipv6Addr> for u128 {
1813     /// Convert an `Ipv6Addr` into a host byte order `u128`.
1814     ///
1815     /// # Examples
1816     ///
1817     /// ```
1818     /// use std::net::Ipv6Addr;
1819     ///
1820     /// let addr = Ipv6Addr::new(
1821     ///     0x1020, 0x3040, 0x5060, 0x7080,
1822     ///     0x90A0, 0xB0C0, 0xD0E0, 0xF00D,
1823     /// );
1824     /// assert_eq!(0x102030405060708090A0B0C0D0E0F00D_u128, u128::from(addr));
1825     /// ```
1826     #[inline]
1827     fn from(ip: Ipv6Addr) -> u128 {
1828         let ip = ip.octets();
1829         u128::from_be_bytes(ip)
1830     }
1831 }
1832 #[stable(feature = "i128", since = "1.26.0")]
1833 impl From<u128> for Ipv6Addr {
1834     /// Convert a host byte order `u128` into an `Ipv6Addr`.
1835     ///
1836     /// # Examples
1837     ///
1838     /// ```
1839     /// use std::net::Ipv6Addr;
1840     ///
1841     /// let addr = Ipv6Addr::from(0x102030405060708090A0B0C0D0E0F00D_u128);
1842     /// assert_eq!(
1843     ///     Ipv6Addr::new(
1844     ///         0x1020, 0x3040, 0x5060, 0x7080,
1845     ///         0x90A0, 0xB0C0, 0xD0E0, 0xF00D,
1846     ///     ),
1847     ///     addr);
1848     /// ```
1849     #[inline]
1850     fn from(ip: u128) -> Ipv6Addr {
1851         Ipv6Addr::from(ip.to_be_bytes())
1852     }
1853 }
1854
1855 #[stable(feature = "ipv6_from_octets", since = "1.9.0")]
1856 impl From<[u8; 16]> for Ipv6Addr {
1857     /// Creates an `Ipv6Addr` from a sixteen element byte array.
1858     ///
1859     /// # Examples
1860     ///
1861     /// ```
1862     /// use std::net::Ipv6Addr;
1863     ///
1864     /// let addr = Ipv6Addr::from([
1865     ///     25u8, 24u8, 23u8, 22u8, 21u8, 20u8, 19u8, 18u8,
1866     ///     17u8, 16u8, 15u8, 14u8, 13u8, 12u8, 11u8, 10u8,
1867     /// ]);
1868     /// assert_eq!(
1869     ///     Ipv6Addr::new(
1870     ///         0x1918, 0x1716,
1871     ///         0x1514, 0x1312,
1872     ///         0x1110, 0x0f0e,
1873     ///         0x0d0c, 0x0b0a
1874     ///     ),
1875     ///     addr
1876     /// );
1877     /// ```
1878     #[inline]
1879     fn from(octets: [u8; 16]) -> Ipv6Addr {
1880         let inner = c::in6_addr { s6_addr: octets };
1881         Ipv6Addr::from_inner(inner)
1882     }
1883 }
1884
1885 #[stable(feature = "ipv6_from_segments", since = "1.16.0")]
1886 impl From<[u16; 8]> for Ipv6Addr {
1887     /// Creates an `Ipv6Addr` from an eight element 16-bit array.
1888     ///
1889     /// # Examples
1890     ///
1891     /// ```
1892     /// use std::net::Ipv6Addr;
1893     ///
1894     /// let addr = Ipv6Addr::from([
1895     ///     525u16, 524u16, 523u16, 522u16,
1896     ///     521u16, 520u16, 519u16, 518u16,
1897     /// ]);
1898     /// assert_eq!(
1899     ///     Ipv6Addr::new(
1900     ///         0x20d, 0x20c,
1901     ///         0x20b, 0x20a,
1902     ///         0x209, 0x208,
1903     ///         0x207, 0x206
1904     ///     ),
1905     ///     addr
1906     /// );
1907     /// ```
1908     #[inline]
1909     fn from(segments: [u16; 8]) -> Ipv6Addr {
1910         let [a, b, c, d, e, f, g, h] = segments;
1911         Ipv6Addr::new(a, b, c, d, e, f, g, h)
1912     }
1913 }
1914
1915 #[stable(feature = "ip_from_slice", since = "1.17.0")]
1916 impl From<[u8; 16]> for IpAddr {
1917     /// Creates an `IpAddr::V6` from a sixteen element byte array.
1918     ///
1919     /// # Examples
1920     ///
1921     /// ```
1922     /// use std::net::{IpAddr, Ipv6Addr};
1923     ///
1924     /// let addr = IpAddr::from([
1925     ///     25u8, 24u8, 23u8, 22u8, 21u8, 20u8, 19u8, 18u8,
1926     ///     17u8, 16u8, 15u8, 14u8, 13u8, 12u8, 11u8, 10u8,
1927     /// ]);
1928     /// assert_eq!(
1929     ///     IpAddr::V6(Ipv6Addr::new(
1930     ///         0x1918, 0x1716,
1931     ///         0x1514, 0x1312,
1932     ///         0x1110, 0x0f0e,
1933     ///         0x0d0c, 0x0b0a
1934     ///     )),
1935     ///     addr
1936     /// );
1937     /// ```
1938     #[inline]
1939     fn from(octets: [u8; 16]) -> IpAddr {
1940         IpAddr::V6(Ipv6Addr::from(octets))
1941     }
1942 }
1943
1944 #[stable(feature = "ip_from_slice", since = "1.17.0")]
1945 impl From<[u16; 8]> for IpAddr {
1946     /// Creates an `IpAddr::V6` from an eight element 16-bit array.
1947     ///
1948     /// # Examples
1949     ///
1950     /// ```
1951     /// use std::net::{IpAddr, Ipv6Addr};
1952     ///
1953     /// let addr = IpAddr::from([
1954     ///     525u16, 524u16, 523u16, 522u16,
1955     ///     521u16, 520u16, 519u16, 518u16,
1956     /// ]);
1957     /// assert_eq!(
1958     ///     IpAddr::V6(Ipv6Addr::new(
1959     ///         0x20d, 0x20c,
1960     ///         0x20b, 0x20a,
1961     ///         0x209, 0x208,
1962     ///         0x207, 0x206
1963     ///     )),
1964     ///     addr
1965     /// );
1966     /// ```
1967     #[inline]
1968     fn from(segments: [u16; 8]) -> IpAddr {
1969         IpAddr::V6(Ipv6Addr::from(segments))
1970     }
1971 }