diff --git a/system/gd/rust/linux/dbus_projection/Cargo.toml b/system/gd/rust/linux/dbus_projection/Cargo.toml index 166d9288af58b17375b366eadd9c4de161ed1eeb..3cac0d889ccbfb6366dbcd986752fa54a97cb9c1 100644 --- a/system/gd/rust/linux/dbus_projection/Cargo.toml +++ b/system/gd/rust/linux/dbus_projection/Cargo.toml @@ -4,4 +4,6 @@ version = "0.1.0" edition = "2018" [dependencies] +dbus_macros = { path = "dbus_macros" } dbus = "0.9.2" +dbus-tokio = "0.7.3" diff --git a/system/gd/rust/linux/dbus_projection/dbus_macros/Cargo.toml b/system/gd/rust/linux/dbus_projection/dbus_macros/Cargo.toml index 84585d8d4c264e4168e768ba30d9c15410510170..997a11b354023c535b6f84ca8ac3c92268877c54 100644 --- a/system/gd/rust/linux/dbus_projection/dbus_macros/Cargo.toml +++ b/system/gd/rust/linux/dbus_projection/dbus_macros/Cargo.toml @@ -7,6 +7,6 @@ edition = "2018" proc-macro = true [dependencies] -syn = "1.0" +syn = { version = "1.0.58", features = ['default', 'full'] } quote = "1.0" proc-macro2 = "1.0" diff --git a/system/gd/rust/linux/dbus_projection/dbus_macros/src/lib.rs b/system/gd/rust/linux/dbus_projection/dbus_macros/src/lib.rs index 9f06c5aa824ca69ce7db0000cd366356f6961e7f..aa4399ed302673793358763de0bce8c5c98ff7cd 100644 --- a/system/gd/rust/linux/dbus_projection/dbus_macros/src/lib.rs +++ b/system/gd/rust/linux/dbus_projection/dbus_macros/src/lib.rs @@ -183,13 +183,13 @@ pub fn generate_dbus_exporter(attr: TokenStream, item: TokenStream) -> TokenStre pub fn #fn_ident<T: 'static + #api_iface_ident + Send + ?Sized, P: Into<dbus::Path<'static>>>( path: P, - conn: std::sync::Arc<SyncConnection>, + conn: std::sync::Arc<dbus::nonblock::SyncConnection>, cr: &mut dbus_crossroads::Crossroads, obj: #obj_type, disconnect_watcher: std::sync::Arc<std::sync::Mutex<dbus_projection::DisconnectWatcher>>, ) { fn get_iface_token<T: #api_iface_ident + Send + ?Sized>( - conn: std::sync::Arc<SyncConnection>, + conn: std::sync::Arc<dbus::nonblock::SyncConnection>, cr: &mut dbus_crossroads::Crossroads, disconnect_watcher: std::sync::Arc<std::sync::Mutex<dbus_projection::DisconnectWatcher>>, ) -> dbus_crossroads::IfaceToken<#obj_type> { @@ -314,7 +314,7 @@ pub fn dbus_propmap(attr: TokenStream, item: TokenStream) -> TokenStream { fn from_dbus( data__: dbus::arg::PropMap, - conn__: Option<std::sync::Arc<SyncConnection>>, + conn__: Option<std::sync::Arc<dbus::nonblock::SyncConnection>>, remote__: Option<dbus::strings::BusName<'static>>, disconnect_watcher__: Option<std::sync::Arc<std::sync::Mutex<dbus_projection::DisconnectWatcher>>>, ) -> Result<#struct_ident, Box<dyn std::error::Error>> { @@ -440,7 +440,7 @@ pub fn dbus_proxy_obj(attr: TokenStream, item: TokenStream) -> TokenStream { } struct #struct_ident { - conn: std::sync::Arc<SyncConnection>, + conn: std::sync::Arc<dbus::nonblock::SyncConnection>, remote: dbus::strings::BusName<'static>, objpath: Path<'static>, disconnect_watcher: std::sync::Arc<std::sync::Mutex<DisconnectWatcher>>, @@ -465,7 +465,7 @@ pub fn dbus_proxy_obj(attr: TokenStream, item: TokenStream) -> TokenStream { fn from_dbus( objpath__: Path<'static>, - conn__: Option<std::sync::Arc<SyncConnection>>, + conn__: Option<std::sync::Arc<dbus::nonblock::SyncConnection>>, remote__: Option<dbus::strings::BusName<'static>>, disconnect_watcher__: Option<std::sync::Arc<std::sync::Mutex<DisconnectWatcher>>>, ) -> Result<Box<dyn #trait_ + Send>, Box<dyn std::error::Error>> { @@ -559,10 +559,18 @@ pub fn generate_dbus_arg(_item: TokenStream) -> TokenStream { type RustType = dbus::arg::PropMap; fn ref_arg_to_rust( arg: &(dyn dbus::arg::RefArg + 'static), - _name: String, + name: String, ) -> Result<Self::RustType, Box<dyn Error>> { let mut map: dbus::arg::PropMap = std::collections::HashMap::new(); - let mut iter = arg.as_iter().unwrap(); + let mut iter = match arg.as_iter() { + None => { + return Err(Box::new(DBusArgError::new(String::from(format!( + "{} is not iterable", + name, + ))))) + } + Some(item) => item, + }; let mut key = iter.next(); let mut val = iter.next(); while !key.is_none() && !val.is_none() { @@ -602,7 +610,7 @@ pub fn generate_dbus_arg(_item: TokenStream) -> TokenStream { fn from_dbus( x: Self::DBusType, - conn: Option<Arc<SyncConnection>>, + conn: Option<Arc<dbus::nonblock::SyncConnection>>, remote: Option<BusName<'static>>, disconnect_watcher: Option<Arc<Mutex<DisconnectWatcher>>>, ) -> Result<Self, Box<dyn Error>> @@ -627,7 +635,7 @@ pub fn generate_dbus_arg(_item: TokenStream) -> TokenStream { fn from_dbus( data: T, - _conn: Option<Arc<SyncConnection>>, + _conn: Option<Arc<dbus::nonblock::SyncConnection>>, _remote: Option<BusName<'static>>, _disconnect_watcher: Option<Arc<Mutex<DisconnectWatcher>>>, ) -> Result<T, Box<dyn Error>> { @@ -644,7 +652,7 @@ pub fn generate_dbus_arg(_item: TokenStream) -> TokenStream { fn from_dbus( data: Vec<T::DBusType>, - conn: Option<Arc<SyncConnection>>, + conn: Option<Arc<dbus::nonblock::SyncConnection>>, remote: Option<BusName<'static>>, disconnect_watcher: Option<Arc<Mutex<DisconnectWatcher>>>, ) -> Result<Vec<T>, Box<dyn Error>> { diff --git a/system/gd/rust/linux/dbus_projection/tests/conversions.rs b/system/gd/rust/linux/dbus_projection/tests/conversions.rs new file mode 100644 index 0000000000000000000000000000000000000000..ab57d71947be38d35ed34c624cb10a095276b33c --- /dev/null +++ b/system/gd/rust/linux/dbus_projection/tests/conversions.rs @@ -0,0 +1,176 @@ +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); + } +} diff --git a/system/gd/rust/linux/mgmt/src/bin/btmanagerd/bluetooth_manager_dbus.rs b/system/gd/rust/linux/mgmt/src/bin/btmanagerd/bluetooth_manager_dbus.rs index b06b52adfcac3381d3051485067928f7f0488865..9ff9cea800c4c4292ebb4dee6ea4cbeaafada633 100644 --- a/system/gd/rust/linux/mgmt/src/bin/btmanagerd/bluetooth_manager_dbus.rs +++ b/system/gd/rust/linux/mgmt/src/bin/btmanagerd/bluetooth_manager_dbus.rs @@ -1,5 +1,4 @@ use dbus::arg::RefArg; -use dbus::nonblock::SyncConnection; use dbus::strings::Path; use dbus_macros::{dbus_method, dbus_propmap, dbus_proxy_obj, generate_dbus_exporter}; use dbus_projection::DisconnectWatcher; diff --git a/system/gd/rust/linux/service/src/iface_bluetooth_media.rs b/system/gd/rust/linux/service/src/iface_bluetooth_media.rs index abb39e838958b022fe74b722f2c8dd870635743e..57464912e87be27e59039517058c828443035fe7 100644 --- a/system/gd/rust/linux/service/src/iface_bluetooth_media.rs +++ b/system/gd/rust/linux/service/src/iface_bluetooth_media.rs @@ -3,7 +3,6 @@ use btstack::bluetooth_media::{IBluetoothMedia, IBluetoothMediaCallback}; use btstack::RPCProxy; use dbus::arg::RefArg; -use dbus::nonblock::SyncConnection; use dbus::strings::Path; use dbus_macros::{dbus_method, dbus_propmap, dbus_proxy_obj, generate_dbus_exporter};