sett 0.4.0

Rust port of sett (data compression, encryption and transfer tool).
Documentation
//! Error namespace

use crate::remote::s3;

/// Error occurring when parsing urls
#[derive(Debug)]
pub struct UrlParseError(pub String);

impl UrlParseError {
    /// Convert from other errors explicitly
    pub fn from(err: impl std::fmt::Display) -> Self {
        Self(format!("{err}"))
    }
}

impl std::fmt::Display for UrlParseError {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        self.0.fmt(f)
    }
}
impl std::error::Error for UrlParseError {}

/// Error occurring when trying to establish a connection to portal
#[derive(Debug)]
pub enum CreateError {
    /// Neither http nor https
    InvalidScheme(String),
    /// Url parse errors
    InvalidUrl(UrlParseError),
    /// Connection errors
    ConnectionError(reqwest::Error),
}

impl std::fmt::Display for CreateError {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        write!(f, "Portal create error")?;
        if let Self::InvalidScheme(url) = self {
            write!(f, ": invalid scheme {url}")?;
        }
        Ok(())
    }
}

impl std::error::Error for CreateError {
    fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
        match self {
            Self::InvalidUrl(source) => Some(source),
            Self::ConnectionError(source) => Some(source),
            _ => None,
        }
    }
}

impl From<UrlParseError> for CreateError {
    fn from(value: UrlParseError) -> Self {
        Self::InvalidUrl(value)
    }
}

impl From<reqwest::Error> for CreateError {
    fn from(value: reqwest::Error) -> Self {
        Self::ConnectionError(value)
    }
}

/// Error happening when sending a request to portal
#[derive(Debug)]
pub enum Error<E = std::convert::Infallible> {
    /// Error during the request
    Request(reqwest::Error),
    /// URL parse error
    InvalidUrl(UrlParseError),
    /// HTTP response with a status code which is not success
    Server(E),
    /// No valid authentication available.
    Unauthorized,
}

impl<E: std::fmt::Display> std::fmt::Display for Error<E> {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        write!(f, "Portal error")?;
        if let Self::Server(reason) = self {
            write!(f, ": {reason}")?;
        }
        Ok(())
    }
}

impl<E: std::fmt::Debug + std::fmt::Display> std::error::Error for Error<E> {
    fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
        match self {
            Self::InvalidUrl(source) => Some(source),
            Self::Request(source) => Some(source),
            _ => None,
        }
    }
}

impl<E> From<reqwest::Error> for Error<E> {
    fn from(value: reqwest::Error) -> Self {
        Self::Request(value)
    }
}
impl<E> From<UrlParseError> for Error<E> {
    fn from(value: UrlParseError) -> Self {
        Self::InvalidUrl(value)
    }
}

/// Error context for [Error] indicating an invalid package
#[derive(Debug)]
pub struct InvalidPackage(pub String);

impl std::fmt::Display for InvalidPackage {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        write!(f, "Package is invalid or could not be verified: {}", self.0)
    }
}
impl From<InvalidPackage> for Error<InvalidPackage> {
    fn from(value: InvalidPackage) -> Self {
        Self::Server(value)
    }
}

/// Error context for [Error] indicating an S3 related error.
#[derive(Debug)]
pub struct FetchS3Credentials(pub String);

impl std::fmt::Display for FetchS3Credentials {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        write!(f, "Failed to fetch s3 credentials: {}", self.0)
    }
}
impl From<FetchS3Credentials> for Error<FetchS3Credentials> {
    fn from(value: FetchS3Credentials) -> Self {
        Self::Server(value)
    }
}

impl From<Error<FetchS3Credentials>> for s3::error::CredentialsRetrievalError {
    fn from(value: Error<FetchS3Credentials>) -> Self {
        Self {
            message: value.to_string(),
        }
    }
}

impl From<Error<FetchS3Credentials>> for s3::error::ClientError {
    fn from(value: Error<FetchS3Credentials>) -> Self {
        s3::error::CredentialsRetrievalError::from(value).into()
    }
}

/// Error context for [Error] indicating a data transfer related error
#[derive(Debug)]
pub struct FetchDataTransfer(pub String);

impl std::fmt::Display for FetchDataTransfer {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        write!(f, "Failed to fetch data transfers: {}", self.0)
    }
}
impl From<FetchDataTransfer> for Error<FetchDataTransfer> {
    fn from(value: FetchDataTransfer) -> Self {
        Self::Server(value)
    }
}