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