use super::{super::problem::*, common::*};

//
// GlossProblemResult
//

/// Map [Err] into a gloss error problem.
pub trait GlossProblemResult<OkT, ErrorT> {
    /// Map [Err] into a gloss error problem.
    fn into_gloss<GlossErrorT>(self) -> Result<OkT, Problem>
    where
        ErrorT: ToString,
        GlossErrorT: 'static + std::error::Error + From<String> + Send + Sync;

    /// Map [Err] into a [GlossError] problem.
    #[track_caller]
    fn gloss(self) -> Result<OkT, Problem>
    where
        Self: Sized,
        ErrorT: ToString,
    {
        self.into_gloss::<GlossError>()
    }

    /// Map [Err] into a [ThreadError] problem.
    #[track_caller]
    fn into_thread_problem(self) -> Result<OkT, Problem>
    where
        Self: Sized,
        ErrorT: ToString,
    {
        self.into_gloss::<ThreadError>()
    }
}

impl<OkT, ErrorT> GlossProblemResult<OkT, ErrorT> for Result<OkT, ErrorT> {
    #[track_caller]
    fn into_gloss<GlossErrorT>(self) -> Result<OkT, Problem>
    where
        ErrorT: ToString,
        GlossErrorT: 'static + std::error::Error + From<String> + Send + Sync,
    {
        // Note that we are *not* using map_err() here because a closure cannot be annotated  with #[track_caller]
        match self {
            Ok(ok) => Ok(ok),
            Err(error) => Err(GlossErrorT::from(error.to_string()).into_problem()),
        }
    }
}
