#![allow(unused_macros)]
use core::fmt;
use signatory::signature;
use std::{
error::Error as StdError,
string::{String, ToString},
};
#[derive(Debug)]
pub struct Error {
kind: ErrorKind,
description: Option<String>,
}
#[derive(Debug, Copy, Clone, PartialEq)]
pub enum ErrorKind {
InvalidPrefix,
InvalidKeyLength,
VerifyError,
SignatureError,
ChecksumFailure,
CodecFailure,
IncorrectKeyType,
InvalidPayload,
InvalidSignatureLength,
}
#[macro_export]
macro_rules! err {
($variant:ident, $msg:expr) => {
$crate::error::Error::new(
$crate::error::ErrorKind::$variant,
Some($msg)
)
};
($variant:ident, $fmt:expr, $($arg:tt)+) => {
err!($variant, &format!($fmt, $($arg)+))
};
}
impl ErrorKind {
pub fn as_str(self) -> &'static str {
match self {
ErrorKind::InvalidPrefix => "Invalid byte prefix",
ErrorKind::InvalidKeyLength => "Invalid key length",
ErrorKind::InvalidSignatureLength => "Invalid signature length",
ErrorKind::VerifyError => "Signature verification failure",
ErrorKind::ChecksumFailure => "Checksum match failure",
ErrorKind::CodecFailure => "Codec failure",
ErrorKind::SignatureError => "Signature failure",
ErrorKind::IncorrectKeyType => "Incorrect key type",
ErrorKind::InvalidPayload => "Invalid payload",
}
}
}
impl fmt::Display for ErrorKind {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", self.as_str())
}
}
impl Error {
pub fn new(kind: ErrorKind, description: Option<&str>) -> Self {
Error {
kind,
description: description.map(|desc| desc.to_string()),
}
}
pub fn kind(&self) -> ErrorKind {
self.kind
}
}
impl From<signature::Error> for Error {
fn from(source: signature::Error) -> Error {
err!(SignatureError, &format!("Signature error: {}", source))
}
}
impl From<data_encoding::DecodeError> for Error {
fn from(source: data_encoding::DecodeError) -> Error {
err!(CodecFailure, "Data encoding failure: {}", source)
}
}
impl StdError for Error {
fn description(&self) -> &str {
if let Some(ref desc) = self.description {
desc
} else {
self.kind.as_str()
}
}
}
impl fmt::Display for Error {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self.description {
Some(ref desc) => write!(f, "{}: {}", self.kind.as_str(), desc),
None => write!(f, "{}", self.kind.as_str()),
}
}
}
#[cfg(test)]
mod tests {
#[test]
fn test_error_to_string() {
assert_eq!(
err!(InvalidKeyLength, "Testing").to_string(),
"Invalid key length: Testing"
);
assert_eq!(
err!(InvalidKeyLength, "Testing {}", 1).to_string(),
"Invalid key length: Testing 1"
);
}
}