Skip to main content

c_ares/
string.rs

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
8/// A smart pointer wrapping a string as allocated by c-ares.
9pub 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
60/// A smart pointer wrapping a byte buffer as allocated by c-ares.
61pub 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}