gio/
inet_address.rs

1// Take a look at the license at the top of the repository in the LICENSE file.
2
3use std::net::IpAddr;
4
5use glib::{prelude::*, translate::*};
6
7use crate::{ffi, prelude::*, InetAddress, SocketFamily};
8
9#[derive(Debug)]
10pub enum InetAddressBytes<'a> {
11    V4(&'a [u8; 4]),
12    V6(&'a [u8; 16]),
13}
14
15impl InetAddressBytes<'_> {
16    #[inline]
17    fn deref(&self) -> &[u8] {
18        use self::InetAddressBytes::*;
19
20        match *self {
21            V4(bytes) => bytes,
22            V6(bytes) => bytes,
23        }
24    }
25}
26
27impl InetAddress {
28    /// Creates a new #GInetAddress from the given @family and @bytes.
29    /// @bytes should be 4 bytes for [`SocketFamily::Ipv4`][crate::SocketFamily::Ipv4] and 16 bytes for
30    /// [`SocketFamily::Ipv6`][crate::SocketFamily::Ipv6].
31    /// ## `bytes`
32    /// raw address data
33    /// ## `family`
34    /// the address family of @bytes
35    ///
36    /// # Returns
37    ///
38    /// a new #GInetAddress corresponding to @family and @bytes.
39    ///     Free the returned object with g_object_unref().
40    #[doc(alias = "g_inet_address_new_from_bytes")]
41    pub fn from_bytes(inet_address_bytes: InetAddressBytes) -> Self {
42        let bytes = inet_address_bytes.deref();
43
44        let family = match inet_address_bytes {
45            InetAddressBytes::V4(_) => SocketFamily::Ipv4,
46            InetAddressBytes::V6(_) => SocketFamily::Ipv6,
47        };
48        unsafe {
49            from_glib_full(ffi::g_inet_address_new_from_bytes(
50                bytes.to_glib_none().0,
51                family.into_glib(),
52            ))
53        }
54    }
55
56    /// Creates a new [`InetAddress`][crate::InetAddress] from the given @family, @bytes
57    /// and @scope_id.
58    ///
59    /// @bytes must be 4 bytes for [enum@Gio.SocketFamily.IPV4] and 16 bytes for
60    /// [enum@Gio.SocketFamily.IPV6].
61    /// ## `bytes`
62    /// raw address data
63    /// ## `family`
64    /// the address family of @bytes
65    /// ## `scope_id`
66    /// the scope-id of the address
67    ///
68    /// # Returns
69    ///
70    /// a new internet address corresponding to
71    ///   @family, @bytes and @scope_id
72    #[cfg(feature = "v2_86")]
73    #[cfg_attr(docsrs, doc(cfg(feature = "v2_86")))]
74    #[doc(alias = "g_inet_address_new_from_bytes_with_ipv6_info")]
75    #[doc(alias = "new_from_bytes_with_ipv6_info")]
76    pub fn from_bytes_with_ipv6_info(
77        inet_address_bytes: InetAddressBytes,
78        flowinfo: u32,
79        scope_id: u32,
80    ) -> InetAddress {
81        let bytes = inet_address_bytes.deref();
82
83        let family = match inet_address_bytes {
84            InetAddressBytes::V4(_) => SocketFamily::Ipv4,
85            InetAddressBytes::V6(_) => SocketFamily::Ipv6,
86        };
87        unsafe {
88            from_glib_full(ffi::g_inet_address_new_from_bytes_with_ipv6_info(
89                bytes.to_glib_none().0,
90                family.into_glib(),
91                flowinfo,
92                scope_id,
93            ))
94        }
95    }
96}
97
98pub trait InetAddressExtManual: IsA<InetAddress> + 'static {
99    // rustdoc-stripper-ignore-next
100    /// Returns `None` in case the address has a native size different than 4 and 16.
101    // rustdoc-stripper-ignore-next-stop
102    /// Gets the raw binary address data from @self.
103    ///
104    /// # Returns
105    ///
106    /// a pointer to an internal array of the bytes in @self,
107    /// which should not be modified, stored, or freed. The size of this
108    /// array can be gotten with g_inet_address_get_native_size().
109    #[doc(alias = "g_inet_address_to_bytes")]
110    #[inline]
111    fn to_bytes(&self) -> Option<InetAddressBytes<'_>> {
112        let size = self.native_size();
113        unsafe {
114            let bytes = ffi::g_inet_address_to_bytes(self.as_ref().to_glib_none().0);
115            if size == 4 {
116                Some(InetAddressBytes::V4(&*(bytes as *const [u8; 4])))
117            } else if size == 16 {
118                Some(InetAddressBytes::V6(&*(bytes as *const [u8; 16])))
119            } else {
120                None
121            }
122        }
123    }
124}
125
126impl<O: IsA<InetAddress>> InetAddressExtManual for O {}
127
128impl From<IpAddr> for InetAddress {
129    fn from(addr: IpAddr) -> Self {
130        match addr {
131            IpAddr::V4(v4) => Self::from_bytes(InetAddressBytes::V4(&v4.octets())),
132            IpAddr::V6(v6) => Self::from_bytes(InetAddressBytes::V6(&v6.octets())),
133        }
134    }
135}
136
137impl From<InetAddress> for IpAddr {
138    fn from(addr: InetAddress) -> Self {
139        match addr.to_bytes() {
140            Some(InetAddressBytes::V4(bytes)) => IpAddr::from(*bytes),
141            Some(InetAddressBytes::V6(bytes)) => IpAddr::from(*bytes),
142            None => panic!("Unknown IP kind"),
143        }
144    }
145}
146
147#[cfg(test)]
148mod tests {
149    use std::net::IpAddr;
150
151    use crate::InetAddress;
152
153    #[test]
154    fn test_ipv6_to_rust() {
155        let rust_addr = "2606:50c0:8000::153".parse::<IpAddr>().unwrap();
156        assert!(rust_addr.is_ipv6());
157        let gio_addr = InetAddress::from(rust_addr);
158        assert_eq!(rust_addr, IpAddr::from(gio_addr));
159    }
160
161    #[test]
162    fn test_ipv4_to_rust() {
163        let rust_addr = "185.199.108.153".parse::<IpAddr>().unwrap();
164        assert!(rust_addr.is_ipv4());
165        let gio_addr = InetAddress::from(rust_addr);
166        assert_eq!(rust_addr, IpAddr::from(gio_addr));
167    }
168}