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