rkyv/
net.rs

1//! Archived versions of network types.
2
3use core::net::{
4    IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr, SocketAddrV4, SocketAddrV6,
5};
6
7use munge::munge;
8
9use crate::{
10    primitive::{ArchivedU16, ArchivedU32},
11    Archive, Place, Portable,
12};
13
14/// An archived [`Ipv4Addr`].
15#[derive(Portable)]
16#[rkyv(crate)]
17#[cfg_attr(feature = "bytecheck", derive(bytecheck::CheckBytes))]
18#[derive(Clone, Copy, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd)]
19#[repr(transparent)]
20pub struct ArchivedIpv4Addr {
21    octets: [u8; 4],
22}
23
24impl ArchivedIpv4Addr {
25    /// Returns the four eight-bit integers that make up this address.
26    #[inline]
27    pub const fn octets(&self) -> [u8; 4] {
28        self.octets
29    }
30
31    /// Returns an [`Ipv4Addr`] with the same value.
32    #[inline]
33    pub const fn as_ipv4(&self) -> Ipv4Addr {
34        let octets = self.octets();
35        Ipv4Addr::new(octets[0], octets[1], octets[2], octets[3])
36    }
37
38    /// Returns `true` if this is a broadcast address (255.255.255.255).
39    ///
40    /// See [`Ipv4Addr::is_broadcast`] for more details.
41    #[inline]
42    pub const fn is_broadcast(&self) -> bool {
43        self.as_ipv4().is_broadcast()
44    }
45
46    /// Returns `true` if this address is in a range designated for
47    /// documentation.
48    ///
49    /// See [`Ipv4Addr::is_documentation`] for more details.
50    #[inline]
51    pub const fn is_documentation(&self) -> bool {
52        self.as_ipv4().is_documentation()
53    }
54
55    /// Returns `true` if the address is link-local (169.254.0.0/16).
56    ///
57    /// See [`Ipv4Addr::is_link_local`] for more details.
58    #[inline]
59    pub const fn is_link_local(&self) -> bool {
60        self.as_ipv4().is_link_local()
61    }
62
63    /// Returns `true` if this is a loopback address (127.0.0.0/8).
64    ///
65    /// See [`Ipv4Addr::is_loopback`] for more details.
66    #[inline]
67    pub const fn is_loopback(&self) -> bool {
68        self.as_ipv4().is_loopback()
69    }
70
71    /// Returns `true` if this is a multicast address (224.0.0.0/4).
72    ///
73    /// See [`Ipv4Addr::is_multicast`] for more details.
74    #[inline]
75    pub const fn is_multicast(&self) -> bool {
76        self.as_ipv4().is_multicast()
77    }
78
79    /// Returns `true` if this is a private address.
80    ///
81    /// See [`Ipv4Addr::is_private`] for more details.
82    #[inline]
83    pub const fn is_private(&self) -> bool {
84        self.as_ipv4().is_private()
85    }
86
87    /// Returns `true` for the special 'unspecified' address (0.0.0.0).
88    ///
89    /// See [`Ipv4Addr::is_unspecified`] for more details.
90    #[inline]
91    pub const fn is_unspecified(&self) -> bool {
92        self.as_ipv4().is_unspecified()
93    }
94
95    /// Converts this address to an IPv4-compatible
96    /// [`IPv6` address](std::net::Ipv6Addr).
97    ///
98    /// See [`Ipv4Addr::to_ipv6_compatible`] for more
99    /// details.
100    #[inline]
101    #[allow(clippy::wrong_self_convention)]
102    pub const fn to_ipv6_compatible(&self) -> Ipv6Addr {
103        self.as_ipv4().to_ipv6_compatible()
104    }
105
106    /// Converts this address to an IPv4-mapped
107    /// [`IPv6` address](std::net::Ipv6Addr).
108    ///
109    /// See [`Ipv4Addr::to_ipv6_mapped`] for more details.
110    #[inline]
111    #[allow(clippy::wrong_self_convention)]
112    pub const fn to_ipv6_mapped(&self) -> Ipv6Addr {
113        self.as_ipv4().to_ipv6_mapped()
114    }
115
116    /// Emplaces an `ArchivedIpv4Addr` with the given octets into a place.
117    #[inline]
118    pub fn emplace(octets: [u8; 4], out: Place<Self>) {
119        unsafe {
120            out.cast_unchecked::<[u8; 4]>().write(octets);
121        }
122    }
123}
124
125/// An archived [`Ipv6Addr`].
126#[derive(Portable)]
127#[rkyv(crate)]
128#[cfg_attr(feature = "bytecheck", derive(bytecheck::CheckBytes))]
129#[derive(Clone, Copy, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd)]
130#[repr(transparent)]
131pub struct ArchivedIpv6Addr {
132    octets: [u8; 16],
133}
134
135impl ArchivedIpv6Addr {
136    /// Returns the eight 16-bit segments that make up this address.
137    #[inline]
138    pub const fn segments(&self) -> [u16; 8] {
139        [
140            u16::from_be_bytes([self.octets[0], self.octets[1]]),
141            u16::from_be_bytes([self.octets[2], self.octets[3]]),
142            u16::from_be_bytes([self.octets[4], self.octets[5]]),
143            u16::from_be_bytes([self.octets[6], self.octets[7]]),
144            u16::from_be_bytes([self.octets[8], self.octets[9]]),
145            u16::from_be_bytes([self.octets[10], self.octets[11]]),
146            u16::from_be_bytes([self.octets[12], self.octets[13]]),
147            u16::from_be_bytes([self.octets[14], self.octets[15]]),
148        ]
149    }
150
151    /// Returns an [`Ipv6Addr`] with the same value.
152    #[inline]
153    pub const fn as_ipv6(&self) -> Ipv6Addr {
154        let segments = self.segments();
155        Ipv6Addr::new(
156            segments[0],
157            segments[1],
158            segments[2],
159            segments[3],
160            segments[4],
161            segments[5],
162            segments[6],
163            segments[7],
164        )
165    }
166
167    /// Returns `true` if this is a loopback address (::1).
168    ///
169    /// See [`Ipv6Addr::is_loopback()`](std::net::Ipv6Addr::is_loopback()) for
170    /// more details.
171    #[inline]
172    pub const fn is_loopback(&self) -> bool {
173        self.as_ipv6().is_loopback()
174    }
175
176    /// Returns `true` if this is a multicast address (ff00::/8).
177    ///
178    /// See [`Ipv6Addr::is_multicast()`](std::net::Ipv6Addr::is_multicast()) for
179    /// more details.
180    #[inline]
181    pub const fn is_multicast(&self) -> bool {
182        self.as_ipv6().is_multicast()
183    }
184
185    /// Returns `true` for the special 'unspecified' address (::).
186    ///
187    /// See [`Ipv6Addr::is_unspecified()`](std::net::Ipv6Addr::is_unspecified())
188    /// for more details.
189    #[inline]
190    pub const fn is_unspecified(&self) -> bool {
191        self.as_ipv6().is_unspecified()
192    }
193
194    /// Returns the sixteen eight-bit integers the IPv6 address consists of.
195    #[inline]
196    pub const fn octets(&self) -> [u8; 16] {
197        self.as_ipv6().octets()
198    }
199
200    /// Converts this address to an [`IPv4` address](std::net::Ipv4Addr).
201    /// Returns [`None`] if this address is neither IPv4-compatible or
202    /// IPv4-mapped.
203    #[inline]
204    #[allow(clippy::wrong_self_convention)]
205    pub const fn to_ipv4(&self) -> Option<Ipv4Addr> {
206        self.as_ipv6().to_ipv4()
207    }
208
209    /// Emplaces an `ArchivedIpv6Addr` with the given octets into a place.
210    #[inline]
211    pub fn emplace(octets: [u8; 16], out: Place<Self>) {
212        unsafe {
213            out.cast_unchecked::<[u8; 16]>().write(octets);
214        }
215    }
216}
217
218/// An archived [`IpAddr`].
219#[derive(Portable)]
220#[rkyv(crate)]
221#[cfg_attr(feature = "bytecheck", derive(bytecheck::CheckBytes))]
222#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
223#[repr(u8)]
224pub enum ArchivedIpAddr {
225    /// An IPv4 address.
226    V4(ArchivedIpv4Addr),
227    /// An IPv6 address.
228    V6(ArchivedIpv6Addr),
229}
230
231impl ArchivedIpAddr {
232    /// Returns `true` if this address is an [`IPv4`
233    /// address](std::net::IpAddr::V4), and `false` otherwise.
234    #[inline]
235    pub const fn is_ipv4(&self) -> bool {
236        matches!(self, ArchivedIpAddr::V4(_))
237    }
238
239    /// Returns `true` if this address is an [`IPv6`
240    /// address](std::net::IpAddr::V6), and `false` otherwise.
241    #[inline]
242    pub const fn is_ipv6(&self) -> bool {
243        matches!(self, ArchivedIpAddr::V6(_))
244    }
245
246    /// Returns an [`IpAddr`] with the same value.
247    #[inline]
248    pub const fn as_ipaddr(&self) -> IpAddr {
249        match self {
250            ArchivedIpAddr::V4(ipv4) => IpAddr::V4(ipv4.as_ipv4()),
251            ArchivedIpAddr::V6(ipv6) => IpAddr::V6(ipv6.as_ipv6()),
252        }
253    }
254
255    /// Returns `true` if this is a loopback address.
256    ///
257    /// See [`IpAddr::is_loopback()`](std::net::IpAddr::is_loopback()) for more
258    /// details.
259    #[inline]
260    pub const fn is_loopback(&self) -> bool {
261        match self {
262            ArchivedIpAddr::V4(ip) => ip.is_loopback(),
263            ArchivedIpAddr::V6(ip) => ip.is_loopback(),
264        }
265    }
266
267    /// Returns `true` if this is a multicast address.
268    ///
269    /// See [`IpAddr::is_multicast()`](std::net::IpAddr::is_multicast()) for
270    /// more details.
271    #[inline]
272    pub const fn is_multicast(&self) -> bool {
273        match self {
274            ArchivedIpAddr::V4(ip) => ip.is_multicast(),
275            ArchivedIpAddr::V6(ip) => ip.is_multicast(),
276        }
277    }
278
279    /// Returns `true` for the special 'unspecified' address.
280    ///
281    /// See [`IpAddr::is_unspecified()`](std::net::IpAddr::is_unspecified()) for
282    /// more details.
283    #[inline]
284    pub const fn is_unspecified(&self) -> bool {
285        match self {
286            ArchivedIpAddr::V4(ip) => ip.is_unspecified(),
287            ArchivedIpAddr::V6(ip) => ip.is_unspecified(),
288        }
289    }
290}
291
292/// An archived [`SocketAddrV4`].
293#[derive(
294    Clone, Copy, Debug, Default, Eq, Hash, Ord, PartialEq, Portable, PartialOrd,
295)]
296#[cfg_attr(feature = "bytecheck", derive(bytecheck::CheckBytes))]
297#[rkyv(crate)]
298#[repr(C)]
299pub struct ArchivedSocketAddrV4 {
300    ip: ArchivedIpv4Addr,
301    port: ArchivedU16,
302}
303
304impl ArchivedSocketAddrV4 {
305    /// Returns the IP address associated with this socket address.
306    #[inline]
307    pub const fn ip(&self) -> &ArchivedIpv4Addr {
308        &self.ip
309    }
310
311    /// Returns the port number associated with this socket address.
312    #[inline]
313    pub const fn port(&self) -> u16 {
314        self.port.to_native()
315    }
316
317    /// Returns a [`SocketAddrV4`] with the same value.
318    #[inline]
319    pub fn as_socket_addr_v4(&self) -> SocketAddrV4 {
320        SocketAddrV4::new(self.ip().as_ipv4(), self.port())
321    }
322
323    /// Emplaces an `ArchivedSocketAddrV4` of the given `value` into a place.
324    #[inline]
325    pub fn emplace(value: &SocketAddrV4, out: Place<Self>) {
326        munge!(let ArchivedSocketAddrV4 { ip, port } = out);
327        value.ip().resolve((), ip);
328        value.port().resolve((), port);
329    }
330}
331
332/// An archived [`SocketAddrV6`].
333#[derive(
334    Clone, Copy, Debug, Default, Eq, Hash, Ord, PartialEq, Portable, PartialOrd,
335)]
336#[cfg_attr(feature = "bytecheck", derive(bytecheck::CheckBytes))]
337#[rkyv(crate)]
338#[repr(C)]
339pub struct ArchivedSocketAddrV6 {
340    ip: ArchivedIpv6Addr,
341    port: ArchivedU16,
342    flowinfo: ArchivedU32,
343    scope_id: ArchivedU32,
344}
345
346impl ArchivedSocketAddrV6 {
347    /// Returns the flow information associated with this address.
348    ///
349    /// See [`SocketAddrV6::flowinfo()`](std::net::SocketAddrV6::flowinfo()) for
350    /// more details.
351    #[inline]
352    pub const fn flowinfo(&self) -> u32 {
353        self.flowinfo.to_native()
354    }
355
356    /// Returns the IP address associated with this socket address.
357    #[inline]
358    pub const fn ip(&self) -> &ArchivedIpv6Addr {
359        &self.ip
360    }
361
362    /// Returns the port number associated with this socket address.
363    #[inline]
364    pub const fn port(&self) -> u16 {
365        self.port.to_native()
366    }
367
368    /// Returns the scope ID associated with this address.
369    ///
370    /// See [`SocketAddrV6::scope_id()`](std::net::SocketAddrV6::scope_id()) for
371    /// more details.
372    #[inline]
373    pub const fn scope_id(&self) -> u32 {
374        self.scope_id.to_native()
375    }
376
377    /// Returns a [`SocketAddrV6`] with the same value.
378    #[inline]
379    pub fn as_socket_addr_v6(&self) -> SocketAddrV6 {
380        SocketAddrV6::new(
381            self.ip().as_ipv6(),
382            self.port(),
383            self.flowinfo(),
384            self.scope_id(),
385        )
386    }
387
388    /// Emplaces an `ArchivedSocketAddrV6` of the given `value` into a place.
389    #[inline]
390    pub fn emplace(value: &SocketAddrV6, out: Place<Self>) {
391        munge!(let ArchivedSocketAddrV6 { ip, port, flowinfo, scope_id } = out);
392        value.ip().resolve((), ip);
393        value.port().resolve((), port);
394        value.flowinfo().resolve((), flowinfo);
395        value.scope_id().resolve((), scope_id);
396    }
397}
398
399/// An archived [`SocketAddr`].
400#[derive(Portable)]
401#[rkyv(crate)]
402#[cfg_attr(feature = "bytecheck", derive(bytecheck::CheckBytes))]
403#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
404#[repr(u8)]
405pub enum ArchivedSocketAddr {
406    /// An IPv4 socket address.
407    V4(ArchivedSocketAddrV4),
408    /// An IPv6 socket address.
409    V6(ArchivedSocketAddrV6),
410}
411
412impl ArchivedSocketAddr {
413    /// Returns the port number associated with this socket address.
414    #[inline]
415    pub fn port(&self) -> u16 {
416        match self {
417            ArchivedSocketAddr::V4(addr) => addr.port(),
418            ArchivedSocketAddr::V6(addr) => addr.port(),
419        }
420    }
421
422    /// Returns `true` if the [IP address](std::net::IpAddr) in this
423    /// `ArchivedSocketAddr` is an [`IPv4` address](std::net::IpAddr::V4),
424    /// and `false` otherwise.
425    #[inline]
426    pub fn is_ipv4(&self) -> bool {
427        matches!(self, ArchivedSocketAddr::V4(_))
428    }
429
430    /// Returns `true` if the [IP address](std::net::IpAddr) in this
431    /// `ArchivedSocketAddr` is an [`IPv6` address](std::net::IpAddr::V6),
432    /// and `false` otherwise.
433    #[inline]
434    pub fn is_ipv6(&self) -> bool {
435        matches!(self, ArchivedSocketAddr::V6(_))
436    }
437
438    /// Returns a [`SocketAddr`] with the same value.
439    #[inline]
440    pub fn as_socket_addr(&self) -> SocketAddr {
441        match self {
442            ArchivedSocketAddr::V4(addr) => {
443                SocketAddr::V4(addr.as_socket_addr_v4())
444            }
445            ArchivedSocketAddr::V6(addr) => {
446                SocketAddr::V6(addr.as_socket_addr_v6())
447            }
448        }
449    }
450
451    /// Returns the IP address associated with this socket address.
452    #[inline]
453    pub fn ip(&self) -> IpAddr {
454        match self {
455            ArchivedSocketAddr::V4(addr) => IpAddr::V4(addr.ip().as_ipv4()),
456            ArchivedSocketAddr::V6(addr) => IpAddr::V6(addr.ip().as_ipv6()),
457        }
458    }
459}