1 // CString wrappers.
2
3 use std::{str, fmt, ops, default, hash};
4 use std::ffi::{CStr, CString};
5 use std::borrow::{Borrow, Cow};
6 use std::os::raw::c_char;
7
8 #[cfg(not(feature = "no-string-validation"))]
9 use Error;
10 #[cfg(not(feature = "no-string-validation"))]
11 use ffi;
12
13 macro_rules! cstring_wrapper {
14 ($t: ident, $s: ident) => {
15
16 impl<'m> $t<'m> {
17 #[cfg(feature = "no-string-validation")]
18 fn check_valid(_: *const c_char) -> Result<(), String> { Ok(()) }
19
20 #[cfg(not(feature = "no-string-validation"))]
21 fn check_valid(c: *const c_char) -> Result<(), String> {
22 let mut e = Error::empty();
23 let b = unsafe { ffi::$s(c, e.get_mut()) };
24 if b != 0 { Ok(()) } else { Err(e.message().unwrap().into()) }
25 }
26
27 /// Creates a new instance of this struct.
28 ///
29 /// Note: If the no-string-validation feature is activated, this string
30 /// will not be checked for conformance with the D-Bus specification.
31 pub fn new<S: Into<Vec<u8>>>(s: S) -> Result<$t<'m>, String> {
32 let c = try!(CString::new(s).map_err(|e| e.to_string()));
33 $t::check_valid(c.as_ptr()).map(|_| $t(Cow::Owned(c)))
34 }
35
36 /// Creates a new instance of this struct. If you end it with \0,
37 /// it can borrow the slice without extra allocation.
38 ///
39 /// Note: If the no-string-validation feature is activated, this string
40 /// will not be checked for conformance with the D-Bus specification.
41 pub fn from_slice(s: &'m [u8]) -> Result<$t<'m>, String> {
42 if s.len() == 0 || s[s.len()-1] != 0 { return $t::new(s) };
43 $t::check_valid(s.as_ptr() as *const c_char).map(|_| {
44 let c = unsafe { CStr::from_ptr(s.as_ptr() as *const c_char) };
45 $t(Cow::Borrowed(c))
46 })
47 }
48
49 /// This function creates a new instance of this struct, without checking.
50 /// It's up to you to guarantee that s ends with a \0 and is valid.
51 pub unsafe fn from_slice_unchecked(s: &'m [u8]) -> $t<'m> {
52 debug_assert!(s[s.len()-1] == 0);
53 $t(Cow::Borrowed(CStr::from_ptr(s.as_ptr() as *const c_char)))
54 }
55
56 /// View this struct as a CStr.
57 pub fn as_cstr(&self) -> &CStr { &self.0 }
58
59 /// Makes sure this string does not contain borrows.
60 pub fn into_static(self) -> $t<'static> {
61 $t(Cow::Owned(self.0.into_owned()))
62 }
63
64 /// Converts this struct to a CString.
65 pub fn into_cstring(self) -> CString { self.0.into_owned() }
66 }
67
68 /*
69 /// #Panics
70 ///
71 /// If given string is not valid.
72 /// impl<S: Into<Vec<u8>>> From<S> for $t { fn from(s: S) -> $t { $t::new(s).unwrap() } }
73 */
74
75 /// #Panics
76 ///
77 /// If given string is not valid.
78 impl<'m> From<String> for $t<'m> { fn from(s: String) -> $t<'m> { $t::new(s).unwrap() } }
79
80 /// #Panics
81 ///
82 /// If given string is not valid.
83 impl<'m> From<&'m String> for $t<'m> { fn from(s: &'m String) -> $t<'m> { $t::from_slice(s.as_bytes()).unwrap() } }
84
85 /// #Panics
86 ///
87 /// If given string is not valid.
88 impl<'m> From<&'m str> for $t<'m> { fn from(s: &'m str) -> $t<'m> { $t::from_slice(s.as_bytes()).unwrap() } }
89
90 impl<'m> From<$t<'m>> for CString { fn from(s: $t<'m>) -> CString { s.0.into_owned() } }
91
92
93 /// #Panics
94 ///
95 /// If given string is not valid.
96 impl<'m> From<Cow<'m, str>> for $t<'m> {
97 fn from(s: Cow<'m, str>) -> $t<'m> {
98 match s {
99 Cow::Borrowed(z) => z.into(),
100 Cow::Owned(z) => z.into(),
101 }
102 }
103 }
104
105 impl<'inner, 'm: 'inner> From<&'m $t<'inner>> for $t<'m> {
106 fn from(borrow: &'m $t<'inner>) -> $t<'m> {
107 $t(Cow::Borrowed(borrow.0.borrow()))
108 }
109 }
110
111 impl<'m> ops::Deref for $t<'m> {
112 type Target = str;
113 fn deref(&self) -> &str { str::from_utf8(self.0.to_bytes()).unwrap() }
114 }
115
116 impl<'m> fmt::Display for $t<'m> {
117 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
118 let s: &str = &self;
119 (&s as &fmt::Display).fmt(f)
120 }
121 }
122
123 impl<'m> AsRef<CStr> for $t<'m> {
124 fn as_ref(&self) -> &CStr { &self.0 }
125 }
126
127 impl<'m> hash::Hash for $t<'m> {
128 fn hash<H: hash::Hasher>(&self, state: &mut H) {
129 self.0.hash(state);
130 }
131 }
132
133 }}
134
135 /// A wrapper around a string that is guaranteed to be
136 /// a valid (single) D-Bus type signature. Supersedes TypeSig.
137 #[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone)]
138 pub struct Signature<'a>(Cow<'a, CStr>);
139
140 cstring_wrapper!(Signature, dbus_signature_validate_single);
141
142 impl Signature<'static> {
143 /// Makes a D-Bus signature that corresponds to A.
make<A: super::arg::Arg>() -> Signature<'static>144 pub fn make<A: super::arg::Arg>() -> Signature<'static> { A::signature() }
145 }
146
147 /// A wrapper around a string that is guaranteed to be
148 /// a valid D-Bus object path.
149 #[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone)]
150 pub struct Path<'a>(Cow<'a, CStr>);
151
152 cstring_wrapper!(Path, dbus_validate_path);
153
154 // This is needed so one can make arrays of paths easily
155 impl<'a> default::Default for Path<'a> {
default() -> Path<'a>156 fn default() -> Path<'a> { Path(Cow::Borrowed(unsafe { CStr::from_ptr(b"/\0".as_ptr() as *const c_char)})) }
157 }
158
159 /// A wrapper around a string that is guaranteed to be
160 /// a valid D-Bus member, i e, a signal or method name.
161 #[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone)]
162 pub struct Member<'a>(Cow<'a, CStr>);
163
164 cstring_wrapper!(Member, dbus_validate_member);
165
166 /// A wrapper around a string that is guaranteed to be
167 /// a valid D-Bus interface name.
168 #[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone)]
169 pub struct Interface<'a>(Cow<'a, CStr>);
170
171 cstring_wrapper!(Interface, dbus_validate_interface);
172
173 /// A wrapper around a string that is guaranteed to be
174 /// a valid D-Bus bus name.
175 #[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone)]
176 pub struct BusName<'a>(Cow<'a, CStr>);
177
178 cstring_wrapper!(BusName, dbus_validate_bus_name);
179
180 /// A wrapper around a string that is guaranteed to be
181 /// a valid D-Bus bus name.
182 #[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone)]
183 pub struct ErrorName<'a>(Cow<'a, CStr>);
184
185 cstring_wrapper!(ErrorName, dbus_validate_error_name);
186
187 #[test]
some_path()188 fn some_path() {
189 use std::os::raw::c_char;
190 let p1: Path = "/valid".into();
191 let p2 = Path::new("##invalid##");
192 assert_eq!(p1, Path(Cow::Borrowed(unsafe { CStr::from_ptr(b"/valid\0".as_ptr() as *const c_char) })));
193 #[cfg(not(feature = "no-string-validation"))]
194 assert_eq!(p2, Err("Object path was not valid: '##invalid##'".into()));
195 #[cfg(feature = "no-string-validation")]
196 assert_eq!(p2, Ok(Path(Cow::Borrowed(unsafe { CStr::from_ptr(b"##invalid##\0".as_ptr() as *const c_char) }))));
197 }
198
199 #[test]
reborrow_path()200 fn reborrow_path() {
201 let p1 = Path::from("/valid");
202 let p2 = p1.clone();
203 {
204 let p2_borrow: &Path = &p2;
205 let p3 = Path::from(p2_borrow);
206 // Check path created from borrow
207 assert_eq!(p2, p3);
208 }
209 // Check path that was previously borrowed
210 assert_eq!(p1, p2);
211 }
212
213 #[test]
make_sig()214 fn make_sig() {
215 assert_eq!(&*Signature::make::<(&str, u8)>(), "(sy)");
216 }
217