1use std::fmt;
2use std::mem;
3use std::net::Ipv4Addr;
4use std::os::raw::{c_int, c_uchar, c_void};
5use std::ptr;
6use std::slice;
7
8use itertools::Itertools;
9
10use crate::error::{Error, Result};
11use crate::panic;
12use crate::types::MAX_ADDRTTLS;
13use crate::utils::ipv4_from_in_addr;
14
15#[derive(Clone, Copy)]
17pub struct AResults {
18 naddrttls: usize,
19 addrttls: [c_ares_sys::ares_addrttl; MAX_ADDRTTLS],
20}
21
22#[derive(Clone, Copy)]
24pub struct AResult<'a> {
25 addrttl: &'a c_ares_sys::ares_addrttl,
26}
27
28impl AResults {
29 pub fn parse_from(data: &[u8]) -> Result<AResults> {
31 let mut results: AResults = AResults {
32 naddrttls: MAX_ADDRTTLS,
33 addrttls: unsafe { mem::MaybeUninit::zeroed().assume_init() },
34 };
35 let parse_status = unsafe {
36 c_ares_sys::ares_parse_a_reply(
37 data.as_ptr(),
38 data.len() as c_int,
39 ptr::null_mut(),
40 results.addrttls.as_mut_ptr(),
41 ptr::from_mut(&mut results.naddrttls).cast(),
42 )
43 };
44 if parse_status == c_ares_sys::ares_status_t::ARES_SUCCESS as i32 {
45 Ok(results)
46 } else {
47 Err(Error::from(parse_status))
48 }
49 }
50
51 pub fn iter(&self) -> AResultsIter {
53 AResultsIter {
54 addrttls: self.addrttls[0..self.naddrttls].iter(),
55 }
56 }
57}
58
59impl fmt::Display for AResults {
60 fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
61 let results = self.iter().format("}, {");
62 write!(fmt, "[{{{results}}}]")
63 }
64}
65
66#[derive(Clone)]
68pub struct AResultsIter<'a> {
69 addrttls: slice::Iter<'a, c_ares_sys::ares_addrttl>,
70}
71
72impl<'a> Iterator for AResultsIter<'a> {
73 type Item = AResult<'a>;
74 fn next(&mut self) -> Option<Self::Item> {
75 self.addrttls.next().map(|addrttl| AResult { addrttl })
76 }
77}
78
79impl<'a> IntoIterator for &'a AResults {
80 type Item = AResult<'a>;
81 type IntoIter = AResultsIter<'a>;
82
83 fn into_iter(self) -> Self::IntoIter {
84 self.iter()
85 }
86}
87
88impl AResult<'_> {
89 pub fn ipv4(self) -> Ipv4Addr {
91 ipv4_from_in_addr(self.addrttl.ipaddr)
92 }
93
94 pub fn ttl(self) -> i32 {
96 #[allow(clippy::unnecessary_cast)]
97 let ttl = self.addrttl.ttl as i32;
98 ttl
99 }
100}
101
102impl fmt::Display for AResult<'_> {
103 fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
104 write!(fmt, "IPv4: {}, ", self.ipv4())?;
105 write!(fmt, "TTL: {}", self.ttl())
106 }
107}
108
109pub(crate) unsafe extern "C" fn query_a_callback<F>(
110 arg: *mut c_void,
111 status: c_int,
112 _timeouts: c_int,
113 abuf: *mut c_uchar,
114 alen: c_int,
115) where
116 F: FnOnce(Result<AResults>) + Send + 'static,
117{
118 ares_callback!(arg.cast::<F>(), status, abuf, alen, AResults::parse_from);
119}