ex3-canister-error 0.17.3

Underlying error types used over ex3 core canisters.
Documentation
//! Error-related macros

/// Compare two errors.
///
/// NOTE: Used for testing only!
#[doc(hidden)]
#[macro_export]
macro_rules! assert_error_eq {
    ($left:expr, $right:expr) => {
        assert_eq!(
            Into::<$crate::Error>::into($left).to_string(),
            Into::<$crate::Error>::into($right).to_string(),
        );
    };
    ($left:expr, $right:expr,) => {
        $crate::assert_error_eq!($left, $right);
    };
    ($left:expr, $right:expr, $($arg:tt)+) => {
        assert_eq!(
            Into::<$crate::Error>::into($left).to_string(),
            Into::<$crate::Error>::into($right).to_string(),
            $($arg)+
        );
    }
}

#[doc(hidden)]
#[macro_export]
macro_rules! impl_error_info_conversion {
    ($source:ty) => {
        impl ::std::convert::From<$source> for ErrorInfo {
            fn from(error: $source) -> Self {
                ErrorInfo {
                    code: error.error_code(),
                    message: error.to_string(),
                }
            }
        }
    };
}

// macro_rules! impl_error_info_conversion {
//     ($source:ty) => {
//         impl ::std::convert::Into<ErrorInfo> for $source {
//             fn into(self) -> ErrorInfo {
//                 ErrorInfo {
//                     code: self.error_code(),
//                     message: self.to_string(),
//                 }
//             }
//         }
//     };
// }

/// A macro to implement conversion from source type to target type based on an implicit middle adaptor.
///
/// ## Examples
///
/// ```text
/// impl_error_conversion_with_adaptor!(SourceType, AdaptorType, TargetType)
/// ```
///
/// the expanded code:
///
/// ```text
/// impl From<SourceType> for TargetType {
///     fn from(source: SourceType) -> TargetType {
///         let adaptor: AdaptorType = source.into();
///         let target: TargetType = adaptor.into();
///         target
///     }
/// }
/// ```
#[doc(hidden)]
#[macro_export]
macro_rules! impl_error_conversion_with_adaptor {
    ($source:ty, $adaptor:ty, $target:ty) => {
        impl ::std::convert::From<$source> for $target {
            fn from(error: $source) -> Self {
                ::std::convert::Into::<$adaptor>::into(error).into()
            }
        }
    };
}

#[doc(hidden)]
#[macro_export]
macro_rules! def_error_base_on_kind {
    ($error:ident, $error_kind:ty, $comment_error:expr, $comment_because:expr, $comment_simple:expr) => {
        #[doc = $comment_error]
        #[derive(Error, Debug, Clone)]
        pub struct $error {
            kind: $error_kind,
            inner: ex3_common_error_info::ErrorInfo,
        }

        impl ::std::fmt::Display for $error {
            fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
                let err = self.cause();
                if f.alternate() {
                    write!(f, "{}: {}", self.kind(), err)
                } else {
                    write!(f, "{}({})", self.kind(), err)
                }
            }
        }

        impl $error_kind {
            #[doc = $comment_because]
            pub fn because<E>(self, reason: E) -> $error
            where
                E: Into<ex3_common_error_info::ErrorInfo>,
            {
                let error_info = reason.into();
                $error {
                    kind: self,
                    inner: ex3_common_error_info::ErrorInfo {
                        code: error_info.code,
                        message: format!("{}: {}", self, error_info.message),
                    },
                }
            }

            #[doc = $comment_simple]
            pub fn other<T>(self, reason: T) -> $error
            where
                T: ::std::fmt::Display,
            {
                $error {
                    kind: self,
                    inner: ex3_common_error_info::ErrorInfo {
                        code: 1000000,
                        message: reason.to_string(),
                    },
                }
            }
        }

        impl $error {
            /// Returns the general category of this error.
            pub fn kind(&self) -> $error_kind {
                self.kind
            }

            /// The lower-level source of this error.
            pub fn cause(&self) -> ex3_common_error_info::ErrorInfo {
                self.inner.clone()
            }
        }
    };
    ($error:ident, $error_kind:ty, $comment_error:expr) => {
        def_error_base_on_kind!(
            $error,
            $error_kind,
            $comment_error,
            concat!(
                "Creates `",
                stringify!($error),
                "` base on `",
                stringify!($error_kind),
                "` with an error as the reason."
            ),
            concat!(
                "Creates `",
                stringify!($error),
                "` base on `",
                stringify!($error_kind),
                "` with a simple string as the reason."
            )
        );
    };
    ($error:ident, $error_kind:ty) => {
        def_error_base_on_kind!($error, $error_kind, "/// TODO(doc): @witter");
    };
}

#[doc(hidden)]
#[macro_export]
macro_rules! map_string_err {
    ($message:expr, $target_error_ty:ty) => {
        fn map_string_err(message: String) -> $target_error_ty {
            OtherError::new(message).into()
        };
    };
}

#[doc(hidden)]
#[macro_export]
macro_rules! map_value_error {
    ($value_err:ty, $target_error_ty:ty) => {
        fn map_value_error(value_err: $value_err) -> $target_error_ty {
            OtherError::new(format!("{:?}", value_err)).into()
        };
    };
}

#[doc(hidden)]
#[macro_export]
macro_rules! map_grow_fail {
    ($grow_fail:ty, $target_error_ty:ty) => {
        fn map_grow_fail(grow_fail: $grow_fail) -> $target_error_ty {
            OtherError::new(format!("{:?}", grow_fail)).into()
        };
    };
}