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 
65 /*
66 /// #Panics
67 ///
68 /// If given string is not valid.
69 /// impl<S: Into<Vec<u8>>> From<S> for $t { fn from(s: S) -> $t { $t::new(s).unwrap() } }
70 */
71 
72 /// #Panics
73 ///
74 /// If given string is not valid.
75 impl<'m> From<String> for $t<'m> { fn from(s: String) -> $t<'m> { $t::new(s).unwrap() } }
76 
77 /// #Panics
78 ///
79 /// If given string is not valid.
80 impl<'m> From<&'m String> for $t<'m> { fn from(s: &'m String) -> $t<'m> { $t::from_slice(s.as_bytes()).unwrap() } }
81 
82 /// #Panics
83 ///
84 /// If given string is not valid.
85 impl<'m> From<&'m str> for $t<'m> { fn from(s: &'m str) -> $t<'m> { $t::from_slice(s.as_bytes()).unwrap() } }
86 
87 /// #Panics
88 ///
89 /// If given string is not valid.
90 impl<'m> From<Cow<'m, str>> for $t<'m> {
91     fn from(s: Cow<'m, str>) -> $t<'m> {
92         match s {
93             Cow::Borrowed(z) => z.into(),
94             Cow::Owned(z) => z.into(),
95         }
96     }
97 }
98 
99 impl<'inner, 'm: 'inner> From<&'m $t<'inner>> for $t<'m> {
100     fn from(borrow: &'m $t<'inner>) -> $t<'m> {
101         $t(Cow::Borrowed(borrow.0.borrow()))
102     }
103 }
104 
105 impl<'m> ops::Deref for $t<'m> {
106     type Target = str;
107     fn deref(&self) -> &str { str::from_utf8(self.0.to_bytes()).unwrap() }
108 }
109 
110 impl<'m> fmt::Display for $t<'m> {
111     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
112         let s: &str = &self;
113         (&s as &fmt::Display).fmt(f)
114     }
115 }
116 
117 impl<'m> AsRef<CStr> for $t<'m> {
118     fn as_ref(&self) -> &CStr { &self.0 }
119 }
120 
121 impl<'m> hash::Hash for $t<'m> {
122     fn hash<H: hash::Hasher>(&self, state: &mut H) {
123         self.0.hash(state);
124     }
125 }
126 
127 }}
128 
129 /// A wrapper around a string that is guaranteed to be
130 /// a valid (single) D-Bus type signature. Supersedes TypeSig.
131 #[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone)]
132 pub struct Signature<'a>(Cow<'a, CStr>);
133 
134 cstring_wrapper!(Signature, dbus_signature_validate_single);
135 
136 impl Signature<'static> {
137     /// Makes a D-Bus signature that corresponds to A.
make<A: super::arg::Arg>() -> Signature<'static>138     pub fn make<A: super::arg::Arg>() -> Signature<'static> { A::signature() }
139 }
140 
141 /// A wrapper around a string that is guaranteed to be
142 /// a valid D-Bus object path.
143 #[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone)]
144 pub struct Path<'a>(Cow<'a, CStr>);
145 
146 cstring_wrapper!(Path, dbus_validate_path);
147 
148 // This is needed so one can make arrays of paths easily
149 impl<'a> default::Default for Path<'a> {
default() -> Path<'a>150     fn default() -> Path<'a> { Path(Cow::Borrowed(unsafe { CStr::from_ptr(b"/\0".as_ptr() as *const c_char)})) }
151 }
152 
153 /// A wrapper around a string that is guaranteed to be
154 /// a valid D-Bus member, i e, a signal or method name.
155 #[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone)]
156 pub struct Member<'a>(Cow<'a, CStr>);
157 
158 cstring_wrapper!(Member, dbus_validate_member);
159 
160 /// A wrapper around a string that is guaranteed to be
161 /// a valid D-Bus interface name.
162 #[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone)]
163 pub struct Interface<'a>(Cow<'a, CStr>);
164 
165 cstring_wrapper!(Interface, dbus_validate_interface);
166 
167 /// A wrapper around a string that is guaranteed to be
168 /// a valid D-Bus bus name.
169 #[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone)]
170 pub struct BusName<'a>(Cow<'a, CStr>);
171 
172 cstring_wrapper!(BusName, dbus_validate_bus_name);
173 
174 /// A wrapper around a string that is guaranteed to be
175 /// a valid D-Bus bus name.
176 #[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone)]
177 pub struct ErrorName<'a>(Cow<'a, CStr>);
178 
179 cstring_wrapper!(ErrorName, dbus_validate_error_name);
180 
181 #[test]
some_path()182 fn some_path() {
183     use std::os::raw::c_char;
184     let p1: Path = "/valid".into();
185     let p2 = Path::new("##invalid##");
186     assert_eq!(p1, Path(Cow::Borrowed(unsafe { CStr::from_ptr(b"/valid\0".as_ptr() as *const c_char) })));
187     #[cfg(not(feature = "no-string-validation"))]
188     assert_eq!(p2, Err("Object path was not valid: '##invalid##'".into()));
189     #[cfg(feature = "no-string-validation")]
190     assert_eq!(p2, Ok(Path(Cow::Borrowed(unsafe { CStr::from_ptr(b"##invalid##\0".as_ptr() as *const c_char) }))));
191 }
192 
193 #[test]
reborrow_path()194 fn reborrow_path() {
195     let p1 = Path::from("/valid");
196     let p2 = p1.clone();
197     {
198         let p2_borrow: &Path = &p2;
199         let p3 = Path::from(p2_borrow);
200         // Check path created from borrow
201         assert_eq!(p2, p3);
202     }
203     // Check path that was previously borrowed
204     assert_eq!(p1, p2);
205 }
206 
207 #[test]
make_sig()208 fn make_sig() {
209     assert_eq!(&*Signature::make::<(&str, u8)>(), "(sy)");
210 }
211