1use 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 #[doc(alias = "g_inet_address_new_from_bytes")]
29 pub fn from_bytes(inet_address_bytes: InetAddressBytes) -> Self {
30 let bytes = inet_address_bytes.deref();
31
32 let family = match inet_address_bytes {
33 InetAddressBytes::V4(_) => SocketFamily::Ipv4,
34 InetAddressBytes::V6(_) => SocketFamily::Ipv6,
35 };
36 unsafe {
37 from_glib_full(ffi::g_inet_address_new_from_bytes(
38 bytes.to_glib_none().0,
39 family.into_glib(),
40 ))
41 }
42 }
43
44 #[cfg(feature = "v2_86")]
45 #[cfg_attr(docsrs, doc(cfg(feature = "v2_86")))]
46 #[doc(alias = "g_inet_address_new_from_bytes_with_ipv6_info")]
47 #[doc(alias = "new_from_bytes_with_ipv6_info")]
48 pub fn from_bytes_with_ipv6_info(
49 inet_address_bytes: InetAddressBytes,
50 flowinfo: u32,
51 scope_id: u32,
52 ) -> InetAddress {
53 let bytes = inet_address_bytes.deref();
54
55 let family = match inet_address_bytes {
56 InetAddressBytes::V4(_) => SocketFamily::Ipv4,
57 InetAddressBytes::V6(_) => SocketFamily::Ipv6,
58 };
59 unsafe {
60 from_glib_full(ffi::g_inet_address_new_from_bytes_with_ipv6_info(
61 bytes.to_glib_none().0,
62 family.into_glib(),
63 flowinfo,
64 scope_id,
65 ))
66 }
67 }
68}
69
70pub trait InetAddressExtManual: IsA<InetAddress> + 'static {
71 #[doc(alias = "g_inet_address_to_bytes")]
74 #[inline]
75 fn to_bytes(&self) -> Option<InetAddressBytes<'_>> {
76 let size = self.native_size();
77 unsafe {
78 let bytes = ffi::g_inet_address_to_bytes(self.as_ref().to_glib_none().0);
79 if size == 4 {
80 Some(InetAddressBytes::V4(&*(bytes as *const [u8; 4])))
81 } else if size == 16 {
82 Some(InetAddressBytes::V6(&*(bytes as *const [u8; 16])))
83 } else {
84 None
85 }
86 }
87 }
88}
89
90impl<O: IsA<InetAddress>> InetAddressExtManual for O {}
91
92impl From<IpAddr> for InetAddress {
93 fn from(addr: IpAddr) -> Self {
94 match addr {
95 IpAddr::V4(v4) => Self::from_bytes(InetAddressBytes::V4(&v4.octets())),
96 IpAddr::V6(v6) => Self::from_bytes(InetAddressBytes::V6(&v6.octets())),
97 }
98 }
99}
100
101impl From<InetAddress> for IpAddr {
102 fn from(addr: InetAddress) -> Self {
103 match addr.to_bytes() {
104 Some(InetAddressBytes::V4(bytes)) => IpAddr::from(*bytes),
105 Some(InetAddressBytes::V6(bytes)) => IpAddr::from(*bytes),
106 None => panic!("Unknown IP kind"),
107 }
108 }
109}
110
111#[cfg(test)]
112mod tests {
113 use std::net::IpAddr;
114
115 use crate::InetAddress;
116
117 #[test]
118 fn test_ipv6_to_rust() {
119 let rust_addr = "2606:50c0:8000::153".parse::<IpAddr>().unwrap();
120 assert!(rust_addr.is_ipv6());
121 let gio_addr = InetAddress::from(rust_addr);
122 assert_eq!(rust_addr, IpAddr::from(gio_addr));
123 }
124
125 #[test]
126 fn test_ipv4_to_rust() {
127 let rust_addr = "185.199.108.153".parse::<IpAddr>().unwrap();
128 assert!(rust_addr.is_ipv4());
129 let gio_addr = InetAddress::from(rust_addr);
130 assert_eq!(rust_addr, IpAddr::from(gio_addr));
131 }
132}