ntex-error 2.0.0

ntex error management
Documentation
use std::{error, fmt, panic::Location, sync::Arc};

use crate::{Backtrace, Bytes, ErrorDiagnostic, ResultType, ext::Extensions};

pub(crate) struct ErrorRepr<E> {
    pub(crate) error: E,
    pub(crate) tag: Option<Bytes>,
    pub(crate) service: Option<&'static str>,
    pub(crate) backtrace: Backtrace,
    pub(crate) ext: Extensions,
}

impl<E: Clone> ErrorRepr<E> {
    pub(crate) fn unpack(
        slf: Arc<ErrorRepr<E>>,
    ) -> (
        E,
        Option<Bytes>,
        Option<&'static str>,
        Backtrace,
        Extensions,
    ) {
        match Arc::try_unwrap(slf) {
            Ok(inner) => (
                inner.error,
                inner.tag,
                inner.service,
                inner.backtrace,
                inner.ext,
            ),
            Err(inner) => (
                inner.error.clone(),
                inner.tag.clone(),
                inner.service,
                inner.backtrace.clone(),
                inner.ext.clone(),
            ),
        }
    }

    pub(crate) fn with_mut<F>(mut slf: Arc<ErrorRepr<E>>, f: F) -> Arc<ErrorRepr<E>>
    where
        F: FnOnce(&mut ErrorRepr<E>),
    {
        if let Some(inner) = Arc::get_mut(&mut slf) {
            f(inner);
            slf
        } else {
            let mut inner = ErrorRepr::new2(
                slf.error.clone(),
                slf.tag.clone(),
                slf.service,
                slf.backtrace.clone(),
                slf.ext.clone(),
            );
            f(&mut inner);
            Arc::new(inner)
        }
    }
}

impl<E> ErrorRepr<E> {
    pub(crate) fn new2(
        error: E,
        tag: Option<Bytes>,
        service: Option<&'static str>,
        backtrace: Backtrace,
        ext: Extensions,
    ) -> Self {
        Self {
            error,
            tag,
            service,
            backtrace,
            ext,
        }
    }

    pub(crate) fn new3(
        error: E,
        tag: Option<Bytes>,
        service: Option<&'static str>,
        loc: &'static Location<'static>,
    ) -> Self {
        Self {
            error,
            tag,
            service,
            ext: Extensions::default(),
            backtrace: Backtrace::new(loc),
        }
    }
}

impl<E> ErrorDiagnostic for ErrorRepr<E>
where
    E: ErrorDiagnostic,
{
    fn typ(&self) -> ResultType {
        self.error.typ()
    }

    fn signature(&self) -> &'static str {
        self.error.signature()
    }

    fn tag(&self) -> Option<&Bytes> {
        if self.tag.is_some() {
            self.tag.as_ref()
        } else {
            self.error.tag()
        }
    }

    fn service(&self) -> Option<&'static str> {
        if self.service.is_some() {
            self.service
        } else {
            self.error.service()
        }
    }

    fn backtrace(&self) -> Option<&Backtrace> {
        Some(&self.backtrace)
    }
}

impl<E> error::Error for ErrorRepr<E>
where
    E: ErrorDiagnostic + error::Error,
{
    fn source(&self) -> Option<&(dyn error::Error + 'static)> {
        Some(&self.error)
    }
}

impl<E> fmt::Debug for ErrorRepr<E>
where
    E: ErrorDiagnostic + error::Error,
{
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        fmt::Debug::fmt(&self.error, f)
    }
}

impl<E> fmt::Display for ErrorRepr<E>
where
    E: ErrorDiagnostic + error::Error,
{
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        fmt::Display::fmt(&self.error, f)
    }
}