1use core::ffi::c_char;
2use std::fmt;
3use std::ops::Deref;
4use std::str;
5
6use crate::utils::c_string_as_str_unchecked;
7
8pub struct AresString {
10 ares_string: *mut c_char,
11}
12
13impl AresString {
14 #[allow(dead_code)]
15 pub(crate) fn new(ares_string: *mut c_char) -> Self {
16 AresString { ares_string }
17 }
18}
19
20impl Deref for AresString {
21 type Target = str;
22 fn deref(&self) -> &Self::Target {
23 unsafe { c_string_as_str_unchecked(self.ares_string) }
24 }
25}
26
27impl Drop for AresString {
28 fn drop(&mut self) {
29 unsafe { c_ares_sys::ares_free_string(self.ares_string.cast()) }
30 }
31}
32
33unsafe impl Send for AresString {}
34unsafe impl Sync for AresString {}
35
36impl fmt::Debug for AresString {
37 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
38 fmt::Debug::fmt(&**self, f)
39 }
40}
41
42impl fmt::Display for AresString {
43 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
44 fmt::Display::fmt(&**self, f)
45 }
46}
47
48impl AsRef<str> for AresString {
49 fn as_ref(&self) -> &str {
50 self
51 }
52}
53
54impl From<AresString> for String {
55 fn from(s: AresString) -> Self {
56 (*s).to_owned()
57 }
58}
59
60pub struct AresBuf {
62 buf: *mut u8,
63 len: usize,
64}
65
66impl AresBuf {
67 #[allow(dead_code)]
68 pub(crate) fn new(buf: *mut u8, len: usize) -> Self {
69 AresBuf { buf, len }
70 }
71}
72
73impl Deref for AresBuf {
74 type Target = [u8];
75 fn deref(&self) -> &Self::Target {
76 unsafe { std::slice::from_raw_parts(self.buf, self.len) }
77 }
78}
79
80impl Drop for AresBuf {
81 fn drop(&mut self) {
82 unsafe { c_ares_sys::ares_free_string(self.buf.cast()) }
83 }
84}
85
86unsafe impl Send for AresBuf {}
87unsafe impl Sync for AresBuf {}
88
89impl fmt::Debug for AresBuf {
90 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
91 fmt::Debug::fmt(&**self, f)
92 }
93}
94
95impl AsRef<[u8]> for AresBuf {
96 fn as_ref(&self) -> &[u8] {
97 self
98 }
99}
100
101impl From<AresBuf> for Vec<u8> {
102 fn from(b: AresBuf) -> Self {
103 (*b).to_vec()
104 }
105}
106
107#[cfg(test)]
108mod tests {
109 use super::*;
110
111 #[test]
112 fn ares_string_is_send() {
113 fn assert_send<T: Send>() {}
114 assert_send::<AresString>();
115 }
116
117 #[test]
118 fn ares_string_is_sync() {
119 fn assert_sync<T: Sync>() {}
120 assert_sync::<AresString>();
121 }
122
123 #[test]
124 fn ares_buf_is_send() {
125 fn assert_send<T: Send>() {}
126 assert_send::<AresBuf>();
127 }
128
129 #[test]
130 fn ares_buf_is_sync() {
131 fn assert_sync<T: Sync>() {}
132 assert_sync::<AresBuf>();
133 }
134
135 #[test]
136 fn ares_string_debug() {
137 fn assert_debug<T: fmt::Debug>() {}
138 assert_debug::<AresString>();
139 }
140
141 #[test]
142 fn ares_string_debug_output() {
143 let name = crate::expand_name(b"\x07example\x03com\x00", 0)
144 .expect("expand_name")
145 .0;
146 let debug = format!("{name:?}");
147 assert!(debug.contains("example.com"));
148 }
149
150 #[test]
151 fn ares_buf_debug() {
152 fn assert_debug<T: fmt::Debug>() {}
153 assert_debug::<AresBuf>();
154 }
155
156 #[test]
157 fn ares_buf_debug_output() {
158 let data = crate::expand_string(b"\x05hello", 0)
159 .expect("expand_string")
160 .0;
161 let debug = format!("{data:?}");
162 assert!(!debug.is_empty());
163 }
164
165 #[test]
166 fn ares_string_display() {
167 let name = crate::expand_name(b"\x07example\x03com\x00", 0)
168 .expect("expand_name")
169 .0;
170 assert_eq!(format!("{name}"), "example.com");
171 }
172
173 #[test]
174 fn ares_string_as_ref_str() {
175 let name = crate::expand_name(b"\x07example\x03com\x00", 0)
176 .expect("expand_name")
177 .0;
178 let s: &str = name.as_ref();
179 assert_eq!(s, "example.com");
180 }
181
182 #[test]
183 fn ares_buf_as_ref_slice() {
184 let data = crate::expand_string(b"\x05hello", 0)
185 .expect("expand_string")
186 .0;
187 let bytes: &[u8] = data.as_ref();
188 assert_eq!(bytes, b"hello");
189 }
190
191 #[test]
192 fn ares_string_into_string() {
193 let name = crate::expand_name(b"\x07example\x03com\x00", 0)
194 .expect("expand_name")
195 .0;
196 let owned: String = name.into();
197 assert_eq!(owned, "example.com");
198 }
199
200 #[test]
201 fn ares_buf_into_vec() {
202 let data = crate::expand_string(b"\x05hello", 0)
203 .expect("expand_string")
204 .0;
205 let owned: Vec<u8> = data.into();
206 assert_eq!(owned, b"hello");
207 }
208}