1use crate::zerocopy_type;
11
12zerocopy_type!(
13 pub struct Ipv4Addr {
15 inner: [u8; 4],
16 }
17);
18
19impl Ipv4Addr {
20 pub const UNSPECIFIED: Self = Self { inner: [0; 4] };
22
23 #[inline]
25 pub const fn octets(&self) -> [u8; 4] {
26 self.inner
27 }
28
29 #[inline]
31 pub const fn from_octets(bytes: [u8; 4]) -> Self {
32 Self { inner: bytes }
33 }
34
35 #[inline]
44 const fn into_core(self) -> core::net::Ipv4Addr {
45 core::net::Ipv4Addr::new(
46 self.inner[0],
47 self.inner[1],
48 self.inner[2],
49 self.inner[3],
50 )
51 }
52
53 #[inline]
55 pub const fn is_multicast(&self) -> bool {
56 self.into_core().is_multicast()
57 }
58
59 #[inline]
61 pub const fn is_broadcast(&self) -> bool {
62 self.into_core().is_broadcast()
63 }
64
65 #[inline]
67 pub const fn is_private(&self) -> bool {
68 self.into_core().is_private()
69 }
70
71 #[inline]
73 pub const fn is_loopback(&self) -> bool {
74 self.into_core().is_loopback()
75 }
76
77 #[inline]
79 pub const fn is_unicast(&self) -> bool {
80 !self.is_multicast() && !self.is_broadcast()
81 }
82
83 #[inline]
85 pub const fn is_link_local(&self) -> bool {
86 self.into_core().is_link_local()
87 }
88
89 #[inline]
91 pub const fn is_global(&self) -> bool {
92 !self.is_multicast()
93 && !self.is_private()
94 && !self.is_loopback()
95 && !self.is_link_local()
96 && !self.is_broadcast()
97 }
98
99 #[inline]
112 pub const fn is_documentation(&self) -> bool {
113 matches!(
114 self.octets(),
115 [192, 0, 2, _]
116 | [198, 51, 100, _]
117 | [203, 0, 113, _]
118 | [233, 252, 0, _]
119 )
120 }
121
122 #[inline]
127 pub const fn is_reserved(&self) -> bool {
128 self.octets()[0] & 240 == 240 && !self.is_broadcast()
129 }
130}
131
132impl From<core::net::Ipv4Addr> for Ipv4Addr {
133 #[inline]
134 fn from(ip4: core::net::Ipv4Addr) -> Self {
135 Self { inner: ip4.octets() }
136 }
137}
138
139impl From<Ipv4Addr> for core::net::Ipv4Addr {
140 #[inline]
141 fn from(ip4: Ipv4Addr) -> Self {
142 Self::from(ip4.inner)
143 }
144}
145
146zerocopy_type!(
147 pub struct Ipv6Addr {
149 inner: [u8; 16],
150 }
151);
152
153impl Ipv6Addr {
154 pub const UNSPECIFIED: Self = Self { inner: [0; 16] };
156
157 pub const LOCALHOST: Self =
159 Self { inner: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1] };
160
161 #[inline]
163 pub const fn octets(&self) -> [u8; 16] {
164 self.inner
165 }
166
167 #[inline]
169 pub const fn from_octets(bytes: [u8; 16]) -> Self {
170 Self { inner: bytes }
171 }
172
173 #[inline]
175 pub const fn from_segments(words: [u16; 8]) -> Self {
176 let w0 = words[0].to_be_bytes();
177 let w1 = words[1].to_be_bytes();
178 let w2 = words[2].to_be_bytes();
179 let w3 = words[3].to_be_bytes();
180 let w4 = words[4].to_be_bytes();
181 let w5 = words[5].to_be_bytes();
182 let w6 = words[6].to_be_bytes();
183 let w7 = words[7].to_be_bytes();
184 Self {
185 inner: [
186 w0[0], w0[1], w1[0], w1[1], w2[0], w2[1], w3[0], w3[1], w4[0],
187 w4[1], w5[0], w5[1], w6[0], w6[1], w7[0], w7[1],
188 ],
189 }
190 }
191
192 #[inline]
196 pub const fn segments(&self) -> [u16; 8] {
197 let [a, b, c, d, e, f, g, h] = unsafe {
200 core::mem::transmute::<[u8; 16], [u16; 8]>(self.octets())
201 };
202 [
204 u16::from_be(a),
205 u16::from_be(b),
206 u16::from_be(c),
207 u16::from_be(d),
208 u16::from_be(e),
209 u16::from_be(f),
210 u16::from_be(g),
211 u16::from_be(h),
212 ]
213 }
214
215 #[inline]
223 const fn into_core(self) -> core::net::Ipv6Addr {
224 let segments = self.segments();
225 core::net::Ipv6Addr::new(
226 segments[0],
227 segments[1],
228 segments[2],
229 segments[3],
230 segments[4],
231 segments[5],
232 segments[6],
233 segments[7],
234 )
235 }
236
237 #[inline]
239 pub const fn is_multicast(&self) -> bool {
240 self.into_core().is_multicast()
241 }
242
243 #[inline]
245 pub const fn is_loopback(&self) -> bool {
246 self.into_core().is_loopback()
247 }
248
249 #[inline]
251 pub const fn is_unicast(&self) -> bool {
252 !self.is_multicast()
253 }
254
255 #[inline]
260 pub const fn is_unicast_link_local(&self) -> bool {
261 (self.segments()[0] & 0xffc0) == 0xfe80
262 }
263
264 #[inline]
269 pub const fn is_unique_local(&self) -> bool {
270 (self.segments()[0] & 0xfe00) == 0xfc00
271 }
272
273 #[inline]
275 pub const fn is_unicast_global(&self) -> bool {
276 !self.is_multicast()
277 && !self.is_unicast_link_local()
278 && !self.is_unique_local()
279 }
280
281 #[inline]
290 pub const fn is_documentation(&self) -> bool {
291 let segments = self.segments();
292 (segments[0] == 0x2001) && (segments[1] == 0xdb8)
293 }
294}
295
296impl From<core::net::Ipv6Addr> for Ipv6Addr {
297 #[inline]
298 fn from(ip6: core::net::Ipv6Addr) -> Self {
299 Self { inner: ip6.octets() }
300 }
301}
302
303impl From<Ipv6Addr> for core::net::Ipv6Addr {
304 #[inline]
305 fn from(ip6: Ipv6Addr) -> Self {
306 Self::from(ip6.inner)
307 }
308}
309
310#[cfg(test)]
311mod test {
312 use super::*;
313
314 #[test]
315 fn ipv4() {
316 let addr = Ipv4Addr::from_octets([192, 168, 1, 1]);
317 assert!(addr.is_private());
318 assert!(!addr.is_global());
319 assert!(!addr.is_multicast());
320 assert!(!addr.is_broadcast());
321 assert!(!addr.is_loopback());
322 assert!(addr.is_unicast());
323 assert!(!addr.is_link_local());
324 assert!(!addr.is_documentation());
325 assert!(!addr.is_reserved());
326 }
327
328 #[test]
329 fn ipv4_broadcast() {
330 let addr = Ipv4Addr::from_octets([255, 255, 255, 255]);
331 assert!(!addr.is_private());
332 assert!(!addr.is_global());
333 assert!(!addr.is_multicast());
334 assert!(addr.is_broadcast());
335 assert!(!addr.is_unicast());
336 assert!(!addr.is_loopback());
337 assert!(!addr.is_link_local());
338 assert!(!addr.is_documentation());
339 assert!(!addr.is_reserved());
340 }
341
342 #[test]
343 fn ipv4_loopback() {
344 let addr = Ipv4Addr::from_octets([127, 0, 0, 1]);
345 assert!(!addr.is_private());
346 assert!(!addr.is_global());
347 assert!(!addr.is_multicast());
348 assert!(!addr.is_broadcast());
349 assert!(addr.is_loopback());
350 assert!(addr.is_unicast());
351 assert!(!addr.is_link_local());
352 assert!(!addr.is_documentation());
353 assert!(!addr.is_reserved());
354 }
355
356 #[test]
357 fn ipv6() {
358 let addr = Ipv6Addr::from_octets([
359 0x20, 0x01, 0x0d, 0xb8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1,
360 ]);
361 assert!(!addr.is_multicast());
362 assert!(addr.is_unicast());
363 assert!(!addr.is_unicast_link_local());
364 assert!(!addr.is_unique_local());
365 assert!(addr.is_documentation());
366 assert!(addr.is_unicast_global());
367 }
368
369 #[test]
370 fn ipv6_link_local() {
371 let addr = Ipv6Addr::from_octets([
372 0xfe, 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xde, 0xad, 0xbe, 0xef,
373 ]);
374 assert!(!addr.is_multicast());
375 assert!(addr.is_unicast());
376 assert!(addr.is_unicast_link_local());
377 assert!(!addr.is_unique_local());
378 assert!(!addr.is_documentation());
379 assert!(!addr.is_unicast_global());
380 }
381}