c_ares/
nameinfo.rs

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/// The result of a successful name-info lookup.
9#[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    /// Returns the node from this `NameInfoResult`.
21    pub fn node(&self) -> Option<&str> {
22        self.node.map(|string| unsafe { hostname_as_str(string) })
23    }
24
25    /// Returns the service from this `NameInfoResult`.
26    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}