use std::fmt;
use thiserror::Error;
use crate::types::structs::MethodFault;
use super::client;
pub type Result<T> = std::result::Result<T, Error>;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[non_exhaustive]
pub enum ErrorKind {
RemoteCommunication,
InvalidPropertyType,
MissingRequiredField,
UnexpectedPropertyPath,
NoDataFound,
TaskCancelled,
TaskFailed,
LockPoisoned,
Internal,
}
#[derive(Debug, Error)]
enum ErrorSource {
#[error("invalid property type for '{property}': expected {expected}, got {got}")]
InvalidPropertyType {
property: String,
expected: String,
got: String,
},
#[error("required field '{0}' was None")]
MissingRequiredField(String),
#[error("no data found in ObjectUpdate/ObjectContent")]
NoDataFound,
#[error("unexpected property path: {0}")]
UnexpectedPropertyPath(String),
#[error("remote communication error: {0:?}")]
RemoteCommunication(#[from] client::Error),
#[error("task cancelled")]
TaskCancelled,
#[error("task failed: {0:?}")]
TaskFailed(MethodFault),
#[error("lock poisoned: {0}")]
LockPoisoned(String),
#[error("internal error: {0}")]
Internal(String),
#[error(transparent)]
Other(#[from] Box<dyn std::error::Error + Send + Sync>),
}
#[derive(Debug)]
pub struct Error {
kind: ErrorKind,
source: ErrorSource,
}
impl Error {
pub fn kind(&self) -> ErrorKind {
self.kind
}
pub fn task_fault(&self) -> Option<&MethodFault> {
match &self.source {
ErrorSource::TaskFailed(fault) => Some(fault),
_ => None,
}
}
pub fn client_error(&self) -> Option<&client::Error> {
match &self.source {
ErrorSource::RemoteCommunication(e) => Some(e),
_ => None,
}
}
fn new(kind: ErrorKind, source: ErrorSource) -> Self {
Self { kind, source }
}
pub fn invalid_property_type(property: String, expected: String, got: String) -> Self {
Self::new(
ErrorKind::InvalidPropertyType,
ErrorSource::InvalidPropertyType {
property,
expected,
got,
},
)
}
pub fn missing_required_field(field: String) -> Self {
Self::new(
ErrorKind::MissingRequiredField,
ErrorSource::MissingRequiredField(field),
)
}
pub fn no_data_found() -> Self {
Self::new(ErrorKind::NoDataFound, ErrorSource::NoDataFound)
}
pub fn unexpected_property_path(path: String) -> Self {
Self::new(
ErrorKind::UnexpectedPropertyPath,
ErrorSource::UnexpectedPropertyPath(path),
)
}
pub fn task_cancelled() -> Self {
Self::new(ErrorKind::TaskCancelled, ErrorSource::TaskCancelled)
}
pub fn task_failed(fault: MethodFault) -> Self {
Self::new(ErrorKind::TaskFailed, ErrorSource::TaskFailed(fault))
}
pub fn lock_poisoned(msg: String) -> Self {
Self::new(ErrorKind::LockPoisoned, ErrorSource::LockPoisoned(msg))
}
pub fn internal(msg: String) -> Self {
Self::new(ErrorKind::Internal, ErrorSource::Internal(msg))
}
}
impl fmt::Display for Error {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", self.source)
}
}
impl std::error::Error for Error {
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
self.source.source()
}
}
impl From<client::Error> for Error {
fn from(e: client::Error) -> Self {
Error::new(ErrorKind::RemoteCommunication, ErrorSource::RemoteCommunication(e))
}
}
impl From<Box<dyn std::error::Error + Send + Sync>> for Error {
fn from(e: Box<dyn std::error::Error + Send + Sync>) -> Self {
Error::new(ErrorKind::Internal, ErrorSource::Other(e))
}
}
impl From<miniserde::Error> for Error {
fn from(_e: miniserde::Error) -> Self {
Error::new(ErrorKind::Internal, ErrorSource::Internal("miniserde deserialization error".to_string()))
}
}