1 // Copyright (C) 2016-2017 Sebastian Dröge <sebastian@centricular.com> 2 // 3 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or 4 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license 5 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your 6 // option. This file may not be copied, modified, or distributed 7 // except according to those terms. 8 9 use std::error::Error; 10 use std::fmt; 11 12 use glib; 13 use glib::IsA; 14 15 #[macro_export] 16 macro_rules! gst_error_msg( 17 // Plain strings 18 ($err:expr, ($msg:expr), [$dbg:expr]) => { 19 $crate::ErrorMessage::new(&$err, Some($msg), 20 Some($dbg), 21 file!(), module_path!(), line!()) 22 }; 23 ($err:expr, ($msg:expr)) => { 24 $crate::ErrorMessage::new(&$err, Some($msg), 25 None, 26 file!(), module_path!(), line!()) 27 }; 28 ($err:expr, [$dbg:expr]) => { 29 $crate::ErrorMessage::new(&$err, None, 30 Some($dbg), 31 file!(), module_path!(), line!()) 32 }; 33 34 // Format strings 35 ($err:expr, ($($msg:tt)*), [$($dbg:tt)*]) => { { 36 $crate::ErrorMessage::new(&$err, Some(format!($($msg)*).as_ref()), 37 Some(format!($($dbg)*).as_ref()), 38 file!(), module_path!(), line!()) 39 }}; 40 ($err:expr, ($($msg:tt)*)) => { { 41 $crate::ErrorMessage::new(&$err, Some(format!($($msg)*).as_ref()), 42 None, 43 file!(), module_path!(), line!()) 44 }}; 45 46 ($err:expr, [$($dbg:tt)*]) => { { 47 $crate::ErrorMessage::new(&$err, None, 48 Some(format!($($dbg)*).as_ref()), 49 file!(), module_path!(), line!()) 50 }}; 51 ); 52 53 #[derive(Clone, Debug, PartialEq, Eq)] 54 pub struct ErrorMessage { 55 pub(crate) error_domain: glib::Quark, 56 pub(crate) error_code: i32, 57 pub(crate) message: Option<String>, 58 pub(crate) debug: Option<String>, 59 pub(crate) filename: &'static str, 60 pub(crate) function: &'static str, 61 pub(crate) line: u32, 62 } 63 64 impl ErrorMessage { new<T: ::MessageErrorDomain>( error: &T, message: Option<&str>, debug: Option<&str>, filename: &'static str, function: &'static str, line: u32, ) -> ErrorMessage65 pub fn new<T: ::MessageErrorDomain>( 66 error: &T, 67 message: Option<&str>, 68 debug: Option<&str>, 69 filename: &'static str, 70 function: &'static str, 71 line: u32, 72 ) -> ErrorMessage { 73 let error_domain = T::domain(); 74 let error_code = error.code(); 75 76 ErrorMessage { 77 error_domain, 78 error_code, 79 message: message.map(String::from), 80 debug: debug.map(String::from), 81 filename, 82 function, 83 line, 84 } 85 } 86 } 87 88 impl fmt::Display for ErrorMessage { fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error>89 fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { 90 write!( 91 f, 92 "Error {:?} ({:?}) at {}:{}", 93 self.message, self.debug, self.filename, self.line 94 ) 95 } 96 } 97 98 impl Error for ErrorMessage { description(&self) -> &str99 fn description(&self) -> &str { 100 "ErrorMessage" 101 } 102 } 103 104 #[macro_export] 105 macro_rules! gst_loggable_error( 106 // Plain strings 107 ($cat:expr, $msg:expr) => { 108 $crate::LoggableError::new($cat.clone(), $crate::glib::glib_bool_error!($msg)) 109 }; 110 111 // Format strings 112 ($cat:expr, $($msg:tt)*) => { { 113 $crate::LoggableError::new($cat.clone(), $crate::glib::glib_bool_error!($($msg)*)) 114 }}; 115 ); 116 117 #[macro_export] 118 macro_rules! gst_result_from_gboolean( 119 // Plain strings 120 ($gst_sys_bool:expr, $cat:expr, $msg:expr) => { 121 $crate::glib::glib_result_from_gboolean!($gst_sys_bool, $msg) 122 .map_err(|bool_err| $crate::LoggableError::new($cat.clone(), bool_err)) 123 }; 124 125 // Format strings 126 ($gst_sys_bool:expr, $cat:expr, $($msg:tt)*) => { { 127 $crate::glib::glib_result_from_gboolean!($gst_sys_bool, $($msg)*) 128 .map_err(|bool_err| $crate::LoggableError::new($cat.clone(), bool_err)) 129 }}; 130 ); 131 132 #[derive(Debug, Clone)] 133 pub struct LoggableError { 134 category: ::DebugCategory, 135 bool_error: glib::BoolError, 136 } 137 138 impl LoggableError { new(category: ::DebugCategory, bool_error: glib::BoolError) -> LoggableError139 pub fn new(category: ::DebugCategory, bool_error: glib::BoolError) -> LoggableError { 140 LoggableError { 141 category, 142 bool_error, 143 } 144 } 145 log(&self)146 pub fn log(&self) { 147 self.category.log( 148 None as Option<&::Object>, 149 ::DebugLevel::Error, 150 self.bool_error.filename, 151 self.bool_error.function, 152 self.bool_error.line, 153 format_args!("{}", self.bool_error.message), 154 ); 155 } 156 log_with_object<O: IsA<::Object>>(&self, obj: &O)157 pub fn log_with_object<O: IsA<::Object>>(&self, obj: &O) { 158 self.category.log( 159 Some(obj), 160 ::DebugLevel::Error, 161 self.bool_error.filename, 162 self.bool_error.function, 163 self.bool_error.line, 164 format_args!("{}", self.bool_error.message), 165 ); 166 } 167 category(&self) -> ::DebugCategory168 pub fn category(&self) -> ::DebugCategory { 169 self.category 170 } 171 } 172 173 impl From<glib::BoolError> for LoggableError { from(bool_error: glib::BoolError) -> Self174 fn from(bool_error: glib::BoolError) -> Self { 175 LoggableError { 176 category: *::CAT_RUST, 177 bool_error, 178 } 179 } 180 } 181 182 impl fmt::Display for LoggableError { fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error>183 fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { 184 write!( 185 f, 186 "Error {:?}: {:?} at {}:{}", 187 self.category.get_name(), 188 self.bool_error.message, 189 self.bool_error.filename, 190 self.bool_error.line 191 ) 192 } 193 } 194 195 impl Error for LoggableError { description(&self) -> &str196 fn description(&self) -> &str { 197 self.bool_error.message.as_ref() 198 } 199 } 200