aboutsummaryrefslogtreecommitdiff
path: root/src/eyreish/context.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/eyreish/context.rs')
-rw-r--r--src/eyreish/context.rs217
1 files changed, 217 insertions, 0 deletions
diff --git a/src/eyreish/context.rs b/src/eyreish/context.rs
new file mode 100644
index 0000000..3d9238b
--- /dev/null
+++ b/src/eyreish/context.rs
@@ -0,0 +1,217 @@
+use super::error::{ContextError, ErrorImpl};
+use super::{Report, WrapErr};
+use core::fmt::{self, Debug, Display, Write};
+
+use std::error::Error as StdError;
+
+use crate::{Diagnostic, LabeledSpan};
+
+mod ext {
+ use super::*;
+
+ pub trait Diag {
+ #[cfg_attr(track_caller, track_caller)]
+ fn ext_report<D>(self, msg: D) -> Report
+ where
+ D: Display + Send + Sync + 'static;
+ }
+
+ impl<E> Diag for E
+ where
+ E: Diagnostic + Send + Sync + 'static,
+ {
+ fn ext_report<D>(self, msg: D) -> Report
+ where
+ D: Display + Send + Sync + 'static,
+ {
+ Report::from_msg(msg, self)
+ }
+ }
+
+ impl Diag for Report {
+ fn ext_report<D>(self, msg: D) -> Report
+ where
+ D: Display + Send + Sync + 'static,
+ {
+ self.wrap_err(msg)
+ }
+ }
+}
+
+impl<T, E> WrapErr<T, E> for Result<T, E>
+where
+ E: ext::Diag + Send + Sync + 'static,
+{
+ fn wrap_err<D>(self, msg: D) -> Result<T, Report>
+ where
+ D: Display + Send + Sync + 'static,
+ {
+ match self {
+ Ok(t) => Ok(t),
+ Err(e) => Err(e.ext_report(msg)),
+ }
+ }
+
+ fn wrap_err_with<D, F>(self, msg: F) -> Result<T, Report>
+ where
+ D: Display + Send + Sync + 'static,
+ F: FnOnce() -> D,
+ {
+ match self {
+ Ok(t) => Ok(t),
+ Err(e) => Err(e.ext_report(msg())),
+ }
+ }
+
+ fn context<D>(self, msg: D) -> Result<T, Report>
+ where
+ D: Display + Send + Sync + 'static,
+ {
+ self.wrap_err(msg)
+ }
+
+ fn with_context<D, F>(self, msg: F) -> Result<T, Report>
+ where
+ D: Display + Send + Sync + 'static,
+ F: FnOnce() -> D,
+ {
+ self.wrap_err_with(msg)
+ }
+}
+
+impl<D, E> Debug for ContextError<D, E>
+where
+ D: Display,
+ E: Debug,
+{
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ f.debug_struct("Error")
+ .field("msg", &Quoted(&self.msg))
+ .field("source", &self.error)
+ .finish()
+ }
+}
+
+impl<D, E> Display for ContextError<D, E>
+where
+ D: Display,
+{
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ Display::fmt(&self.msg, f)
+ }
+}
+
+impl<D, E> StdError for ContextError<D, E>
+where
+ D: Display,
+ E: StdError + 'static,
+{
+ fn source(&self) -> Option<&(dyn StdError + 'static)> {
+ Some(&self.error)
+ }
+}
+
+impl<D> StdError for ContextError<D, Report>
+where
+ D: Display,
+{
+ fn source(&self) -> Option<&(dyn StdError + 'static)> {
+ unsafe { Some(ErrorImpl::error(self.error.inner.by_ref())) }
+ }
+}
+
+impl<D, E> Diagnostic for ContextError<D, E>
+where
+ D: Display,
+ E: Diagnostic + 'static,
+{
+ fn code<'a>(&'a self) -> Option<Box<dyn Display + 'a>> {
+ self.error.code()
+ }
+
+ fn severity(&self) -> Option<crate::Severity> {
+ self.error.severity()
+ }
+
+ fn help<'a>(&'a self) -> Option<Box<dyn Display + 'a>> {
+ self.error.help()
+ }
+
+ fn url<'a>(&'a self) -> Option<Box<dyn Display + 'a>> {
+ self.error.url()
+ }
+
+ fn labels<'a>(&'a self) -> Option<Box<dyn Iterator<Item = LabeledSpan> + 'a>> {
+ self.error.labels()
+ }
+
+ fn source_code(&self) -> Option<&dyn crate::SourceCode> {
+ self.error.source_code()
+ }
+
+ fn related<'a>(&'a self) -> Option<Box<dyn Iterator<Item = &'a dyn Diagnostic> + 'a>> {
+ self.error.related()
+ }
+}
+
+impl<D> Diagnostic for ContextError<D, Report>
+where
+ D: Display,
+{
+ fn code<'a>(&'a self) -> Option<Box<dyn Display + 'a>> {
+ unsafe { ErrorImpl::diagnostic(self.error.inner.by_ref()).code() }
+ }
+
+ fn severity(&self) -> Option<crate::Severity> {
+ unsafe { ErrorImpl::diagnostic(self.error.inner.by_ref()).severity() }
+ }
+
+ fn help<'a>(&'a self) -> Option<Box<dyn Display + 'a>> {
+ unsafe { ErrorImpl::diagnostic(self.error.inner.by_ref()).help() }
+ }
+
+ fn url<'a>(&'a self) -> Option<Box<dyn Display + 'a>> {
+ unsafe { ErrorImpl::diagnostic(self.error.inner.by_ref()).url() }
+ }
+
+ fn labels<'a>(&'a self) -> Option<Box<dyn Iterator<Item = LabeledSpan> + 'a>> {
+ unsafe { ErrorImpl::diagnostic(self.error.inner.by_ref()).labels() }
+ }
+
+ fn source_code(&self) -> Option<&dyn crate::SourceCode> {
+ self.error.source_code()
+ }
+
+ fn related<'a>(&'a self) -> Option<Box<dyn Iterator<Item = &'a dyn Diagnostic> + 'a>> {
+ self.error.related()
+ }
+}
+
+struct Quoted<D>(D);
+
+impl<D> Debug for Quoted<D>
+where
+ D: Display,
+{
+ fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
+ formatter.write_char('"')?;
+ Quoted(&mut *formatter).write_fmt(format_args!("{}", self.0))?;
+ formatter.write_char('"')?;
+ Ok(())
+ }
+}
+
+impl Write for Quoted<&mut fmt::Formatter<'_>> {
+ fn write_str(&mut self, s: &str) -> fmt::Result {
+ Display::fmt(&s.escape_debug(), self.0)
+ }
+}
+
+pub(crate) mod private {
+ use super::*;
+
+ pub trait Sealed {}
+
+ impl<T, E> Sealed for Result<T, E> where E: ext::Diag {}
+ impl<T> Sealed for Option<T> {}
+}