no_std_net/
ip.rs

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