From 8e4a9df692ea4a104b5f2588051ce58af0105c48 Mon Sep 17 00:00:00 2001 From: Razvan Cojocaru Date: Sun, 22 Dec 2024 20:22:59 +0200 Subject: [PATCH] =?UTF-8?q?=E2=9C=A8=20zb,zm:=20Support=20SignalEmitter<'?= =?UTF-8?q?=5F>=20in=20property=20getters?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- zbus/src/fdo/object_manager.rs | 3 +- zbus/src/fdo/properties.rs | 6 ++-- zbus/src/object_server/interface/mod.rs | 2 ++ zbus/src/object_server/mod.rs | 6 ++-- zbus/src/object_server/node.rs | 7 +++-- zbus/tests/e2e.rs | 5 ++-- zbus_macros/src/iface.rs | 37 +++++++++++++------------ zbus_macros/src/lib.rs | 3 +- 8 files changed, 41 insertions(+), 28 deletions(-) diff --git a/zbus/src/fdo/object_manager.rs b/zbus/src/fdo/object_manager.rs index 852a5c3f9..184b7e315 100644 --- a/zbus/src/fdo/object_manager.rs +++ b/zbus/src/fdo/object_manager.rs @@ -50,6 +50,7 @@ impl ObjectManager { &self, #[zbus(object_server)] server: &ObjectServer, #[zbus(connection)] connection: &Connection, + #[zbus(signal_emitter)] emitter: SignalEmitter<'_>, #[zbus(header)] header: Header<'_>, ) -> Result { let path = header.path().ok_or(crate::Error::MissingField)?; @@ -58,7 +59,7 @@ impl ObjectManager { .get_child(path) .ok_or_else(|| Error::UnknownObject(format!("Unknown object '{path}'")))?; - node.get_managed_objects(server, connection).await + node.get_managed_objects(server, &emitter, connection).await } /// This signal is emitted when either a new object is added or when an existing object gains diff --git a/zbus/src/fdo/properties.rs b/zbus/src/fdo/properties.rs index 4a81622ab..a060da875 100644 --- a/zbus/src/fdo/properties.rs +++ b/zbus/src/fdo/properties.rs @@ -32,6 +32,7 @@ impl Properties { #[zbus(connection)] conn: &Connection, #[zbus(object_server)] server: &ObjectServer, #[zbus(header)] header: Header<'_>, + #[zbus(signal_emitter)] emitter: SignalEmitter<'_>, ) -> Result { let path = header.path().ok_or(crate::Error::MissingField)?; let root = server.root().read().await; @@ -46,7 +47,7 @@ impl Properties { .instance .read() .await - .get(property_name, server, conn, Some(&header)) + .get(property_name, server, conn, &emitter, Some(&header)) .await; res.unwrap_or_else(|| { Err(Error::UnknownProperty(format!( @@ -120,6 +121,7 @@ impl Properties { interface_name: InterfaceName<'_>, #[zbus(object_server)] server: &ObjectServer, #[zbus(connection)] connection: &Connection, + #[zbus(signal_emitter)] emitter: SignalEmitter<'_>, #[zbus(header)] header: Header<'_>, ) -> Result> { let path = header.path().ok_or(crate::Error::MissingField)?; @@ -135,7 +137,7 @@ impl Properties { .instance .read() .await - .get_all(server, connection, Some(&header)) + .get_all(server, connection, &emitter, Some(&header)) .await?; Ok(res) } diff --git a/zbus/src/object_server/interface/mod.rs b/zbus/src/object_server/interface/mod.rs index 9140d9bc2..b34981a73 100644 --- a/zbus/src/object_server/interface/mod.rs +++ b/zbus/src/object_server/interface/mod.rs @@ -58,6 +58,7 @@ pub trait Interface: Any + Send + Sync { property_name: &str, server: &ObjectServer, connection: &Connection, + emitter: &SignalEmitter<'_>, header: Option<&message::Header<'_>>, ) -> Option>; @@ -66,6 +67,7 @@ pub trait Interface: Any + Send + Sync { &self, object_server: &ObjectServer, connection: &Connection, + emitter: &SignalEmitter<'_>, header: Option<&message::Header<'_>>, ) -> fdo::Result>; diff --git a/zbus/src/object_server/mod.rs b/zbus/src/object_server/mod.rs index 09be6e612..5f3303f50 100644 --- a/zbus/src/object_server/mod.rs +++ b/zbus/src/object_server/mod.rs @@ -148,7 +148,9 @@ impl ObjectServer { if name == ObjectManager::name() { // Just added an object manager. Need to signal all managed objects under it. let ctxt = SignalEmitter::new(&self.connection(), path)?; - let objects = node.get_managed_objects(self, &self.connection()).await?; + let objects = node + .get_managed_objects(self, &ctxt, &self.connection()) + .await?; for (path, owned_interfaces) in objects { let interfaces = owned_interfaces .iter() @@ -166,7 +168,7 @@ impl ObjectServer { let ctxt = SignalEmitter::new(&self.connection(), manager_path.clone())?; let mut interfaces = HashMap::new(); let owned_props = node - .get_properties(self, &self.connection(), name.clone()) + .get_properties(self, &self.connection(), &ctxt, name.clone()) .await?; let props = owned_props .iter() diff --git a/zbus/src/object_server/node.rs b/zbus/src/object_server/node.rs index 235f076a8..90a146b29 100644 --- a/zbus/src/object_server/node.rs +++ b/zbus/src/object_server/node.rs @@ -10,6 +10,7 @@ use zvariant::{ObjectPath, OwnedObjectPath, OwnedValue}; use crate::{ fdo::{self, Introspectable, ManagedObjects, ObjectManager, Peer, Properties}, + object_server::SignalEmitter, Connection, ObjectServer, }; @@ -214,6 +215,7 @@ impl Node { pub(crate) async fn get_managed_objects( &self, object_server: &ObjectServer, + emitter: &SignalEmitter<'_>, connection: &Connection, ) -> fdo::Result { let mut managed_objects = ManagedObjects::new(); @@ -230,7 +232,7 @@ impl Node { && *n != &ObjectManager::name() }) { let props = node - .get_properties(object_server, connection, iface_name.clone()) + .get_properties(object_server, connection, emitter, iface_name.clone()) .await?; interfaces.insert(iface_name.clone().into(), props); } @@ -245,6 +247,7 @@ impl Node { &self, object_server: &ObjectServer, connection: &Connection, + emitter: &SignalEmitter<'_>, interface_name: InterfaceName<'_>, ) -> fdo::Result> { self.interface_lock(interface_name) @@ -252,7 +255,7 @@ impl Node { .instance .read() .await - .get_all(object_server, connection, None) + .get_all(object_server, connection, emitter, None) .await } } diff --git a/zbus/tests/e2e.rs b/zbus/tests/e2e.rs index 76a099fb6..7419f528a 100644 --- a/zbus/tests/e2e.rs +++ b/zbus/tests/e2e.rs @@ -269,10 +269,11 @@ impl MyIface { #[zbus(header)] header: Option>, #[zbus(connection)] connection: &Connection, #[zbus(object_server)] object_server: &ObjectServer, + #[zbus(signal_emitter)] emitter: SignalEmitter<'_>, ) -> bool { debug!( - "`TestHeaderProp` getter called, header: {:?}, connection: {:?}, object_server: {:?}", - header, connection, object_server + "`TestHeaderProp` getter called, header: {:?}, connection: {:?}, object_server: {:?}, emitter: {:?}", + header, connection, object_server, emitter ); header.is_some() } diff --git a/zbus_macros/src/iface.rs b/zbus_macros/src/iface.rs index 73be68d7c..6fe613ba7 100644 --- a/zbus_macros/src/iface.rs +++ b/zbus_macros/src/iface.rs @@ -879,6 +879,7 @@ pub fn expand(args: Punctuated, mut input: ItemImpl) -> syn::Re property_name: &str, object_server: &#zbus::ObjectServer, connection: &#zbus::Connection, + signal_emitter: &#zbus::object_server::SignalEmitter<'_>, header: Option<&#zbus::message::Header<'_>>, ) -> ::std::option::Option<#zbus::fdo::Result<#zbus::zvariant::OwnedValue>> { match property_name { @@ -891,6 +892,7 @@ pub fn expand(args: Punctuated, mut input: ItemImpl) -> syn::Re &self, object_server: &#zbus::ObjectServer, connection: &#zbus::Connection, + signal_emitter: &#zbus::object_server::SignalEmitter<'_>, header: Option<&#zbus::message::Header<'_>>, ) -> #zbus::fdo::Result<::std::collections::HashMap< ::std::string::String, @@ -1051,37 +1053,38 @@ fn get_args_from_inputs( let signal_context_arg = &input.pat; - signal_emitter_arg_decl = Some(quote! { - let #signal_context_arg = match hdr.path() { - ::std::option::Option::Some(p) => { - #zbus::object_server::SignalEmitter::new(connection, p).expect("Infallible conversion failed") - } - ::std::option::Option::None => { - let err = #zbus::fdo::Error::UnknownObject("Path Required".into()); - return connection.reply_dbus_error(&hdr, err).await; - } - }; - }); + signal_emitter_arg_decl = match method_type { + MethodType::Property(PropertyType::Getter) => { + Some(quote! { let #signal_context_arg = signal_emitter.clone(); }) + } + _ => Some(quote! { + let #signal_context_arg = match hdr.path() { + ::std::option::Option::Some(p) => { + #zbus::object_server::SignalEmitter::new(connection, p).expect("Infallible conversion failed") + } + ::std::option::Option::None => { + let err = #zbus::fdo::Error::UnknownObject("Path Required".into()); + return connection.reply_dbus_error(&hdr, err).await; + } + }; + }), + }; } else { args_names.push(pat_ident(input).unwrap()); tys.push(&input.ty); } } - let (hdr_init, msg_init, signal_emitter_arg_decl, args_decl) = match method_type { - MethodType::Property(PropertyType::Getter) => { - (quote! {}, quote! {}, quote! {}, quote! {}) - } + let (hdr_init, msg_init, args_decl) = match method_type { + MethodType::Property(PropertyType::Getter) => (quote! {}, quote! {}, quote! {}), MethodType::Property(PropertyType::Setter) => ( quote! { let hdr = header.as_ref().unwrap(); }, quote! {}, - quote! { #signal_emitter_arg_decl }, quote! {}, ), _ => ( quote! { let hdr = message.header(); }, quote! { let msg_body = message.body(); }, - quote! { #signal_emitter_arg_decl }, quote! { let (#(#args_names),*): (#(#tys),*) = match msg_body.deserialize() { diff --git a/zbus_macros/src/lib.rs b/zbus_macros/src/lib.rs index 4a005ddb7..cda34c866 100644 --- a/zbus_macros/src/lib.rs +++ b/zbus_macros/src/lib.rs @@ -300,8 +300,7 @@ pub fn proxy(attr: TokenStream, item: TokenStream) -> TokenStream { /// which will be set to `None` if the method is called for reasons other than to respond to an /// external property access. /// * `signal_emitter` - This marks the method argument to receive a [`SignalEmitter`] instance, -/// which is needed for emitting signals the easy way. This argument is not available for property -/// getters. +/// which is needed for emitting signals the easy way. /// /// # Example ///