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}