rustnao 0.3.4

A Rust implementation of a wrapper for the SauceNAO API.
Documentation
//! Error components for the library.
//! Much thanks to Andrew Gallant for the basis of this part of the library... followed [the following
//! code for this](https://github.com/BurntSushi/imdb-rename/blob/master/imdb-index/src/error.rs).

use failure::{Backtrace, Context, Fail};
use std::{fmt, result};

/// A type alias for handling errors related to rustnao.
pub type Result<T> = result::Result<T, Error>;

/// An error that can occur while interacting to the SauceNAO API.
#[derive(Debug)]
pub struct Error {
    context: Context<ErrType>,
}

impl Error {
    /// Return the kind of error
    pub fn kind(&self) -> &ErrType {
        self.context.get_context()
    }

    pub(crate) fn invalid_parse<T: AsRef<str>>(unk: T) -> Error {
        Error::from(ErrType::InvalidParse(unk.as_ref().to_string()))
    }

    pub(crate) fn invalid_path<T: AsRef<str>>(unk: T) -> Error {
        Error::from(ErrType::InvalidFile(unk.as_ref().to_string()))
    }

    pub(crate) fn invalid_serde<T: AsRef<str>>(unk: T) -> Error {
        Error::from(ErrType::InvalidSerde(unk.as_ref().to_string()))
    }

    pub(crate) fn invalid_code(code: i32, message: String) -> Error {
        Error::from(ErrType::InvalidCode { code, message })
    }

    pub(crate) fn invalid_request<T: AsRef<str>>(unk: T) -> Error {
        Error::from(ErrType::InvalidRequest(unk.as_ref().to_string()))
    }

    pub(crate) fn invalid_parameter(message: String) -> Error {
        Error::from(ErrType::InvalidParameters(message))
    }
}

impl Fail for Error {
    fn cause(&self) -> Option<&dyn Fail> {
        self.context.cause()
    }

    fn backtrace(&self) -> Option<&Backtrace> {
        self.context.backtrace()
    }
}

impl fmt::Display for Error {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        self.context.fmt(f)
    }
}

/// The specific type of error that can occur.
#[derive(Clone, Debug, Eq, PartialEq)]
pub enum ErrType {
    /// An error when forming the URL for the API.  
    ///
    /// The data provided is the error found.
    InvalidParse(String),
    /// An error when getting the file path of a file for the API.  
    ///
    /// The data provided is the error found.
    InvalidFile(String),
    /// An error when trying to deserialize the resulting JSON from the API
    ///
    /// The data provided is the error found.
    InvalidSerde(String),
    /// An error when receiving an unsuccessful code from the SauceNAO API.
    ///
    /// The data provided is the error code and message.
    InvalidCode {
        /// The error code from SauceNAO
        code: i32,
        /// The message showing the cause of the error from SauceNAO
        message: String,
    },
    /// An error when trying to send an invalid request to the API.
    ///
    /// The data provided is the error code and message.
    InvalidRequest(String),
    /// An error with some data that is passed in by the user.
    ///
    /// The data provided is an error message.
    InvalidParameters(String),
}

impl fmt::Display for ErrType {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self {
            ErrType::InvalidParse(ref unk) => {
                write!(f, "ERROR: URL was invalid, error was due to: {}", unk)
            }
            ErrType::InvalidFile(ref unk) => {
                write!(f, "ERROR: File path was invalid, error was due to: {}", unk)
            }
            ErrType::InvalidSerde(ref unk) => {
                write!(f, "ERROR: Could not properly serde results: {}", unk)
            }
            ErrType::InvalidCode { code, message } => write!(
                f,
                "ERROR: Recieved an invalid status code {} after API call with message: \"{}\"",
                code, message
            ),
            ErrType::InvalidRequest(ref unk) => write!(
                f,
                "ERROR: Failed to make the request, error was due to: {}",
                unk
            ),
            ErrType::InvalidParameters(message) => write!(
                f,
                "ERROR: An invalid parameter was passed, error was due to: {}",
                message
            ),
        }
    }
}

impl From<ErrType> for Error {
    fn from(err_type: ErrType) -> Error {
        Error::from(Context::new(err_type))
    }
}

impl From<Context<ErrType>> for Error {
    fn from(context: Context<ErrType>) -> Error {
        Error { context }
    }
}

impl From<serde_json::Error> for Error {
    fn from(err: serde_json::Error) -> Self {
        Error::invalid_serde(err.to_string())
    }
}

impl From<url::ParseError> for Error {
    fn from(err: url::ParseError) -> Self {
        Error::invalid_parse(err.to_string())
    }
}

impl From<std::num::ParseIntError> for Error {
    fn from(err: std::num::ParseIntError) -> Self {
        Error::invalid_parse(err.to_string())
    }
}

impl From<std::num::ParseFloatError> for Error {
    fn from(err: std::num::ParseFloatError) -> Self {
        Error::invalid_parse(err.to_string())
    }
}

impl From<std::io::Error> for Error {
    fn from(err: std::io::Error) -> Self {
        Error::invalid_path(err.to_string())
    }
}

impl From<surf::Error> for Error {
    fn from(err: surf::Error) -> Self {
        Error::invalid_request(err.to_string())
    }
}