/rust/registry/src/index.crates.io-6f17d22bba15001f/dbus-0.9.7/src/arg/messageitem.rs
Line | Count | Source (jump to first uncovered line) |
1 | | //! MessageItem - old, enum design that is used as parameters and return values from |
2 | | //! method calls, or as data added to a signal. |
3 | | //! |
4 | | //! Note that the newer generic design (see `arg` module) is, in general, both faster |
5 | | //! and smaller than MessageItem, and should be your first hand choice |
6 | | //! whenever applicable. There is also a trait object design called `RefArg` in |
7 | | //! case the generic design is too inflexible. |
8 | | |
9 | | use crate::strings::{Signature, Path, Interface, BusName}; |
10 | | |
11 | | use crate::arg; |
12 | | use crate::arg::{Iter, IterAppend, Arg, ArgType}; |
13 | | use crate::arg::OwnedFd; |
14 | | use std::ffi::CStr; |
15 | | use std::{ops, any}; |
16 | | |
17 | | use crate::{ffidisp::Connection, Message, Error}; |
18 | | use std::collections::BTreeMap; |
19 | | use std::convert::TryFrom; |
20 | | |
21 | 0 | #[derive(Debug,Copy,Clone)] |
22 | | /// Errors that can happen when creating a MessageItem::Array. |
23 | | pub enum ArrayError { |
24 | | /// The array is empty. |
25 | | EmptyArray, |
26 | | /// The array is composed of different element types. |
27 | | DifferentElementTypes, |
28 | | /// The supplied signature is not a valid array signature |
29 | | InvalidSignature, |
30 | | } |
31 | | |
32 | | |
33 | | /// OwnedFd wrapper for MessageItem |
34 | | #[cfg(feature = "stdfd")] |
35 | | #[derive(Debug)] |
36 | | pub struct MessageItemFd(pub OwnedFd); |
37 | | |
38 | | #[cfg(feature = "stdfd")] |
39 | | mod messageitem_fd_impl { |
40 | | use super::*; |
41 | | impl Clone for MessageItemFd { |
42 | | fn clone(&self) -> Self { MessageItemFd(self.0.try_clone().unwrap()) } |
43 | | } |
44 | | |
45 | | impl PartialEq for MessageItemFd { |
46 | | fn eq(&self, _rhs: &Self) -> bool { false } |
47 | | } |
48 | | |
49 | | impl PartialOrd for MessageItemFd { |
50 | | fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> { |
51 | | use std::os::fd::AsRawFd; |
52 | | let a = self.0.as_raw_fd(); |
53 | | let b = other.0.as_raw_fd(); |
54 | | a.partial_cmp(&b) |
55 | | } |
56 | | } |
57 | | |
58 | | impl From<OwnedFd> for MessageItem { fn from(i: OwnedFd) -> MessageItem { MessageItem::UnixFd(MessageItemFd(i)) } } |
59 | | |
60 | | impl<'a> TryFrom<&'a MessageItem> for &'a OwnedFd { |
61 | | type Error = (); |
62 | | fn try_from(i: &'a MessageItem) -> Result<&'a OwnedFd,()> { if let MessageItem::UnixFd(ref b) = i { Ok(&b.0) } else { Err(()) } } |
63 | | } |
64 | | } |
65 | | |
66 | 0 | #[derive(Debug, Clone, PartialEq, PartialOrd)] |
67 | | /// An array of MessageItem where every MessageItem is of the same type. |
68 | | pub struct MessageItemArray { |
69 | | v: Vec<MessageItem>, |
70 | | // signature includes the "a"! |
71 | | sig: Signature<'static>, |
72 | | } |
73 | | |
74 | | impl MessageItemArray { |
75 | | /// Creates a new array where every element has the supplied signature. |
76 | | /// |
77 | | /// Signature is the full array signature, not the signature of the element. |
78 | 0 | pub fn new(v: Vec<MessageItem>, sig: Signature<'static>) -> Result<MessageItemArray, ArrayError> { |
79 | 0 | let a = MessageItemArray {v: v, sig: sig }; |
80 | 0 | if a.sig.as_bytes()[0] != ffi::DBUS_TYPE_ARRAY as u8 { return Err(ArrayError::InvalidSignature) } |
81 | 0 | { |
82 | 0 | let esig = a.element_signature(); |
83 | 0 | for i in &a.v { |
84 | 0 | if i.signature().as_cstr() != esig { return Err(ArrayError::DifferentElementTypes) } |
85 | | } |
86 | | } |
87 | 0 | Ok(a) |
88 | 0 | } |
89 | | |
90 | 0 | fn element_signature(&self) -> &CStr { |
91 | 0 | let z = &self.sig.as_cstr().to_bytes_with_nul()[1..]; |
92 | 0 | unsafe { CStr::from_bytes_with_nul_unchecked(z) } |
93 | 0 | } |
94 | | |
95 | 0 | fn make_sig(m: &MessageItem) -> Signature<'static> { |
96 | 0 | Signature::new(format!("a{}", m.signature())).unwrap() |
97 | 0 | } |
98 | | |
99 | | /// Signature of array (full array signature) |
100 | 0 | pub fn signature(&self) -> &Signature<'static> { &self.sig } |
101 | | |
102 | | /// Consumes the MessageItemArray in order to allow you to modify the individual items of the array. |
103 | 0 | pub fn into_vec(self) -> Vec<MessageItem> { self.v } |
104 | | } |
105 | | |
106 | | impl ops::Deref for MessageItemArray { |
107 | | type Target = [MessageItem]; |
108 | 0 | fn deref(&self) -> &Self::Target { &self.v } |
109 | | } |
110 | | |
111 | | impl arg::Append for MessageItemArray { |
112 | 0 | fn append_by_ref(&self, i: &mut IterAppend) { |
113 | 0 | i.append_container(ArgType::Array, Some(self.element_signature()), |s| { |
114 | 0 | for a in &self.v { a.append_by_ref(s) } |
115 | 0 | }); |
116 | 0 | } |
117 | | } |
118 | | |
119 | 0 | #[derive(Debug, Clone, PartialEq, PartialOrd)] |
120 | | /// An array of MessageItem where every MessageItem is of the same type. |
121 | | pub struct MessageItemDict { |
122 | | v: Vec<(MessageItem, MessageItem)>, |
123 | | // signature includes the "a"! |
124 | | sig: Signature<'static>, |
125 | | } |
126 | | |
127 | | impl MessageItemDict { |
128 | | /// Creates a new dict where every key and value elements have the supplied signature. |
129 | 0 | pub fn new(v: Vec<(MessageItem, MessageItem)>, keysig: Signature<'static>, valuesig: Signature<'static>) -> Result<MessageItemDict, ArrayError> { |
130 | 0 | let sig = Signature::from(format!("a{{{}{}}}", keysig, valuesig)); |
131 | 0 | let a = MessageItemDict {v: v, sig: sig }; |
132 | 0 | for (k, v) in &a.v { |
133 | 0 | if keysig != k.signature() || valuesig != v.signature() { |
134 | 0 | return Err(ArrayError::DifferentElementTypes); |
135 | 0 | } |
136 | | } |
137 | 0 | Ok(a) |
138 | 0 | } |
139 | | |
140 | 0 | fn element_signature(&self) -> &CStr { |
141 | 0 | let z = &self.sig.as_cstr().to_bytes_with_nul()[1..]; |
142 | 0 | unsafe { CStr::from_bytes_with_nul_unchecked(z) } |
143 | 0 | } |
144 | | |
145 | | /// Signature of array (full array signature) |
146 | 0 | pub fn signature(&self) -> &Signature<'static> { &self.sig } |
147 | | |
148 | | /// Consumes the MessageItemDict in order to allow you to modify the individual items of the dict. |
149 | 0 | pub fn into_vec(self) -> Vec<(MessageItem, MessageItem)> { self.v } |
150 | | } |
151 | | |
152 | | impl ops::Deref for MessageItemDict { |
153 | | type Target = [(MessageItem, MessageItem)]; |
154 | 0 | fn deref(&self) -> &Self::Target { &self.v } |
155 | | } |
156 | | |
157 | | impl arg::Append for MessageItemDict { |
158 | 0 | fn append_by_ref(&self, i: &mut IterAppend) { |
159 | 0 | i.append_container(ArgType::Array, Some(self.element_signature()), |s| { |
160 | 0 | for (k, v) in &self.v { |
161 | 0 | s.append_container(ArgType::DictEntry, None, |ss| { |
162 | 0 | k.append_by_ref(ss); |
163 | 0 | v.append_by_ref(ss); |
164 | 0 | }); |
165 | 0 | } |
166 | 0 | }); |
167 | 0 | } |
168 | | } |
169 | | |
170 | | /// MessageItem - used as parameters and return values from |
171 | | /// method calls, or as data added to a signal (old, enum version). |
172 | | /// |
173 | | /// Note that the newer generic design (see `arg` module) is both faster |
174 | | /// and less error prone than MessageItem, and should be your first hand choice |
175 | | /// whenever applicable. |
176 | 0 | #[derive(Debug, PartialEq, PartialOrd, Clone)] |
177 | | pub enum MessageItem { |
178 | | /// A D-Bus array requires all elements to be of the same type. |
179 | | /// All elements must match the Signature. |
180 | | Array(MessageItemArray), |
181 | | /// A D-Bus struct allows for values of different types. |
182 | | Struct(Vec<MessageItem>), |
183 | | /// A D-Bus variant is a wrapper around another `MessageItem`, which |
184 | | /// can be of any type. |
185 | | Variant(Box<MessageItem>), |
186 | | /// A D-Bus dictionary. All keys and values are required to be of the same type. |
187 | | /// Not all types can be dictionary keys, but all can be dictionary values. |
188 | | Dict(MessageItemDict), |
189 | | /// A D-Bus objectpath requires its content to be a valid objectpath, |
190 | | /// so this cannot be any string. |
191 | | ObjectPath(Path<'static>), |
192 | | /// A D-Bus signature requires its content to be a valid type signature, |
193 | | /// so this cannot be any string. |
194 | | Signature(Signature<'static>), |
195 | | /// A D-Bus String is zero terminated, so no \0 s in the String, please. |
196 | | /// (D-Bus strings are also - like Rust strings - required to be valid UTF-8.) |
197 | | Str(String), |
198 | | /// A D-Bus boolean type. |
199 | | Bool(bool), |
200 | | /// A D-Bus unsigned 8 bit type. |
201 | | Byte(u8), |
202 | | /// A D-Bus signed 16 bit type. |
203 | | Int16(i16), |
204 | | /// A D-Bus signed 32 bit type. |
205 | | Int32(i32), |
206 | | /// A D-Bus signed 64 bit type. |
207 | | Int64(i64), |
208 | | /// A D-Bus unsigned 16 bit type. |
209 | | UInt16(u16), |
210 | | /// A D-Bus unsigned 32 bit type. |
211 | | UInt32(u32), |
212 | | /// A D-Bus unsigned 64 bit type. |
213 | | UInt64(u64), |
214 | | /// A D-Bus IEEE-754 double-precision floating point type. |
215 | | Double(f64), |
216 | | /// D-Bus allows for sending file descriptors, which can be used to |
217 | | /// set up SHM, unix pipes, or other communication channels. |
218 | | #[cfg(not(feature = "stdfd"))] |
219 | | UnixFd(OwnedFd), |
220 | | /// D-Bus allows for sending file descriptors, which can be used to |
221 | | /// set up SHM, unix pipes, or other communication channels. |
222 | | #[cfg(feature = "stdfd")] |
223 | | UnixFd(MessageItemFd), |
224 | | } |
225 | | |
226 | | impl MessageItem { |
227 | | /// Get the D-Bus Signature for this MessageItem. |
228 | 0 | pub fn signature(&self) -> Signature<'static> { |
229 | 0 | use crate::arg::Variant; |
230 | 0 | match self { |
231 | 0 | MessageItem::Str(_) => <String as Arg>::signature(), |
232 | 0 | MessageItem::Bool(_) => <bool as Arg>::signature(), |
233 | 0 | MessageItem::Byte(_) => <u8 as Arg>::signature(), |
234 | 0 | MessageItem::Int16(_) => <i16 as Arg>::signature(), |
235 | 0 | MessageItem::Int32(_) => <i32 as Arg>::signature(), |
236 | 0 | MessageItem::Int64(_) => <i64 as Arg>::signature(), |
237 | 0 | MessageItem::UInt16(_) => <u16 as Arg>::signature(), |
238 | 0 | MessageItem::UInt32(_) => <u32 as Arg>::signature(), |
239 | 0 | MessageItem::UInt64(_) => <u64 as Arg>::signature(), |
240 | 0 | MessageItem::Double(_) => <f64 as Arg>::signature(), |
241 | 0 | MessageItem::Array(ref a) => a.sig.clone(), |
242 | 0 | MessageItem::Struct(ref s) => Signature::new(format!("({})", s.iter().fold(String::new(), |s, i| s + &*i.signature()))).unwrap(), |
243 | 0 | MessageItem::Variant(_) => <Variant<u8> as Arg>::signature(), |
244 | 0 | MessageItem::Dict(ref a) => a.sig.clone(), |
245 | 0 | MessageItem::ObjectPath(_) => <Path as Arg>::signature(), |
246 | 0 | MessageItem::Signature(_) => <Signature as Arg>::signature(), |
247 | 0 | MessageItem::UnixFd(_) => <std::fs::File as Arg>::signature(), |
248 | | } |
249 | 0 | } |
250 | | |
251 | | /// Get the arg type of this MessageItem. |
252 | 0 | pub fn arg_type(&self) -> arg::ArgType { |
253 | 0 | match self { |
254 | 0 | MessageItem::Str(_) => ArgType::String, |
255 | 0 | MessageItem::Bool(_) => ArgType::Boolean, |
256 | 0 | MessageItem::Byte(_) => ArgType::Byte, |
257 | 0 | MessageItem::Int16(_) => ArgType::Int16, |
258 | 0 | MessageItem::Int32(_) => ArgType::Int32, |
259 | 0 | MessageItem::Int64(_) => ArgType::Int64, |
260 | 0 | MessageItem::UInt16(_) => ArgType::UInt16, |
261 | 0 | MessageItem::UInt32(_) => ArgType::UInt32, |
262 | 0 | MessageItem::UInt64(_) => ArgType::UInt64, |
263 | 0 | MessageItem::Double(_) => ArgType::Double, |
264 | 0 | MessageItem::Array(_) => ArgType::Array, |
265 | 0 | MessageItem::Struct(_) => ArgType::Struct, |
266 | 0 | MessageItem::Variant(_) => ArgType::Variant, |
267 | 0 | MessageItem::Dict(_) => ArgType::Array, |
268 | 0 | MessageItem::ObjectPath(_) => ArgType::ObjectPath, |
269 | 0 | MessageItem::Signature(_) => ArgType::Signature, |
270 | 0 | MessageItem::UnixFd(_) => ArgType::UnixFd, |
271 | | } |
272 | 0 | } |
273 | | |
274 | | /// Creates a (String, Variant) dictionary from an iterator with Result passthrough (an Err will abort and return that Err) |
275 | 0 | pub fn from_dict<E, I: Iterator<Item=Result<(String, MessageItem),E>>>(i: I) -> Result<MessageItem, E> { |
276 | 0 | let mut v = Vec::new(); |
277 | 0 | for r in i { |
278 | 0 | let (s, vv) = r?; |
279 | 0 | v.push((s.into(), Box::new(vv).into())); |
280 | | } |
281 | 0 | Ok(MessageItem::Dict(MessageItemDict::new(v, Signature::new("s").unwrap(), Signature::new("v").unwrap()).unwrap())) |
282 | 0 | } |
283 | | |
284 | | /// Creates an MessageItem::Array from a list of MessageItems. |
285 | | /// |
286 | | /// Note: This requires `v` to be non-empty. See also |
287 | | /// `MessageItem::from(&[T])`, which can handle empty arrays as well. |
288 | 0 | pub fn new_array(v: Vec<MessageItem>) -> Result<MessageItem, ArrayError> { |
289 | 0 | if v.is_empty() { |
290 | 0 | return Err(ArrayError::EmptyArray); |
291 | 0 | } |
292 | 0 | let s = MessageItemArray::make_sig(&v[0]); |
293 | 0 | Ok(MessageItem::Array(MessageItemArray::new(v, s)?)) |
294 | 0 | } |
295 | | |
296 | | /// Creates an MessageItem::Dict from a list of MessageItem pairs. |
297 | | /// |
298 | | /// Note: This requires `v` to be non-empty. See also |
299 | | /// `MessageItem::from(&[(T1, T2)])`, which can handle empty arrays as well. |
300 | 0 | pub fn new_dict(v: Vec<(MessageItem, MessageItem)>) -> Result<MessageItem, ArrayError> { |
301 | 0 | if v.is_empty() { |
302 | 0 | return Err(ArrayError::EmptyArray); |
303 | 0 | } |
304 | 0 | let (s1, s2) = (v[0].0.signature(), v[0].1.signature()); |
305 | 0 | Ok(MessageItem::Dict(MessageItemDict::new(v, s1, s2)?)) |
306 | 0 | } |
307 | | |
308 | | /// Get the inner value of a `MessageItem` |
309 | | /// |
310 | | /// # Example |
311 | | /// ``` |
312 | | /// use dbus::arg::messageitem::MessageItem; |
313 | | /// let m: MessageItem = 5i64.into(); |
314 | | /// let s: i64 = m.inner().unwrap(); |
315 | | /// assert_eq!(s, 5i64); |
316 | | /// ``` |
317 | 0 | pub fn inner<'a, T: TryFrom<&'a MessageItem>>(&'a self) -> Result<T, T::Error> { |
318 | 0 | T::try_from(self) |
319 | 0 | } Unexecuted instantiation: <dbus::arg::messageitem::MessageItem>::inner::<&alloc::vec::Vec<dbus::arg::messageitem::MessageItem>> Unexecuted instantiation: <dbus::arg::messageitem::MessageItem>::inner::<&[(dbus::arg::messageitem::MessageItem, dbus::arg::messageitem::MessageItem)]> Unexecuted instantiation: <dbus::arg::messageitem::MessageItem>::inner::<&alloc::string::String> Unexecuted instantiation: <dbus::arg::messageitem::MessageItem>::inner::<&alloc::boxed::Box<dbus::arg::messageitem::MessageItem>> |
320 | | |
321 | | /// Get the underlying `MessageItem` of a `MessageItem::Variant` |
322 | | /// |
323 | | /// Nested `MessageItem::Variant`s are unwrapped recursively until a |
324 | | /// non-`Variant` is found. |
325 | | /// |
326 | | /// # Example |
327 | | /// ``` |
328 | | /// use dbus::arg::messageitem::MessageItem; |
329 | | /// let nested = MessageItem::Variant(Box::new(6i64.into())); |
330 | | /// let flat: MessageItem = 6i64.into(); |
331 | | /// assert_ne!(&nested, &flat); |
332 | | /// assert_eq!(nested.peel(), &flat); |
333 | | /// ``` |
334 | 0 | pub fn peel(&self) -> &Self { |
335 | 0 | let mut current = self; |
336 | | |
337 | 0 | while let MessageItem::Variant(b) = current { |
338 | 0 | current = &*b; |
339 | 0 | } |
340 | | |
341 | 0 | current |
342 | 0 | } |
343 | | |
344 | 0 | fn new_array2<D, I>(i: I) -> MessageItem |
345 | 0 | where D: Into<MessageItem>, D: Default, I: Iterator<Item=D> { |
346 | 0 | let v: Vec<MessageItem> = i.map(|ii| ii.into()).collect(); |
347 | 0 | let s = { |
348 | 0 | let d; |
349 | 0 | let t = if v.is_empty() { d = D::default().into(); &d } else { &v[0] }; |
350 | 0 | MessageItemArray::make_sig(t) |
351 | 0 | }; |
352 | 0 | MessageItem::Array(MessageItemArray::new(v, s).unwrap()) |
353 | 0 | } |
354 | | |
355 | 0 | fn new_dict2<K, V, I>(i: I) -> MessageItem |
356 | 0 | where K: Into<MessageItem> + Default, V: Into<MessageItem> + Default, I: Iterator<Item=(K, V)> { |
357 | 0 | let v: Vec<(MessageItem, MessageItem)> = i.map(|(k, v)| (k.into(), v.into())).collect(); |
358 | 0 | let (kt, vt) = if v.is_empty() { |
359 | 0 | let kd = K::default().into(); |
360 | 0 | let vd = V::default().into(); |
361 | 0 | (kd.signature(), vd.signature()) |
362 | 0 | } else { (v[0].0.signature(), v[0].1.signature()) }; |
363 | 0 | MessageItem::Dict(MessageItemDict::new(v, kt, vt).unwrap()) |
364 | 0 | } |
365 | | } |
366 | | |
367 | | macro_rules! msgitem_convert { |
368 | | ($t: ty, $s: ident) => { |
369 | 0 | impl From<$t> for MessageItem { fn from(i: $t) -> MessageItem { MessageItem::$s(i) } } Unexecuted instantiation: <dbus::arg::messageitem::MessageItem as core::convert::From<i64>>::from Unexecuted instantiation: <dbus::arg::messageitem::MessageItem as core::convert::From<u32>>::from Unexecuted instantiation: <dbus::arg::messageitem::MessageItem as core::convert::From<i16>>::from Unexecuted instantiation: <dbus::arg::messageitem::MessageItem as core::convert::From<u64>>::from Unexecuted instantiation: <dbus::arg::messageitem::MessageItem as core::convert::From<f64>>::from Unexecuted instantiation: <dbus::arg::messageitem::MessageItem as core::convert::From<u16>>::from Unexecuted instantiation: <dbus::arg::messageitem::MessageItem as core::convert::From<u8>>::from Unexecuted instantiation: <dbus::arg::messageitem::MessageItem as core::convert::From<i32>>::from Unexecuted instantiation: <dbus::arg::messageitem::MessageItem as core::convert::From<bool>>::from |
370 | | |
371 | | impl<'a> TryFrom<&'a MessageItem> for $t { |
372 | | type Error = (); |
373 | 0 | fn try_from(i: &'a MessageItem) -> Result<$t,()> { |
374 | 0 | if let MessageItem::$s(b) = i.peel() { Ok(*b) } else { Err(()) } |
375 | 0 | } Unexecuted instantiation: <i16 as core::convert::TryFrom<&dbus::arg::messageitem::MessageItem>>::try_from Unexecuted instantiation: <u16 as core::convert::TryFrom<&dbus::arg::messageitem::MessageItem>>::try_from Unexecuted instantiation: <bool as core::convert::TryFrom<&dbus::arg::messageitem::MessageItem>>::try_from Unexecuted instantiation: <u64 as core::convert::TryFrom<&dbus::arg::messageitem::MessageItem>>::try_from Unexecuted instantiation: <i32 as core::convert::TryFrom<&dbus::arg::messageitem::MessageItem>>::try_from Unexecuted instantiation: <f64 as core::convert::TryFrom<&dbus::arg::messageitem::MessageItem>>::try_from Unexecuted instantiation: <u32 as core::convert::TryFrom<&dbus::arg::messageitem::MessageItem>>::try_from Unexecuted instantiation: <i64 as core::convert::TryFrom<&dbus::arg::messageitem::MessageItem>>::try_from Unexecuted instantiation: <u8 as core::convert::TryFrom<&dbus::arg::messageitem::MessageItem>>::try_from |
376 | | } |
377 | | } |
378 | | } |
379 | | |
380 | | msgitem_convert!(u8, Byte); |
381 | | msgitem_convert!(u64, UInt64); |
382 | | msgitem_convert!(u32, UInt32); |
383 | | msgitem_convert!(u16, UInt16); |
384 | | msgitem_convert!(i16, Int16); |
385 | | msgitem_convert!(i32, Int32); |
386 | | msgitem_convert!(i64, Int64); |
387 | | msgitem_convert!(f64, Double); |
388 | | msgitem_convert!(bool, Bool); |
389 | | |
390 | | |
391 | | |
392 | | /// Create a `MessageItem::Array`. |
393 | | impl<'a, T> From<&'a [T]> for MessageItem |
394 | | where T: Into<MessageItem> + Clone + Default { |
395 | 0 | fn from(i: &'a [T]) -> MessageItem { |
396 | 0 | MessageItem::new_array2(i.iter().cloned()) |
397 | 0 | } |
398 | | } |
399 | | |
400 | | /// Create a `MessageItem::Dict`. |
401 | | impl<'a, T1, T2> From<&'a [(T1, T2)]> for MessageItem |
402 | | where T1: Into<MessageItem> + Clone + Default, T2: Into<MessageItem> + Clone + Default { |
403 | 0 | fn from(i: &'a [(T1, T2)]) -> MessageItem { |
404 | 0 | MessageItem::new_dict2(i.iter().cloned()) |
405 | 0 | } |
406 | | } |
407 | | |
408 | 0 | impl<'a> From<&'a str> for MessageItem { fn from(i: &str) -> MessageItem { MessageItem::Str(i.to_string()) } } |
409 | | |
410 | 0 | impl From<String> for MessageItem { fn from(i: String) -> MessageItem { MessageItem::Str(i) } } |
411 | | |
412 | 0 | impl From<Path<'static>> for MessageItem { fn from(i: Path<'static>) -> MessageItem { MessageItem::ObjectPath(i) } } |
413 | | |
414 | 0 | impl From<Signature<'static>> for MessageItem { fn from(i: Signature<'static>) -> MessageItem { MessageItem::Signature(i) } } |
415 | | |
416 | | #[cfg(not(feature = "stdfd"))] |
417 | 0 | impl From<OwnedFd> for MessageItem { fn from(i: OwnedFd) -> MessageItem { MessageItem::UnixFd(i) } } |
418 | | |
419 | | #[cfg(unix)] |
420 | | impl From<std::fs::File> for MessageItem { |
421 | 0 | fn from(i: std::fs::File) -> MessageItem { |
422 | 0 | use std::os::unix::io::{FromRawFd, IntoRawFd}; |
423 | 0 | let fd = unsafe { OwnedFd::from_raw_fd(i.into_raw_fd()) }; |
424 | 0 | fd.into() |
425 | 0 | } |
426 | | } |
427 | | |
428 | | /// Create a `MessageItem::Variant` |
429 | | impl From<Box<MessageItem>> for MessageItem { |
430 | 0 | fn from(i: Box<MessageItem>) -> MessageItem { MessageItem::Variant(i) } |
431 | | } |
432 | | |
433 | | impl<'a> TryFrom<&'a MessageItem> for &'a str { |
434 | | type Error = (); |
435 | 0 | fn try_from(i: &'a MessageItem) -> Result<&'a str, Self::Error> { |
436 | 0 | match i.peel() { |
437 | 0 | MessageItem::Str(ref b) => Ok(b), |
438 | 0 | MessageItem::ObjectPath(ref b) => Ok(b), |
439 | 0 | MessageItem::Signature(ref b) => Ok(b), |
440 | 0 | _ => Err(()), |
441 | | } |
442 | 0 | } |
443 | | } |
444 | | |
445 | | impl<'a> TryFrom<&'a MessageItem> for &'a String { |
446 | | type Error = (); |
447 | 0 | fn try_from(i: &'a MessageItem) -> Result<&'a String,()> { if let MessageItem::Str(b) = i.peel() { Ok(b) } else { Err(()) } } |
448 | | } |
449 | | |
450 | | impl<'a> TryFrom<&'a MessageItem> for &'a Path<'static> { |
451 | | type Error = (); |
452 | 0 | fn try_from(i: &'a MessageItem) -> Result<&'a Path<'static>,()> { if let MessageItem::ObjectPath(b) = i.peel() { Ok(b) } else { Err(()) } } |
453 | | } |
454 | | |
455 | | impl<'a> TryFrom<&'a MessageItem> for &'a Signature<'static> { |
456 | | type Error = (); |
457 | 0 | fn try_from(i: &'a MessageItem) -> Result<&'a Signature<'static>,()> { if let MessageItem::Signature(b) = i.peel() { Ok(b) } else { Err(()) } } |
458 | | } |
459 | | |
460 | | impl<'a> TryFrom<&'a MessageItem> for &'a Box<MessageItem> { |
461 | | type Error = (); |
462 | 0 | fn try_from(i: &'a MessageItem) -> Result<&'a Box<MessageItem>,()> { if let MessageItem::Variant(b) = i { Ok(b) } else { Err(()) } } |
463 | | } |
464 | | |
465 | | impl<'a> TryFrom<&'a MessageItem> for &'a Vec<MessageItem> { |
466 | | type Error = (); |
467 | 0 | fn try_from(i: &'a MessageItem) -> Result<&'a Vec<MessageItem>,()> { |
468 | 0 | match i.peel() { |
469 | 0 | MessageItem::Array(b) => Ok(&b.v), |
470 | 0 | MessageItem::Struct(b) => Ok(b), |
471 | 0 | _ => Err(()), |
472 | | } |
473 | 0 | } |
474 | | } |
475 | | |
476 | | impl<'a> TryFrom<&'a MessageItem> for &'a [MessageItem] { |
477 | | type Error = (); |
478 | 0 | fn try_from(i: &'a MessageItem) -> Result<&'a [MessageItem],()> { i.inner::<&Vec<MessageItem>>().map(|s| &**s) } |
479 | | } |
480 | | |
481 | | #[cfg(not(feature = "stdfd"))] |
482 | | impl<'a> TryFrom<&'a MessageItem> for &'a OwnedFd { |
483 | | type Error = (); |
484 | 0 | fn try_from(i: &'a MessageItem) -> Result<&'a OwnedFd,()> { if let MessageItem::UnixFd(ref b) = i { Ok(b) } else { Err(()) } } |
485 | | } |
486 | | |
487 | | impl<'a> TryFrom<&'a MessageItem> for &'a [(MessageItem, MessageItem)] { |
488 | | type Error = (); |
489 | 0 | fn try_from(i: &'a MessageItem) -> Result<&'a [(MessageItem, MessageItem)],()> { |
490 | 0 | if let MessageItem::Dict(ref d) = i { Ok(&*d.v) } else { Err(()) } |
491 | 0 | } |
492 | | } |
493 | | |
494 | | |
495 | | impl arg::Append for MessageItem { |
496 | 0 | fn append_by_ref(&self, i: &mut IterAppend) { |
497 | 0 | match self { |
498 | 0 | MessageItem::Str(a) => a.append_by_ref(i), |
499 | 0 | MessageItem::Bool(a) => a.append_by_ref(i), |
500 | 0 | MessageItem::Byte(a) => a.append_by_ref(i), |
501 | 0 | MessageItem::Int16(a) => a.append_by_ref(i), |
502 | 0 | MessageItem::Int32(a) => a.append_by_ref(i), |
503 | 0 | MessageItem::Int64(a) => a.append_by_ref(i), |
504 | 0 | MessageItem::UInt16(a) => a.append_by_ref(i), |
505 | 0 | MessageItem::UInt32(a) => a.append_by_ref(i), |
506 | 0 | MessageItem::UInt64(a) => a.append_by_ref(i), |
507 | 0 | MessageItem::Double(a) => a.append_by_ref(i), |
508 | 0 | MessageItem::Array(a) => a.append_by_ref(i), |
509 | 0 | MessageItem::Struct(a) => i.append_container(ArgType::Struct, None, |s| { |
510 | 0 | for v in a { v.append_by_ref(s); } |
511 | 0 | }), |
512 | 0 | MessageItem::Variant(a) => { |
513 | 0 | i.append_container(ArgType::Variant, Some(a.signature().as_cstr()), |s| a.append_by_ref(s)) |
514 | | }, |
515 | 0 | MessageItem::Dict(a) => a.append_by_ref(i), |
516 | 0 | MessageItem::ObjectPath(a) => a.append_by_ref(i), |
517 | 0 | MessageItem::Signature(a) => a.append_by_ref(i), |
518 | | #[cfg(not(feature = "stdfd"))] |
519 | 0 | MessageItem::UnixFd(a) => a.append_by_ref(i), |
520 | | #[cfg(feature = "stdfd")] |
521 | | MessageItem::UnixFd(a) => a.0.append_by_ref(i), |
522 | | } |
523 | 0 | } |
524 | | } |
525 | | |
526 | | impl<'a> arg::Get<'a> for MessageItem { |
527 | 0 | fn get(i: &mut Iter<'a>) -> Option<Self> { |
528 | 0 | Some(match i.arg_type() { |
529 | | ArgType::Array => { |
530 | 0 | let mut s = i.recurse(ArgType::Array).unwrap(); |
531 | 0 | if i.signature().as_bytes()[1] == b'{' { // Dict |
532 | 0 | let mut v = vec!(); |
533 | 0 | while s.arg_type() == ArgType::DictEntry { |
534 | 0 | let mut ss = s.recurse(ArgType::DictEntry).unwrap(); |
535 | 0 | let kk = MessageItem::get(&mut ss).unwrap(); |
536 | 0 | ss.next(); |
537 | 0 | let vv = MessageItem::get(&mut ss).unwrap(); |
538 | 0 | v.push((kk, vv)); |
539 | 0 | s.next(); |
540 | 0 | }; |
541 | 0 | MessageItem::Dict(MessageItemDict { v: v, sig: i.signature() }) |
542 | | } else { |
543 | 0 | let mut v = vec!(); |
544 | 0 | while let Some(mi) = MessageItem::get(&mut s) { v.push(mi); s.next(); }; |
545 | 0 | MessageItem::Array(MessageItemArray { v: v, sig: i.signature() }) |
546 | | } |
547 | | }, |
548 | 0 | ArgType::Variant => MessageItem::Variant({ |
549 | 0 | let mut s = i.recurse(ArgType::Variant).unwrap(); |
550 | 0 | Box::new(MessageItem::get(&mut s).unwrap()) |
551 | 0 | }), |
552 | 0 | ArgType::Boolean => MessageItem::Bool(i.get::<bool>().unwrap()), |
553 | 0 | ArgType::Invalid => return None, |
554 | 0 | ArgType::String => MessageItem::Str(i.get::<String>().unwrap()), |
555 | 0 | ArgType::DictEntry => return None, |
556 | 0 | ArgType::Byte => MessageItem::Byte(i.get::<u8>().unwrap()), |
557 | 0 | ArgType::Int16 => MessageItem::Int16(i.get::<i16>().unwrap()), |
558 | 0 | ArgType::UInt16 => MessageItem::UInt16(i.get::<u16>().unwrap()), |
559 | 0 | ArgType::Int32 => MessageItem::Int32(i.get::<i32>().unwrap()), |
560 | 0 | ArgType::UInt32 => MessageItem::UInt32(i.get::<u32>().unwrap()), |
561 | 0 | ArgType::Int64 => MessageItem::Int64(i.get::<i64>().unwrap()), |
562 | 0 | ArgType::UInt64 => MessageItem::UInt64(i.get::<u64>().unwrap()), |
563 | 0 | ArgType::Double => MessageItem::Double(i.get::<f64>().unwrap()), |
564 | | #[cfg(not(feature = "stdfd"))] |
565 | 0 | ArgType::UnixFd => MessageItem::UnixFd(i.get::<OwnedFd>().unwrap()), |
566 | | #[cfg(feature = "stdfd")] |
567 | | ArgType::UnixFd => MessageItem::UnixFd(MessageItemFd(i.get::<OwnedFd>().unwrap())), |
568 | | ArgType::Struct => MessageItem::Struct({ |
569 | 0 | let mut s = i.recurse(ArgType::Struct).unwrap(); |
570 | 0 | let mut v = vec!(); |
571 | 0 | while let Some(mi) = MessageItem::get(&mut s) { v.push(mi); s.next(); }; |
572 | 0 | v |
573 | | }), |
574 | 0 | ArgType::ObjectPath => MessageItem::ObjectPath(i.get::<Path>().unwrap().into_static()), |
575 | 0 | ArgType::Signature => MessageItem::Signature(i.get::<Signature>().unwrap().into_static()), |
576 | | }) |
577 | 0 | } |
578 | | } |
579 | | |
580 | | impl arg::RefArg for MessageItem { |
581 | 0 | fn arg_type(&self) -> ArgType { MessageItem::arg_type(&self) } |
582 | 0 | fn signature(&self) -> Signature<'static> { MessageItem::signature(&self) } |
583 | 0 | fn append(&self, i: &mut IterAppend) { arg::Append::append_by_ref(self, i) } |
584 | | #[inline] |
585 | 0 | fn as_any(&self) -> &dyn any::Any where Self: 'static { self } |
586 | | #[inline] |
587 | 0 | fn as_any_mut(&mut self) -> &mut dyn any::Any where Self: 'static { self } |
588 | | #[inline] |
589 | 0 | fn box_clone(&self) -> Box<dyn arg::RefArg + 'static> { Box::new(self.clone()) } |
590 | | } |
591 | | |
592 | | |
593 | | impl arg::Append for arg::Variant<MessageItem> { |
594 | 0 | fn append_by_ref(&self, i: &mut IterAppend) { |
595 | 0 | let z = &self.0; |
596 | 0 | let asig = z.signature(); |
597 | 0 | let sig = asig.as_cstr(); |
598 | 0 | i.append_container(ArgType::Variant, Some(&sig), |s| z.append_by_ref(s)); |
599 | 0 | } |
600 | | } |
601 | | |
602 | | |
603 | | /// Client side properties - get and set properties on a remote application. |
604 | | pub struct Props<'a> { |
605 | | name: BusName<'a>, |
606 | | path: Path<'a>, |
607 | | interface: Interface<'a>, |
608 | | timeout_ms: i32, |
609 | | conn: &'a Connection, |
610 | | } |
611 | | |
612 | | impl<'a> Props<'a> { |
613 | | /// Create a new Props. |
614 | 0 | pub fn new<N, P, I>(conn: &'a Connection, name: N, path: P, interface: I, timeout_ms: i32) -> Props<'a> |
615 | 0 | where N: Into<BusName<'a>>, P: Into<Path<'a>>, I: Into<Interface<'a>> { |
616 | 0 | Props { |
617 | 0 | name: name.into(), |
618 | 0 | path: path.into(), |
619 | 0 | interface: interface.into(), |
620 | 0 | timeout_ms: timeout_ms, |
621 | 0 | conn: conn, |
622 | 0 | } |
623 | 0 | } |
624 | | |
625 | | /// Get a single property's value. |
626 | 0 | pub fn get(&self, propname: &str) -> Result<MessageItem, Error> { |
627 | 0 | let mut m = Message::method_call(&self.name, &self.path, |
628 | 0 | &"org.freedesktop.DBus.Properties".into(), &"Get".into()); |
629 | 0 | m.append_items(&[self.interface.to_string().into(), propname.to_string().into()]); |
630 | 0 | let mut r = self.conn.send_with_reply_and_block(m, self.timeout_ms)?; |
631 | 0 | let reply = r.as_result()?.get_items(); |
632 | 0 | if reply.len() == 1 { |
633 | 0 | if let MessageItem::Variant(ref v) = reply[0] { |
634 | 0 | return Ok((**v).clone()) |
635 | 0 | } |
636 | 0 | } |
637 | 0 | let f = format!("Invalid reply for property get {}: '{:?}'", propname, reply); |
638 | 0 | Err(Error::new_custom("InvalidReply", &f)) |
639 | 0 | } |
640 | | |
641 | | /// Set a single property's value. |
642 | 0 | pub fn set(&self, propname: &str, value: MessageItem) -> Result<(), Error> { |
643 | 0 | let mut m = Message::method_call(&self.name, &self.path, |
644 | 0 | &"org.freedesktop.DBus.Properties".into(), &"Set".into()); |
645 | 0 | m.append_items(&[self.interface.to_string().into(), propname.to_string().into(), Box::new(value).into()]); |
646 | 0 | let mut r = self.conn.send_with_reply_and_block(m, self.timeout_ms)?; |
647 | 0 | r.as_result()?; |
648 | 0 | Ok(()) |
649 | 0 | } |
650 | | |
651 | | /// Get a map of all the properties' names and their values. |
652 | 0 | pub fn get_all(&self) -> Result<BTreeMap<String, MessageItem>, Error> { |
653 | 0 | let mut m = Message::method_call(&self.name, &self.path, |
654 | 0 | &"org.freedesktop.DBus.Properties".into(), &"GetAll".into()); |
655 | 0 | m.append_items(&[self.interface.to_string().into()]); |
656 | 0 | let mut r = self.conn.send_with_reply_and_block(m, self.timeout_ms)?; |
657 | 0 | let reply = r.as_result()?.get_items(); |
658 | 0 |
|
659 | 0 | (|| { |
660 | 0 | if reply.len() != 1 { return Err(()) }; |
661 | 0 | let mut tree = BTreeMap::new(); |
662 | 0 | let a: &[(MessageItem, MessageItem)] = reply[0].inner()?; |
663 | 0 | for (k, v) in a.iter() { |
664 | 0 | let (k, v): (&String, &Box<MessageItem>) = (k.inner()?, v.inner()?); |
665 | 0 | tree.insert(k.clone(), *v.clone()); |
666 | | } |
667 | 0 | Ok(tree) |
668 | 0 | })().map_err(|_| { |
669 | 0 | let f = format!("Invalid reply for property GetAll: '{:?}'", reply); |
670 | 0 | Error::new_custom("InvalidReply", &f) |
671 | 0 | }) |
672 | 0 | } |
673 | | } |
674 | | |
675 | | /// Wrapper around Props that keeps a map of fetched properties. |
676 | | pub struct PropHandler<'a> { |
677 | | p: Props<'a>, |
678 | | map: BTreeMap<String, MessageItem>, |
679 | | } |
680 | | |
681 | | impl<'a> PropHandler<'a> { |
682 | | /// Create a new PropHandler from a Props. |
683 | 0 | pub fn new(p: Props) -> PropHandler { |
684 | 0 | PropHandler { p: p, map: BTreeMap::new() } |
685 | 0 | } |
686 | | |
687 | | /// Get a map of all the properties' names and their values. |
688 | 0 | pub fn get_all(&mut self) -> Result<(), Error> { |
689 | 0 | self.map = self.p.get_all()?; |
690 | 0 | Ok(()) |
691 | 0 | } |
692 | | |
693 | | /// Get a mutable reference to the PropHandler's fetched properties. |
694 | 0 | pub fn map_mut(&mut self) -> &mut BTreeMap<String, MessageItem> { &mut self.map } |
695 | | |
696 | | /// Get a reference to the PropHandler's fetched properties. |
697 | 0 | pub fn map(&self) -> &BTreeMap<String, MessageItem> { &self.map } |
698 | | |
699 | | /// Get a single property's value. |
700 | 0 | pub fn get(&mut self, propname: &str) -> Result<&MessageItem, Error> { |
701 | 0 | let v = self.p.get(propname)?; |
702 | 0 | self.map.insert(propname.to_string(), v); |
703 | 0 | Ok(self.map.get(propname).unwrap()) |
704 | 0 | } |
705 | | |
706 | | /// Set a single property's value. |
707 | 0 | pub fn set(&mut self, propname: &str, value: MessageItem) -> Result<(), Error> { |
708 | 0 | self.p.set(propname, value.clone())?; |
709 | 0 | self.map.insert(propname.to_string(), value); |
710 | 0 | Ok(()) |
711 | 0 | } |
712 | | } |
713 | | |
714 | | |
715 | | #[cfg(test)] |
716 | | mod test { |
717 | | extern crate tempfile; |
718 | | |
719 | | use crate::{Message, MessageType, Path, Signature}; |
720 | | use crate::arg::messageitem::MessageItem; |
721 | | use crate::ffidisp::{Connection, BusType}; |
722 | | |
723 | | #[test] |
724 | | fn unix_fd() { |
725 | | use std::io::prelude::*; |
726 | | use std::io::SeekFrom; |
727 | | use std::fs::OpenOptions; |
728 | | |
729 | | let c = Connection::get_private(BusType::Session).unwrap(); |
730 | | c.register_object_path("/hello").unwrap(); |
731 | | let mut m = Message::new_method_call(&c.unique_name(), "/hello", "com.example.hello", "Hello").unwrap(); |
732 | | let tempdir = tempfile::Builder::new().prefix("dbus-rs-test").tempdir().unwrap(); |
733 | | let mut filename = tempdir.path().to_path_buf(); |
734 | | filename.push("test"); |
735 | | println!("Creating file {:?}", filename); |
736 | | let mut file = OpenOptions::new().create(true).read(true).write(true).open(&filename).unwrap(); |
737 | | file.write_all(b"z").unwrap(); |
738 | | file.seek(SeekFrom::Start(0)).unwrap(); |
739 | | #[cfg(unix)] |
740 | | { |
741 | | m.append_items(&[file.into()]); |
742 | | } |
743 | | println!("Sending {:?}", m.get_items()); |
744 | | c.send(m).unwrap(); |
745 | | |
746 | | loop { for n in c.incoming(1000) { |
747 | | if n.msg_type() == MessageType::MethodCall { |
748 | | #[cfg(unix)] |
749 | | { |
750 | | use std::os::unix::io::AsRawFd; |
751 | | let z: crate::arg::OwnedFd = n.read1().unwrap(); |
752 | | println!("Got {:?}", z); |
753 | | let mut q: libc::c_char = 100; |
754 | | assert_eq!(1, unsafe { libc::read(z.as_raw_fd(), &mut q as *mut _ as *mut libc::c_void, 1) }); |
755 | | assert_eq!(q, 'z' as libc::c_char); |
756 | | } |
757 | | return; |
758 | | } else { |
759 | | println!("Got {:?}", n); |
760 | | } |
761 | | }} |
762 | | } |
763 | | |
764 | | #[test] |
765 | | fn message_types() { |
766 | | let c = Connection::get_private(BusType::Session).unwrap(); |
767 | | c.register_object_path("/hello").unwrap(); |
768 | | let mut m = Message::new_method_call(&c.unique_name(), "/hello", "com.example.hello", "Hello").unwrap(); |
769 | | m.append_items(&[ |
770 | | 2000u16.into(), |
771 | | MessageItem::new_array(vec!(129u8.into())).unwrap(), |
772 | | ["Hello", "world"][..].into(), |
773 | | 987654321u64.into(), |
774 | | (-1i32).into(), |
775 | | format!("Hello world").into(), |
776 | | (-3.14f64).into(), |
777 | | MessageItem::Struct(vec!(256i16.into())), |
778 | | Path::new("/some/path").unwrap().into(), |
779 | | MessageItem::new_dict(vec!((123543u32.into(), true.into()).into())).unwrap() |
780 | | ]); |
781 | | let sending = format!("{:?}", m.get_items()); |
782 | | println!("Sending {}", sending); |
783 | | c.send(m).unwrap(); |
784 | | |
785 | | loop { for n in c.incoming(1000) { |
786 | | if n.msg_type() == MessageType::MethodCall { |
787 | | let receiving = format!("{:?}", n.get_items()); |
788 | | println!("Receiving {}", receiving); |
789 | | assert_eq!(sending, receiving); |
790 | | return; |
791 | | } else { |
792 | | println!("Got {:?}", n); |
793 | | } |
794 | | }} |
795 | | } |
796 | | |
797 | | #[test] |
798 | | fn dict_of_dicts() { |
799 | | use std::collections::BTreeMap; |
800 | | |
801 | | let officeactions: BTreeMap<&'static str, MessageItem> = BTreeMap::new(); |
802 | | let mut officethings = BTreeMap::new(); |
803 | | officethings.insert("pencil", 2u16.into()); |
804 | | officethings.insert("paper", 5u16.into()); |
805 | | let mut homethings = BTreeMap::new(); |
806 | | homethings.insert("apple", 11u16.into()); |
807 | | let mut homeifaces = BTreeMap::new(); |
808 | | homeifaces.insert("getThings", homethings); |
809 | | let mut officeifaces = BTreeMap::new(); |
810 | | officeifaces.insert("getThings", officethings); |
811 | | officeifaces.insert("getActions", officeactions); |
812 | | let mut paths = BTreeMap::new(); |
813 | | paths.insert("/hello/office", officeifaces); |
814 | | paths.insert("/hello/home", homeifaces); |
815 | | |
816 | | println!("Original treemap: {:?}", paths); |
817 | | let m = MessageItem::new_dict(paths.iter().map( |
818 | | |(path, ifaces)| (MessageItem::ObjectPath(Path::new(*path).unwrap()), |
819 | | MessageItem::new_dict(ifaces.iter().map( |
820 | | |(iface, props)| (iface.to_string().into(), |
821 | | MessageItem::from_dict::<(),_>(props.iter().map( |
822 | | |(name, value)| Ok((name.to_string(), value.clone())) |
823 | | )).unwrap() |
824 | | ).into() |
825 | | ).collect()).unwrap() |
826 | | ).into() |
827 | | ).collect()).unwrap(); |
828 | | println!("As MessageItem: {:?}", m); |
829 | | assert_eq!(&*m.signature(), "a{oa{sa{sv}}}"); |
830 | | |
831 | | let c = Connection::get_private(BusType::Session).unwrap(); |
832 | | c.register_object_path("/hello").unwrap(); |
833 | | let mut msg = Message::new_method_call(&c.unique_name(), "/hello", "org.freedesktop.DBusObjectManager", "GetManagedObjects").unwrap(); |
834 | | msg.append_items(&[m]); |
835 | | let sending = format!("{:?}", msg.get_items()); |
836 | | println!("Sending {}", sending); |
837 | | c.send(msg).unwrap(); |
838 | | |
839 | | loop { for n in c.incoming(1000) { |
840 | | if n.msg_type() == MessageType::MethodCall { |
841 | | let receiving = format!("{:?}", n.get_items()); |
842 | | println!("Receiving {}", receiving); |
843 | | assert_eq!(sending, receiving); |
844 | | return; |
845 | | } else { |
846 | | println!("Got {:?}", n); |
847 | | } |
848 | | } } |
849 | | } |
850 | | |
851 | | #[test] |
852 | | fn issue24() { |
853 | | let c = Connection::get_private(BusType::Session).unwrap(); |
854 | | let mut m = Message::new_method_call("org.test.rust", "/", "org.test.rust", "Test").unwrap(); |
855 | | |
856 | | let a = MessageItem::from("test".to_string()); |
857 | | let b = MessageItem::from("test".to_string()); |
858 | | let foo = MessageItem::Struct(vec!(a, b)); |
859 | | let bar = foo.clone(); |
860 | | |
861 | | let args = [MessageItem::new_array(vec!(foo, bar)).unwrap()]; |
862 | | println!("{:?}", args); |
863 | | |
864 | | m.append_items(&args); |
865 | | c.send(m).unwrap(); |
866 | | } |
867 | | |
868 | | /* Unfortunately org.freedesktop.DBus has no properties we can use for testing, but hostname1 should be around on most distros. */ |
869 | | #[cfg(unix)] |
870 | | #[test] |
871 | | fn test_get_hostname1_prop() { |
872 | | use super::Props; |
873 | | |
874 | | let c = Connection::new_system().unwrap(); |
875 | | let p = Props::new(&c, "org.freedesktop.hostname1", "/org/freedesktop/hostname1", |
876 | | "org.freedesktop.hostname1", 10000); |
877 | | |
878 | | /* Let's use both the get and getall methods and see if we get the same result */ |
879 | | let v = p.get("StaticHostname").unwrap(); |
880 | | let vall = p.get_all().unwrap(); |
881 | | let v2 = vall.get("StaticHostname").unwrap(); |
882 | | |
883 | | assert_eq!(&v, &*v2); |
884 | | match v { |
885 | | MessageItem::Str(ref s) => { println!("StaticHostname is {}", s); } |
886 | | _ => { panic!("Invalid Get: {:?}", v); } |
887 | | }; |
888 | | } |
889 | | |
890 | | #[test] |
891 | | fn message_listnames() { |
892 | | let c = Connection::get_private(BusType::Session).unwrap(); |
893 | | let m = Message::method_call(&"org.freedesktop.DBus".into(), &"/".into(), |
894 | | &"org.freedesktop.DBus".into(), &"ListNames".into()); |
895 | | let r = c.send_with_reply_and_block(m, 2000).unwrap(); |
896 | | let reply = r.get_items(); |
897 | | println!("{:?}", reply); |
898 | | } |
899 | | |
900 | | #[test] |
901 | | fn message_namehasowner() { |
902 | | let c = Connection::get_private(BusType::Session).unwrap(); |
903 | | let mut m = Message::new_method_call("org.freedesktop.DBus", "/", "org.freedesktop.DBus", "NameHasOwner").unwrap(); |
904 | | m.append_items(&[MessageItem::Str("org.freedesktop.DBus".to_string())]); |
905 | | let r = c.send_with_reply_and_block(m, 2000).unwrap(); |
906 | | let reply = r.get_items(); |
907 | | println!("{:?}", reply); |
908 | | assert_eq!(reply, vec!(MessageItem::Bool(true))); |
909 | | } |
910 | | |
911 | | #[test] |
912 | | fn message_inner_str() { |
913 | | let ob = MessageItem::ObjectPath("/path".into()); |
914 | | assert_eq!("/path", ob.inner::<&str>().unwrap()); |
915 | | |
916 | | let ob = MessageItem::ObjectPath("/path".into()); |
917 | | assert_ne!("/path/another", ob.inner::<&str>().unwrap()); |
918 | | |
919 | | let ob = MessageItem::Str("String".into()); |
920 | | assert_eq!("String", ob.inner::<&str>().unwrap()); |
921 | | |
922 | | let ob = MessageItem::Str("String".into()); |
923 | | assert_ne!("StringDiff", ob.inner::<&str>().unwrap()); |
924 | | |
925 | | let ob = MessageItem::Signature(Signature::make::<i32>()); |
926 | | assert_eq!("i", ob.inner::<&str>().unwrap()); |
927 | | |
928 | | let ob = MessageItem::Signature(Signature::make::<u32>()); |
929 | | assert_ne!("i", ob.inner::<&str>().unwrap()); |
930 | | |
931 | | } |
932 | | |
933 | | #[test] |
934 | | fn message_peel() { |
935 | | let flat_str = MessageItem::Str("foobar".into()); |
936 | | assert_eq!(flat_str.peel(), &flat_str); |
937 | | |
938 | | let flat_path = MessageItem::ObjectPath("/path".into()); |
939 | | assert_eq!(flat_path.peel(), &flat_path); |
940 | | |
941 | | let flat_sig = MessageItem::Signature(Signature::make::<i32>()); |
942 | | assert_eq!(flat_sig.peel(), &flat_sig); |
943 | | |
944 | | let flat_int = MessageItem::Int32(1234); |
945 | | assert_eq!(flat_int.peel(), &flat_int); |
946 | | |
947 | | let layered_str = MessageItem::Variant(Box::new(flat_str)); |
948 | | assert_eq!(layered_str.peel(), &MessageItem::Str("foobar".into())); |
949 | | |
950 | | let layered_path = MessageItem::Variant(Box::new(flat_path)); |
951 | | assert_eq!(layered_path.peel(), &MessageItem::ObjectPath("/path".into())); |
952 | | |
953 | | let layered_sig = MessageItem::Variant(Box::new(flat_sig)); |
954 | | assert_eq!(layered_sig.peel(), &MessageItem::Signature(Signature::make::<i32>())); |
955 | | |
956 | | let layered_int = MessageItem::Variant(Box::new(flat_int)); |
957 | | assert_eq!(layered_int.peel(), &MessageItem::Int32(1234)); |
958 | | |
959 | | let very_deep = |
960 | | MessageItem::Variant(Box::new( |
961 | | MessageItem::Variant(Box::new( |
962 | | MessageItem::Variant(Box::new( |
963 | | MessageItem::Variant(Box::new( |
964 | | MessageItem::Variant(Box::new( |
965 | | MessageItem::Variant(Box::new( |
966 | | MessageItem::Variant(Box::new( |
967 | | MessageItem::Variant(Box::new( |
968 | | MessageItem::Variant(Box::new( |
969 | | MessageItem::Variant(Box::new( |
970 | | MessageItem::Int32(1234) |
971 | | )))))))))))))))))))); |
972 | | |
973 | | assert_eq!(very_deep.peel(), &MessageItem::Int32(1234)); |
974 | | |
975 | | } |
976 | | |
977 | | #[test] |
978 | | fn inner_from_variant() { |
979 | | let msg_u8 = MessageItem::Variant(Box::new(3u8.into())); |
980 | | assert_eq!(msg_u8.inner::<u8>().unwrap(), 3u8); |
981 | | |
982 | | let msg_u16 = MessageItem::Variant(Box::new(4u16.into())); |
983 | | assert_eq!(msg_u16.inner::<u16>().unwrap(), 4u16); |
984 | | |
985 | | let msg_u32 = MessageItem::Variant(Box::new(5u32.into())); |
986 | | assert_eq!(msg_u32.inner::<u32>().unwrap(), 5u32); |
987 | | |
988 | | let msg_u64 = MessageItem::Variant(Box::new(6u64.into())); |
989 | | assert_eq!(msg_u64.inner::<u64>().unwrap(), 6u64); |
990 | | |
991 | | let msg_i16 = MessageItem::Variant(Box::new(4i16.into())); |
992 | | assert_eq!(msg_i16.inner::<i16>().unwrap(), 4i16); |
993 | | |
994 | | let msg_i32 = MessageItem::Variant(Box::new(5i32.into())); |
995 | | assert_eq!(msg_i32.inner::<i32>().unwrap(), 5i32); |
996 | | |
997 | | let msg_i64 = MessageItem::Variant(Box::new(6i64.into())); |
998 | | assert_eq!(msg_i64.inner::<i64>().unwrap(), 6i64); |
999 | | |
1000 | | let msg_f64 = MessageItem::Variant(Box::new(6.5f64.into())); |
1001 | | assert_eq!(msg_f64.inner::<f64>().unwrap(), 6.5f64); |
1002 | | |
1003 | | let msg_bool = MessageItem::Variant(Box::new(false.into())); |
1004 | | assert_eq!(msg_bool.inner::<bool>().unwrap(), false); |
1005 | | |
1006 | | let msg_string = MessageItem::Variant(Box::new("asdf".to_string().into())); |
1007 | | assert_eq!(msg_string.inner::<&String>().unwrap(), "asdf"); |
1008 | | |
1009 | | let path: Path = "/path".into(); |
1010 | | let msg_path = MessageItem::Variant(Box::new(MessageItem::ObjectPath(path.clone()))); |
1011 | | assert_eq!(msg_path.inner::<&Path>().unwrap(), &path); |
1012 | | |
1013 | | let sig: Signature = "a{si}".into(); |
1014 | | let msg_sig = MessageItem::Variant(Box::new(MessageItem::Signature(sig.clone()))); |
1015 | | assert_eq!(msg_sig.inner::<&Signature>().unwrap(), &sig); |
1016 | | |
1017 | | assert_eq!(msg_string.inner::<&str>().unwrap(), "asdf"); |
1018 | | assert_eq!(msg_path.inner::<&str>().unwrap(), "/path"); |
1019 | | assert_eq!(msg_sig.inner::<&str>().unwrap(), "a{si}"); |
1020 | | |
1021 | | } |
1022 | | |
1023 | | } |