magic_migrate 2.0.0

Automagically load and migrate deserialized structs to the latest version
Documentation
use std::fmt::Debug;
use std::fmt::Display;
use std::ops::Deref;

pub struct MagicError {
    inner: ErrorImpl,
}

struct ErrorImpl {
    inner: Box<dyn std::error::Error + Send + Sync>,
}

impl Debug for MagicError {
    fn fmt(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
        Debug::fmt(&self.inner, formatter)
    }
}

impl Display for MagicError {
    fn fmt(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
        Display::fmt(&self.inner, formatter)
    }
}

impl<E> From<E> for ErrorImpl
where
    E: std::error::Error + Send + Sync + 'static,
{
    #[cold]
    fn from(error: E) -> Self {
        ErrorImpl {
            inner: Box::new(error),
        }
    }
}

impl From<MagicError> for Box<dyn std::error::Error + Send + Sync + 'static> {
    fn from(value: MagicError) -> Self {
        value.inner.inner
    }
}

impl From<MagicError> for Box<dyn std::error::Error + Send + 'static> {
    fn from(value: MagicError) -> Self {
        value.inner.inner
    }
}

impl From<MagicError> for Box<dyn std::error::Error + 'static> {
    fn from(value: MagicError) -> Self {
        value.inner.inner
    }
}

impl<E> From<E> for MagicError
where
    E: std::error::Error + Send + Sync + 'static,
{
    fn from(error: E) -> Self {
        MagicError {
            inner: Box::new(error).into(),
        }
    }
}

impl Debug for ErrorImpl {
    fn fmt(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
        Debug::fmt(&self.inner, formatter)
    }
}

impl Display for ErrorImpl {
    fn fmt(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
        Display::fmt(&self.inner, formatter)
    }
}

impl Deref for MagicError {
    type Target = dyn std::error::Error + Send + Sync + 'static;

    fn deref(&self) -> &Self::Target {
        self.inner.inner.as_ref()
    }
}

impl AsRef<dyn std::error::Error + Send + Sync> for MagicError {
    fn as_ref(&self) -> &(dyn std::error::Error + Send + Sync + 'static) {
        &**self
    }
}

impl AsRef<dyn std::error::Error> for MagicError {
    fn as_ref(&self) -> &(dyn std::error::Error + 'static) {
        &**self
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_into_magic_migrate_error() {
        #[derive(Debug, thiserror::Error)]
        enum Error {
            #[error("Ohno: {0}")]
            OhNo(String),
        }

        let error: MagicError = Error::OhNo("An error".to_string()).into();
        let _: Box<dyn std::error::Error> = error.into();
    }
}