1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
use std::fmt;
use std::marker::PhantomData;
use std::os::raw::{c_int, c_uchar, c_void};
use std::ptr;
use std::slice;
use std::str;
use c_ares_sys;
use itertools::Itertools;
use error::{Error, Result};
use panic;
#[derive(Debug)]
pub struct TXTResults {
txt_reply: *mut c_ares_sys::ares_txt_ext,
phantom: PhantomData<c_ares_sys::ares_txt_ext>,
}
#[derive(Clone, Copy)]
pub struct TXTResult<'a> {
txt_reply: &'a c_ares_sys::ares_txt_ext,
}
impl TXTResults {
pub fn parse_from(data: &[u8]) -> Result<TXTResults> {
let mut txt_reply: *mut c_ares_sys::ares_txt_ext = ptr::null_mut();
let parse_status = unsafe {
c_ares_sys::ares_parse_txt_reply_ext(data.as_ptr(), data.len() as c_int, &mut txt_reply)
};
if parse_status == c_ares_sys::ARES_SUCCESS {
let result = TXTResults::new(txt_reply);
Ok(result)
} else {
Err(Error::from(parse_status))
}
}
fn new(txt_reply: *mut c_ares_sys::ares_txt_ext) -> TXTResults {
TXTResults {
txt_reply,
phantom: PhantomData,
}
}
pub fn iter(&self) -> TXTResultsIter {
TXTResultsIter {
next: unsafe { self.txt_reply.as_ref() },
}
}
}
impl fmt::Display for TXTResults {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
let results = self.iter().format("}, {");
write!(fmt, "[{{{}}}]", results)
}
}
#[derive(Clone, Copy)]
pub struct TXTResultsIter<'a> {
next: Option<&'a c_ares_sys::ares_txt_ext>,
}
impl<'a> Iterator for TXTResultsIter<'a> {
type Item = TXTResult<'a>;
fn next(&mut self) -> Option<Self::Item> {
let opt_reply = self.next;
self.next = opt_reply.and_then(|reply| unsafe { reply.next.as_ref() });
opt_reply.map(|reply| TXTResult { txt_reply: reply })
}
}
impl<'a> IntoIterator for &'a TXTResults {
type Item = TXTResult<'a>;
type IntoIter = TXTResultsIter<'a>;
fn into_iter(self) -> Self::IntoIter {
self.iter()
}
}
impl Drop for TXTResults {
fn drop(&mut self) {
unsafe {
c_ares_sys::ares_free_data(self.txt_reply as *mut c_void);
}
}
}
unsafe impl<'a> Send for TXTResult<'a> {}
unsafe impl<'a> Sync for TXTResult<'a> {}
unsafe impl Send for TXTResults {}
unsafe impl Sync for TXTResults {}
unsafe impl<'a> Send for TXTResultsIter<'a> {}
unsafe impl<'a> Sync for TXTResultsIter<'a> {}
impl<'a> TXTResult<'a> {
pub fn record_start(self) -> bool {
self.txt_reply.record_start != 0
}
pub fn text(self) -> &'a [u8] {
unsafe { slice::from_raw_parts(self.txt_reply.txt, self.txt_reply.length) }
}
}
impl<'a> fmt::Display for TXTResult<'a> {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
let text = str::from_utf8(self.text()).unwrap_or("<binary>");
write!(fmt, "Record start: {}, Text: {}", self.record_start(), text)
}
}
pub unsafe extern "C" fn query_txt_callback<F>(
arg: *mut c_void,
status: c_int,
_timeouts: c_int,
abuf: *mut c_uchar,
alen: c_int,
) where
F: FnOnce(Result<TXTResults>) + Send + 'static,
{
ares_callback!(arg as *mut F, status, abuf, alen, TXTResults::parse_from);
}