indy-data-types 0.7.1

Common data types for Hyperledger Indy (https://www.hyperledger.org/projects), which provides a distributed-ledger-based foundation for self-sovereign identity (https://sovrin.org).
Documentation
use std::error::Error as StdError;
use thiserror::Error;

type DynError = Box<dyn StdError + Send + Sync + 'static>;

macro_rules! define_error {
    ($name:tt, $short:expr, $doc:tt) => {
        #[derive(Debug, Error)]
        #[doc=$doc]
        pub struct $name {
            pub context: Option<String>,
            pub source: Option<DynError>,
        }

        impl $name {
            #[allow(unused)]
            pub fn from_msg<T: Into<String>>(msg: T) -> Self {
                Self::from(msg.into())
            }

            #[allow(unused)]
            pub fn from_err<E>(err: E) -> Self
            where
                E: StdError + Send + Sync + 'static,
            {
                Self {
                    context: None,
                    source: Some(Box::new(err) as DynError),
                }
            }

            pub fn from_msg_err<M, E>(msg: M, err: E) -> Self
            where
                M: Into<String>,
                E: StdError + Send + Sync + 'static,
            {
                Self {
                    context: Some(msg.into()),
                    source: Some(Box::new(err) as DynError),
                }
            }
        }

        impl From<&str> for $name {
            fn from(context: &str) -> Self {
                Self {
                    context: Some(context.to_owned()),
                    source: None,
                }
            }
        }

        impl From<String> for $name {
            fn from(context: String) -> Self {
                Self {
                    context: Some(context),
                    source: None,
                }
            }
        }

        impl From<Option<String>> for $name {
            fn from(context: Option<String>) -> Self {
                Self {
                    context,
                    source: None,
                }
            }
        }

        impl<M, E> From<(M, E)> for $name
        where
            M: Into<String>,
            E: StdError + Send + Sync + 'static,
        {
            fn from((context, err): (M, E)) -> Self {
                Self::from_msg_err(context, err)
            }
        }

        impl From<$name> for String {
            fn from(val: $name) -> String {
                val.to_string()
            }
        }

        impl std::fmt::Display for $name {
            fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
                write!(f, $short)?;
                match self.context {
                    Some(ref context) => write!(f, ": {}", context),
                    None => Ok(()),
                }
            }
        }
    };
}

define_error!(
    ConversionError,
    "Conversion error",
    "Error type for general data conversion errors"
);

define_error!(
    EncryptionError,
    "Encryption error",
    "Error type for failure of encryption and decryption operations"
);

define_error!(
    UnexpectedError,
    "Unexpected error",
    "Error type for eventualities that shouldn't normally occur"
);

define_error!(
    ValidationError,
    "Validation error",
    "Error type for failures of `Validatable::validate`"
);

#[cfg(feature = "serde_json")]
impl From<serde_json::error::Error> for ConversionError {
    fn from(err: serde_json::error::Error) -> Self {
        Self::from_msg(err.to_string())
    }
}

impl From<std::str::Utf8Error> for ConversionError {
    fn from(_err: std::str::Utf8Error) -> Self {
        Self::from("UTF-8 decoding error")
    }
}

impl From<std::string::FromUtf8Error> for ConversionError {
    fn from(_err: std::string::FromUtf8Error) -> Self {
        Self::from("UTF-8 decoding error")
    }
}

impl From<ValidationError> for ConversionError {
    fn from(err: ValidationError) -> Self {
        Self {
            context: err.context,
            source: err.source,
        }
    }
}

impl From<ConversionError> for ValidationError {
    fn from(err: ConversionError) -> Self {
        Self {
            context: err.context,
            source: err.source,
        }
    }
}

impl From<UnexpectedError> for ConversionError {
    fn from(err: UnexpectedError) -> Self {
        Self {
            context: err.context,
            source: err.source,
        }
    }
}

impl From<UnexpectedError> for EncryptionError {
    fn from(err: UnexpectedError) -> Self {
        Self {
            context: err.context,
            source: err.source,
        }
    }
}