1 | use crate::ffi; |
2 | use super::*; |
3 | use super::check; |
4 | use crate::strings::{Signature, Path, Member, ErrorName, Interface}; |
5 | use std::{ptr, any, mem}; |
6 | use std::ffi::CStr; |
7 | use std::os::raw::{c_void, c_char, c_int}; |
8 | use std::fs::File; |
9 | |
10 | |
11 | fn arg_append_basic<T>(i: *mut ffi::DBusMessageIter, arg_type: ArgType, v: T) { |
12 | let p: *const c_void = &v as *const _ as *const c_void; |
13 | unsafe { |
14 | check(f:"dbus_message_iter_append_basic" , i:ffi::dbus_message_iter_append_basic(iter:i, t:arg_type as c_int, value:p)); |
15 | }; |
16 | } |
17 | |
18 | fn arg_get_basic<T>(i: *mut ffi::DBusMessageIter, arg_type: ArgType) -> Option<T> { |
19 | unsafe { |
20 | if ffi::dbus_message_iter_get_arg_type(iter:i) != arg_type as c_int { return None }; |
21 | let mut c: MaybeUninit = mem::MaybeUninit::uninit(); |
22 | ffi::dbus_message_iter_get_basic(iter:i, &mut c as *mut _ as *mut c_void); |
23 | Some(c.assume_init()) |
24 | } |
25 | } |
26 | |
27 | fn arg_append_str(i: *mut ffi::DBusMessageIter, arg_type: ArgType, v: &CStr) { |
28 | let p: *const i8 = v.as_ptr(); |
29 | let q: *const c_void = &p as *const _ as *const c_void; |
30 | unsafe { |
31 | check(f:"dbus_message_iter_append_basic" , i:ffi::dbus_message_iter_append_basic(iter:i, t:arg_type as c_int, value:q)); |
32 | }; |
33 | } |
34 | |
35 | unsafe fn arg_get_str<'a>(i: *mut ffi::DBusMessageIter, arg_type: ArgType) -> Option<&'a CStr> { |
36 | if ffi::dbus_message_iter_get_arg_type(iter:i) != arg_type as c_int { return None }; |
37 | let mut p: *mut i8 = ptr::null_mut(); |
38 | ffi::dbus_message_iter_get_basic(iter:i, &mut p as *mut _ as *mut c_void); |
39 | Some(CStr::from_ptr(p as *const c_char)) |
40 | } |
41 | |
42 | |
43 | |
44 | |
45 | // Implementation for basic types. |
46 | |
47 | macro_rules! integer_impl { |
48 | ($t: ident, $s: ident, $f: expr, $i: ident, $ii: expr, $u: ident, $uu: expr, $fff: ident, $ff: expr) => { |
49 | |
50 | impl Arg for $t { |
51 | const ARG_TYPE: ArgType = ArgType::$s; |
52 | #[inline] |
53 | fn signature() -> Signature<'static> { unsafe { Signature::from_slice_unchecked($f) } } |
54 | } |
55 | |
56 | impl Append for $t { |
57 | fn append_by_ref(&self, i: &mut IterAppend) { arg_append_basic(&mut i.0, ArgType::$s, *self) } |
58 | } |
59 | |
60 | impl<'a> Get<'a> for $t { |
61 | fn get(i: &mut Iter) -> Option<Self> { arg_get_basic(&mut i.0, ArgType::$s) } |
62 | } |
63 | |
64 | impl RefArg for $t { |
65 | #[inline] |
66 | fn arg_type(&self) -> ArgType { ArgType::$s } |
67 | #[inline] |
68 | fn signature(&self) -> Signature<'static> { unsafe { Signature::from_slice_unchecked($f) } } |
69 | #[inline] |
70 | fn append(&self, i: &mut IterAppend) { arg_append_basic(&mut i.0, ArgType::$s, *self) } |
71 | #[inline] |
72 | fn as_any(&self) -> &dyn any::Any { self } |
73 | #[inline] |
74 | fn as_any_mut(&mut self) -> &mut dyn any::Any { self } |
75 | #[inline] |
76 | fn as_i64(&self) -> Option<i64> { let $i = *self; $ii } |
77 | #[inline] |
78 | fn as_u64(&self) -> Option<u64> { let $u = *self; $uu } |
79 | #[inline] |
80 | fn as_f64(&self) -> Option<f64> { let $fff = *self; $ff } |
81 | #[inline] |
82 | fn box_clone(&self) -> Box<dyn RefArg + 'static> { Box::new(self.clone()) } |
83 | fn array_clone(v: &[Self]) -> Option<Box<dyn RefArg + 'static>> where Self: Sized { Some(Box::new(v.to_vec())) } |
84 | } |
85 | |
86 | impl DictKey for $t {} |
87 | unsafe impl FixedArray for $t {} |
88 | |
89 | }} // End of macro_rules |
90 | |
91 | integer_impl!(u8, Byte, "y \0" , i, Some(i as i64), u, Some(u as u64), f, Some(f as f64)); |
92 | integer_impl!(i16, Int16, "n \0" , i, Some(i as i64), _u, None, f, Some(f as f64)); |
93 | integer_impl!(u16, UInt16, "q \0" , i, Some(i as i64), u, Some(u as u64), f, Some(f as f64)); |
94 | integer_impl!(i32, Int32, "i \0" , i, Some(i as i64), _u, None, f, Some(f as f64)); |
95 | integer_impl!(u32, UInt32, "u \0" , i, Some(i as i64), u, Some(u as u64), f, Some(f as f64)); |
96 | integer_impl!(i64, Int64, "x \0" , i, Some(i), _u, None, _f, None); |
97 | integer_impl!(u64, UInt64, "t \0" , _i, None, u, Some(u as u64), _f, None); |
98 | |
99 | |
100 | macro_rules! refarg_impl { |
101 | ($t: ty, $i: ident, $ii: expr, $ss: expr, $uu: expr, $ff: expr) => { |
102 | |
103 | impl RefArg for $t { |
104 | #[inline] |
105 | fn arg_type(&self) -> ArgType { <$t as Arg>::ARG_TYPE } |
106 | #[inline] |
107 | fn signature(&self) -> Signature<'static> { <$t as Arg>::signature() } |
108 | #[inline] |
109 | fn append(&self, i: &mut IterAppend) { <$t as Append>::append_by_ref(self, i) } |
110 | #[inline] |
111 | fn as_any(&self) -> &dyn any::Any { self } |
112 | #[inline] |
113 | fn as_any_mut(&mut self) -> &mut dyn any::Any { self } |
114 | #[inline] |
115 | fn as_i64(&self) -> Option<i64> { let $i = self; $ii } |
116 | #[inline] |
117 | fn as_u64(&self) -> Option<u64> { let $i = self; $uu } |
118 | #[inline] |
119 | fn as_f64(&self) -> Option<f64> { let $i = self; $ff } |
120 | #[inline] |
121 | fn as_str(&self) -> Option<&str> { let $i = self; $ss } |
122 | #[inline] |
123 | fn box_clone(&self) -> Box<dyn RefArg + 'static> { Box::new(self.clone()) } |
124 | fn array_clone(v: &[Self]) -> Option<Box<dyn RefArg + 'static>> where Self: Sized { Some(Box::new(v.to_vec())) } |
125 | |
126 | } |
127 | |
128 | } |
129 | } |
130 | |
131 | |
132 | impl Arg for bool { |
133 | const ARG_TYPE: ArgType = ArgType::Boolean; |
134 | fn signature() -> Signature<'static> { unsafe { Signature::from_slice_unchecked("b \0" ) } } |
135 | } |
136 | impl Append for bool { |
137 | fn append_by_ref(&self, i: &mut IterAppend) { arg_append_basic(&mut i.0, ArgType::Boolean, v:if *self {1} else {0}) } |
138 | } |
139 | impl DictKey for bool {} |
140 | impl<'a> Get<'a> for bool { |
141 | fn get(i: &mut Iter) -> Option<Self> { arg_get_basic::<u32>(&mut i.0, ArgType::Boolean).map(|q: u32| q != 0) } |
142 | } |
143 | |
144 | refarg_impl!(bool, _i, Some(if *_i { 1 } else { 0 }), None, Some(if *_i { 1 as u64 } else { 0 as u64 }), Some(if *_i { 1 as f64 } else { 0 as f64 })); |
145 | |
146 | impl Arg for f64 { |
147 | const ARG_TYPE: ArgType = ArgType::Double; |
148 | fn signature() -> Signature<'static> { unsafe { Signature::from_slice_unchecked("d \0" ) } } |
149 | } |
150 | impl Append for f64 { |
151 | fn append_by_ref(&self, i: &mut IterAppend) { arg_append_basic(&mut i.0, ArgType::Double, *self) } |
152 | } |
153 | impl DictKey for f64 {} |
154 | impl<'a> Get<'a> for f64 { |
155 | fn get(i: &mut Iter) -> Option<Self> { arg_get_basic(&mut i.0, ArgType::Double) } |
156 | } |
157 | unsafe impl FixedArray for f64 {} |
158 | |
159 | refarg_impl!(f64, _i, None, None, None, Some(*_i)); |
160 | |
161 | /// Represents a D-Bus string. |
162 | impl<'a> Arg for &'a str { |
163 | const ARG_TYPE: ArgType = ArgType::String; |
164 | fn signature() -> Signature<'static> { unsafe { Signature::from_slice_unchecked("s \0" ) } } |
165 | } |
166 | |
167 | impl<'a> Append for &'a str { |
168 | fn append_by_ref(&self, i: &mut IterAppend) { |
169 | use std::borrow::Cow; |
170 | let b: &[u8] = self.as_bytes(); |
171 | let v: Cow<[u8]> = if !b.is_empty() && b[b.len()-1] == 0 { Cow::Borrowed(b) } |
172 | else { |
173 | let mut bb: Vec<u8> = b.into(); |
174 | bb.push(0); |
175 | Cow::Owned(bb) |
176 | }; |
177 | let z: &CStr = unsafe { CStr::from_ptr(v.as_ptr() as *const c_char) }; |
178 | arg_append_str(&mut i.0, ArgType::String, &z) |
179 | } |
180 | } |
181 | impl<'a> DictKey for &'a str {} |
182 | impl<'a> Get<'a> for &'a str { |
183 | fn get(i: &mut Iter<'a>) -> Option<&'a str> { unsafeOption<&CStr> { arg_get_str(&mut i.0, ArgType::String) } |
184 | .and_then(|s: &CStr| s.to_str().ok()) } |
185 | } |
186 | |
187 | impl<'a> Arg for String { |
188 | const ARG_TYPE: ArgType = ArgType::String; |
189 | fn signature() -> Signature<'static> { unsafe { Signature::from_slice_unchecked("s \0" ) } } |
190 | } |
191 | impl<'a> Append for String { |
192 | fn append(mut self, i: &mut IterAppend) { |
193 | self.push_str(string:" \0" ); |
194 | let s: &str = &self; |
195 | s.append(ia:i) |
196 | } |
197 | fn append_by_ref(&self, i: &mut IterAppend) { |
198 | (&**self).append_by_ref(i) |
199 | } |
200 | } |
201 | impl<'a> DictKey for String {} |
202 | impl<'a> Get<'a> for String { |
203 | fn get(i: &mut Iter<'a>) -> Option<String> { <&str>::get(i).map(String::from) } |
204 | } |
205 | |
206 | refarg_impl!(String, _i, None, Some(&_i), None, None); |
207 | |
208 | /// Represents a D-Bus string. |
209 | impl<'a> Arg for &'a CStr { |
210 | const ARG_TYPE: ArgType = ArgType::String; |
211 | fn signature() -> Signature<'static> { unsafe { Signature::from_slice_unchecked("s \0" ) } } |
212 | } |
213 | |
214 | /* |
215 | /// Note: Will give D-Bus errors in case the CStr is not valid UTF-8. |
216 | impl<'a> Append for &'a CStr { |
217 | fn append(self, i: &mut IterAppend) { |
218 | arg_append_str(&mut i.0, Self::arg_type(), &self) |
219 | } |
220 | } |
221 | */ |
222 | |
223 | impl<'a> DictKey for &'a CStr {} |
224 | impl<'a> Get<'a> for &'a CStr { |
225 | fn get(i: &mut Iter<'a>) -> Option<&'a CStr> { unsafe { arg_get_str(&mut i.0, Self::ARG_TYPE) }} |
226 | } |
227 | |
228 | impl Arg for OwnedFd { |
229 | const ARG_TYPE: ArgType = ArgType::UnixFd; |
230 | fn signature() -> Signature<'static> { unsafe { Signature::from_slice_unchecked("h \0" ) } } |
231 | } |
232 | impl Append for OwnedFd { |
233 | #[cfg (unix)] |
234 | fn append_by_ref(&self, i: &mut IterAppend) { |
235 | arg_append_basic(&mut i.0, ArgType::UnixFd, self.as_raw_fd()) |
236 | } |
237 | #[cfg (windows)] |
238 | fn append_by_ref(&self, _i: &mut IterAppend) { |
239 | panic!("File descriptor passing not available on Windows" ); |
240 | } |
241 | } |
242 | impl DictKey for OwnedFd {} |
243 | impl<'a> Get<'a> for OwnedFd { |
244 | #[cfg (unix)] |
245 | fn get(i: &mut Iter) -> Option<Self> { |
246 | arg_get_basic(&mut i.0, ArgType::UnixFd).map(|fd: i32| unsafe { OwnedFd::from_raw_fd(fd) }) |
247 | } |
248 | #[cfg (windows)] |
249 | fn get(_i: &mut Iter) -> Option<Self> { |
250 | None |
251 | } |
252 | } |
253 | |
254 | #[cfg (all(unix, feature = "io-lifetimes" ))] |
255 | impl Arg for io_lifetimes::OwnedFd { |
256 | const ARG_TYPE: ArgType = ArgType::UnixFd; |
257 | fn signature() -> Signature<'static> { unsafe { Signature::from_slice_unchecked("h \0" ) } } |
258 | } |
259 | #[cfg (all(unix, feature = "io-lifetimes" ))] |
260 | impl Append for io_lifetimes::OwnedFd { |
261 | fn append_by_ref(&self, i: &mut IterAppend) { |
262 | arg_append_basic(&mut i.0, ArgType::UnixFd, self.as_raw_fd()) |
263 | } |
264 | } |
265 | #[cfg (all(unix, feature = "io-lifetimes" ))] |
266 | impl DictKey for io_lifetimes::OwnedFd {} |
267 | #[cfg (all(unix, feature = "io-lifetimes" ))] |
268 | impl<'a> Get<'a> for io_lifetimes::OwnedFd { |
269 | fn get(i: &mut Iter) -> Option<Self> { |
270 | arg_get_basic(&mut i.0, ArgType::UnixFd).map(|fd| unsafe { io_lifetimes::OwnedFd::from_raw_fd(fd) }) |
271 | } |
272 | } |
273 | |
274 | #[cfg (unix)] |
275 | impl RefArg for OwnedFd { |
276 | #[inline ] |
277 | fn arg_type(&self) -> ArgType { <Self as Arg>::ARG_TYPE } |
278 | #[inline ] |
279 | fn signature(&self) -> Signature<'static> { <Self as Arg>::signature() } |
280 | #[inline ] |
281 | fn append(&self, i: &mut IterAppend) { <Self as Append>::append_by_ref(self, i) } |
282 | #[inline ] |
283 | fn as_any(&self) -> &dyn any::Any { self } |
284 | #[inline ] |
285 | fn as_any_mut(&mut self) -> &mut dyn any::Any { self } |
286 | #[inline ] |
287 | fn as_i64(&self) -> Option<i64> { Some(self.as_raw_fd() as i64) } |
288 | #[inline ] |
289 | fn box_clone(&self) -> Box<dyn RefArg + 'static> { Box::new(self.try_clone().unwrap()) } |
290 | } |
291 | |
292 | #[cfg (windows)] |
293 | refarg_impl!(OwnedFd, _i, None, None, None, None); |
294 | |
295 | impl Arg for File { |
296 | const ARG_TYPE: ArgType = ArgType::UnixFd; |
297 | fn signature() -> Signature<'static> { unsafe { Signature::from_slice_unchecked("h \0" ) } } |
298 | } |
299 | impl Append for File { |
300 | #[cfg (unix)] |
301 | fn append_by_ref(&self, i: &mut IterAppend) { |
302 | arg_append_basic(&mut i.0, ArgType::UnixFd, self.as_raw_fd()) |
303 | } |
304 | #[cfg (windows)] |
305 | fn append_by_ref(&self, _i: &mut IterAppend) { |
306 | panic!("File descriptor passing not available on Windows" ); |
307 | } |
308 | } |
309 | impl DictKey for File {} |
310 | impl<'a> Get<'a> for File { |
311 | #[cfg (unix)] |
312 | fn get(i: &mut Iter) -> Option<Self> { |
313 | arg_get_basic(&mut i.0, ArgType::UnixFd).map(|fd: i32| unsafe { File::from_raw_fd(fd) }) |
314 | } |
315 | #[cfg (windows)] |
316 | fn get(_i: &mut Iter) -> Option<Self> { |
317 | None |
318 | } |
319 | } |
320 | |
321 | impl RefArg for File { |
322 | #[inline ] |
323 | fn arg_type(&self) -> ArgType { <File as Arg>::ARG_TYPE } |
324 | #[inline ] |
325 | fn signature(&self) -> Signature<'static> { <File as Arg>::signature() } |
326 | #[inline ] |
327 | fn append(&self, i: &mut IterAppend) { <File as Append>::append_by_ref(self, i) } |
328 | #[inline ] |
329 | fn as_any(&self) -> &dyn any::Any { self } |
330 | #[inline ] |
331 | fn as_any_mut(&mut self) -> &mut dyn any::Any { self } |
332 | #[cfg (unix)] |
333 | #[inline ] |
334 | fn as_i64(&self) -> Option<i64> { Some(self.as_raw_fd() as i64) } |
335 | #[inline ] |
336 | fn box_clone(&self) -> Box<dyn RefArg + 'static> { Box::new(self.try_clone().unwrap()) } |
337 | } |
338 | |
339 | #[cfg (all(unix, feature = "io-lifetimes" ))] |
340 | impl RefArg for io_lifetimes::OwnedFd { |
341 | #[inline ] |
342 | fn arg_type(&self) -> ArgType { <Self as Arg>::ARG_TYPE } |
343 | #[inline ] |
344 | fn signature(&self) -> Signature<'static> { <Self as Arg>::signature() } |
345 | #[inline ] |
346 | fn append(&self, i: &mut IterAppend) { <Self as Append>::append_by_ref(self, i) } |
347 | #[inline ] |
348 | fn as_any(&self) -> &dyn any::Any { self } |
349 | #[inline ] |
350 | fn as_any_mut(&mut self) -> &mut dyn any::Any { self } |
351 | #[cfg (unix)] |
352 | #[inline ] |
353 | fn as_i64(&self) -> Option<i64> { Some(self.as_raw_fd() as i64) } |
354 | #[inline ] |
355 | fn box_clone(&self) -> Box<dyn RefArg + 'static> { Box::new(self.try_clone().unwrap()) } |
356 | } |
357 | |
358 | |
359 | macro_rules! string_impl { |
360 | ($t: ident, $s: ident, $f: expr) => { |
361 | |
362 | impl<'a> Arg for $t<'a> { |
363 | const ARG_TYPE: ArgType = ArgType::$s; |
364 | fn signature() -> Signature<'static> { unsafe { Signature::from_slice_unchecked($f) } } |
365 | } |
366 | |
367 | impl RefArg for $t<'static> { |
368 | fn arg_type(&self) -> ArgType { ArgType::$s } |
369 | fn signature(&self) -> Signature<'static> { unsafe { Signature::from_slice_unchecked($f) } } |
370 | fn append(&self, i: &mut IterAppend) { arg_append_str(&mut i.0, ArgType::$s, self.as_cstr()) } |
371 | #[inline] |
372 | fn as_any(&self) -> &dyn any::Any { self } |
373 | #[inline] |
374 | fn as_any_mut(&mut self) -> &mut dyn any::Any { self } |
375 | #[inline] |
376 | fn as_str(&self) -> Option<&str> { Some(self) } |
377 | #[inline] |
378 | fn box_clone(&self) -> Box<dyn RefArg + 'static> { Box::new(self.clone().into_static()) } |
379 | fn array_clone(v: &[Self]) -> Option<Box<dyn RefArg + 'static>> where Self: Sized { Some(Box::new(v.to_vec())) } |
380 | } |
381 | |
382 | impl<'a> DictKey for $t<'a> {} |
383 | |
384 | impl<'a> Append for $t<'a> { |
385 | fn append_by_ref(&self, i: &mut IterAppend) { |
386 | arg_append_str(&mut i.0, ArgType::$s, self.as_cstr()) |
387 | } |
388 | } |
389 | |
390 | /* |
391 | |
392 | Unfortunately, this does not work because it conflicts with getting a $t<'static>. |
393 | |
394 | impl<'a> Get<'a> for $t<'a> { |
395 | fn get(i: &mut Iter<'a>) -> Option<$t<'a>> { unsafe { arg_get_str(&mut i.0, ArgType::$s) } |
396 | .map(|s| unsafe { $t::from_slice_unchecked(s.to_bytes_with_nul()) } ) } |
397 | } |
398 | */ |
399 | |
400 | impl<'a> Get<'a> for $t<'static> { |
401 | fn get(i: &mut Iter<'a>) -> Option<$t<'static>> { unsafe { |
402 | let c = arg_get_str(&mut i.0, ArgType::$s)?; |
403 | let s = std::str::from_utf8(c.to_bytes_with_nul()).ok()?; |
404 | Some($t::from_slice_unchecked(s).into_static()) |
405 | }} |
406 | } |
407 | |
408 | |
409 | } |
410 | } |
411 | |
412 | string_impl!(Interface, String, "s \0" ); |
413 | string_impl!(ErrorName, String, "s \0" ); |
414 | string_impl!(Member, String, "s \0" ); |
415 | string_impl!(Path, ObjectPath, "o \0" ); |
416 | string_impl!(Signature, Signature, "g \0" ); |
417 | |