blob: ab57d71947be38d35ed34c624cb10a095276b33c [file] [log] [blame]
use core::any::Any;
use dbus_macros::{dbus_propmap, generate_dbus_arg};
use dbus::arg::{Arg, ArgType, IterAppend, RefArg};
use dbus::Signature;
generate_dbus_arg!();
#[derive(Debug, Default, Clone, PartialEq)]
struct OtherStruct {
address: String,
}
#[dbus_propmap(OtherStruct)]
struct OtherStructDBus {
address: String,
}
#[derive(Debug, Default, Clone, PartialEq)]
struct SomeStruct {
name: String,
number: i32,
other_struct: OtherStruct,
bytes: Vec<u8>,
nested: Vec<Vec<String>>,
recursive: Vec<SomeStruct>,
}
#[dbus_propmap(SomeStruct)]
struct SomeStructDBus {
name: String,
number: i32,
other_struct: OtherStruct,
bytes: Vec<u8>,
nested: Vec<Vec<String>>,
recursive: Vec<SomeStruct>,
}
// Pretends to be a D-Bus dictionary.
#[derive(Debug)]
struct FakeDictionary {
items: Vec<(String, Box<dyn RefArg>)>,
}
impl RefArg for FakeDictionary {
fn arg_type(&self) -> ArgType {
todo!()
}
fn signature(&self) -> dbus::Signature<'static> {
todo!()
}
fn append(&self, _: &mut IterAppend<'_>) {
todo!()
}
fn as_any(&self) -> &(dyn Any + 'static) {
todo!()
}
fn as_any_mut(&mut self) -> &mut (dyn Any + 'static) {
todo!()
}
fn box_clone(&self) -> Box<dyn RefArg + 'static> {
Box::new(FakeDictionary {
items: self.items.iter().map(|(k, v)| (k.clone(), v.box_clone())).collect(),
})
}
fn as_iter<'b>(&'b self) -> Option<Box<dyn Iterator<Item = &'b dyn RefArg> + 'b>> {
Some(Box::new(
self.items
.iter()
.flat_map(|(k, v)| vec![k as &dyn RefArg, v as &dyn RefArg].into_iter()),
))
}
}
impl Arg for FakeDictionary {
const ARG_TYPE: ArgType = ArgType::Array;
fn signature() -> dbus::Signature<'static> {
Signature::from("a{sv}")
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_dbus_propmap_error() {
let data_dbus = String::from("some data");
let result = <dbus::arg::PropMap as RefArgToRust>::ref_arg_to_rust(
&data_dbus,
String::from("Some Variable"),
);
assert!(result.is_err());
assert_eq!("Some Variable is not iterable", result.unwrap_err().to_string());
}
#[test]
fn test_dbus_propmap_success() {
let data_dbus = FakeDictionary {
items: vec![
(String::from("name"), Box::new(String::from("foo"))),
(String::from("number"), Box::new(100)),
(
String::from("other_struct"),
Box::new(FakeDictionary {
items: vec![(
String::from("address"),
Box::new(String::from("aa:bb:cc:dd:ee:ff")),
)],
}),
),
(String::from("bytes"), Box::new(vec![1 as u8, 2, 3])),
(
String::from("nested"),
Box::new(vec![
vec![
String::from("string a"),
String::from("string b"),
String::from("string c"),
],
vec![String::from("string 1"), String::from("string 2")],
]),
),
(
String::from("recursive"),
Box::new(vec![FakeDictionary {
items: vec![
(String::from("name"), Box::new(String::from("bar"))),
(String::from("number"), Box::new(200)),
(
String::from("other_struct"),
Box::new(FakeDictionary {
items: vec![(
String::from("address"),
Box::new(String::from("xx")),
)],
}),
),
(String::from("bytes"), Box::new(Vec::<u8>::new())),
(String::from("nested"), Box::new(Vec::<Vec<u8>>::new())),
(String::from("recursive"), Box::new(Vec::<FakeDictionary>::new())),
],
}]),
),
],
};
let result = <dbus::arg::PropMap as RefArgToRust>::ref_arg_to_rust(
&data_dbus,
String::from("Some Variable"),
);
assert!(result.is_ok());
let result = result.unwrap();
let result_struct = <SomeStruct as DBusArg>::from_dbus(result, None, None, None).unwrap();
let expected_struct = SomeStruct {
name: String::from("foo"),
number: 100,
other_struct: OtherStruct { address: String::from("aa:bb:cc:dd:ee:ff") },
bytes: vec![1, 2, 3],
nested: vec![
vec![String::from("string a"), String::from("string b"), String::from("string c")],
vec![String::from("string 1"), String::from("string 2")],
],
recursive: vec![SomeStruct {
name: String::from("bar"),
number: 200,
other_struct: OtherStruct { address: String::from("xx") },
bytes: vec![],
nested: vec![],
recursive: vec![],
}],
};
assert_eq!(expected_struct, result_struct);
}
}