use std::error;
use std::fmt;
use std::time::Duration;
use tokio_dbus::org_freedesktop_dbus;
use tokio_dbus::{SignatureBuf, SignatureError};
pub type Result<T, E = Error> = std::result::Result<T, E>;
#[derive(Debug)]
pub struct Error {
kind: Box<ErrorKind>,
}
impl Error {
pub(crate) fn new(kind: ErrorKind) -> Self {
Self {
kind: Box::new(kind),
}
}
pub fn remote(name: impl AsRef<str>, message: impl fmt::Display) -> Self {
Self::new(ErrorKind::Remote {
name: name.as_ref().into(),
message: message.to_string().into(),
})
}
pub fn name(&self) -> Option<&str> {
match &*self.kind {
ErrorKind::Remote { name, .. } => Some(name),
ErrorKind::Timeout(..) => Some(org_freedesktop_dbus::NO_REPLY_ERROR),
_ => None,
}
}
pub fn is_remote(&self) -> bool {
matches!(&*self.kind, ErrorKind::Remote { .. })
}
pub fn is_name_taken(&self) -> bool {
matches!(&*self.kind, ErrorKind::NameTaken(..))
}
pub fn is_timeout(&self) -> bool {
matches!(&*self.kind, ErrorKind::Timeout(..))
}
}
impl From<tokio_dbus::Error> for Error {
#[inline]
fn from(error: tokio_dbus::Error) -> Self {
Self::new(ErrorKind::Dbus(error))
}
}
impl From<SignatureError> for Error {
#[inline]
fn from(error: SignatureError) -> Self {
Self::new(ErrorKind::Signature(error))
}
}
impl From<std::io::Error> for Error {
#[inline]
fn from(error: std::io::Error) -> Self {
Self::new(ErrorKind::Dbus(error.into()))
}
}
impl fmt::Display for Error {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match &*self.kind {
ErrorKind::Dbus(..) => write!(f, "D-Bus error"),
ErrorKind::Signature(..) => write!(f, "Signature error"),
ErrorKind::Remote { name, message } => write!(f, "{name}: {message}"),
ErrorKind::UnsupportedType(signature) => {
write!(f, "Cannot represent a value of type `{signature}`")
}
ErrorKind::UnexpectedSignature(signatures) => {
let (expected, actual) = &**signatures;
write!(f, "Expected a value of type `{expected}`, got `{actual}`")
}
ErrorKind::MissingUniqueName => {
write!(f, "The bus did not reply to `Hello` with a unique name")
}
ErrorKind::NameTaken(name) => {
write!(f, "Could not acquire the name `{name}`")
}
ErrorKind::Timeout(timeout) => {
write!(f, "Call did not receive a reply within {timeout:?}")
}
}
}
}
impl error::Error for Error {
fn source(&self) -> Option<&(dyn error::Error + 'static)> {
match &*self.kind {
ErrorKind::Dbus(error) => Some(error),
ErrorKind::Signature(error) => Some(error),
_ => None,
}
}
}
#[derive(Debug)]
pub(crate) enum ErrorKind {
Dbus(tokio_dbus::Error),
Signature(SignatureError),
Remote { name: Box<str>, message: Box<str> },
UnsupportedType(Box<SignatureBuf>),
UnexpectedSignature(Box<(SignatureBuf, SignatureBuf)>),
MissingUniqueName,
NameTaken(Box<str>),
Timeout(Duration),
}