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