1 use core::any::Any;
2 use std::collections::HashMap;
3 
4 use dbus_macros::{dbus_propmap, generate_dbus_arg};
5 
6 use dbus::arg::{Arg, ArgType, IterAppend};
7 use dbus::Signature;
8 
9 generate_dbus_arg!();
10 
11 #[derive(Debug, Default, Clone, PartialEq)]
12 struct OtherStruct {
13     address: String,
14 }
15 
16 #[dbus_propmap(OtherStruct)]
17 struct OtherStructDBus {
18     address: String,
19 }
20 
21 #[derive(Debug, Default, Clone, PartialEq)]
22 struct SomeStruct {
23     name: String,
24     number: i32,
25     other_struct: OtherStruct,
26     bytes: Vec<u8>,
27     dict: HashMap<String, Vec<i32>>,
28     nested: Vec<Vec<String>>,
29     recursive: Vec<SomeStruct>,
30 }
31 
32 #[dbus_propmap(SomeStruct)]
33 struct SomeStructDBus {
34     name: String,
35     number: i32,
36     other_struct: OtherStruct,
37     bytes: Vec<u8>,
38     dict: HashMap<String, Vec<i32>>,
39     nested: Vec<Vec<String>>,
40     recursive: Vec<SomeStruct>,
41 }
42 
43 // Pretends to be a D-Bus dictionary.
44 #[derive(Debug)]
45 struct FakeDictionary {
46     items: Vec<(String, Box<dyn RefArg>)>,
47 }
48 
49 impl RefArg for FakeDictionary {
arg_type(&self) -> ArgType50     fn arg_type(&self) -> ArgType {
51         todo!()
52     }
signature(&self) -> dbus::Signature<'static>53     fn signature(&self) -> dbus::Signature<'static> {
54         todo!()
55     }
append(&self, _: &mut IterAppend<'_>)56     fn append(&self, _: &mut IterAppend<'_>) {
57         todo!()
58     }
as_any(&self) -> &(dyn Any + 'static)59     fn as_any(&self) -> &(dyn Any + 'static) {
60         todo!()
61     }
as_any_mut(&mut self) -> &mut (dyn Any + 'static)62     fn as_any_mut(&mut self) -> &mut (dyn Any + 'static) {
63         todo!()
64     }
box_clone(&self) -> Box<dyn RefArg + 'static>65     fn box_clone(&self) -> Box<dyn RefArg + 'static> {
66         Box::new(FakeDictionary {
67             items: self.items.iter().map(|(k, v)| (k.clone(), v.box_clone())).collect(),
68         })
69     }
70 
as_iter<'b>(&'b self) -> Option<Box<dyn Iterator<Item = &'b dyn RefArg> + 'b>>71     fn as_iter<'b>(&'b self) -> Option<Box<dyn Iterator<Item = &'b dyn RefArg> + 'b>> {
72         Some(Box::new(
73             self.items
74                 .iter()
75                 .flat_map(|(k, v)| vec![k as &dyn RefArg, v as &dyn RefArg].into_iter()),
76         ))
77     }
78 }
79 
80 impl Arg for FakeDictionary {
81     const ARG_TYPE: ArgType = ArgType::Array;
signature() -> dbus::Signature<'static>82     fn signature() -> dbus::Signature<'static> {
83         Signature::from("a{sv}")
84     }
85 }
86 
87 #[cfg(test)]
88 mod tests {
89     use super::*;
90 
91     #[test]
test_dbus_propmap_error()92     fn test_dbus_propmap_error() {
93         let data_dbus = String::from("some data");
94         let result = <dbus::arg::PropMap as RefArgToRust>::ref_arg_to_rust(
95             &data_dbus,
96             String::from("Some Variable"),
97         );
98         assert!(result.is_err());
99         assert_eq!("Some Variable is not iterable", result.unwrap_err().to_string());
100     }
101 
wrap_variant<T: 'static + dbus::arg::RefArg>(data: T) -> Box<dyn RefArg>102     fn wrap_variant<T: 'static + dbus::arg::RefArg>(data: T) -> Box<dyn RefArg> {
103         Box::new(dbus::arg::Variant(data))
104     }
105 
106     #[test]
test_dbus_propmap_success()107     fn test_dbus_propmap_success() {
108         let data_dbus = FakeDictionary {
109             items: vec![
110                 (String::from("name"), wrap_variant(String::from("foo"))),
111                 (String::from("number"), wrap_variant(100)),
112                 (
113                     String::from("other_struct"),
114                     wrap_variant(FakeDictionary {
115                         items: vec![(
116                             String::from("address"),
117                             wrap_variant(String::from("aa:bb:cc:dd:ee:ff")),
118                         )],
119                     }),
120                 ),
121                 (String::from("bytes"), wrap_variant(vec![1 as u8, 2, 3])),
122                 (
123                     String::from("dict"),
124                     wrap_variant(HashMap::from([
125                         (String::from("key-0"), Box::new(vec![5, 6, 7, 8])),
126                         (String::from("key-1"), Box::new(vec![-5, -6, -7, -8])),
127                     ])),
128                 ),
129                 (
130                     String::from("nested"),
131                     wrap_variant(vec![
132                         vec![
133                             String::from("string a"),
134                             String::from("string b"),
135                             String::from("string c"),
136                         ],
137                         vec![String::from("string 1"), String::from("string 2")],
138                     ]),
139                 ),
140                 (
141                     String::from("recursive"),
142                     wrap_variant(vec![FakeDictionary {
143                         items: vec![
144                             (String::from("name"), wrap_variant(String::from("bar"))),
145                             (String::from("number"), wrap_variant(200)),
146                             (
147                                 String::from("other_struct"),
148                                 wrap_variant(FakeDictionary {
149                                     items: vec![(
150                                         String::from("address"),
151                                         wrap_variant(String::from("xx")),
152                                     )],
153                                 }),
154                             ),
155                             (String::from("bytes"), wrap_variant(Vec::<u8>::new())),
156                             (
157                                 String::from("dict"),
158                                 wrap_variant(HashMap::from([
159                                     (String::from("key-2"), Box::new(vec![5, 5, 6, 8, 8])),
160                                     (String::from("key-3"), Box::new(vec![])),
161                                 ])),
162                             ),
163                             (String::from("nested"), wrap_variant(Vec::<Vec<u8>>::new())),
164                             (String::from("recursive"), wrap_variant(Vec::<FakeDictionary>::new())),
165                         ],
166                     }]),
167                 ),
168             ],
169         };
170         let result = <dbus::arg::PropMap as RefArgToRust>::ref_arg_to_rust(
171             &data_dbus,
172             String::from("Some Variable"),
173         );
174         assert!(result.is_ok());
175         let result = result.unwrap();
176         let result_struct = <SomeStruct as DBusArg>::from_dbus(result, None, None, None).unwrap();
177         let expected_struct = SomeStruct {
178             name: String::from("foo"),
179             number: 100,
180             other_struct: OtherStruct { address: String::from("aa:bb:cc:dd:ee:ff") },
181             bytes: vec![1, 2, 3],
182             dict: HashMap::from([
183                 (String::from("key-0"), vec![5, 6, 7, 8]),
184                 (String::from("key-1"), vec![-5, -6, -7, -8]),
185             ]),
186             nested: vec![
187                 vec![String::from("string a"), String::from("string b"), String::from("string c")],
188                 vec![String::from("string 1"), String::from("string 2")],
189             ],
190             recursive: vec![SomeStruct {
191                 name: String::from("bar"),
192                 number: 200,
193                 other_struct: OtherStruct { address: String::from("xx") },
194                 bytes: vec![],
195                 dict: HashMap::from([
196                     (String::from("key-2"), vec![5, 5, 6, 8, 8]),
197                     (String::from("key-3"), vec![]),
198                 ]),
199                 nested: vec![],
200                 recursive: vec![],
201             }],
202         };
203         assert_eq!(expected_struct, result_struct);
204     }
205 }
206