use crate::error::ComponentError;
use skellige::{fungus::errors::*, prelude::git};
use std::{error::Error as StdError, fmt, io};
pub type RelicResult<T> = std::result::Result<T, RelicError>;
#[derive(Debug)]
pub enum RelicError {
Component(ComponentError),
Io(io::Error),
PackageNotFound(String),
RepoNotFound(String),
Fungus(FuError),
SerdeYaml(serde_yaml::Error),
Skellige(git::Error),
}
impl RelicError {
pub fn package_not_found<T: AsRef<str>>(pkg: T) -> RelicError {
RelicError::PackageNotFound(pkg.as_ref().to_string())
}
pub fn repo_not_found<T: AsRef<str>>(repo: T) -> RelicError {
RelicError::RepoNotFound(repo.as_ref().to_string())
}
pub fn is<T: StdError+'static>(&self) -> bool {
self.as_ref().is::<T>()
}
pub fn downcast_ref<T: StdError+'static>(&self) -> Option<&T> {
self.as_ref().downcast_ref::<T>()
}
pub fn downcast_mut<T: StdError+'static>(&mut self) -> Option<&mut T> {
self.as_mut().downcast_mut::<T>()
}
pub fn source(&self) -> Option<&(dyn StdError+'static)> {
self.as_ref().source()
}
}
impl StdError for RelicError {}
impl fmt::Display for RelicError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match *self {
RelicError::Component(ref err) => write!(f, "{}", err),
RelicError::Io(ref err) => write!(f, "{}", err),
RelicError::PackageNotFound(ref pkg) => write!(f, "failed to find package: {}", pkg),
RelicError::RepoNotFound(ref repo) => write!(f, "failed to find repo: {}", repo),
RelicError::Fungus(ref err) => write!(f, "{}", err),
RelicError::SerdeYaml(ref err) => write!(f, "{}", err),
RelicError::Skellige(ref err) => write!(f, "{}", err),
}
}
}
impl AsRef<dyn StdError> for RelicError {
fn as_ref(&self) -> &(dyn StdError+'static) {
match *self {
RelicError::Component(ref err) => err,
RelicError::Io(ref err) => err,
RelicError::PackageNotFound(_) => self,
RelicError::RepoNotFound(_) => self,
RelicError::Fungus(ref err) => err.as_ref(),
RelicError::SerdeYaml(ref err) => err as &(dyn StdError+'static),
RelicError::Skellige(ref err) => err.as_ref(),
}
}
}
impl AsMut<dyn StdError> for RelicError {
fn as_mut(&mut self) -> &mut (dyn StdError+'static) {
match *self {
RelicError::Component(ref mut err) => err,
RelicError::Io(ref mut err) => err,
RelicError::PackageNotFound(_) => self,
RelicError::RepoNotFound(_) => self,
RelicError::Fungus(ref mut err) => err.as_mut(),
RelicError::SerdeYaml(ref mut err) => err as &mut (dyn StdError+'static),
RelicError::Skellige(ref mut err) => err.as_mut(),
}
}
}
impl From<ComponentError> for RelicError {
fn from(err: ComponentError) -> RelicError {
RelicError::Component(err)
}
}
impl From<io::Error> for RelicError {
fn from(err: io::Error) -> RelicError {
RelicError::Io(err)
}
}
impl From<FuError> for RelicError {
fn from(err: FuError) -> RelicError {
RelicError::Fungus(err)
}
}
impl From<git::Error> for RelicError {
fn from(err: git::Error) -> RelicError {
RelicError::Skellige(err)
}
}
impl From<serde_yaml::Error> for RelicError {
fn from(err: serde_yaml::Error) -> RelicError {
RelicError::SerdeYaml(err)
}
}
#[cfg(test)]
mod tests {
use crate::prelude::*;
#[test]
fn test_errors() {
let mut err = RelicError::PackageNotFound("foo".to_string());
assert_eq!(RelicError::package_not_found("foo").to_string(), err.to_string());
assert_eq!("failed to find package: foo", err.to_string());
assert_eq!("failed to find package: foo", err.as_ref().to_string());
assert_eq!("failed to find package: foo", err.as_mut().to_string());
assert!(err.is::<RelicError>());
assert!(err.downcast_ref::<RelicError>().is_some());
assert!(err.downcast_mut::<RelicError>().is_some());
assert!(err.source().is_none());
let mut err = RelicError::RepoNotFound("foo".to_string());
assert_eq!(RelicError::repo_not_found("foo").to_string(), err.to_string());
assert_eq!("failed to find repo: foo", err.to_string());
assert_eq!("failed to find repo: foo", err.as_ref().to_string());
assert_eq!("failed to find repo: foo", err.as_mut().to_string());
assert!(err.is::<RelicError>());
assert!(err.downcast_ref::<RelicError>().is_some());
assert!(err.downcast_mut::<RelicError>().is_some());
assert!(err.source().is_none());
let mut err = RelicError::from(FuError::from(FileError::FailedToExtractString));
assert_eq!("failed to extract string from file", err.to_string());
assert_eq!("failed to extract string from file", err.as_ref().to_string());
assert_eq!("failed to extract string from file", err.as_mut().to_string());
assert!(err.is::<FileError>());
assert!(err.downcast_ref::<FileError>().is_some());
assert!(err.downcast_mut::<FileError>().is_some());
assert!(err.source().is_none());
let mut err = RelicError::from(git::Error::from(FuError::from(FileError::FailedToExtractString)));
assert_eq!("failed to extract string from file", err.to_string());
assert_eq!("failed to extract string from file", err.as_ref().to_string());
assert_eq!("failed to extract string from file", err.as_mut().to_string());
assert!(err.is::<FileError>());
assert!(err.downcast_ref::<FileError>().is_some());
assert!(err.downcast_mut::<FileError>().is_some());
assert!(err.source().is_none());
let mut err = git::Error::from(git2::Error::new(git2::ErrorCode::Ambiguous, git2::ErrorClass::Checkout, "foo"));
assert_eq!("foo; class=Checkout (20); code=Ambiguous (-5)", err.to_string());
assert_eq!("foo; class=Checkout (20); code=Ambiguous (-5)", err.as_ref().to_string());
assert_eq!("foo; class=Checkout (20); code=Ambiguous (-5)", err.as_mut().to_string());
assert!(err.is::<git2::Error>());
assert!(err.downcast_ref::<git2::Error>().is_some());
assert!(err.downcast_mut::<git2::Error>().is_some());
assert!(err.source().is_none());
}
}