1use glib_sys;
8use std::borrow::Cow;
9use std::error;
10use std::ffi::CStr;
11use std::fmt;
12use std::str;
13use translate::*;
14use Quark;
15
16glib_wrapper! {
17 #[derive(PartialEq, Eq, PartialOrd, Ord, Hash)]
19 pub struct Error(Boxed<glib_sys::GError>);
20
21 match fn {
22 copy => |ptr| glib_sys::g_error_copy(ptr),
23 free => |ptr| glib_sys::g_error_free(ptr),
24 get_type => || glib_sys::g_error_get_type(),
25 }
26}
27
28unsafe impl Send for Error {}
29unsafe impl Sync for Error {}
30
31impl Error {
32 pub fn new<T: ErrorDomain>(error: T, message: &str) -> Error {
34 unsafe {
35 from_glib_full(glib_sys::g_error_new_literal(
36 T::domain().to_glib(),
37 error.code(),
38 message.to_glib_none().0,
39 ))
40 }
41 }
42
43 pub fn is<T: ErrorDomain>(&self) -> bool {
45 self.0.domain == T::domain().to_glib()
46 }
47
48 pub fn kind<T: ErrorDomain>(&self) -> Option<T> {
73 if self.0.domain == T::domain().to_glib() {
74 T::from(self.0.code)
75 } else {
76 None
77 }
78 }
79
80 fn message(&self) -> &str {
81 unsafe {
82 let bytes = CStr::from_ptr(self.0.message).to_bytes();
83 str::from_utf8(bytes)
84 .unwrap_or_else(|err| str::from_utf8(&bytes[..err.valid_up_to()]).unwrap())
85 }
86 }
87}
88
89impl fmt::Display for Error {
90 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
91 f.write_str(self.message())
92 }
93}
94
95impl error::Error for Error {
96 fn description(&self) -> &str {
97 self.message()
98 }
99}
100
101impl fmt::Debug for Error {
102 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
103 f.debug_struct("Error")
104 .field("domain", &::Quark::from_glib(self.0.domain))
105 .field("code", &self.0.code)
106 .field("message", &self.message())
107 .finish()
108 }
109}
110
111pub trait ErrorDomain: Copy {
115 fn domain() -> Quark;
119
120 fn code(self) -> i32;
122
123 fn from(code: i32) -> Option<Self>
128 where
129 Self: Sized;
130}
131
132#[macro_export]
134macro_rules! glib_bool_error(
135($msg:expr) => {
137 $crate::BoolError::new($msg, file!(), module_path!(), line!())
138 };
139
140($($msg:tt)*) => { {
142 $crate::BoolError::new(format!($($msg)*), file!(), module_path!(), line!())
143 }};
144);
145
146#[macro_export]
147macro_rules! glib_result_from_gboolean(
148($ffi_bool:expr, $msg:expr) => {
150 $crate::BoolError::from_glib($ffi_bool, $msg, file!(), module_path!(), line!())
151 };
152
153($ffi_bool:expr, $($msg:tt)*) => { {
155 $crate::BoolError::from_glib(
156 $ffi_bool,
157 format!($($msg)*),
158 file!(),
159 module_path!(),
160 line!(),
161 )
162 }};
163);
164
165#[derive(Debug, Clone)]
166pub struct BoolError {
167 pub message: Cow<'static, str>,
168 #[doc(hidden)]
169 pub filename: &'static str,
170 #[doc(hidden)]
171 pub function: &'static str,
172 #[doc(hidden)]
173 pub line: u32,
174}
175
176impl BoolError {
177 pub fn new<Msg: Into<Cow<'static, str>>>(
178 message: Msg,
179 filename: &'static str,
180 function: &'static str,
181 line: u32,
182 ) -> Self {
183 BoolError {
184 message: message.into(),
185 filename,
186 function,
187 line,
188 }
189 }
190
191 pub fn from_glib<Msg: Into<Cow<'static, str>>>(
192 b: glib_sys::gboolean,
193 message: Msg,
194 filename: &'static str,
195 function: &'static str,
196 line: u32,
197 ) -> Result<(), Self> {
198 match b {
199 glib_sys::GFALSE => Err(BoolError::new(message, filename, function, line)),
200 _ => Ok(()),
201 }
202 }
203}
204
205impl fmt::Display for BoolError {
206 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
207 write!(
208 f,
209 "Error {:?} in {:?} at {}:{}",
210 self.message, self.function, self.filename, self.line
211 )
212 }
213}
214
215impl error::Error for BoolError {
216 fn description(&self) -> &str {
217 self.message.as_ref()
218 }
219}
220
221#[cfg(test)]
222mod tests {
223 use super::*;
224
225 #[test]
226 fn test_bool_error() {
227 use std::error::Error;
228
229 let from_static_msg = glib_bool_error!("Static message");
230 assert_eq!(from_static_msg.description(), "Static message");
231
232 let from_dynamic_msg = glib_bool_error!("{} message", "Dynamic");
233 assert_eq!(from_dynamic_msg.description(), "Dynamic message");
234
235 let false_static_res = glib_result_from_gboolean!(glib_sys::GFALSE, "Static message");
236 assert!(false_static_res.is_err());
237 let static_err = false_static_res.err().unwrap();
238 assert_eq!(static_err.description(), "Static message");
239
240 let true_static_res = glib_result_from_gboolean!(glib_sys::GTRUE, "Static message");
241 assert!(true_static_res.is_ok());
242
243 let false_dynamic_res =
244 glib_result_from_gboolean!(glib_sys::GFALSE, "{} message", "Dynamic");
245 assert!(false_dynamic_res.is_err());
246 let dynamic_err = false_dynamic_res.err().unwrap();
247 assert_eq!(dynamic_err.description(), "Dynamic message");
248
249 let true_dynamic_res = glib_result_from_gboolean!(glib_sys::GTRUE, "{} message", "Dynamic");
250 assert!(true_dynamic_res.is_ok());
251 }
252}