Files
Nishant Joshi d107b44fd3 feat(api_models): add error structs (#532)
Co-authored-by: Sanchith Hegde <22217505+SanchithHegde@users.noreply.github.com>
2023-02-16 09:19:14 +00:00

107 lines
3.5 KiB
Rust

//! Errors and error specific types for universal use
/// Custom Result
/// A custom datatype that wraps the error variant <E> into a report, allowing
/// error_stack::Report<E> specific extendability
///
/// Effectively, equivalent to `Result<T, error_stack::Report<E>>`
///
pub type CustomResult<T, E> = error_stack::Result<T, E>;
macro_rules! impl_error_display {
($st: ident, $arg: tt) => {
impl std::fmt::Display for $st {
fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
fmt.write_str(&format!(
"{{ error_type: {:?}, error_description: {} }}",
self, $arg
))
}
}
};
}
macro_rules! impl_error_type {
($name: ident, $arg: tt) => {
#[doc = ""]
#[doc = stringify!(Error variant $name)]
#[doc = stringify!(Custom error variant for $arg)]
#[doc = ""]
#[derive(Debug)]
pub struct $name;
impl_error_display!($name, $arg);
impl std::error::Error for $name {}
};
}
impl_error_type!(ParsingError, "Parsing error");
/// Validation errors.
#[allow(missing_docs)] // Only to prevent warnings about struct fields not being documented
#[derive(Debug, thiserror::Error)]
pub enum ValidationError {
/// The provided input is missing a required field.
#[error("Missing required field: {field_name}")]
MissingRequiredField { field_name: String },
/// An incorrect value was provided for the field specified by `field_name`.
#[error("Incorrect value provided for field: {field_name}")]
IncorrectValueProvided { field_name: &'static str },
/// An invalid input was provided.
#[error("{message}")]
InvalidValue { message: String },
}
/// Cryptographic algorithm errors
#[derive(Debug, thiserror::Error)]
pub enum CryptoError {
/// The cryptographic algorithm was unable to encode the message
#[error("Failed to encode given message")]
EncodingFailed,
/// The cryptographic algorithm was unable to decode the message
#[error("Failed to decode given message")]
DecodingFailed,
/// The cryptographic algorithm was unable to sign the message
#[error("Failed to sign message")]
MessageSigningFailed,
/// The cryptographic algorithm was unable to verify the given signature
#[error("Failed to verify signature")]
SignatureVerificationFailed,
}
/// Allows [error_stack::Report] to change between error contexts
/// using the dependent [ErrorSwitch] trait to define relations & mappings between traits
pub trait ReportSwitchExt<T, U> {
/// Switch to the intended report by calling switch
/// requires error switch to be already implemented on the error type
fn switch(self) -> Result<T, error_stack::Report<U>>;
}
impl<T, U, V> ReportSwitchExt<T, U> for Result<T, error_stack::Report<V>>
where
V: ErrorSwitch<U> + error_stack::Context,
U: error_stack::Context,
{
#[track_caller]
fn switch(self) -> Result<T, error_stack::Report<U>> {
match self {
Ok(i) => Ok(i),
Err(er) => {
let new_c = er.current_context().switch();
Err(er.change_context(new_c))
}
}
}
}
/// Allow [error_stack::Report] to convert between error types
/// This autoimplements [ReportSwitchExt] for the corresponding errors
pub trait ErrorSwitch<T> {
/// Get the next error type that the source error can be escalated into
/// This does not consume the source error since we need to keep it in context
fn switch(&self) -> T;
}