1use glib::{prelude::*, translate::*};
4use thiserror::Error;
5
6#[macro_export]
7macro_rules! error_msg(
8 ($err:expr, ($($msg:tt)*), [$($dbg:tt)*]) => { {
9 $crate::ErrorMessage::new(&$err, Some(format!($($msg)*).as_ref()),
10 Some(format!($($dbg)*).as_ref()),
11 file!(), $crate::glib::function_name!(), line!())
12 }};
13 ($err:expr, ($($msg:tt)*)) => { {
14 $crate::ErrorMessage::new(&$err, Some(format!($($msg)*).as_ref()),
15 None,
16 file!(), $crate::glib::function_name!(), line!())
17 }};
18
19 ($err:expr, [$($dbg:tt)*]) => { {
20 $crate::ErrorMessage::new(&$err, None,
21 Some(format!($($dbg)*).as_ref()),
22 file!(), $crate::glib::function_name!(), line!())
23 }};
24);
25
26#[derive(Clone, Debug, PartialEq, Eq, Error)]
27#[error("Error {:?} ({:?}) at {}:{}", .message, .debug, .filename, .line)]
28pub struct ErrorMessage {
29 pub(crate) error_domain: glib::Quark,
30 pub(crate) error_code: i32,
31 pub(crate) message: Option<String>,
32 pub(crate) debug: Option<String>,
33 pub(crate) filename: &'static str,
34 pub(crate) function: &'static str,
35 pub(crate) line: u32,
36}
37
38impl ErrorMessage {
39 pub fn new<T: crate::MessageErrorDomain>(
40 error: &T,
41 message: Option<&str>,
42 debug: Option<&str>,
43 filename: &'static str,
44 function: &'static str,
45 line: u32,
46 ) -> ErrorMessage {
47 skip_assert_initialized!();
48 let error_domain = T::domain();
49 let error_code = error.code();
50
51 ErrorMessage {
52 error_domain,
53 error_code,
54 message: message.map(String::from),
55 debug: debug.map(String::from),
56 filename,
57 function,
58 line,
59 }
60 }
61}
62
63#[macro_export]
64macro_rules! loggable_error(
65 ($cat:expr, $($msg:tt)*) => { {
66 $crate::LoggableError::new($cat.clone(), $crate::glib::bool_error!($($msg)*))
67 }};
68);
69
70#[macro_export]
71macro_rules! result_from_gboolean(
72 ($ffi_bool:expr, $cat:expr, $($msg:tt)*) => { {
73 $crate::glib::result_from_gboolean!($ffi_bool, $($msg)*)
74 .map_err(|bool_err| $crate::LoggableError::new($cat.clone(), bool_err))
75 }};
76);
77
78#[derive(Debug, Clone, Error)]
79#[error("Error {:?}: {:?} at {}:{}", .category.name(), .bool_error.message, .bool_error.filename, .bool_error.line)]
80pub struct LoggableError {
81 category: crate::DebugCategory,
82 bool_error: glib::BoolError,
83}
84
85impl LoggableError {
86 pub fn new(category: crate::DebugCategory, bool_error: glib::BoolError) -> LoggableError {
87 skip_assert_initialized!();
88 LoggableError {
89 category,
90 bool_error,
91 }
92 }
93
94 #[inline(never)]
95 pub fn log(&self) {
96 self.bool_error.filename.run_with_gstr(|filename| {
97 self.category.log(
98 None::<&glib::Object>,
99 crate::DebugLevel::Error,
100 filename,
101 self.bool_error.function,
102 self.bool_error.line,
103 format_args!("{}", self.bool_error.message),
104 );
105 });
106 }
107
108 pub fn log_with_object(&self, obj: &impl IsA<glib::Object>) {
109 self.log_with_object_internal(obj.as_ref());
110 }
111
112 #[inline(never)]
113 fn log_with_object_internal(&self, obj: &glib::Object) {
114 self.bool_error.filename.run_with_gstr(|filename| {
115 self.category.log(
116 Some(obj),
117 crate::DebugLevel::Error,
118 filename,
119 self.bool_error.function,
120 self.bool_error.line,
121 format_args!("{}", self.bool_error.message),
122 );
123 });
124 }
125
126 pub fn log_with_imp(&self, imp: &impl glib::subclass::types::ObjectSubclass) {
127 use glib::subclass::prelude::*;
128
129 self.log_with_object_internal(unsafe { imp.obj().unsafe_cast_ref::<glib::Object>() });
130 }
131
132 pub fn category(&self) -> crate::DebugCategory {
133 self.category
134 }
135}
136
137impl From<glib::BoolError> for LoggableError {
138 fn from(bool_error: glib::BoolError) -> Self {
139 skip_assert_initialized!();
140 LoggableError {
141 category: *crate::CAT_RUST,
142 bool_error,
143 }
144 }
145}
146
147#[cfg(test)]
148mod tests {
149 use super::*;
150
151 #[test]
152 fn error_message() {
153 crate::init().unwrap();
154
155 let e = ErrorMessage::new(
156 &crate::CoreError::Failed,
157 Some("message"),
158 Some("debug"),
159 "filename",
160 "function",
161 7,
162 );
163 assert_eq!(
164 format!("{e}"),
165 "Error Some(\"message\") (Some(\"debug\")) at filename:7"
166 );
167 }
168
169 #[test]
170 fn logabble_error() {
171 crate::init().unwrap();
172
173 let e: LoggableError = glib::BoolError::new("msg", "filename", "function", 7).into();
174 assert_eq!(format!("{e}"), "Error \"GST_RUST\": \"msg\" at filename:7");
175 }
176}