use std::fmt; use std::error::Error as StdError; use reqwest::Error as ReqError; use serde::{ Serialize, Deserialize }; //pub type BoxError = Box<(dyn StdError + Send + Sync + 'static)>; pub type UResult = std::result::Result; #[derive(Serialize, Deserialize, Clone, Debug)] pub enum JobErrType { AlreadyRunning, Finished, System } #[derive(Serialize, Deserialize, Clone, Debug)] pub enum UErrType { ConnectionError, ParseError, JobError(JobErrType), Unknown, Raw(String) } #[derive(Serialize, Deserialize, Clone, Debug)] struct Inner { err_type: UErrType, source: String, } #[derive(Serialize, Deserialize, Clone)] pub struct UError { inner: Box } impl UError { pub fn new(err_type: UErrType, source: String) -> Self { Self { inner: Box::new(Inner { source, err_type }) } } pub fn new_type(err_type: UErrType) -> Self { UError::new(err_type, String::new()) } } impl fmt::Debug for UError { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { let mut builder = f.debug_struct("errors::UError"); builder.field("kind", &self.inner.err_type); builder.field("source", &self.inner.source); builder.finish() } } impl fmt::Display for UError { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { let e_type = match self.inner.err_type { UErrType::Raw(ref msg) => msg.clone(), UErrType::ConnectionError => "Connection error".to_string(), UErrType::ParseError => "Parse error".to_string(), UErrType::JobError(ref inner) => (String::from("Job error: ") + match *inner { JobErrType::AlreadyRunning => "job is already running", JobErrType::Finished => "once-scheduled job is already finished", JobErrType::System => "system error" }), UErrType::Unknown => "Unknown error".to_string(), }; f.write_str(&e_type)?; write!(f, ": {}", self.inner.source) } } impl From for UError { fn from(e: ReqError) -> Self { let err_type = if e.is_request() { UErrType::ConnectionError } else if e.is_decode() { UErrType::ParseError } else { UErrType::Unknown }; UError::new(err_type, e.to_string()) } }