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")]
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 #[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 #[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}