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

use {
    serde::*,
    std::{error::*, fmt},
};

//
// SerdeProblem
//

/// [Problem] with support for [ser::Error] and [de::Error].
///
/// Note that unlike [Problem] it also supports [Error], so take care to avoid adding it to a
/// [Problem]'s causation chain.
#[cfg_attr(docsrs, doc(cfg(feature = "serde")))]
pub struct SerdeProblem {
    /// Problem.
    pub problem: Problem,
}

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

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

impl Error for SerdeProblem {}

impl ser::Error for SerdeProblem {
    fn custom<ToStringT>(custom: ToStringT) -> Self
    where
        ToStringT: ToString,
    {
        SerializationError::new(format!("serde: {}", custom.to_string()))
            .into_problem()
            .into()
    }
}

impl de::Error for SerdeProblem {
    #[track_caller]
    fn custom<ToStringT>(custom: ToStringT) -> Self
    where
        ToStringT: ToString,
    {
        DeserializationError::as_problem(format!("serde: {}", custom.to_string())).into()
    }
}

impl From<Problem> for SerdeProblem {
    fn from(problem: Problem) -> Self {
        Self { problem }
    }
}
