1use crate::arg::TypeMismatchError;
2use std::ffi::CString;
3use std::{ptr, fmt};
4use crate::{arg, to_c_str, c_str_to_slice, init_dbus, Message};
5use crate::strings::ErrorName;
6use std::error::Error as stdError;
7
8/// D-Bus Error wrapper.
9///
10/// This is a wrapper around the libc dbus error object.
11pub struct Error {
12 e: ffi::DBusError,
13}
14
15unsafe impl Send for Error {}
16
17// Note! For this Sync impl to be safe, it requires that no functions that take &self,
18// actually calls into FFI. All functions that call into FFI with a ffi::DBusError
19// must take &mut self.
20
21unsafe impl Sync for Error {}
22
23impl Error {
24
25 /// Create a new custom D-Bus Error.
26 pub fn new_custom<'a, N: Into<ErrorName<'a>>>(name: N, message: &str) -> Error {
27 let n = to_c_str(&name.into());
28 let m = to_c_str(&message.replace("%","%%"));
29 let mut e = Error::empty();
30
31 unsafe { ffi::dbus_set_error(e.get_mut(), n.as_ptr(), m.as_ptr()) };
32 e
33 }
34
35 /// Create a new generic D-Bus Error with "org.freedesktop.DBus.Error.Failed" as the Error name.
36 pub fn new_failed(message: &str) -> Error {
37 Error::new_custom("org.freedesktop.DBus.Error.Failed", message)
38 }
39
40 pub (crate) fn empty() -> Error {
41 init_dbus();
42 let mut e = ffi::DBusError {
43 name: ptr::null(),
44 message: ptr::null(),
45 dummy: 0,
46 padding1: ptr::null()
47 };
48 unsafe { ffi::dbus_error_init(&mut e); }
49 Error{ e: e }
50 }
51
52 /// Error name/type, e g 'org.freedesktop.DBus.Error.Failed'
53 pub fn name(&self) -> Option<&str> {
54 c_str_to_slice(&self.e.name)
55 }
56
57 /// Custom message, e g 'Could not find a matching object path'
58 pub fn message(&self) -> Option<&str> {
59 c_str_to_slice(&self.e.message)
60 }
61
62 pub (crate) fn get_mut(&mut self) -> &mut ffi::DBusError { &mut self.e }
63}
64
65impl Drop for Error {
66 fn drop(&mut self) {
67 unsafe { ffi::dbus_error_free(&mut self.e); }
68 }
69}
70
71impl fmt::Debug for Error {
72 fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
73 write!(f, "D-Bus error: {} ({})", self.message().unwrap_or(""),
74 self.name().unwrap_or(""))
75 }
76}
77
78impl stdError for Error {
79 fn description(&self) -> &str { "D-Bus error" }
80}
81
82impl fmt::Display for Error {
83 fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
84 if let Some(x: &str) = self.message() {
85 write!(f, "{}", x)
86 } else { Ok(()) }
87 }
88}
89
90impl From<arg::TypeMismatchError> for Error {
91 fn from(t: arg::TypeMismatchError) -> Error {
92 Error::new_custom(name:"org.freedesktop.DBus.Error.Failed", &format!("{}", t))
93 }
94}
95
96
97impl From<MethodErr> for Error {
98 fn from(t: MethodErr) -> Error {
99 Error::new_custom(name:t.errorname(), message:t.description())
100 }
101}
102
103
104#[derive(Clone, Debug, PartialOrd, Ord, PartialEq, Eq)]
105/// A D-Bus Method Error, containing an error name and a description.
106///
107/// Unlike the "Error" struct, this is a Rust native struct.
108pub struct MethodErr(ErrorName<'static>, String);
109
110impl MethodErr {
111 /// Create an Invalid Args MethodErr.
112 pub fn invalid_arg<T: fmt::Debug + ?Sized>(a: &T) -> MethodErr {
113 ("org.freedesktop.DBus.Error.InvalidArgs", format!("Invalid argument {:?}", a)).into()
114 }
115 /// Create a MethodErr that there are not enough arguments given.
116 pub fn no_arg() -> MethodErr {
117 ("org.freedesktop.DBus.Error.InvalidArgs", "Not enough arguments").into()
118 }
119 /// Create a MethodErr that the method failed in the way specified.
120 pub fn failed<T: fmt::Display + ?Sized>(a: &T) -> MethodErr {
121 ("org.freedesktop.DBus.Error.Failed", a.to_string()).into()
122 }
123
124 /// Create a MethodErr that the Object path was unknown.
125 pub fn no_path<T: fmt::Display + ?Sized>(a: &T) -> MethodErr {
126 ("org.freedesktop.DBus.Error.UnknownObject", format!("Unknown object path {}", a)).into()
127 }
128
129 /// Create a MethodErr that the Interface was unknown.
130 pub fn no_interface<T: fmt::Display + ?Sized>(a: &T) -> MethodErr {
131 ("org.freedesktop.DBus.Error.UnknownInterface", format!("Unknown interface {}", a)).into()
132 }
133 /// Create a MethodErr that the Method was unknown.
134 pub fn no_method<T: fmt::Display + ?Sized>(a: &T) -> MethodErr {
135 ("org.freedesktop.DBus.Error.UnknownMethod", format!("Unknown method {}", a)).into()
136 }
137 /// Create a MethodErr that the Property was unknown.
138 pub fn no_property<T: fmt::Display + ?Sized>(a: &T) -> MethodErr {
139 ("org.freedesktop.DBus.Error.UnknownProperty", format!("Unknown property {}", a)).into()
140 }
141 /// Create a MethodErr that the Property was read-only.
142 pub fn ro_property<T: fmt::Display + ?Sized>(a: &T) -> MethodErr {
143 ("org.freedesktop.DBus.Error.PropertyReadOnly", format!("Property {} is read only", a)).into()
144 }
145
146 /// Error name accessor
147 pub fn errorname(&self) -> &ErrorName<'static> { &self.0 }
148 /// Description accessor
149 pub fn description(&self) -> &str { &self.1 }
150
151 /// Creates an error reply from a method call message.
152 ///
153 /// Note: You normally don't need to use this function,
154 /// as it is called internally from Tree::handle.
155 pub fn to_message(&self, msg: &Message) -> Message {
156 msg.error(&self.0, &CString::new(&*self.1).unwrap())
157 }
158}
159
160impl fmt::Display for MethodErr {
161 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
162 write!(f, "{}", self.description())
163 }
164}
165
166impl stdError for MethodErr {}
167
168impl From<TypeMismatchError> for MethodErr {
169 fn from(t: TypeMismatchError) -> MethodErr { ("org.freedesktop.DBus.Error.Failed", format!("{}", t)).into() }
170}
171
172impl<T: Into<ErrorName<'static>>, M: Into<String>> From<(T, M)> for MethodErr {
173 fn from((t: T, m: M): (T, M)) -> MethodErr { MethodErr(t.into(), m.into()) }
174}
175
176impl From<Error> for MethodErr {
177 fn from(t: Error) -> MethodErr {
178 let n: &str = t.name().unwrap_or(default:"org.freedesktop.DBus.Error.Failed");
179 let m: &str = t.message().unwrap_or(default:"Unknown error");
180 MethodErr(String::from(n).into(), m.into())
181 }
182}
183