diff --git a/Cargo.lock b/Cargo.lock index 4138772..d02b876 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -47,9 +47,9 @@ dependencies = [ [[package]] name = "cfg-expr" -version = "0.20.9" +version = "0.20.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fe4ece8474b5f766c63426647e7b4b316b67431ade1036a8313cee24a03ae917" +checksum = "9ba9e9ec16c447027685b1f897b720e18e9a8afd00bd7332c483537e38086c9f" dependencies = [ "smallvec", "target-lexicon", @@ -231,9 +231,9 @@ dependencies = [ [[package]] name = "libc" -version = "0.2.189" +version = "0.2.190" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3eaf3ede3fee6db1a4c2ee091bf8a8b4dccdc6d17f656fb07896ee72867612f2" +checksum = "ce5d3ddc6d3fa000eb1536d85e147bfe31aacaba692ed6a876f95cb7c855be78" [[package]] name = "libloading" @@ -247,7 +247,7 @@ dependencies = [ [[package]] name = "libnotify-rs" -version = "0.2.0" +version = "0.3.0" dependencies = [ "bindgen", "glib", diff --git a/Cargo.toml b/Cargo.toml index c8e4853..77ca318 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "libnotify-rs" -version = "0.2.1" +version = "0.3.0" edition = "2024" authors = [ "szymon_jozef"] description = "Rust bindings for libnotify" diff --git a/src/api/errors.rs b/src/api/errors.rs new file mode 100644 index 0000000..416748b --- /dev/null +++ b/src/api/errors.rs @@ -0,0 +1,58 @@ +/// Enum mapping every possible error that can happen in this lib, with a nice enum. +#[derive(Debug)] +pub enum LibnotifyError { + /// [Libnotify init](https://gnome.pages.gitlab.gnome.org/libnotify/func.init.html) failed + InitError, + /// `&str` contains a null terminator. Read more at [std documentation](https://doc.rust-lang.org/std/ffi/struct.NulError.html) + NulError(std::ffi::NulError), + /// [Libnotify notification constructor](https://gnome.pages.gitlab.gnome.org/libnotify/ctor.Notification.new.html) failed allocating + NewNotificationError, + /// Custom libnotify error with explanation. + GerrorError(String), + /// Data failed allocating. Could indicate that system doesn't have enough memory + AllocationError, +} + +impl std::fmt::Display for LibnotifyError { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + LibnotifyError::InitError => { + write!(f, "Libnotify failed to init") + } + + LibnotifyError::NulError(_) => { + write!(f, "Argument contains a null terminator") + } + + LibnotifyError::NewNotificationError => { + write!(f, "Notification constructor failed") + } + + LibnotifyError::GerrorError(e) => { + write!(f, "Libnotify returned an error: {}", e) + } + + LibnotifyError::AllocationError => { + write!(f, "Libnotify failed allocating memory") + } + } + } +} + +impl std::error::Error for LibnotifyError { + fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { + match self { + LibnotifyError::InitError => None, + LibnotifyError::NulError(nul_error) => Some(nul_error), + LibnotifyError::NewNotificationError => None, + LibnotifyError::GerrorError(_) => None, + LibnotifyError::AllocationError => None, + } + } +} + +impl From for LibnotifyError { + fn from(value: std::ffi::NulError) -> Self { + Self::NulError(value) + } +} diff --git a/src/api/functions.rs b/src/api/functions.rs index c716336..c314b74 100644 --- a/src/api/functions.rs +++ b/src/api/functions.rs @@ -1,3 +1,5 @@ +use crate::api::errors::LibnotifyError; + use super::utils::c_str_to_rs_str_and_free; use super::libnotify::*; @@ -10,7 +12,7 @@ use super::libnotify::*; /// Initialized libnotify. This must be called before any other functions. /// /// Starting from 0.8, if the provided app_name is NULL, libnotify will try to figure it out from the running application. Before it was not allowed, and was causing libnotify not to be initialized. -pub fn init<'a, T>(app_name: T) -> Result<(), Box> +pub fn init<'a, T>(app_name: T) -> Result<(), LibnotifyError> where T: Into>, { @@ -24,7 +26,7 @@ where ) } == 0 { - return Err("Libnotify init failed".into()); + return Err(LibnotifyError::InitError); } Ok(()) @@ -161,7 +163,7 @@ pub fn get_server_info() -> Option { */ /// Sets the application name -pub fn set_app_name(app_name: &str) -> Result<(), std::ffi::NulError> { +pub fn set_app_name(app_name: &str) -> Result<(), LibnotifyError> { let app_name_c = std::ffi::CString::new(app_name)?; unsafe { notify_set_app_name(app_name_c.as_ptr()) }; @@ -172,7 +174,7 @@ pub fn set_app_name(app_name: &str) -> Result<(), std::ffi::NulError> { /// Available since: 0.8.4 /// /// app_icon is icon name or path to an image -pub fn set_app_icon(app_icon: &str) -> Result<(), std::ffi::NulError> { +pub fn set_app_icon(app_icon: &str) -> Result<(), LibnotifyError> { let app_icon_c = std::ffi::CString::new(app_icon)?; unsafe { notify_set_app_icon(app_icon_c.as_ptr()) }; @@ -195,11 +197,10 @@ mod tests { #[test] fn test_bad_init() { - assert!( - init("Mor\0ius") - .unwrap_err() - .is::() - ); + assert!(matches!( + init("Mor\0ius").unwrap_err(), + LibnotifyError::NulError(_) + )); } #[test] diff --git a/src/api/mod.rs b/src/api/mod.rs index 15241f4..ed18bb0 100644 --- a/src/api/mod.rs +++ b/src/api/mod.rs @@ -1,3 +1,5 @@ +/// Custom error types +pub mod errors; /// Same as [libnotify global functions](https://gnome.pages.gitlab.gnome.org/libnotify/index.html#functions) pub mod functions; mod libnotify; diff --git a/src/api/notification.rs b/src/api/notification.rs index ace6194..e5859a1 100644 --- a/src/api/notification.rs +++ b/src/api/notification.rs @@ -1,3 +1,5 @@ +use crate::api::errors::LibnotifyError; + use super::libnotify::*; #[derive(Debug, Clone, Copy)] @@ -67,7 +69,7 @@ impl<'a> Notification { /// the position of the nul byte. /// /// On libnotify fail it will return Err(&str.into). May change in the future. - pub fn new(summary: &str, body: T, icon: Y) -> Result> + pub fn new(summary: &str, body: T, icon: Y) -> Result where T: Into>, Y: Into>, @@ -87,7 +89,7 @@ impl<'a> Notification { }; if inner.is_null() { - return Err("notify_notification_new returned null".into()); + return Err(LibnotifyError::NewNotificationError); } Ok(Self { inner }) @@ -107,7 +109,7 @@ impl<'a> Notification { action: &str, label: &str, callback: F, - ) -> Result<(), Box> + ) -> Result<(), LibnotifyError> where F: Fn(&str) + 'static, { @@ -144,19 +146,19 @@ impl<'a> Notification { } /// Synchronously tells the notification server to hide the notification on the screen - pub fn close(&self) -> Result<(), Box> { + pub fn close(&self) -> Result<(), LibnotifyError> { let mut gerror = std::ptr::null_mut() as *mut GError; if unsafe { notify_notification_close(self.inner, &mut gerror) } == 0 { if gerror.is_null() { - return Err("Unknown error".into()); + return Err(LibnotifyError::AllocationError); } let e = unsafe { *gerror }.message; if e.is_null() { unsafe { g_error_free(gerror) }; - return Err("Unknown error".into()); + return Err(LibnotifyError::AllocationError); } let e_str = unsafe { std::ffi::CStr::from_ptr(e) } @@ -165,7 +167,7 @@ impl<'a> Notification { unsafe { g_error_free(gerror) }; - return Err(e_str.into()); + return Err(LibnotifyError::GerrorError(e_str)); } Ok(()) @@ -191,7 +193,7 @@ impl<'a> Notification { /// `set_app_icon()`. /// /// Available since: 0.8.4 - pub fn set_app_icon(&mut self, app_icon: &str) -> Result<(), std::ffi::NulError> { + pub fn set_app_icon(&mut self, app_icon: &str) -> Result<(), LibnotifyError> { let app_icon_c = std::ffi::CString::new(app_icon)?; unsafe { notify_notification_set_app_icon(self.inner, app_icon_c.as_ptr()) }; @@ -203,7 +205,7 @@ impl<'a> Notification { /// If this function is not called, the application name will be set from the value used in init() or overridden with set_app_name(). /// /// Available since: 0.7.3 - pub fn set_app_name(&mut self, app_name: &str) -> Result<(), std::ffi::NulError> { + pub fn set_app_name(&mut self, app_name: &str) -> Result<(), LibnotifyError> { let app_name_c = std::ffi::CString::new(app_name)?; unsafe { notify_notification_set_app_name(self.inner, app_name_c.as_ptr()) }; @@ -213,7 +215,7 @@ impl<'a> Notification { /// Sets the category of this notification. /// /// This can be used by the notification server to filter or display the data in a certain way - pub fn set_category(&mut self, category: &str) -> Result<(), std::ffi::NulError> { + pub fn set_category(&mut self, category: &str) -> Result<(), LibnotifyError> { let category_c = std::ffi::CString::new(category)?; unsafe { notify_notification_set_category(self.inner, category_c.as_ptr()) }; @@ -223,11 +225,7 @@ impl<'a> Notification { /// Sets a hint for key with value value /// /// Available since: 0.6 - pub fn set_hint( - &mut self, - key: &str, - value: HintValue, - ) -> Result<(), Box> { + pub fn set_hint(&mut self, key: &str, value: HintValue) -> Result<(), LibnotifyError> { let key_c = std::ffi::CString::new(key)?; let value_c = match value { @@ -242,7 +240,7 @@ impl<'a> Notification { }; if value_c.is_null() { - return Err("Couldn't create hint value".into()); + return Err(LibnotifyError::AllocationError); } unsafe { notify_notification_set_hint(self.inner, key_c.as_ptr(), value_c) }; diff --git a/src/wrappers/builder.rs b/src/wrappers/builder.rs index b691328..afd4a14 100644 --- a/src/wrappers/builder.rs +++ b/src/wrappers/builder.rs @@ -1,5 +1,8 @@ use crate::{ - api::notification::{HintValue, Notification, Timeout, Urgency}, + api::{ + errors::LibnotifyError, + notification::{HintValue, Notification, Timeout, Urgency}, + }, wrappers::context::LibnotifyContext, }; @@ -31,19 +34,19 @@ impl<'a> NotificationBuilder<'a> { } /// Sets app name for this specific notification. - pub fn set_app_name(mut self, app_name: &str) -> Result { + pub fn set_app_name(mut self, app_name: &str) -> Result { self.notification.set_app_name(app_name)?; Ok(self) } /// Sets app icon fot this specific notification. - pub fn set_app_icon(mut self, app_icon: &str) -> Result { + pub fn set_app_icon(mut self, app_icon: &str) -> Result { self.notification.set_app_icon(app_icon)?; Ok(self) } /// Sets category for this specific notification - pub fn set_category(mut self, category: &str) -> Result { + pub fn set_category(mut self, category: &str) -> Result { self.notification.set_category(category)?; Ok(self) } diff --git a/src/wrappers/context.rs b/src/wrappers/context.rs index 7bddcb9..12c1c65 100644 --- a/src/wrappers/context.rs +++ b/src/wrappers/context.rs @@ -1,4 +1,7 @@ -use crate::api::functions::{init, is_initted, set_app_icon, set_app_name, uninit}; +use crate::api::{ + errors::LibnotifyError, + functions::{init, is_initted, set_app_icon, set_app_name, uninit}, +}; /// Notification context. Handles libnotify initializing and uninitializing. pub struct LibnotifyContext {} @@ -25,13 +28,13 @@ impl LibnotifyContext { } /// Sets global app name - pub fn set_new_name(&self, app_name: &str) -> Result<(), std::ffi::NulError> { + pub fn set_new_name(&self, app_name: &str) -> Result<(), LibnotifyError> { set_app_name(app_name)?; Ok(()) } /// Sets global app icon - pub fn set_app_icon(&self, app_icon: &str) -> Result<(), std::ffi::NulError> { + pub fn set_app_icon(&self, app_icon: &str) -> Result<(), LibnotifyError> { set_app_icon(app_icon)?; Ok(()) }