From 0ac79b06ad83f6db46c0368297b94023ddd3e236 Mon Sep 17 00:00:00 2001 From: Hendrik Sollich Date: Wed, 29 Apr 2026 23:41:50 +0200 Subject: [PATCH] feat: return Result from wait/on_close Propagate errors in zbus/dbus implementations instead of unwrapping internally or eating the error --- examples/actions.rs | 6 ++-- examples/wait_for_closing.rs | 4 +-- examples/wait_for_closing_async.rs | 6 ++-- justfile | 54 ++++++++++++++++++++++++++++++ src/xdg/dbus_rs.rs | 2 +- src/xdg/mod.rs | 24 +++++++------ src/xdg/zbus_rs.rs | 25 ++++++++------ 7 files changed, 93 insertions(+), 28 deletions(-) create mode 100644 justfile diff --git a/examples/actions.rs b/examples/actions.rs index 1ea1f153..c59aca8d 100644 --- a/examples/actions.rs +++ b/examples/actions.rs @@ -20,7 +20,8 @@ fn main() { // FIXME: here "__closed" is a hardcoded keyword, it will be deprecated!! "__closed" => println!("the notification was closed"), _ => (), - }); + }) + .unwrap(); Notification::new() .summary("click me") @@ -39,5 +40,6 @@ fn main() { // FIXME: here "__closed" is a hardcoded keyword, it will be deprecated!! "__closed" => println!("the notification was closed"), _ => (), - }); + }) + .unwrap(); } diff --git a/examples/wait_for_closing.rs b/examples/wait_for_closing.rs index 8b44b840..73e1f921 100644 --- a/examples/wait_for_closing.rs +++ b/examples/wait_for_closing.rs @@ -4,7 +4,6 @@ fn main() { } #[cfg(all(unix, not(target_os = "macos")))] - fn main() { use notify_rust::CloseReason; @@ -14,5 +13,6 @@ fn main() { .body("I'll be gone soon enough.\nSorry for the inconvenience.") .show() .unwrap() - .on_close(|reason: CloseReason| println!("the notification was closed reason: {reason:?}")); + .on_close(|reason: CloseReason| println!("the notification was closed reason: {reason:?}")) + .unwrap(); } diff --git a/examples/wait_for_closing_async.rs b/examples/wait_for_closing_async.rs index 9d646d8f..3d3e6c69 100644 --- a/examples/wait_for_closing_async.rs +++ b/examples/wait_for_closing_async.rs @@ -17,7 +17,8 @@ fn main() { .unwrap() .on_close(|reason: CloseReason| { println!("the notification was closed reason: {reason:?}") - }); + }) + .unwrap(); Notification::new() .summary("Pick an option") @@ -30,6 +31,7 @@ fn main() { .wait_for_action_async(|action| { println!("action invoked: {action:?}"); }) - .await; + .await + .unwrap(); }) } diff --git a/justfile b/justfile new file mode 100644 index 00000000..452430b0 --- /dev/null +++ b/justfile @@ -0,0 +1,54 @@ +# Feature combinations from .github/workflows/build-platforms.yml (linux job) +# Features: d | d,images | z | z,images | z,d + +# Run all Linux CI checks for every feature combination +default: + @just --list + +# --- default features --- + +check-default: + cargo check + +clippy: + cargo clippy + +# --- per-feature helpers (internal) --- + +[private] +check-features features: + cargo check --no-default-features --features {{features}} + +[private] +test-lib features: + cargo test --lib --no-default-features --features {{features}} + +[private] +test-doc features: + cargo test --doc --no-default-features --features {{features}} + +[private] +test-features features: (test-lib features) (test-doc features) + +# --- individual feature-set targets --- + +check-d: (check-features "d") +check-d-images: (check-features "d,images") +check-z: (check-features "z") +check-z-images: (check-features "z,images") +check-z-d: (check-features "z,d") + +test-d: (test-features "d") +test-d-images: (test-features "d,images") +test-z: (test-features "z") +test-z-images: (test-features "z,images") +test-z-d: (test-features "z,d") + +# --- aggregate targets --- + +check-all: check-default check-d check-d-images check-z check-z-images check-z-d + +test-all: test-d test-d-images test-z test-z-images test-z-d + +# Run the full Linux CI matrix locally (check + test + clippy) +ci: check-all test-all clippy diff --git a/src/xdg/dbus_rs.rs b/src/xdg/dbus_rs.rs index 6b643d22..9a041ef5 100644 --- a/src/xdg/dbus_rs.rs +++ b/src/xdg/dbus_rs.rs @@ -94,7 +94,7 @@ impl DbusNotificationHandle { pub fn close(self) { let mut message = build_message("CloseNotification", Default::default()); message.append_items(&[self.id.into()]); - let _ = self.connection.send(message); // If closing fails there's nothing we could do anyway + self.connection.send(message); // If closing fails there's nothing we could do anyway } pub fn on_close(self, closure: F) -> Result<()> diff --git a/src/xdg/mod.rs b/src/xdg/mod.rs index 4122994f..41e0868b 100644 --- a/src/xdg/mod.rs +++ b/src/xdg/mod.rs @@ -93,17 +93,17 @@ impl NotificationHandle { /// Waits for the user to act on a notification and then calls /// `invocation_closure` with the name of the corresponding action. - pub fn wait_for_action(self, invocation_closure: F) + pub fn wait_for_action(self, invocation_closure: F) -> Result<()> where F: FnOnce(&str), { match self.inner { #[cfg(feature = "dbus")] NotificationHandleInner::Dbus(inner) => { - let _ = inner.wait_for_action(|action: &ActionResponse| match action { + inner.wait_for_action(|action: &ActionResponse| match action { ActionResponse::Custom(action) => invocation_closure(action), ActionResponse::Closed(_reason) => invocation_closure("__closed"), // FIXME: remove backward compatibility with 5.0 - }); + }) } #[cfg(feature = "zbus")] @@ -113,9 +113,9 @@ impl NotificationHandle { ActionResponse::Custom(action) => invocation_closure(action), ActionResponse::Closed(_reason) => invocation_closure("__closed"), // FIXME: remove backward compatibility with 5.0 }), - ); + ) } - }; + } } /// Returns a future that waits for the user to act on a notification and then calls @@ -154,7 +154,7 @@ impl NotificationHandle { /// # } /// ``` #[cfg(feature = "zbus")] - pub async fn wait_for_action_async(&self, invocation_closure: F) + pub async fn wait_for_action_async(&self, invocation_closure: F) -> Result<()> where F: FnOnce(&ActionResponse), { @@ -164,8 +164,11 @@ impl NotificationHandle { unimplemented!("async methods are not supported with the `dbus` backend"); } #[cfg(feature = "zbus")] - NotificationHandleInner::Zbus(inner) => inner.wait_for_action(invocation_closure).await, + NotificationHandleInner::Zbus(inner) => { + inner.wait_for_action(invocation_closure).await?; + } } + Ok(()) } /// Manually close the notification @@ -236,11 +239,11 @@ impl NotificationHandle { /// .unwrap() /// .on_close(|reason| println!("closed: {:?}", reason)); /// ``` - pub fn on_close(self, handler: impl CloseHandler) { + pub fn on_close(self, handler: impl CloseHandler) -> Result<()> { match self.inner { #[cfg(feature = "dbus")] NotificationHandleInner::Dbus(inner) => { - let _ = inner.wait_for_action(|action: &ActionResponse| { + inner.wait_for_action(|action: &ActionResponse| { if let ActionResponse::Closed(reason) = action { handler.call(*reason); } @@ -252,9 +255,10 @@ impl NotificationHandle { if let ActionResponse::Closed(reason) = action { handler.call(*reason); } - })); + })) } }; + Ok(()) } /// Replace the original notification with an updated version diff --git a/src/xdg/zbus_rs.rs b/src/xdg/zbus_rs.rs index c839b365..733743a2 100644 --- a/src/xdg/zbus_rs.rs +++ b/src/xdg/zbus_rs.rs @@ -77,8 +77,11 @@ impl ZbusNotificationHandle { } } - pub async fn wait_for_action(&self, invocation_closure: impl ActionResponseHandler) { - wait_for_action_signal(&self.connection, self.id, invocation_closure).await; + pub async fn wait_for_action( + &self, + invocation_closure: impl ActionResponseHandler, + ) -> Result<()> { + wait_for_action_signal(&self.connection, self.id, invocation_closure).await } pub async fn close_fallible(&self) -> Result<()> { @@ -98,7 +101,7 @@ impl ZbusNotificationHandle { let _ = self.close_fallible().await; } - pub fn on_close(self, closure: F) + pub fn on_close(self, closure: F) -> Result<()> where F: FnOnce(CloseReason), { @@ -106,7 +109,7 @@ impl ZbusNotificationHandle { if let ActionResponse::Closed(reason) = action { closure(*reason); } - })); + })) } pub fn update_fallible(&mut self) -> Result<()> { @@ -227,22 +230,22 @@ pub async fn get_server_information() -> Result { /// Listens for the `ActionInvoked(UInt32, String)` Signal. /// /// No need to use this, check out `Notification::show_and_wait_for_action(FnOnce(action:&str))` -pub async fn handle_action(id: u32, func: impl ActionResponseHandler) { +pub async fn handle_action(id: u32, func: impl ActionResponseHandler) -> Result<()> { let connection = zbus::Connection::session().await.unwrap(); - wait_for_action_signal(&connection, id, func).await; + wait_for_action_signal(&connection, id, func).await?; + Ok(()) } async fn wait_for_action_signal( connection: &zbus::Connection, id: u32, handler: impl ActionResponseHandler, -) { +) -> Result<()> { let action_signal_rule = MatchRule::builder() .msg_type(zbus::message::Type::Signal) .interface(xdg::NOTIFICATION_INTERFACE) .unwrap() - .member("ActionInvoked") - .unwrap() + .member("ActionInvoked")? .build(); let proxy = zbus::fdo::DBusProxy::new(connection).await.unwrap(); @@ -252,8 +255,7 @@ async fn wait_for_action_signal( .msg_type(zbus::message::Type::Signal) .interface(xdg::NOTIFICATION_INTERFACE) .unwrap() - .member("NotificationClosed") - .unwrap() + .member("NotificationClosed")? .build(); proxy.add_match_rule(close_signal_rule).await.unwrap(); @@ -283,4 +285,5 @@ async fn wait_for_action_signal( } } } + Ok(()) }