minio-rsc 0.2.6

rust for minio, api is compliant with the Amazon S3 protocol.
Documentation
//! Error and Result module.
use http::{
    header::{InvalidHeaderName, InvalidHeaderValue},
    Error as RequestError,
};
use serde::Deserialize;
use std::convert::Infallible;
use std::result;

/// A `Result` typedef to use with the [minio-rsc::error](Error) type
pub type Result<T> = result::Result<T, Error>;

/// Indicates an illegal variable was used.
#[derive(thiserror::Error, Debug)]
#[error("value error: {0}")]
pub struct ValueError(String);

impl ValueError {
    pub fn new<T: Into<String>>(value: T) -> Self {
        Self(value.into())
    }
}

impl From<&str> for ValueError {
    fn from(err: &str) -> Self {
        Self(err.to_string())
    }
}

impl From<InvalidHeaderValue> for ValueError {
    fn from(err: InvalidHeaderValue) -> Self {
        return ValueError(err.to_string());
    }
}

impl From<InvalidHeaderName> for ValueError {
    fn from(err: InvalidHeaderName) -> Self {
        return ValueError(err.to_string());
    }
}

impl From<Infallible> for ValueError {
    fn from(err: Infallible) -> Self {
        return ValueError(err.to_string());
    }
}

impl From<http::uri::InvalidUri> for ValueError {
    fn from(err: http::uri::InvalidUri) -> Self {
        return ValueError(err.to_string());
    }
}

/// S3 service returned error response.
#[derive(thiserror::Error, Debug, Deserialize)]
#[serde(rename_all = "PascalCase", rename = "Error")]
#[error("S3Error: {message}")]
pub struct S3Error {
    pub code: String,
    pub message: String,
    #[serde(default)]
    pub resource: String,
    pub request_id: String,
    pub host_id: Option<String>,
    pub bucket_name: Option<String>,
    pub object_name: Option<String>,
}

impl TryFrom<&[u8]> for S3Error {
    type Error = crate::xml::error::Error;
    fn try_from(res: &[u8]) -> std::result::Result<Self, Self::Error> {
        return Ok(crate::xml::de::from_reader(res)?);
    }
}

impl TryFrom<&str> for S3Error {
    type Error = crate::xml::error::Error;
    fn try_from(value: &str) -> std::result::Result<Self, Self::Error> {
        value.as_bytes().try_into()
    }
}

/// InternalException - thrown to indicate internal library error.
/// ErrorResponseException - thrown to indicate S3 service returned an error response.
/// thrown to indicate I/O error on S3 operation.
/// ServerException Thrown to indicate that S3 service returning HTTP server error.
#[derive(thiserror::Error, Debug)]
pub enum Error {
    /// inducate an illegal variable was used.
    #[error("{0}")]
    ValueError(String),

    /// indicate conncet to S3 service failed.
    #[error("{0}")]
    RequestError(#[from] RequestError),

    /// indicate XML parsing error.
    #[error("{0}")]
    XmlError(#[from] crate::xml::error::Error),

    /// indicate S3 service returned error response.
    #[error("{0}")]
    S3Error(#[from] S3Error),

    /// indicate S3 service returned invalid or no error response.
    #[error("{0}")]
    HttpError(#[from] reqwest::Error),

    /// indicate the http response returned is not expected by S3.
    #[error("Unexpected HTTP responses, status: {}", .0.status())]
    UnknownResponse(reqwest::Response),

    /// Message decoding failed in `select object content`.
    #[error("{0}")]
    MessageDecodeError(String),

    /// return an Error Message in `select_object_content`.
    #[error("{0}")]
    SelectObjectError(String),

    /// indicate I/O error, had on S3 operation.
    #[error("{0}")]
    IoError(#[from] std::io::Error),
}

impl<T: Into<ValueError>> From<T> for Error {
    fn from(err: T) -> Self {
        Error::ValueError(err.into().0)
    }
}

impl From<reqwest::Response> for Error {
    fn from(err: reqwest::Response) -> Self {
        Self::UnknownResponse(err)
    }
}

#[cfg(test)]
mod tests {
    use super::S3Error;
    use crate::xml::error::Error as XmlError;

    #[test]
    fn test_s3_error() {
        let res = r#"<?xml version="1.0" encoding="UTF-8"?>
        <Error>
            <Code>NoSuchKey</Code>
            <Message>The resource you requested does not exist</Message>
            <Resource>/mybucket/myfoto.jpg</Resource>
            <RequestId>4442587FB7D0A2F9</RequestId>
        </Error>"#;
        let result: std::result::Result<S3Error, XmlError> = res.as_bytes().try_into();
        assert!(result.is_ok());
        println!("{:?}", result);
    }
}