crypt-config 0.2.2

A crypt module that encrypt/decrypt json data based on the configuration. This might be used as a layer before saving data in Mongo DB or after fetching the data from the DB in order to decrypt them.
Documentation
use base64;
use openssl;
use serde_json;
use std::fmt::Display;
use std::string;
use std::{error, io};

pub type CryptResult<T> = Result<T, CryptError>;

#[derive(Debug)]
pub enum CryptError {
  Io(io::Error),
  Base64Decode(base64::DecodeError),
  Str(string::FromUtf8Error),
  Json(serde_json::Error),
  OpenSSL(openssl::error::ErrorStack),
  HasherNotFound(String),
  CipherNotFound(String),
  UnsupportedConfigVersion(),
  DuplicationCipherConfigVersion(String),
  DuplicationHasherConfigVersion(String),
  UnsupportedCipherAlgorithm(String),
  UnsupportedHasherAlgorithm(String),
  BadIterationCount(),
  InvalidDocument(String),
  InvalidQuery(String),
  OperationNotImplemented(String)
  // ...
}

macro_rules! impl_from_error {
  ($f: ty, $e: expr) => {
    impl From<$f> for CryptError {
      fn from(f: $f) -> CryptError {
        $e(f)
      }
    }
  };
}

impl_from_error!(io::Error, CryptError::Io);
impl_from_error!(base64::DecodeError, CryptError::Base64Decode);
impl_from_error!(string::FromUtf8Error, CryptError::Str);
impl_from_error!(serde_json::Error, CryptError::Json);
impl_from_error!(openssl::error::ErrorStack, CryptError::OpenSSL);

impl Display for CryptError {
  fn fmt(&self, f: &mut ::std::fmt::Formatter) -> Result<(), ::std::fmt::Error> {
    match *self {
      CryptError::Io(ref err) => err.fmt(f),
      CryptError::Base64Decode(ref err) => err.fmt(f),
      CryptError::Str(ref err) => err.fmt(f),
      CryptError::Json(ref err) => err.fmt(f),
      CryptError::OpenSSL(ref err) => err.fmt(f),
      CryptError::HasherNotFound(ref algorithm) => write!(f, "Hasher algorithm: {} not implemented", algorithm),
      CryptError::CipherNotFound(ref algorithm) => write!(f, "Cipher algorithm: {} not implemented", algorithm),
      CryptError::UnsupportedConfigVersion() => write!(f, "Crypt config version not supported"),
      CryptError::DuplicationCipherConfigVersion(ref version) => write!(f, "Duplication of cipher config version: {}", version),
      CryptError::DuplicationHasherConfigVersion(ref version) => write!(f, "Duplication of hasher config version: {}", version),
      CryptError::UnsupportedCipherAlgorithm(ref algorithm) => write!(f, "Unsupported cipher algorithm: {}", algorithm),
      CryptError::UnsupportedHasherAlgorithm(ref algorithm) => write!(f, "Unsupported hasher algorithm: {}", algorithm),
      CryptError::BadIterationCount() => write!(f, "Bad iteration count"),
      CryptError::InvalidDocument(ref reason) => write!(f, "Invalid document: {}", reason),
      CryptError::InvalidQuery(ref reason) => write!(f, "Invalid query: {}", reason),
      CryptError::OperationNotImplemented(ref info) => write!(f, "Operation not implemented: {}", info)
    }
  }
}

impl error::Error for CryptError {
  fn description(&self) -> &str {
    match *self {
      CryptError::Io(ref err) => err.description(),
      CryptError::Base64Decode(ref err) => err.description(),
      CryptError::Str(ref err) => err.description(),
      CryptError::Json(ref err) => err.description(),
      CryptError::OpenSSL(ref err) => err.description(),
      CryptError::HasherNotFound(ref _algorithm) => "Hasher algorithm not implemented",
      CryptError::CipherNotFound(ref _algorithm) => "Cipher algorithm not implemented",
      CryptError::UnsupportedConfigVersion() => "Crypt config version not supported",
      CryptError::DuplicationCipherConfigVersion(ref _version) => "Duplication of cipher config version",
      CryptError::DuplicationHasherConfigVersion(ref _version) => "Duplication of hasher config version",
      CryptError::UnsupportedCipherAlgorithm(ref _algorithm) => "Unsupported cipher algorithm",
      CryptError::UnsupportedHasherAlgorithm(ref _algorithm) => "Unsupported hasher algorithm",
      CryptError::BadIterationCount() => "Bad iteration count",
      CryptError::InvalidDocument(ref _reason) => "Invalid document",
      CryptError::InvalidQuery(ref _reason) => "Invalid query",
      CryptError::OperationNotImplemented(ref _info) => "Operation not implemented"
    }
  }

  fn source(&self) -> Option<&(dyn error::Error + 'static)> {
    match *self {
      CryptError::Io(ref err) => Some(err),
      CryptError::Base64Decode(ref err) => Some(err),
      CryptError::Str(ref err) => Some(err),
      CryptError::Json(ref err) => Some(err),
      CryptError::OpenSSL(ref err) => Some(err),
      _ => None
    }
  }
}