1use std::os::raw::{c_char, c_int, c_void};
2use std::{fmt, str};
3
4use crate::error::{Error, Result};
5use crate::panic;
6use crate::utils::{c_string_as_str_unchecked, hostname_as_str};
7
8#[derive(Clone, Copy, Debug)]
10pub struct NameInfoResult<'a> {
11 node: Option<&'a c_char>,
12 service: Option<&'a c_char>,
13}
14
15impl<'a> NameInfoResult<'a> {
16 fn new(node: Option<&'a c_char>, service: Option<&'a c_char>) -> Self {
17 NameInfoResult { node, service }
18 }
19
20 pub fn node(&self) -> Option<&str> {
22 self.node.map(|string| unsafe { hostname_as_str(string) })
23 }
24
25 pub fn service(&self) -> Option<&str> {
27 self.service
28 .map(|string| unsafe { c_string_as_str_unchecked(string) })
29 }
30}
31
32impl fmt::Display for NameInfoResult<'_> {
33 fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
34 let node = self.node().unwrap_or("<None>");
35 write!(fmt, "Node: {node}, ")?;
36 let service = self.service().unwrap_or("<None>");
37 write!(fmt, "Service: {service}")
38 }
39}
40
41unsafe impl Send for NameInfoResult<'_> {}
42unsafe impl Sync for NameInfoResult<'_> {}
43
44pub(crate) unsafe extern "C" fn get_name_info_callback<F>(
45 arg: *mut c_void,
46 status: c_int,
47 _timeouts: c_int,
48 node: *mut c_char,
49 service: *mut c_char,
50) where
51 F: FnOnce(Result<NameInfoResult>) + Send + 'static,
52{
53 let result = if status == c_ares_sys::ares_status_t::ARES_SUCCESS as i32 {
54 let name_info_result =
55 NameInfoResult::new(unsafe { node.as_ref() }, unsafe { service.as_ref() });
56 Ok(name_info_result)
57 } else {
58 Err(Error::from(status))
59 };
60 let handler = unsafe { Box::from_raw(arg.cast::<F>()) };
61 panic::catch(|| handler(result));
62}