summaryrefslogtreecommitdiff
path: root/vendor/miette/src
diff options
context:
space:
mode:
authorValentin Popov <valentin@popov.link>2024-01-08 00:21:28 +0300
committerValentin Popov <valentin@popov.link>2024-01-08 00:21:28 +0300
commit1b6a04ca5504955c571d1c97504fb45ea0befee4 (patch)
tree7579f518b23313e8a9748a88ab6173d5e030b227 /vendor/miette/src
parent5ecd8cf2cba827454317368b68571df0d13d7842 (diff)
downloadfparkan-1b6a04ca5504955c571d1c97504fb45ea0befee4.tar.xz
fparkan-1b6a04ca5504955c571d1c97504fb45ea0befee4.zip
Initial vendor packages
Signed-off-by: Valentin Popov <valentin@popov.link>
Diffstat (limited to 'vendor/miette/src')
-rw-r--r--vendor/miette/src/chain.rs117
-rw-r--r--vendor/miette/src/diagnostic_chain.rs93
-rw-r--r--vendor/miette/src/error.rs27
-rw-r--r--vendor/miette/src/eyreish/context.rs217
-rw-r--r--vendor/miette/src/eyreish/error.rs810
-rw-r--r--vendor/miette/src/eyreish/fmt.rs20
-rw-r--r--vendor/miette/src/eyreish/into_diagnostic.rs33
-rw-r--r--vendor/miette/src/eyreish/kind.rs111
-rw-r--r--vendor/miette/src/eyreish/macros.rs300
-rw-r--r--vendor/miette/src/eyreish/mod.rs485
-rw-r--r--vendor/miette/src/eyreish/ptr.rs188
-rw-r--r--vendor/miette/src/eyreish/wrapper.rs234
-rw-r--r--vendor/miette/src/handler.rs323
-rw-r--r--vendor/miette/src/handlers/debug.rs71
-rw-r--r--vendor/miette/src/handlers/graphical.rs920
-rw-r--r--vendor/miette/src/handlers/json.rs182
-rw-r--r--vendor/miette/src/handlers/mod.rs24
-rw-r--r--vendor/miette/src/handlers/narratable.rs423
-rw-r--r--vendor/miette/src/handlers/theme.rs275
-rw-r--r--vendor/miette/src/lib.rs682
-rw-r--r--vendor/miette/src/macro_helpers.rs38
-rw-r--r--vendor/miette/src/miette_diagnostic.rs365
-rw-r--r--vendor/miette/src/named_source.rs61
-rw-r--r--vendor/miette/src/panic.rs86
-rw-r--r--vendor/miette/src/protocol.rs697
-rw-r--r--vendor/miette/src/source_impls.rs301
26 files changed, 7083 insertions, 0 deletions
diff --git a/vendor/miette/src/chain.rs b/vendor/miette/src/chain.rs
new file mode 100644
index 0000000..7a66383
--- /dev/null
+++ b/vendor/miette/src/chain.rs
@@ -0,0 +1,117 @@
+/*!
+Iterate over error `.source()` chains.
+
+NOTE: This module is taken wholesale from <https://crates.io/crates/eyre>.
+*/
+use std::error::Error as StdError;
+use std::vec;
+
+use ChainState::*;
+
+/// Iterator of a chain of source errors.
+///
+/// This type is the iterator returned by [`Report::chain`].
+///
+/// # Example
+///
+/// ```
+/// use miette::Report;
+/// use std::io;
+///
+/// pub fn underlying_io_error_kind(error: &Report) -> Option<io::ErrorKind> {
+/// for cause in error.chain() {
+/// if let Some(io_error) = cause.downcast_ref::<io::Error>() {
+/// return Some(io_error.kind());
+/// }
+/// }
+/// None
+/// }
+/// ```
+#[derive(Clone)]
+#[allow(missing_debug_implementations)]
+pub struct Chain<'a> {
+ state: crate::chain::ChainState<'a>,
+}
+
+#[derive(Clone)]
+pub(crate) enum ChainState<'a> {
+ Linked {
+ next: Option<&'a (dyn StdError + 'static)>,
+ },
+ Buffered {
+ rest: vec::IntoIter<&'a (dyn StdError + 'static)>,
+ },
+}
+
+impl<'a> Chain<'a> {
+ pub(crate) fn new(head: &'a (dyn StdError + 'static)) -> Self {
+ Chain {
+ state: ChainState::Linked { next: Some(head) },
+ }
+ }
+}
+
+impl<'a> Iterator for Chain<'a> {
+ type Item = &'a (dyn StdError + 'static);
+
+ fn next(&mut self) -> Option<Self::Item> {
+ match &mut self.state {
+ Linked { next } => {
+ let error = (*next)?;
+ *next = error.source();
+ Some(error)
+ }
+ Buffered { rest } => rest.next(),
+ }
+ }
+
+ fn size_hint(&self) -> (usize, Option<usize>) {
+ let len = self.len();
+ (len, Some(len))
+ }
+}
+
+impl DoubleEndedIterator for Chain<'_> {
+ fn next_back(&mut self) -> Option<Self::Item> {
+ match &mut self.state {
+ Linked { mut next } => {
+ let mut rest = Vec::new();
+ while let Some(cause) = next {
+ next = cause.source();
+ rest.push(cause);
+ }
+ let mut rest = rest.into_iter();
+ let last = rest.next_back();
+ self.state = Buffered { rest };
+ last
+ }
+ Buffered { rest } => rest.next_back(),
+ }
+ }
+}
+
+impl ExactSizeIterator for Chain<'_> {
+ fn len(&self) -> usize {
+ match &self.state {
+ Linked { mut next } => {
+ let mut len = 0;
+ while let Some(cause) = next {
+ next = cause.source();
+ len += 1;
+ }
+ len
+ }
+ Buffered { rest } => rest.len(),
+ }
+ }
+}
+
+impl Default for Chain<'_> {
+ fn default() -> Self {
+ Chain {
+ state: ChainState::Buffered {
+ rest: Vec::new().into_iter(),
+ },
+ }
+ }
+}
diff --git a/vendor/miette/src/diagnostic_chain.rs b/vendor/miette/src/diagnostic_chain.rs
new file mode 100644
index 0000000..1e5e0c2
--- /dev/null
+++ b/vendor/miette/src/diagnostic_chain.rs
@@ -0,0 +1,93 @@
+/*!
+Iterate over error `.diagnostic_source()` chains.
+*/
+
+use crate::protocol::Diagnostic;
+
+/// Iterator of a chain of cause errors.
+#[derive(Clone, Default)]
+#[allow(missing_debug_implementations)]
+pub(crate) struct DiagnosticChain<'a> {
+ state: Option<ErrorKind<'a>>,
+}
+
+impl<'a> DiagnosticChain<'a> {
+ pub(crate) fn from_diagnostic(head: &'a dyn Diagnostic) -> Self {
+ DiagnosticChain {
+ state: Some(ErrorKind::Diagnostic(head)),
+ }
+ }
+
+ pub(crate) fn from_stderror(head: &'a (dyn std::error::Error + 'static)) -> Self {
+ DiagnosticChain {
+ state: Some(ErrorKind::StdError(head)),
+ }
+ }
+}
+
+impl<'a> Iterator for DiagnosticChain<'a> {
+ type Item = ErrorKind<'a>;
+
+ fn next(&mut self) -> Option<Self::Item> {
+ if let Some(err) = self.state.take() {
+ self.state = err.get_nested();
+ Some(err)
+ } else {
+ None
+ }
+ }
+
+ fn size_hint(&self) -> (usize, Option<usize>) {
+ let len = self.len();
+ (len, Some(len))
+ }
+}
+
+impl ExactSizeIterator for DiagnosticChain<'_> {
+ fn len(&self) -> usize {
+ fn depth(d: Option<&ErrorKind<'_>>) -> usize {
+ match d {
+ Some(d) => 1 + depth(d.get_nested().as_ref()),
+ None => 0,
+ }
+ }
+
+ depth(self.state.as_ref())
+ }
+}
+
+#[derive(Clone)]
+pub(crate) enum ErrorKind<'a> {
+ Diagnostic(&'a dyn Diagnostic),
+ StdError(&'a (dyn std::error::Error + 'static)),
+}
+
+impl<'a> ErrorKind<'a> {
+ fn get_nested(&self) -> Option<ErrorKind<'a>> {
+ match self {
+ ErrorKind::Diagnostic(d) => d
+ .diagnostic_source()
+ .map(ErrorKind::Diagnostic)
+ .or_else(|| d.source().map(ErrorKind::StdError)),
+ ErrorKind::StdError(e) => e.source().map(ErrorKind::StdError),
+ }
+ }
+}
+
+impl<'a> std::fmt::Debug for ErrorKind<'a> {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ match self {
+ ErrorKind::Diagnostic(d) => d.fmt(f),
+ ErrorKind::StdError(e) => e.fmt(f),
+ }
+ }
+}
+
+impl<'a> std::fmt::Display for ErrorKind<'a> {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ match self {
+ ErrorKind::Diagnostic(d) => d.fmt(f),
+ ErrorKind::StdError(e) => e.fmt(f),
+ }
+ }
+}
diff --git a/vendor/miette/src/error.rs b/vendor/miette/src/error.rs
new file mode 100644
index 0000000..56041ca
--- /dev/null
+++ b/vendor/miette/src/error.rs
@@ -0,0 +1,27 @@
+use std::io;
+
+use thiserror::Error;
+
+use crate::{self as miette, Diagnostic};
+
+/**
+Error enum for miette. Used by certain operations in the protocol.
+*/
+#[derive(Debug, Diagnostic, Error)]
+pub enum MietteError {
+ /// Wrapper around [`std::io::Error`]. This is returned when something went
+ /// wrong while reading a [`SourceCode`](crate::SourceCode).
+ #[error(transparent)]
+ #[diagnostic(code(miette::io_error), url(docsrs))]
+ IoError(#[from] io::Error),
+
+ /// Returned when a [`SourceSpan`](crate::SourceSpan) extends beyond the
+ /// bounds of a given [`SourceCode`](crate::SourceCode).
+ #[error("The given offset is outside the bounds of its Source")]
+ #[diagnostic(
+ code(miette::span_out_of_bounds),
+ help("Double-check your spans. Do you have an off-by-one error?"),
+ url(docsrs)
+ )]
+ OutOfBounds,
+}
diff --git a/vendor/miette/src/eyreish/context.rs b/vendor/miette/src/eyreish/context.rs
new file mode 100644
index 0000000..3d9238b
--- /dev/null
+++ b/vendor/miette/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> {}
+}
diff --git a/vendor/miette/src/eyreish/error.rs b/vendor/miette/src/eyreish/error.rs
new file mode 100644
index 0000000..6b0dc34
--- /dev/null
+++ b/vendor/miette/src/eyreish/error.rs
@@ -0,0 +1,810 @@
+use core::any::TypeId;
+use core::fmt::{self, Debug, Display};
+use core::mem::ManuallyDrop;
+use core::ptr::{self, NonNull};
+use std::error::Error as StdError;
+
+use super::ptr::{Mut, Own, Ref};
+use super::Report;
+use super::ReportHandler;
+use crate::chain::Chain;
+use crate::eyreish::wrapper::WithSourceCode;
+use crate::{Diagnostic, SourceCode};
+use core::ops::{Deref, DerefMut};
+
+impl Report {
+ /// Create a new error object from any error type.
+ ///
+ /// The error type must be thread safe and `'static`, so that the `Report`
+ /// will be as well.
+ ///
+ /// If the error type does not provide a backtrace, a backtrace will be
+ /// created here to ensure that a backtrace exists.
+ #[cfg_attr(track_caller, track_caller)]
+ pub fn new<E>(error: E) -> Self
+ where
+ E: Diagnostic + Send + Sync + 'static,
+ {
+ Report::from_std(error)
+ }
+
+ /// Create a new error object from a printable error message.
+ ///
+ /// If the argument implements std::error::Error, prefer `Report::new`
+ /// instead which preserves the underlying error's cause chain and
+ /// backtrace. If the argument may or may not implement std::error::Error
+ /// now or in the future, use `miette!(err)` which handles either way
+ /// correctly.
+ ///
+ /// `Report::msg("...")` is equivalent to `miette!("...")` but occasionally
+ /// convenient in places where a function is preferable over a macro, such
+ /// as iterator or stream combinators:
+ ///
+ /// ```
+ /// # mod ffi {
+ /// # pub struct Input;
+ /// # pub struct Output;
+ /// # pub async fn do_some_work(_: Input) -> Result<Output, &'static str> {
+ /// # unimplemented!()
+ /// # }
+ /// # }
+ /// #
+ /// # use ffi::{Input, Output};
+ /// #
+ /// use futures::stream::{Stream, StreamExt, TryStreamExt};
+ /// use miette::{Report, Result};
+ ///
+ /// async fn demo<S>(stream: S) -> Result<Vec<Output>>
+ /// where
+ /// S: Stream<Item = Input>,
+ /// {
+ /// stream
+ /// .then(ffi::do_some_work) // returns Result<Output, &str>
+ /// .map_err(Report::msg)
+ /// .try_collect()
+ /// .await
+ /// }
+ /// ```
+ #[cfg_attr(track_caller, track_caller)]
+ pub fn msg<M>(message: M) -> Self
+ where
+ M: Display + Debug + Send + Sync + 'static,
+ {
+ Report::from_adhoc(message)
+ }
+
+ /// Create a new error object from a boxed [`Diagnostic`].
+ ///
+ /// The boxed type must be thread safe and 'static, so that the `Report`
+ /// will be as well.
+ ///
+ /// Boxed `Diagnostic`s don't implement `Diagnostic` themselves due to trait coherence issues.
+ /// This method allows you to create a `Report` from a boxed `Diagnostic`.
+ #[cfg_attr(track_caller, track_caller)]
+ pub fn new_boxed(error: Box<dyn Diagnostic + Send + Sync + 'static>) -> Self {
+ Report::from_boxed(error)
+ }
+
+ #[cfg_attr(track_caller, track_caller)]
+ pub(crate) fn from_std<E>(error: E) -> Self
+ where
+ E: Diagnostic + Send + Sync + 'static,
+ {
+ let vtable = &ErrorVTable {
+ object_drop: object_drop::<E>,
+ object_ref: object_ref::<E>,
+ object_ref_stderr: object_ref_stderr::<E>,
+ object_boxed: object_boxed::<E>,
+ object_boxed_stderr: object_boxed_stderr::<E>,
+ object_downcast: object_downcast::<E>,
+ object_drop_rest: object_drop_front::<E>,
+ };
+
+ // Safety: passing vtable that operates on the right type E.
+ let handler = Some(super::capture_handler(&error));
+
+ unsafe { Report::construct(error, vtable, handler) }
+ }
+
+ #[cfg_attr(track_caller, track_caller)]
+ pub(crate) fn from_adhoc<M>(message: M) -> Self
+ where
+ M: Display + Debug + Send + Sync + 'static,
+ {
+ use super::wrapper::MessageError;
+ let error: MessageError<M> = MessageError(message);
+ let vtable = &ErrorVTable {
+ object_drop: object_drop::<MessageError<M>>,
+ object_ref: object_ref::<MessageError<M>>,
+ object_ref_stderr: object_ref_stderr::<MessageError<M>>,
+ object_boxed: object_boxed::<MessageError<M>>,
+ object_boxed_stderr: object_boxed_stderr::<MessageError<M>>,
+ object_downcast: object_downcast::<M>,
+ object_drop_rest: object_drop_front::<M>,
+ };
+
+ // Safety: MessageError is repr(transparent) so it is okay for the
+ // vtable to allow casting the MessageError<M> to M.
+ let handler = Some(super::capture_handler(&error));
+
+ unsafe { Report::construct(error, vtable, handler) }
+ }
+
+ #[cfg_attr(track_caller, track_caller)]
+ pub(crate) fn from_msg<D, E>(msg: D, error: E) -> Self
+ where
+ D: Display + Send + Sync + 'static,
+ E: Diagnostic + Send + Sync + 'static,
+ {
+ let error: ContextError<D, E> = ContextError { msg, error };
+
+ let vtable = &ErrorVTable {
+ object_drop: object_drop::<ContextError<D, E>>,
+ object_ref: object_ref::<ContextError<D, E>>,
+ object_ref_stderr: object_ref_stderr::<ContextError<D, E>>,
+ object_boxed: object_boxed::<ContextError<D, E>>,
+ object_boxed_stderr: object_boxed_stderr::<ContextError<D, E>>,
+ object_downcast: context_downcast::<D, E>,
+ object_drop_rest: context_drop_rest::<D, E>,
+ };
+
+ // Safety: passing vtable that operates on the right type.
+ let handler = Some(super::capture_handler(&error));
+
+ unsafe { Report::construct(error, vtable, handler) }
+ }
+
+ #[cfg_attr(track_caller, track_caller)]
+ pub(crate) fn from_boxed(error: Box<dyn Diagnostic + Send + Sync>) -> Self {
+ use super::wrapper::BoxedError;
+ let error = BoxedError(error);
+ let handler = Some(super::capture_handler(&error));
+
+ let vtable = &ErrorVTable {
+ object_drop: object_drop::<BoxedError>,
+ object_ref: object_ref::<BoxedError>,
+ object_ref_stderr: object_ref_stderr::<BoxedError>,
+ object_boxed: object_boxed::<BoxedError>,
+ object_boxed_stderr: object_boxed_stderr::<BoxedError>,
+ object_downcast: object_downcast::<Box<dyn Diagnostic + Send + Sync>>,
+ object_drop_rest: object_drop_front::<Box<dyn Diagnostic + Send + Sync>>,
+ };
+
+ // Safety: BoxedError is repr(transparent) so it is okay for the vtable
+ // to allow casting to Box<dyn StdError + Send + Sync>.
+ unsafe { Report::construct(error, vtable, handler) }
+ }
+
+ // Takes backtrace as argument rather than capturing it here so that the
+ // user sees one fewer layer of wrapping noise in the backtrace.
+ //
+ // Unsafe because the given vtable must have sensible behavior on the error
+ // value of type E.
+ unsafe fn construct<E>(
+ error: E,
+ vtable: &'static ErrorVTable,
+ handler: Option<Box<dyn ReportHandler>>,
+ ) -> Self
+ where
+ E: Diagnostic + Send + Sync + 'static,
+ {
+ let inner = Box::new(ErrorImpl {
+ vtable,
+ handler,
+ _object: error,
+ });
+ // Erase the concrete type of E from the compile-time type system. This
+ // is equivalent to the safe unsize coercion from Box<ErrorImpl<E>> to
+ // Box<ErrorImpl<dyn StdError + Send + Sync + 'static>> except that the
+ // result is a thin pointer. The necessary behavior for manipulating the
+ // underlying ErrorImpl<E> is preserved in the vtable provided by the
+ // caller rather than a builtin fat pointer vtable.
+ let inner = Own::new(inner).cast::<ErasedErrorImpl>();
+ Report { inner }
+ }
+
+ /// Create a new error from an error message to wrap the existing error.
+ ///
+ /// For attaching a higher level error message to a `Result` as it is
+ /// propagated, the [crate::WrapErr] extension trait may be more
+ /// convenient than this function.
+ ///
+ /// The primary reason to use `error.wrap_err(...)` instead of
+ /// `result.wrap_err(...)` via the `WrapErr` trait would be if the
+ /// message needs to depend on some data held by the underlying error:
+ pub fn wrap_err<D>(self, msg: D) -> Self
+ where
+ D: Display + Send + Sync + 'static,
+ {
+ let handler = unsafe { self.inner.by_mut().deref_mut().handler.take() };
+ let error: ContextError<D, Report> = ContextError { msg, error: self };
+
+ let vtable = &ErrorVTable {
+ object_drop: object_drop::<ContextError<D, Report>>,
+ object_ref: object_ref::<ContextError<D, Report>>,
+ object_ref_stderr: object_ref_stderr::<ContextError<D, Report>>,
+ object_boxed: object_boxed::<ContextError<D, Report>>,
+ object_boxed_stderr: object_boxed_stderr::<ContextError<D, Report>>,
+ object_downcast: context_chain_downcast::<D>,
+ object_drop_rest: context_chain_drop_rest::<D>,
+ };
+
+ // Safety: passing vtable that operates on the right type.
+ unsafe { Report::construct(error, vtable, handler) }
+ }
+
+ /// Compatibility re-export of wrap_err for interop with `anyhow`
+ pub fn context<D>(self, msg: D) -> Self
+ where
+ D: Display + Send + Sync + 'static,
+ {
+ self.wrap_err(msg)
+ }
+
+ /// An iterator of the chain of source errors contained by this Report.
+ ///
+ /// This iterator will visit every error in the cause chain of this error
+ /// object, beginning with the error that this error object was created
+ /// from.
+ ///
+ /// # Example
+ ///
+ /// ```
+ /// use miette::Report;
+ /// use std::io;
+ ///
+ /// pub fn underlying_io_error_kind(error: &Report) -> Option<io::ErrorKind> {
+ /// for cause in error.chain() {
+ /// if let Some(io_error) = cause.downcast_ref::<io::Error>() {
+ /// return Some(io_error.kind());
+ /// }
+ /// }
+ /// None
+ /// }
+ /// ```
+ pub fn chain(&self) -> Chain<'_> {
+ unsafe { ErrorImpl::chain(self.inner.by_ref()) }
+ }
+
+ /// The lowest level cause of this error &mdash; this error's cause's
+ /// cause's cause etc.
+ ///
+ /// The root cause is the last error in the iterator produced by
+ /// [`chain()`](Report::chain).
+ pub fn root_cause(&self) -> &(dyn StdError + 'static) {
+ self.chain().last().unwrap()
+ }
+
+ /// Returns true if `E` is the type held by this error object.
+ ///
+ /// For errors constructed from messages, this method returns true if `E`
+ /// matches the type of the message `D` **or** the type of the error on
+ /// which the message has been attached. For details about the
+ /// interaction between message and downcasting, [see here].
+ ///
+ /// [see here]: trait.WrapErr.html#effect-on-downcasting
+ pub fn is<E>(&self) -> bool
+ where
+ E: Display + Debug + Send + Sync + 'static,
+ {
+ self.downcast_ref::<E>().is_some()
+ }
+
+ /// Attempt to downcast the error object to a concrete type.
+ pub fn downcast<E>(self) -> Result<E, Self>
+ where
+ E: Display + Debug + Send + Sync + 'static,
+ {
+ let target = TypeId::of::<E>();
+ let inner = self.inner.by_mut();
+ unsafe {
+ // Use vtable to find NonNull<()> which points to a value of type E
+ // somewhere inside the data structure.
+ let addr = match (vtable(inner.ptr).object_downcast)(inner.by_ref(), target) {
+ Some(addr) => addr.by_mut().extend(),
+ None => return Err(self),
+ };
+
+ // Prepare to read E out of the data structure. We'll drop the rest
+ // of the data structure separately so that E is not dropped.
+ let outer = ManuallyDrop::new(self);
+
+ // Read E from where the vtable found it.
+ let error = addr.cast::<E>().read();
+
+ // Drop rest of the data structure outside of E.
+ (vtable(outer.inner.ptr).object_drop_rest)(outer.inner, target);
+
+ Ok(error)
+ }
+ }
+
+ /// Downcast this error object by reference.
+ ///
+ /// # Example
+ ///
+ /// ```
+ /// # use miette::{Report, miette};
+ /// # use std::fmt::{self, Display};
+ /// # use std::task::Poll;
+ /// #
+ /// # #[derive(Debug)]
+ /// # enum DataStoreError {
+ /// # Censored(()),
+ /// # }
+ /// #
+ /// # impl Display for DataStoreError {
+ /// # fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ /// # unimplemented!()
+ /// # }
+ /// # }
+ /// #
+ /// # impl std::error::Error for DataStoreError {}
+ /// #
+ /// # const REDACTED_CONTENT: () = ();
+ /// #
+ /// # let error: Report = miette!("...");
+ /// # let root_cause = &error;
+ /// #
+ /// # let ret =
+ /// // If the error was caused by redaction, then return a tombstone instead
+ /// // of the content.
+ /// match root_cause.downcast_ref::<DataStoreError>() {
+ /// Some(DataStoreError::Censored(_)) => Ok(Poll::Ready(REDACTED_CONTENT)),
+ /// None => Err(error),
+ /// }
+ /// # ;
+ /// ```
+ pub fn downcast_ref<E>(&self) -> Option<&E>
+ where
+ E: Display + Debug + Send + Sync + 'static,
+ {
+ let target = TypeId::of::<E>();
+ unsafe {
+ // Use vtable to find NonNull<()> which points to a value of type E
+ // somewhere inside the data structure.
+ let addr = (vtable(self.inner.ptr).object_downcast)(self.inner.by_ref(), target)?;
+ Some(addr.cast::<E>().deref())
+ }
+ }
+
+ /// Downcast this error object by mutable reference.
+ pub fn downcast_mut<E>(&mut self) -> Option<&mut E>
+ where
+ E: Display + Debug + Send + Sync + 'static,
+ {
+ let target = TypeId::of::<E>();
+ unsafe {
+ // Use vtable to find NonNull<()> which points to a value of type E
+ // somewhere inside the data structure.
+ let addr =
+ (vtable(self.inner.ptr).object_downcast)(self.inner.by_ref(), target)?.by_mut();
+ Some(addr.cast::<E>().deref_mut())
+ }
+ }
+
+ /// Get a reference to the Handler for this Report.
+ pub fn handler(&self) -> &dyn ReportHandler {
+ unsafe {
+ self.inner
+ .by_ref()
+ .deref()
+ .handler
+ .as_ref()
+ .unwrap()
+ .as_ref()
+ }
+ }
+
+ /// Get a mutable reference to the Handler for this Report.
+ pub fn handler_mut(&mut self) -> &mut dyn ReportHandler {
+ unsafe {
+ self.inner
+ .by_mut()
+ .deref_mut()
+ .handler
+ .as_mut()
+ .unwrap()
+ .as_mut()
+ }
+ }
+
+ /// Provide source code for this error
+ pub fn with_source_code(self, source_code: impl SourceCode + Send + Sync + 'static) -> Report {
+ WithSourceCode {
+ source_code,
+ error: self,
+ }
+ .into()
+ }
+}
+
+impl<E> From<E> for Report
+where
+ E: Diagnostic + Send + Sync + 'static,
+{
+ #[cfg_attr(track_caller, track_caller)]
+ fn from(error: E) -> Self {
+ Report::from_std(error)
+ }
+}
+
+impl Deref for Report {
+ type Target = dyn Diagnostic + Send + Sync + 'static;
+
+ fn deref(&self) -> &Self::Target {
+ unsafe { ErrorImpl::diagnostic(self.inner.by_ref()) }
+ }
+}
+
+impl DerefMut for Report {
+ fn deref_mut(&mut self) -> &mut Self::Target {
+ unsafe { ErrorImpl::diagnostic_mut(self.inner.by_mut()) }
+ }
+}
+
+impl Display for Report {
+ fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
+ unsafe { ErrorImpl::display(self.inner.by_ref(), formatter) }
+ }
+}
+
+impl Debug for Report {
+ fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
+ unsafe { ErrorImpl::debug(self.inner.by_ref(), formatter) }
+ }
+}
+
+impl Drop for Report {
+ fn drop(&mut self) {
+ unsafe {
+ // Invoke the vtable's drop behavior.
+ (vtable(self.inner.ptr).object_drop)(self.inner);
+ }
+ }
+}
+
+struct ErrorVTable {
+ object_drop: unsafe fn(Own<ErasedErrorImpl>),
+ object_ref:
+ unsafe fn(Ref<'_, ErasedErrorImpl>) -> Ref<'_, dyn Diagnostic + Send + Sync + 'static>,
+ object_ref_stderr:
+ unsafe fn(Ref<'_, ErasedErrorImpl>) -> Ref<'_, dyn StdError + Send + Sync + 'static>,
+ #[allow(clippy::type_complexity)]
+ object_boxed: unsafe fn(Own<ErasedErrorImpl>) -> Box<dyn Diagnostic + Send + Sync + 'static>,
+ #[allow(clippy::type_complexity)]
+ object_boxed_stderr:
+ unsafe fn(Own<ErasedErrorImpl>) -> Box<dyn StdError + Send + Sync + 'static>,
+ object_downcast: unsafe fn(Ref<'_, ErasedErrorImpl>, TypeId) -> Option<Ref<'_, ()>>,
+ object_drop_rest: unsafe fn(Own<ErasedErrorImpl>, TypeId),
+}
+
+// Safety: requires layout of *e to match ErrorImpl<E>.
+unsafe fn object_drop<E>(e: Own<ErasedErrorImpl>) {
+ // Cast back to ErrorImpl<E> so that the allocator receives the correct
+ // Layout to deallocate the Box's memory.
+ let unerased = e.cast::<ErrorImpl<E>>().boxed();
+ drop(unerased);
+}
+
+// Safety: requires layout of *e to match ErrorImpl<E>.
+unsafe fn object_drop_front<E>(e: Own<ErasedErrorImpl>, target: TypeId) {
+ // Drop the fields of ErrorImpl other than E as well as the Box allocation,
+ // without dropping E itself. This is used by downcast after doing a
+ // ptr::read to take ownership of the E.
+ let _ = target;
+ let unerased = e.cast::<ErrorImpl<ManuallyDrop<E>>>().boxed();
+ drop(unerased);
+}
+
+// Safety: requires layout of *e to match ErrorImpl<E>.
+unsafe fn object_ref<E>(
+ e: Ref<'_, ErasedErrorImpl>,
+) -> Ref<'_, dyn Diagnostic + Send + Sync + 'static>
+where
+ E: Diagnostic + Send + Sync + 'static,
+{
+ // Attach E's native StdError vtable onto a pointer to self._object.
+ let unerased = e.cast::<ErrorImpl<E>>();
+
+ Ref::from_raw(NonNull::new_unchecked(
+ ptr::addr_of!((*unerased.as_ptr())._object) as *mut E,
+ ))
+}
+
+// Safety: requires layout of *e to match ErrorImpl<E>.
+unsafe fn object_ref_stderr<E>(
+ e: Ref<'_, ErasedErrorImpl>,
+) -> Ref<'_, dyn StdError + Send + Sync + 'static>
+where
+ E: StdError + Send + Sync + 'static,
+{
+ // Attach E's native StdError vtable onto a pointer to self._object.
+ let unerased = e.cast::<ErrorImpl<E>>();
+
+ Ref::from_raw(NonNull::new_unchecked(
+ ptr::addr_of!((*unerased.as_ptr())._object) as *mut E,
+ ))
+}
+
+// Safety: requires layout of *e to match ErrorImpl<E>.
+unsafe fn object_boxed<E>(e: Own<ErasedErrorImpl>) -> Box<dyn Diagnostic + Send + Sync + 'static>
+where
+ E: Diagnostic + Send + Sync + 'static,
+{
+ // Attach ErrorImpl<E>'s native StdError vtable. The StdError impl is below.
+ e.cast::<ErrorImpl<E>>().boxed()
+}
+
+// Safety: requires layout of *e to match ErrorImpl<E>.
+unsafe fn object_boxed_stderr<E>(
+ e: Own<ErasedErrorImpl>,
+) -> Box<dyn StdError + Send + Sync + 'static>
+where
+ E: StdError + Send + Sync + 'static,
+{
+ // Attach ErrorImpl<E>'s native StdError vtable. The StdError impl is below.
+ e.cast::<ErrorImpl<E>>().boxed()
+}
+
+// Safety: requires layout of *e to match ErrorImpl<E>.
+unsafe fn object_downcast<E>(e: Ref<'_, ErasedErrorImpl>, target: TypeId) -> Option<Ref<'_, ()>>
+where
+ E: 'static,
+{
+ if TypeId::of::<E>() == target {
+ // Caller is looking for an E pointer and e is ErrorImpl<E>, take a
+ // pointer to its E field.
+ let unerased = e.cast::<ErrorImpl<E>>();
+
+ Some(
+ Ref::from_raw(NonNull::new_unchecked(
+ ptr::addr_of!((*unerased.as_ptr())._object) as *mut E,
+ ))
+ .cast::<()>(),
+ )
+ } else {
+ None
+ }
+}
+
+// Safety: requires layout of *e to match ErrorImpl<ContextError<D, E>>.
+unsafe fn context_downcast<D, E>(e: Ref<'_, ErasedErrorImpl>, target: TypeId) -> Option<Ref<'_, ()>>
+where
+ D: 'static,
+ E: 'static,
+{
+ if TypeId::of::<D>() == target {
+ let unerased = e.cast::<ErrorImpl<ContextError<D, E>>>().deref();
+ Some(Ref::new(&unerased._object.msg).cast::<()>())
+ } else if TypeId::of::<E>() == target {
+ let unerased = e.cast::<ErrorImpl<ContextError<D, E>>>().deref();
+ Some(Ref::new(&unerased._object.error).cast::<()>())
+ } else {
+ None
+ }
+}
+
+// Safety: requires layout of *e to match ErrorImpl<ContextError<D, E>>.
+unsafe fn context_drop_rest<D, E>(e: Own<ErasedErrorImpl>, target: TypeId)
+where
+ D: 'static,
+ E: 'static,
+{
+ // Called after downcasting by value to either the D or the E and doing a
+ // ptr::read to take ownership of that value.
+ if TypeId::of::<D>() == target {
+ let unerased = e
+ .cast::<ErrorImpl<ContextError<ManuallyDrop<D>, E>>>()
+ .boxed();
+ drop(unerased);
+ } else {
+ let unerased = e
+ .cast::<ErrorImpl<ContextError<D, ManuallyDrop<E>>>>()
+ .boxed();
+ drop(unerased);
+ }
+}
+
+// Safety: requires layout of *e to match ErrorImpl<ContextError<D, Report>>.
+unsafe fn context_chain_downcast<D>(
+ e: Ref<'_, ErasedErrorImpl>,
+ target: TypeId,
+) -> Option<Ref<'_, ()>>
+where
+ D: 'static,
+{
+ let unerased = e.cast::<ErrorImpl<ContextError<D, Report>>>().deref();
+ if TypeId::of::<D>() == target {
+ Some(Ref::new(&unerased._object.msg).cast::<()>())
+ } else {
+ // Recurse down the context chain per the inner error's vtable.
+ let source = &unerased._object.error;
+ (vtable(source.inner.ptr).object_downcast)(source.inner.by_ref(), target)
+ }
+}
+
+// Safety: requires layout of *e to match ErrorImpl<ContextError<D, Report>>.
+unsafe fn context_chain_drop_rest<D>(e: Own<ErasedErrorImpl>, target: TypeId)
+where
+ D: 'static,
+{
+ // Called after downcasting by value to either the D or one of the causes
+ // and doing a ptr::read to take ownership of that value.
+ if TypeId::of::<D>() == target {
+ let unerased = e
+ .cast::<ErrorImpl<ContextError<ManuallyDrop<D>, Report>>>()
+ .boxed();
+ // Drop the entire rest of the data structure rooted in the next Report.
+ drop(unerased);
+ } else {
+ let unerased = e
+ .cast::<ErrorImpl<ContextError<D, ManuallyDrop<Report>>>>()
+ .boxed();
+ // Read out a ManuallyDrop<Box<ErasedErrorImpl>> from the next error.
+ let inner = unerased._object.error.inner;
+ drop(unerased);
+ let vtable = vtable(inner.ptr);
+ // Recursively drop the next error using the same target typeid.
+ (vtable.object_drop_rest)(inner, target);
+ }
+}
+
+// repr C to ensure that E remains in the final position.
+#[repr(C)]
+pub(crate) struct ErrorImpl<E> {
+ vtable: &'static ErrorVTable,
+ pub(crate) handler: Option<Box<dyn ReportHandler>>,
+ // NOTE: Don't use directly. Use only through vtable. Erased type may have
+ // different alignment.
+ _object: E,
+}
+
+// repr C to ensure that ContextError<D, E> has the same layout as
+// ContextError<ManuallyDrop<D>, E> and ContextError<D, ManuallyDrop<E>>.
+#[repr(C)]
+pub(crate) struct ContextError<D, E> {
+ pub(crate) msg: D,
+ pub(crate) error: E,
+}
+
+type ErasedErrorImpl = ErrorImpl<()>;
+
+// Safety: `ErrorVTable` must be the first field of `ErrorImpl`
+unsafe fn vtable(p: NonNull<ErasedErrorImpl>) -> &'static ErrorVTable {
+ (p.as_ptr() as *const &'static ErrorVTable).read()
+}
+
+impl<E> ErrorImpl<E> {
+ fn erase(&self) -> Ref<'_, ErasedErrorImpl> {
+ // Erase the concrete type of E but preserve the vtable in self.vtable
+ // for manipulating the resulting thin pointer. This is analogous to an
+ // unsize coercion.
+ Ref::new(self).cast::<ErasedErrorImpl>()
+ }
+}
+
+impl ErasedErrorImpl {
+ pub(crate) unsafe fn error<'a>(
+ this: Ref<'a, Self>,
+ ) -> &'a (dyn StdError + Send + Sync + 'static) {
+ // Use vtable to attach E's native StdError vtable for the right
+ // original type E.
+ (vtable(this.ptr).object_ref_stderr)(this).deref()
+ }
+
+ pub(crate) unsafe fn diagnostic<'a>(
+ this: Ref<'a, Self>,
+ ) -> &'a (dyn Diagnostic + Send + Sync + 'static) {
+ // Use vtable to attach E's native StdError vtable for the right
+ // original type E.
+ (vtable(this.ptr).object_ref)(this).deref()
+ }
+
+ pub(crate) unsafe fn diagnostic_mut<'a>(
+ this: Mut<'a, Self>,
+ ) -> &'a mut (dyn Diagnostic + Send + Sync + 'static) {
+ // Use vtable to attach E's native StdError vtable for the right
+ // original type E.
+ (vtable(this.ptr).object_ref)(this.by_ref())
+ .by_mut()
+ .deref_mut()
+ }
+
+ pub(crate) unsafe fn chain(this: Ref<'_, Self>) -> Chain<'_> {
+ Chain::new(Self::error(this))
+ }
+}
+
+impl<E> StdError for ErrorImpl<E>
+where
+ E: StdError,
+{
+ fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
+ unsafe { ErrorImpl::diagnostic(self.erase()).source() }
+ }
+}
+
+impl<E> Diagnostic for ErrorImpl<E> where E: Diagnostic {}
+
+impl<E> Debug for ErrorImpl<E>
+where
+ E: Debug,
+{
+ fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
+ unsafe { ErrorImpl::debug(self.erase(), formatter) }
+ }
+}
+
+impl<E> Display for ErrorImpl<E>
+where
+ E: Display,
+{
+ fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
+ unsafe { Display::fmt(ErrorImpl::diagnostic(self.erase()), formatter) }
+ }
+}
+
+impl From<Report> for Box<dyn Diagnostic + Send + Sync + 'static> {
+ fn from(error: Report) -> Self {
+ let outer = ManuallyDrop::new(error);
+ unsafe {
+ // Use vtable to attach ErrorImpl<E>'s native StdError vtable for
+ // the right original type E.
+ (vtable(outer.inner.ptr).object_boxed)(outer.inner)
+ }
+ }
+}
+
+impl From<Report> for Box<dyn StdError + Send + Sync + 'static> {
+ fn from(error: Report) -> Self {
+ let outer = ManuallyDrop::new(error);
+ unsafe {
+ // Use vtable to attach ErrorImpl<E>'s native StdError vtable for
+ // the right original type E.
+ (vtable(outer.inner.ptr).object_boxed_stderr)(outer.inner)
+ }
+ }
+}
+
+impl From<Report> for Box<dyn Diagnostic + 'static> {
+ fn from(error: Report) -> Self {
+ Box::<dyn Diagnostic + Send + Sync>::from(error)
+ }
+}
+
+impl From<Report> for Box<dyn StdError + 'static> {
+ fn from(error: Report) -> Self {
+ Box::<dyn StdError + Send + Sync>::from(error)
+ }
+}
+
+impl AsRef<dyn Diagnostic + Send + Sync> for Report {
+ fn as_ref(&self) -> &(dyn Diagnostic + Send + Sync + 'static) {
+ &**self
+ }
+}
+
+impl AsRef<dyn Diagnostic> for Report {
+ fn as_ref(&self) -> &(dyn Diagnostic + 'static) {
+ &**self
+ }
+}
+
+impl AsRef<dyn StdError + Send + Sync> for Report {
+ fn as_ref(&self) -> &(dyn StdError + Send + Sync + 'static) {
+ unsafe { ErrorImpl::error(self.inner.by_ref()) }
+ }
+}
+
+impl AsRef<dyn StdError> for Report {
+ fn as_ref(&self) -> &(dyn StdError + 'static) {
+ unsafe { ErrorImpl::error(self.inner.by_ref()) }
+ }
+}
+
+impl std::borrow::Borrow<dyn Diagnostic> for Report {
+ fn borrow(&self) -> &(dyn Diagnostic + 'static) {
+ self.as_ref()
+ }
+}
diff --git a/vendor/miette/src/eyreish/fmt.rs b/vendor/miette/src/eyreish/fmt.rs
new file mode 100644
index 0000000..9e385d1
--- /dev/null
+++ b/vendor/miette/src/eyreish/fmt.rs
@@ -0,0 +1,20 @@
+use super::{error::ErrorImpl, ptr::Ref};
+use core::fmt;
+
+impl ErrorImpl<()> {
+ pub(crate) unsafe fn display(this: Ref<'_, Self>, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ this.deref()
+ .handler
+ .as_ref()
+ .map(|handler| handler.display(Self::error(this), f))
+ .unwrap_or_else(|| core::fmt::Display::fmt(Self::diagnostic(this), f))
+ }
+
+ pub(crate) unsafe fn debug(this: Ref<'_, Self>, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ this.deref()
+ .handler
+ .as_ref()
+ .map(|handler| handler.debug(Self::diagnostic(this), f))
+ .unwrap_or_else(|| core::fmt::Debug::fmt(Self::diagnostic(this), f))
+ }
+}
diff --git a/vendor/miette/src/eyreish/into_diagnostic.rs b/vendor/miette/src/eyreish/into_diagnostic.rs
new file mode 100644
index 0000000..6480013
--- /dev/null
+++ b/vendor/miette/src/eyreish/into_diagnostic.rs
@@ -0,0 +1,33 @@
+use thiserror::Error;
+
+use crate::{Diagnostic, Report};
+
+/// Convenience [`Diagnostic`] that can be used as an "anonymous" wrapper for
+/// Errors. This is intended to be paired with [`IntoDiagnostic`].
+#[derive(Debug, Error)]
+#[error(transparent)]
+struct DiagnosticError(Box<dyn std::error::Error + Send + Sync + 'static>);
+impl Diagnostic for DiagnosticError {}
+
+/**
+Convenience trait that adds a [`.into_diagnostic()`](IntoDiagnostic::into_diagnostic) method that converts a type implementing
+[`std::error::Error`] to a [`Result<T, Report>`].
+
+## Warning
+
+Calling this on a type implementing [`Diagnostic`] will reduce it to the common denominator of
+[`std::error::Error`]. Meaning all extra information provided by [`Diagnostic`] will be
+inaccessible. If you have a type implementing [`Diagnostic`] consider simply returning it or using
+[`Into`] or the [`Try`](std::ops::Try) operator (`?`).
+*/
+pub trait IntoDiagnostic<T, E> {
+ /// Converts [`Result`] types that return regular [`std::error::Error`]s
+ /// into a [`Result`] that returns a [`Diagnostic`].
+ fn into_diagnostic(self) -> Result<T, Report>;
+}
+
+impl<T, E: std::error::Error + Send + Sync + 'static> IntoDiagnostic<T, E> for Result<T, E> {
+ fn into_diagnostic(self) -> Result<T, Report> {
+ self.map_err(|e| DiagnosticError(Box::new(e)).into())
+ }
+}
diff --git a/vendor/miette/src/eyreish/kind.rs b/vendor/miette/src/eyreish/kind.rs
new file mode 100644
index 0000000..ce60b50
--- /dev/null
+++ b/vendor/miette/src/eyreish/kind.rs
@@ -0,0 +1,111 @@
+#![allow(missing_debug_implementations, missing_docs)]
+// Tagged dispatch mechanism for resolving the behavior of `miette!($expr)`.
+//
+// When miette! is given a single expr argument to turn into miette::Report, we
+// want the resulting Report to pick up the input's implementation of source()
+// and backtrace() if it has a std::error::Error impl, otherwise require nothing
+// more than Display and Debug.
+//
+// Expressed in terms of specialization, we want something like:
+//
+// trait EyreNew {
+// fn new(self) -> Report;
+// }
+//
+// impl<T> EyreNew for T
+// where
+// T: Display + Debug + Send + Sync + 'static,
+// {
+// default fn new(self) -> Report {
+// /* no std error impl */
+// }
+// }
+//
+// impl<T> EyreNew for T
+// where
+// T: std::error::Error + Send + Sync + 'static,
+// {
+// fn new(self) -> Report {
+// /* use std error's source() and backtrace() */
+// }
+// }
+//
+// Since specialization is not stable yet, instead we rely on autoref behavior
+// of method resolution to perform tagged dispatch. Here we have two traits
+// AdhocKind and TraitKind that both have an miette_kind() method. AdhocKind is
+// implemented whether or not the caller's type has a std error impl, while
+// TraitKind is implemented only when a std error impl does exist. The ambiguity
+// is resolved by AdhocKind requiring an extra autoref so that it has lower
+// precedence.
+//
+// The miette! macro will set up the call in this form:
+//
+// #[allow(unused_imports)]
+// use $crate::private::{AdhocKind, TraitKind};
+// let error = $msg;
+// (&error).miette_kind().new(error)
+
+use super::Report;
+use core::fmt::{Debug, Display};
+
+use crate::Diagnostic;
+
+pub struct Adhoc;
+
+pub trait AdhocKind: Sized {
+ #[inline]
+ fn miette_kind(&self) -> Adhoc {
+ Adhoc
+ }
+}
+
+impl<T> AdhocKind for &T where T: ?Sized + Display + Debug + Send + Sync + 'static {}
+
+impl Adhoc {
+ #[cfg_attr(track_caller, track_caller)]
+ pub fn new<M>(self, message: M) -> Report
+ where
+ M: Display + Debug + Send + Sync + 'static,
+ {
+ Report::from_adhoc(message)
+ }
+}
+
+pub struct Trait;
+
+pub trait TraitKind: Sized {
+ #[inline]
+ fn miette_kind(&self) -> Trait {
+ Trait
+ }
+}
+
+impl<E> TraitKind for E where E: Into<Report> {}
+
+impl Trait {
+ #[cfg_attr(track_caller, track_caller)]
+ pub fn new<E>(self, error: E) -> Report
+ where
+ E: Into<Report>,
+ {
+ error.into()
+ }
+}
+
+pub struct Boxed;
+
+pub trait BoxedKind: Sized {
+ #[inline]
+ fn miette_kind(&self) -> Boxed {
+ Boxed
+ }
+}
+
+impl BoxedKind for Box<dyn Diagnostic + Send + Sync> {}
+
+impl Boxed {
+ #[cfg_attr(track_caller, track_caller)]
+ pub fn new(self, error: Box<dyn Diagnostic + Send + Sync>) -> Report {
+ Report::from_boxed(error)
+ }
+}
diff --git a/vendor/miette/src/eyreish/macros.rs b/vendor/miette/src/eyreish/macros.rs
new file mode 100644
index 0000000..e13309f
--- /dev/null
+++ b/vendor/miette/src/eyreish/macros.rs
@@ -0,0 +1,300 @@
+/// Return early with an error.
+///
+/// This macro is equivalent to `return Err(From::from($err))`.
+///
+/// # Example
+///
+/// ```
+/// # use miette::{bail, Result};
+/// #
+/// # fn has_permission(user: usize, resource: usize) -> bool {
+/// # true
+/// # }
+/// #
+/// # fn main() -> Result<()> {
+/// # let user = 0;
+/// # let resource = 0;
+/// #
+/// if !has_permission(user, resource) {
+#[cfg_attr(
+ not(feature = "no-format-args-capture"),
+ doc = r#" bail!("permission denied for accessing {resource}");"#
+)]
+#[cfg_attr(
+ feature = "no-format-args-capture",
+ doc = r#" bail!("permission denied for accessing {}", resource);"#
+)]
+/// }
+/// # Ok(())
+/// # }
+/// ```
+///
+/// ```
+/// # use miette::{bail, Result};
+/// # use thiserror::Error;
+/// #
+/// # const MAX_DEPTH: usize = 1;
+/// #
+/// #[derive(Error, Debug)]
+/// enum ScienceError {
+/// #[error("recursion limit exceeded")]
+/// RecursionLimitExceeded,
+/// # #[error("...")]
+/// # More = (stringify! {
+/// ...
+/// # }, 1).1,
+/// }
+///
+/// # fn main() -> Result<()> {
+/// # let depth = 0;
+/// # let err: &'static dyn std::error::Error = &ScienceError::RecursionLimitExceeded;
+/// #
+/// if depth > MAX_DEPTH {
+/// bail!(ScienceError::RecursionLimitExceeded);
+/// }
+/// # Ok(())
+/// # }
+/// ```
+///
+/// ```
+/// use miette::{bail, Result, Severity};
+///
+/// fn divide(x: f64, y: f64) -> Result<f64> {
+/// if y.abs() < 1e-3 {
+/// bail!(
+/// severity = Severity::Warning,
+#[cfg_attr(
+ not(feature = "no-format-args-capture"),
+ doc = r#" "dividing by value ({y}) close to 0""#
+)]
+#[cfg_attr(
+ feature = "no-format-args-capture",
+ doc = r#" "dividing by value ({}) close to 0", y"#
+)]
+/// );
+/// }
+/// Ok(x / y)
+/// }
+/// ```
+#[macro_export]
+macro_rules! bail {
+ ($($key:ident = $value:expr,)* $fmt:literal $($arg:tt)*) => {
+ return $crate::private::Err(
+ $crate::miette!($($key = $value,)* $fmt $($arg)*)
+ );
+ };
+ ($err:expr $(,)?) => {
+ return $crate::private::Err($crate::miette!($err));
+ };
+}
+
+/// Return early with an error if a condition is not satisfied.
+///
+/// This macro is equivalent to `if !$cond { return Err(From::from($err)); }`.
+///
+/// Analogously to `assert!`, `ensure!` takes a condition and exits the function
+/// if the condition fails. Unlike `assert!`, `ensure!` returns an `Error`
+/// rather than panicking.
+///
+/// # Example
+///
+/// ```
+/// # use miette::{ensure, Result};
+/// #
+/// # fn main() -> Result<()> {
+/// # let user = 0;
+/// #
+/// ensure!(user == 0, "only user 0 is allowed");
+/// # Ok(())
+/// # }
+/// ```
+///
+/// ```
+/// # use miette::{ensure, Result};
+/// # use thiserror::Error;
+/// #
+/// # const MAX_DEPTH: usize = 1;
+/// #
+/// #[derive(Error, Debug)]
+/// enum ScienceError {
+/// #[error("recursion limit exceeded")]
+/// RecursionLimitExceeded,
+/// # #[error("...")]
+/// # More = (stringify! {
+/// ...
+/// # }, 1).1,
+/// }
+///
+/// # fn main() -> Result<()> {
+/// # let depth = 0;
+/// #
+/// ensure!(depth <= MAX_DEPTH, ScienceError::RecursionLimitExceeded);
+/// # Ok(())
+/// # }
+/// ```
+///
+/// ```
+/// use miette::{ensure, Result, Severity};
+///
+/// fn divide(x: f64, y: f64) -> Result<f64> {
+/// ensure!(
+/// y.abs() >= 1e-3,
+/// severity = Severity::Warning,
+#[cfg_attr(
+ not(feature = "no-format-args-capture"),
+ doc = r#" "dividing by value ({y}) close to 0""#
+)]
+#[cfg_attr(
+ feature = "no-format-args-capture",
+ doc = r#" "dividing by value ({}) close to 0", y"#
+)]
+/// );
+/// Ok(x / y)
+/// }
+/// ```
+#[macro_export]
+macro_rules! ensure {
+ ($cond:expr, $($key:ident = $value:expr,)* $fmt:literal $($arg:tt)*) => {
+ if !$cond {
+ return $crate::private::Err(
+ $crate::miette!($($key = $value,)* $fmt $($arg)*)
+ );
+ }
+ };
+ ($cond:expr, $err:expr $(,)?) => {
+ if !$cond {
+ return $crate::private::Err($crate::miette!($err));
+ }
+ };
+}
+
+/// Construct an ad-hoc [`Report`].
+///
+/// # Examples
+///
+/// With string literal and interpolation:
+/// ```
+/// # use miette::miette;
+/// let x = 1;
+/// let y = 2;
+#[cfg_attr(
+ not(feature = "no-format-args-capture"),
+ doc = r#"let report = miette!("{x} + {} = {z}", y, z = x + y);"#
+)]
+#[cfg_attr(
+ feature = "no-format-args-capture",
+ doc = r#"let report = miette!("{} + {} = {z}", x, y, z = x + y);"#
+)]
+///
+/// assert_eq!(report.to_string().as_str(), "1 + 2 = 3");
+///
+/// let z = x + y;
+#[cfg_attr(
+ not(feature = "no-format-args-capture"),
+ doc = r#"let report = miette!("{x} + {y} = {z}");"#
+)]
+#[cfg_attr(
+ feature = "no-format-args-capture",
+ doc = r#"let report = miette!("{} + {} = {}", x, y, z);"#
+)]
+/// assert_eq!(report.to_string().as_str(), "1 + 2 = 3");
+/// ```
+///
+/// With [`diagnostic!`]-like arguments:
+/// ```
+/// use miette::{miette, LabeledSpan, Severity};
+///
+/// let source = "(2 + 2".to_string();
+/// let report = miette!(
+/// // Those fields are optional
+/// severity = Severity::Error,
+/// code = "expected::rparen",
+/// help = "always close your parens",
+/// labels = vec![LabeledSpan::at_offset(6, "here")],
+/// url = "https://example.com",
+/// // Rest of the arguments are passed to `format!`
+/// // to form diagnostic message
+/// "expected closing ')'"
+/// )
+/// .with_source_code(source);
+/// ```
+///
+/// ## `anyhow`/`eyre` Users
+///
+/// You can just replace `use`s of the `anyhow!`/`eyre!` macros with `miette!`.
+///
+/// [`diagnostic!`]: crate::diagnostic!
+/// [`Report`]: crate::Report
+#[macro_export]
+macro_rules! miette {
+ ($($key:ident = $value:expr,)* $fmt:literal $($arg:tt)*) => {
+ $crate::Report::from(
+ $crate::diagnostic!($($key = $value,)* $fmt $($arg)*)
+ )
+ };
+ ($err:expr $(,)?) => ({
+ use $crate::private::kind::*;
+ let error = $err;
+ (&error).miette_kind().new(error)
+ });
+}
+
+/// Construct a [`MietteDiagnostic`] in more user-friendly way.
+///
+/// # Examples
+/// ```
+/// use miette::{diagnostic, LabeledSpan, Severity};
+///
+/// let source = "(2 + 2".to_string();
+/// let diag = diagnostic!(
+/// // Those fields are optional
+/// severity = Severity::Error,
+/// code = "expected::rparen",
+/// help = "always close your parens",
+/// labels = vec![LabeledSpan::at_offset(6, "here")],
+/// url = "https://example.com",
+/// // Rest of the arguments are passed to `format!`
+/// // to form diagnostic message
+/// "expected closing ')'",
+/// );
+/// ```
+/// Diagnostic without any fields:
+/// ```
+/// # use miette::diagnostic;
+/// let x = 1;
+/// let y = 2;
+///
+#[cfg_attr(
+ not(feature = "no-format-args-capture"),
+ doc = r#" let diag = diagnostic!("{x} + {} = {z}", y, z = x + y);"#
+)]
+#[cfg_attr(
+ feature = "no-format-args-capture",
+ doc = r#" let diag = diagnostic!("{} + {} = {z}", x, y, z = x + y);"#
+)]
+/// assert_eq!(diag.message, "1 + 2 = 3");
+///
+/// let z = x + y;
+#[cfg_attr(
+ not(feature = "no-format-args-capture"),
+ doc = r#"let diag = diagnostic!("{x} + {y} = {z}");"#
+)]
+#[cfg_attr(
+ feature = "no-format-args-capture",
+ doc = r#"let diag = diagnostic!("{} + {} = {}", x, y, z);"#
+)]
+/// assert_eq!(diag.message, "1 + 2 = 3");
+/// ```
+///
+/// [`MietteDiagnostic`]: crate::MietteDiagnostic
+#[macro_export]
+macro_rules! diagnostic {
+ ($fmt:literal $($arg:tt)*) => {{
+ $crate::MietteDiagnostic::new(format!($fmt $($arg)*))
+ }};
+ ($($key:ident = $value:expr,)+ $fmt:literal $($arg:tt)*) => {{
+ let mut diag = $crate::MietteDiagnostic::new(format!($fmt $($arg)*));
+ $(diag.$key = Some($value.into());)*
+ diag
+ }};
+}
diff --git a/vendor/miette/src/eyreish/mod.rs b/vendor/miette/src/eyreish/mod.rs
new file mode 100644
index 0000000..0efceed
--- /dev/null
+++ b/vendor/miette/src/eyreish/mod.rs
@@ -0,0 +1,485 @@
+#![cfg_attr(doc_cfg, feature(doc_cfg))]
+#![allow(
+ clippy::needless_doctest_main,
+ clippy::new_ret_no_self,
+ clippy::wrong_self_convention
+)]
+use core::fmt::Display;
+
+use std::error::Error as StdError;
+
+use once_cell::sync::OnceCell;
+
+#[allow(unreachable_pub)]
+pub use into_diagnostic::*;
+#[doc(hidden)]
+#[allow(unreachable_pub)]
+pub use Report as ErrReport;
+/// Compatibility re-export of `Report` for interop with `anyhow`
+#[allow(unreachable_pub)]
+pub use Report as Error;
+#[doc(hidden)]
+#[allow(unreachable_pub)]
+pub use ReportHandler as EyreContext;
+/// Compatibility re-export of `WrapErr` for interop with `anyhow`
+#[allow(unreachable_pub)]
+pub use WrapErr as Context;
+
+#[cfg(not(feature = "fancy-no-backtrace"))]
+use crate::DebugReportHandler;
+use crate::Diagnostic;
+#[cfg(feature = "fancy-no-backtrace")]
+use crate::MietteHandler;
+
+use error::ErrorImpl;
+
+use self::ptr::Own;
+
+mod context;
+mod error;
+mod fmt;
+mod into_diagnostic;
+mod kind;
+mod macros;
+mod ptr;
+mod wrapper;
+
+/**
+Core Diagnostic wrapper type.
+
+## `eyre` Users
+
+You can just replace `use`s of `eyre::Report` with `miette::Report`.
+*/
+pub struct Report {
+ inner: Own<ErrorImpl<()>>,
+}
+
+unsafe impl Sync for Report {}
+unsafe impl Send for Report {}
+
+///
+pub type ErrorHook =
+ Box<dyn Fn(&(dyn Diagnostic + 'static)) -> Box<dyn ReportHandler> + Sync + Send + 'static>;
+
+static HOOK: OnceCell<ErrorHook> = OnceCell::new();
+
+/// Error indicating that [`set_hook()`] was unable to install the provided
+/// [`ErrorHook`].
+#[derive(Debug)]
+pub struct InstallError;
+
+impl core::fmt::Display for InstallError {
+ fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
+ f.write_str("cannot install provided ErrorHook, a hook has already been installed")
+ }
+}
+
+impl StdError for InstallError {}
+impl Diagnostic for InstallError {}
+
+/**
+Set the error hook.
+*/
+pub fn set_hook(hook: ErrorHook) -> Result<(), InstallError> {
+ HOOK.set(hook).map_err(|_| InstallError)
+}
+
+#[cfg_attr(track_caller, track_caller)]
+#[cfg_attr(not(track_caller), allow(unused_mut))]
+fn capture_handler(error: &(dyn Diagnostic + 'static)) -> Box<dyn ReportHandler> {
+ let hook = HOOK.get_or_init(|| Box::new(get_default_printer)).as_ref();
+
+ #[cfg(track_caller)]
+ {
+ let mut handler = hook(error);
+ handler.track_caller(std::panic::Location::caller());
+ handler
+ }
+ #[cfg(not(track_caller))]
+ {
+ hook(error)
+ }
+}
+
+fn get_default_printer(_err: &(dyn Diagnostic + 'static)) -> Box<dyn ReportHandler + 'static> {
+ #[cfg(feature = "fancy-no-backtrace")]
+ return Box::new(MietteHandler::new());
+ #[cfg(not(feature = "fancy-no-backtrace"))]
+ return Box::new(DebugReportHandler::new());
+}
+
+impl dyn ReportHandler {
+ ///
+ pub fn is<T: ReportHandler>(&self) -> bool {
+ // Get `TypeId` of the type this function is instantiated with.
+ let t = core::any::TypeId::of::<T>();
+
+ // Get `TypeId` of the type in the trait object (`self`).
+ let concrete = self.type_id();
+
+ // Compare both `TypeId`s on equality.
+ t == concrete
+ }
+
+ ///
+ pub fn downcast_ref<T: ReportHandler>(&self) -> Option<&T> {
+ if self.is::<T>() {
+ unsafe { Some(&*(self as *const dyn ReportHandler as *const T)) }
+ } else {
+ None
+ }
+ }
+
+ ///
+ pub fn downcast_mut<T: ReportHandler>(&mut self) -> Option<&mut T> {
+ if self.is::<T>() {
+ unsafe { Some(&mut *(self as *mut dyn ReportHandler as *mut T)) }
+ } else {
+ None
+ }
+ }
+}
+
+/// Error Report Handler trait for customizing `miette::Report`
+pub trait ReportHandler: core::any::Any + Send + Sync {
+ /// Define the report format
+ ///
+ /// Used to override the report format of `miette::Report`
+ ///
+ /// # Example
+ ///
+ /// ```rust
+ /// use indenter::indented;
+ /// use miette::{Diagnostic, ReportHandler};
+ ///
+ /// pub struct Handler;
+ ///
+ /// impl ReportHandler for Handler {
+ /// fn debug(
+ /// &self,
+ /// error: &dyn Diagnostic,
+ /// f: &mut core::fmt::Formatter<'_>,
+ /// ) -> core::fmt::Result {
+ /// use core::fmt::Write as _;
+ ///
+ /// if f.alternate() {
+ /// return core::fmt::Debug::fmt(error, f);
+ /// }
+ ///
+ /// write!(f, "{}", error)?;
+ ///
+ /// Ok(())
+ /// }
+ /// }
+ /// ```
+ fn debug(
+ &self,
+ error: &(dyn Diagnostic),
+ f: &mut core::fmt::Formatter<'_>,
+ ) -> core::fmt::Result;
+
+ /// Override for the `Display` format
+ fn display(
+ &self,
+ error: &(dyn StdError + 'static),
+ f: &mut core::fmt::Formatter<'_>,
+ ) -> core::fmt::Result {
+ write!(f, "{}", error)?;
+
+ if f.alternate() {
+ for cause in crate::chain::Chain::new(error).skip(1) {
+ write!(f, ": {}", cause)?;
+ }
+ }
+
+ Ok(())
+ }
+
+ /// Store the location of the caller who constructed this error report
+ #[allow(unused_variables)]
+ fn track_caller(&mut self, location: &'static std::panic::Location<'static>) {}
+}
+
+/// type alias for `Result<T, Report>`
+///
+/// This is a reasonable return type to use throughout your application but also
+/// for `main()`. If you do, failures will be printed along with a backtrace if
+/// one was captured.
+///
+/// `miette::Result` may be used with one *or* two type parameters.
+///
+/// ```rust
+/// use miette::Result;
+///
+/// # const IGNORE: &str = stringify! {
+/// fn demo1() -> Result<T> {...}
+/// // ^ equivalent to std::result::Result<T, miette::Error>
+///
+/// fn demo2() -> Result<T, OtherError> {...}
+/// // ^ equivalent to std::result::Result<T, OtherError>
+/// # };
+/// ```
+///
+/// # Example
+///
+/// ```
+/// # pub trait Deserialize {}
+/// #
+/// # mod serde_json {
+/// # use super::Deserialize;
+/// # use std::io;
+/// #
+/// # pub fn from_str<T: Deserialize>(json: &str) -> io::Result<T> {
+/// # unimplemented!()
+/// # }
+/// # }
+/// #
+/// # #[derive(Debug)]
+/// # struct ClusterMap;
+/// #
+/// # impl Deserialize for ClusterMap {}
+/// #
+/// use miette::{IntoDiagnostic, Result};
+///
+/// fn main() -> Result<()> {
+/// # return Ok(());
+/// let config = std::fs::read_to_string("cluster.json").into_diagnostic()?;
+/// let map: ClusterMap = serde_json::from_str(&config).into_diagnostic()?;
+/// println!("cluster info: {:#?}", map);
+/// Ok(())
+/// }
+/// ```
+///
+/// ## `anyhow`/`eyre` Users
+///
+/// You can just replace `use`s of `anyhow::Result`/`eyre::Result` with
+/// `miette::Result`.
+pub type Result<T, E = Report> = core::result::Result<T, E>;
+
+/// Provides the [`wrap_err()`](WrapErr::wrap_err) method for [`Result`].
+///
+/// This trait is sealed and cannot be implemented for types outside of
+/// `miette`.
+///
+/// # Example
+///
+/// ```
+/// use miette::{WrapErr, IntoDiagnostic, Result};
+/// use std::{fs, path::PathBuf};
+///
+/// pub struct ImportantThing {
+/// path: PathBuf,
+/// }
+///
+/// impl ImportantThing {
+/// # const IGNORE: &'static str = stringify! {
+/// pub fn detach(&mut self) -> Result<()> {...}
+/// # };
+/// # fn detach(&mut self) -> Result<()> {
+/// # unimplemented!()
+/// # }
+/// }
+///
+/// pub fn do_it(mut it: ImportantThing) -> Result<Vec<u8>> {
+/// it.detach().wrap_err("Failed to detach the important thing")?;
+///
+/// let path = &it.path;
+/// let content = fs::read(path)
+/// .into_diagnostic()
+/// .wrap_err_with(|| format!(
+/// "Failed to read instrs from {}",
+/// path.display())
+/// )?;
+///
+/// Ok(content)
+/// }
+/// ```
+///
+/// When printed, the outermost error would be printed first and the lower
+/// level underlying causes would be enumerated below.
+///
+/// ```console
+/// Error: Failed to read instrs from ./path/to/instrs.json
+///
+/// Caused by:
+/// No such file or directory (os error 2)
+/// ```
+///
+/// # Wrapping Types That Do Not Implement `Error`
+///
+/// For example `&str` and `Box<dyn Error>`.
+///
+/// Due to restrictions for coherence `Report` cannot implement `From` for types
+/// that don't implement `Error`. Attempts to do so will give `"this type might
+/// implement Error in the future"` as an error. As such, `wrap_err()`, which
+/// uses `From` under the hood, cannot be used to wrap these types. Instead we
+/// encourage you to use the combinators provided for `Result` in `std`/`core`.
+///
+/// For example, instead of this:
+///
+/// ```rust,compile_fail
+/// use std::error::Error;
+/// use miette::{WrapErr, Report};
+///
+/// fn wrap_example(err: Result<(), Box<dyn Error + Send + Sync + 'static>>)
+/// -> Result<(), Report>
+/// {
+/// err.wrap_err("saw a downstream error")
+/// }
+/// ```
+///
+/// We encourage you to write this:
+///
+/// ```rust
+/// use miette::{miette, Report, WrapErr};
+/// use std::error::Error;
+///
+/// fn wrap_example(err: Result<(), Box<dyn Error + Send + Sync + 'static>>) -> Result<(), Report> {
+/// err.map_err(|e| miette!(e))
+/// .wrap_err("saw a downstream error")
+/// }
+/// ```
+///
+/// # Effect on Downcasting
+///
+/// After attaching a message of type `D` onto an error of type `E`, the
+/// resulting `miette::Error` may be downcast to `D` **or** to `E`.
+///
+/// That is, in codebases that rely on downcasting, `miette`'s `wrap_err()`
+/// supports both of the following use cases:
+///
+/// - **Attaching messages whose type is insignificant onto errors whose type
+/// is used in downcasts.**
+///
+/// In other error libraries whose `wrap_err()` is not designed this way, it
+/// can be risky to introduce messages to existing code because new message
+/// might break existing working downcasts. In miette, any downcast that
+/// worked before adding the message will continue to work after you add a
+/// message, so you should freely wrap errors wherever it would be helpful.
+///
+/// ```
+/// # use miette::bail;
+/// # use thiserror::Error;
+/// #
+/// # #[derive(Error, Debug)]
+/// # #[error("???")]
+/// # struct SuspiciousError;
+/// #
+/// # fn helper() -> Result<()> {
+/// # bail!(SuspiciousError);
+/// # }
+/// #
+/// use miette::{WrapErr, Result};
+///
+/// fn do_it() -> Result<()> {
+/// helper().wrap_err("Failed to complete the work")?;
+/// # const IGNORE: &str = stringify! {
+/// ...
+/// # };
+/// # unreachable!()
+/// }
+///
+/// fn main() {
+/// let err = do_it().unwrap_err();
+/// if let Some(e) = err.downcast_ref::<SuspiciousError>() {
+/// // If helper() returned SuspiciousError, this downcast will
+/// // correctly succeed even with the message in between.
+/// # return;
+/// }
+/// # panic!("expected downcast to succeed");
+/// }
+/// ```
+///
+/// - **Attaching message whose type is used in downcasts onto errors whose
+/// type is insignificant.**
+///
+/// Some codebases prefer to use machine-readable messages to categorize
+/// lower level errors in a way that will be actionable to higher levels of
+/// the application.
+///
+/// ```
+/// # use miette::bail;
+/// # use thiserror::Error;
+/// #
+/// # #[derive(Error, Debug)]
+/// # #[error("???")]
+/// # struct HelperFailed;
+/// #
+/// # fn helper() -> Result<()> {
+/// # bail!("no such file or directory");
+/// # }
+/// #
+/// use miette::{WrapErr, Result};
+///
+/// fn do_it() -> Result<()> {
+/// helper().wrap_err(HelperFailed)?;
+/// # const IGNORE: &str = stringify! {
+/// ...
+/// # };
+/// # unreachable!()
+/// }
+///
+/// fn main() {
+/// let err = do_it().unwrap_err();
+/// if let Some(e) = err.downcast_ref::<HelperFailed>() {
+/// // If helper failed, this downcast will succeed because
+/// // HelperFailed is the message that has been attached to
+/// // that error.
+/// # return;
+/// }
+/// # panic!("expected downcast to succeed");
+/// }
+/// ```
+pub trait WrapErr<T, E>: context::private::Sealed {
+ /// Wrap the error value with a new adhoc error
+ #[cfg_attr(track_caller, track_caller)]
+ fn wrap_err<D>(self, msg: D) -> Result<T, Report>
+ where
+ D: Display + Send + Sync + 'static;
+
+ /// Wrap the error value with a new adhoc error that is evaluated lazily
+ /// only once an error does occur.
+ #[cfg_attr(track_caller, track_caller)]
+ fn wrap_err_with<D, F>(self, f: F) -> Result<T, Report>
+ where
+ D: Display + Send + Sync + 'static,
+ F: FnOnce() -> D;
+
+ /// Compatibility re-export of `wrap_err()` for interop with `anyhow`
+ #[cfg_attr(track_caller, track_caller)]
+ fn context<D>(self, msg: D) -> Result<T, Report>
+ where
+ D: Display + Send + Sync + 'static;
+
+ /// Compatibility re-export of `wrap_err_with()` for interop with `anyhow`
+ #[cfg_attr(track_caller, track_caller)]
+ fn with_context<D, F>(self, f: F) -> Result<T, Report>
+ where
+ D: Display + Send + Sync + 'static,
+ F: FnOnce() -> D;
+}
+
+// Private API. Referenced by macro-generated code.
+#[doc(hidden)]
+pub mod private {
+ use super::Report;
+ use core::fmt::{Debug, Display};
+
+ pub use core::result::Result::Err;
+
+ #[doc(hidden)]
+ pub mod kind {
+ pub use super::super::kind::{AdhocKind, TraitKind};
+
+ pub use super::super::kind::BoxedKind;
+ }
+
+ #[cfg_attr(track_caller, track_caller)]
+ pub fn new_adhoc<M>(message: M) -> Report
+ where
+ M: Display + Debug + Send + Sync + 'static,
+ {
+ Report::from_adhoc(message)
+ }
+}
diff --git a/vendor/miette/src/eyreish/ptr.rs b/vendor/miette/src/eyreish/ptr.rs
new file mode 100644
index 0000000..fa954d1
--- /dev/null
+++ b/vendor/miette/src/eyreish/ptr.rs
@@ -0,0 +1,188 @@
+use std::{marker::PhantomData, ptr::NonNull};
+
+#[repr(transparent)]
+/// A raw pointer that owns its pointee
+pub(crate) struct Own<T>
+where
+ T: ?Sized,
+{
+ pub(crate) ptr: NonNull<T>,
+}
+
+unsafe impl<T> Send for Own<T> where T: ?Sized {}
+unsafe impl<T> Sync for Own<T> where T: ?Sized {}
+
+impl<T> Copy for Own<T> where T: ?Sized {}
+
+impl<T> Clone for Own<T>
+where
+ T: ?Sized,
+{
+ fn clone(&self) -> Self {
+ *self
+ }
+}
+
+impl<T> Own<T>
+where
+ T: ?Sized,
+{
+ pub(crate) fn new(ptr: Box<T>) -> Self {
+ Own {
+ ptr: unsafe { NonNull::new_unchecked(Box::into_raw(ptr)) },
+ }
+ }
+
+ pub(crate) fn cast<U: CastTo>(self) -> Own<U::Target> {
+ Own {
+ ptr: self.ptr.cast(),
+ }
+ }
+
+ pub(crate) unsafe fn boxed(self) -> Box<T> {
+ Box::from_raw(self.ptr.as_ptr())
+ }
+
+ pub(crate) const fn by_ref<'a>(&self) -> Ref<'a, T> {
+ Ref {
+ ptr: self.ptr,
+ lifetime: PhantomData,
+ }
+ }
+
+ pub(crate) fn by_mut<'a>(self) -> Mut<'a, T> {
+ Mut {
+ ptr: self.ptr,
+ lifetime: PhantomData,
+ }
+ }
+}
+
+#[allow(explicit_outlives_requirements)]
+#[repr(transparent)]
+/// A raw pointer that represents a shared borrow of its pointee
+pub(crate) struct Ref<'a, T>
+where
+ T: ?Sized,
+{
+ pub(crate) ptr: NonNull<T>,
+ lifetime: PhantomData<&'a T>,
+}
+
+impl<'a, T> Copy for Ref<'a, T> where T: ?Sized {}
+
+impl<'a, T> Clone for Ref<'a, T>
+where
+ T: ?Sized,
+{
+ fn clone(&self) -> Self {
+ *self
+ }
+}
+
+impl<'a, T> Ref<'a, T>
+where
+ T: ?Sized,
+{
+ pub(crate) fn new(ptr: &'a T) -> Self {
+ Ref {
+ ptr: NonNull::from(ptr),
+ lifetime: PhantomData,
+ }
+ }
+
+ pub(crate) const fn from_raw(ptr: NonNull<T>) -> Self {
+ Ref {
+ ptr,
+ lifetime: PhantomData,
+ }
+ }
+
+ pub(crate) fn cast<U: CastTo>(self) -> Ref<'a, U::Target> {
+ Ref {
+ ptr: self.ptr.cast(),
+ lifetime: PhantomData,
+ }
+ }
+
+ pub(crate) fn by_mut(self) -> Mut<'a, T> {
+ Mut {
+ ptr: self.ptr,
+ lifetime: PhantomData,
+ }
+ }
+
+ pub(crate) const fn as_ptr(self) -> *const T {
+ self.ptr.as_ptr() as *const T
+ }
+
+ pub(crate) unsafe fn deref(self) -> &'a T {
+ &*self.ptr.as_ptr()
+ }
+}
+
+#[allow(explicit_outlives_requirements)]
+#[repr(transparent)]
+/// A raw pointer that represents a unique borrow of its pointee
+pub(crate) struct Mut<'a, T>
+where
+ T: ?Sized,
+{
+ pub(crate) ptr: NonNull<T>,
+ lifetime: PhantomData<&'a mut T>,
+}
+
+impl<'a, T> Copy for Mut<'a, T> where T: ?Sized {}
+
+impl<'a, T> Clone for Mut<'a, T>
+where
+ T: ?Sized,
+{
+ fn clone(&self) -> Self {
+ *self
+ }
+}
+
+impl<'a, T> Mut<'a, T>
+where
+ T: ?Sized,
+{
+ pub(crate) fn cast<U: CastTo>(self) -> Mut<'a, U::Target> {
+ Mut {
+ ptr: self.ptr.cast(),
+ lifetime: PhantomData,
+ }
+ }
+
+ pub(crate) const fn by_ref(self) -> Ref<'a, T> {
+ Ref {
+ ptr: self.ptr,
+ lifetime: PhantomData,
+ }
+ }
+
+ pub(crate) fn extend<'b>(self) -> Mut<'b, T> {
+ Mut {
+ ptr: self.ptr,
+ lifetime: PhantomData,
+ }
+ }
+
+ pub(crate) unsafe fn deref_mut(self) -> &'a mut T {
+ &mut *self.ptr.as_ptr()
+ }
+}
+
+impl<'a, T> Mut<'a, T> {
+ pub(crate) unsafe fn read(self) -> T {
+ self.ptr.as_ptr().read()
+ }
+}
+
+pub(crate) trait CastTo {
+ type Target;
+}
+
+impl<T> CastTo for T {
+ type Target = T;
+}
diff --git a/vendor/miette/src/eyreish/wrapper.rs b/vendor/miette/src/eyreish/wrapper.rs
new file mode 100644
index 0000000..91a5ef3
--- /dev/null
+++ b/vendor/miette/src/eyreish/wrapper.rs
@@ -0,0 +1,234 @@
+use core::fmt::{self, Debug, Display};
+
+use std::error::Error as StdError;
+
+use crate::{Diagnostic, LabeledSpan, Report, SourceCode};
+
+use crate as miette;
+
+#[repr(transparent)]
+pub(crate) struct DisplayError<M>(pub(crate) M);
+
+#[repr(transparent)]
+pub(crate) struct MessageError<M>(pub(crate) M);
+
+pub(crate) struct NoneError;
+
+impl<M> Debug for DisplayError<M>
+where
+ M: Display,
+{
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ Display::fmt(&self.0, f)
+ }
+}
+
+impl<M> Display for DisplayError<M>
+where
+ M: Display,
+{
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ Display::fmt(&self.0, f)
+ }
+}
+
+impl<M> StdError for DisplayError<M> where M: Display + 'static {}
+impl<M> Diagnostic for DisplayError<M> where M: Display + 'static {}
+
+impl<M> Debug for MessageError<M>
+where
+ M: Display + Debug,
+{
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ Debug::fmt(&self.0, f)
+ }
+}
+
+impl<M> Display for MessageError<M>
+where
+ M: Display + Debug,
+{
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ Display::fmt(&self.0, f)
+ }
+}
+
+impl<M> StdError for MessageError<M> where M: Display + Debug + 'static {}
+impl<M> Diagnostic for MessageError<M> where M: Display + Debug + 'static {}
+
+impl Debug for NoneError {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ Debug::fmt("Option was None", f)
+ }
+}
+
+impl Display for NoneError {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ Display::fmt("Option was None", f)
+ }
+}
+
+impl StdError for NoneError {}
+impl Diagnostic for NoneError {}
+
+#[repr(transparent)]
+pub(crate) struct BoxedError(pub(crate) Box<dyn Diagnostic + Send + Sync>);
+
+impl Diagnostic for BoxedError {
+ fn code<'a>(&'a self) -> Option<Box<dyn Display + 'a>> {
+ self.0.code()
+ }
+
+ fn severity(&self) -> Option<miette::Severity> {
+ self.0.severity()
+ }
+
+ fn help<'a>(&'a self) -> Option<Box<dyn Display + 'a>> {
+ self.0.help()
+ }
+
+ fn url<'a>(&'a self) -> Option<Box<dyn Display + 'a>> {
+ self.0.url()
+ }
+
+ fn labels<'a>(&'a self) -> Option<Box<dyn Iterator<Item = LabeledSpan> + 'a>> {
+ self.0.labels()
+ }
+
+ fn source_code(&self) -> Option<&dyn miette::SourceCode> {
+ self.0.source_code()
+ }
+
+ fn related<'a>(&'a self) -> Option<Box<dyn Iterator<Item = &'a dyn Diagnostic> + 'a>> {
+ self.0.related()
+ }
+
+ fn diagnostic_source(&self) -> Option<&dyn Diagnostic> {
+ self.0.diagnostic_source()
+ }
+}
+
+impl Debug for BoxedError {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ Debug::fmt(&self.0, f)
+ }
+}
+
+impl Display for BoxedError {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ Display::fmt(&self.0, f)
+ }
+}
+
+impl StdError for BoxedError {
+ fn source(&self) -> Option<&(dyn StdError + 'static)> {
+ self.0.source()
+ }
+
+ fn description(&self) -> &str {
+ #[allow(deprecated)]
+ self.0.description()
+ }
+
+ fn cause(&self) -> Option<&dyn StdError> {
+ #[allow(deprecated)]
+ self.0.cause()
+ }
+}
+
+pub(crate) struct WithSourceCode<E, C> {
+ pub(crate) error: E,
+ pub(crate) source_code: C,
+}
+
+impl<E: Diagnostic, C: SourceCode> Diagnostic for WithSourceCode<E, C> {
+ fn code<'a>(&'a self) -> Option<Box<dyn Display + 'a>> {
+ self.error.code()
+ }
+
+ fn severity(&self) -> Option<miette::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 miette::SourceCode> {
+ Some(&self.source_code)
+ }
+
+ fn related<'a>(&'a self) -> Option<Box<dyn Iterator<Item = &'a dyn Diagnostic> + 'a>> {
+ self.error.related()
+ }
+
+ fn diagnostic_source(&self) -> Option<&dyn Diagnostic> {
+ self.error.diagnostic_source()
+ }
+}
+
+impl<C: SourceCode> Diagnostic for WithSourceCode<Report, C> {
+ fn code<'a>(&'a self) -> Option<Box<dyn Display + 'a>> {
+ self.error.code()
+ }
+
+ fn severity(&self) -> Option<miette::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 miette::SourceCode> {
+ Some(&self.source_code)
+ }
+
+ fn related<'a>(&'a self) -> Option<Box<dyn Iterator<Item = &'a dyn Diagnostic> + 'a>> {
+ self.error.related()
+ }
+
+ fn diagnostic_source(&self) -> Option<&dyn Diagnostic> {
+ self.error.diagnostic_source()
+ }
+}
+
+impl<E: Debug, C> Debug for WithSourceCode<E, C> {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ Debug::fmt(&self.error, f)
+ }
+}
+
+impl<E: Display, C> Display for WithSourceCode<E, C> {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ Display::fmt(&self.error, f)
+ }
+}
+
+impl<E: StdError, C> StdError for WithSourceCode<E, C> {
+ fn source(&self) -> Option<&(dyn StdError + 'static)> {
+ self.error.source()
+ }
+}
+
+impl<C> StdError for WithSourceCode<Report, C> {
+ fn source(&self) -> Option<&(dyn StdError + 'static)> {
+ self.error.source()
+ }
+}
diff --git a/vendor/miette/src/handler.rs b/vendor/miette/src/handler.rs
new file mode 100644
index 0000000..e983a55
--- /dev/null
+++ b/vendor/miette/src/handler.rs
@@ -0,0 +1,323 @@
+use std::fmt;
+
+use crate::protocol::Diagnostic;
+use crate::GraphicalReportHandler;
+use crate::GraphicalTheme;
+use crate::NarratableReportHandler;
+use crate::ReportHandler;
+use crate::ThemeCharacters;
+use crate::ThemeStyles;
+
+/// Settings to control the color format used for graphical rendering.
+#[derive(Copy, Clone, Debug, Eq, PartialEq)]
+pub enum RgbColors {
+ /// Use RGB colors even if the terminal does not support them
+ Always,
+ /// Use RGB colors instead of ANSI if the terminal supports RGB
+ Preferred,
+ /// Always use ANSI, regardless of terminal support for RGB
+ Never,
+}
+
+impl Default for RgbColors {
+ fn default() -> RgbColors {
+ RgbColors::Never
+ }
+}
+
+/**
+Create a custom [`MietteHandler`] from options.
+
+## Example
+
+```no_run
+miette::set_hook(Box::new(|_| {
+ Box::new(miette::MietteHandlerOpts::new()
+ .terminal_links(true)
+ .unicode(false)
+ .context_lines(3)
+ .build())
+}))
+# .unwrap();
+```
+*/
+#[derive(Default, Debug, Clone)]
+pub struct MietteHandlerOpts {
+ pub(crate) linkify: Option<bool>,
+ pub(crate) width: Option<usize>,
+ pub(crate) theme: Option<GraphicalTheme>,
+ pub(crate) force_graphical: Option<bool>,
+ pub(crate) force_narrated: Option<bool>,
+ pub(crate) rgb_colors: RgbColors,
+ pub(crate) color: Option<bool>,
+ pub(crate) unicode: Option<bool>,
+ pub(crate) footer: Option<String>,
+ pub(crate) context_lines: Option<usize>,
+ pub(crate) tab_width: Option<usize>,
+ pub(crate) with_cause_chain: Option<bool>,
+}
+
+impl MietteHandlerOpts {
+ /// Create a new `MietteHandlerOpts`.
+ pub fn new() -> Self {
+ Default::default()
+ }
+
+ /// If true, specify whether the graphical handler will make codes be
+ /// clickable links in supported terminals. Defaults to auto-detection
+ /// based on known supported terminals.
+ pub fn terminal_links(mut self, linkify: bool) -> Self {
+ self.linkify = Some(linkify);
+ self
+ }
+
+ /// Set a graphical theme for the handler when rendering in graphical mode.
+ /// Use [`force_graphical()`](`MietteHandlerOpts::force_graphical) to force
+ /// graphical mode. This option overrides
+ /// [`color()`](`MietteHandlerOpts::color).
+ pub fn graphical_theme(mut self, theme: GraphicalTheme) -> Self {
+ self.theme = Some(theme);
+ self
+ }
+
+ /// Sets the width to wrap the report at. Defaults to 80.
+ pub fn width(mut self, width: usize) -> Self {
+ self.width = Some(width);
+ self
+ }
+
+ /// Include the cause chain of the top-level error in the report.
+ pub fn with_cause_chain(mut self) -> Self {
+ self.with_cause_chain = Some(true);
+ self
+ }
+
+ /// Do not include the cause chain of the top-level error in the report.
+ pub fn without_cause_chain(mut self) -> Self {
+ self.with_cause_chain = Some(false);
+ self
+ }
+
+ /// If true, colors will be used during graphical rendering, regardless
+ /// of whether or not the terminal supports them.
+ ///
+ /// If false, colors will never be used.
+ ///
+ /// If unspecified, colors will be used only if the terminal supports them.
+ ///
+ /// The actual format depends on the value of
+ /// [`MietteHandlerOpts::rgb_colors`].
+ pub fn color(mut self, color: bool) -> Self {
+ self.color = Some(color);
+ self
+ }
+
+ /// Controls which color format to use if colors are used in graphical
+ /// rendering.
+ ///
+ /// The default is `Never`.
+ ///
+ /// This value does not control whether or not colors are being used in the
+ /// first place. That is handled by the [`MietteHandlerOpts::color`]
+ /// setting. If colors are not being used, the value of `rgb_colors` has
+ /// no effect.
+ pub fn rgb_colors(mut self, color: RgbColors) -> Self {
+ self.rgb_colors = color;
+ self
+ }
+
+ /// If true, forces unicode display for graphical output. If set to false,
+ /// forces ASCII art display.
+ pub fn unicode(mut self, unicode: bool) -> Self {
+ self.unicode = Some(unicode);
+ self
+ }
+
+ /// If true, graphical rendering will be used regardless of terminal
+ /// detection.
+ pub fn force_graphical(mut self, force: bool) -> Self {
+ self.force_graphical = Some(force);
+ self
+ }
+
+ /// If true, forces use of the narrated renderer.
+ pub fn force_narrated(mut self, force: bool) -> Self {
+ self.force_narrated = Some(force);
+ self
+ }
+
+ /// Set a footer to be displayed at the bottom of the report.
+ pub fn footer(mut self, footer: String) -> Self {
+ self.footer = Some(footer);
+ self
+ }
+
+ /// Sets the number of context lines before and after a span to display.
+ pub fn context_lines(mut self, context_lines: usize) -> Self {
+ self.context_lines = Some(context_lines);
+ self
+ }
+
+ /// Set the displayed tab width in spaces.
+ pub fn tab_width(mut self, width: usize) -> Self {
+ self.tab_width = Some(width);
+ self
+ }
+
+ /// Builds a [`MietteHandler`] from this builder.
+ pub fn build(self) -> MietteHandler {
+ let graphical = self.is_graphical();
+ let width = self.get_width();
+ if !graphical {
+ let mut handler = NarratableReportHandler::new();
+ if let Some(footer) = self.footer {
+ handler = handler.with_footer(footer);
+ }
+ if let Some(context_lines) = self.context_lines {
+ handler = handler.with_context_lines(context_lines);
+ }
+ if let Some(with_cause_chain) = self.with_cause_chain {
+ if with_cause_chain {
+ handler = handler.with_cause_chain();
+ } else {
+ handler = handler.without_cause_chain();
+ }
+ }
+ MietteHandler {
+ inner: Box::new(handler),
+ }
+ } else {
+ let linkify = self.use_links();
+ let characters = match self.unicode {
+ Some(true) => ThemeCharacters::unicode(),
+ Some(false) => ThemeCharacters::ascii(),
+ None if supports_unicode::on(supports_unicode::Stream::Stderr) => {
+ ThemeCharacters::unicode()
+ }
+ None => ThemeCharacters::ascii(),
+ };
+ let styles = if self.color == Some(false) {
+ ThemeStyles::none()
+ } else if let Some(color) = supports_color::on(supports_color::Stream::Stderr) {
+ match self.rgb_colors {
+ RgbColors::Always => ThemeStyles::rgb(),
+ RgbColors::Preferred if color.has_16m => ThemeStyles::rgb(),
+ _ => ThemeStyles::ansi(),
+ }
+ } else if self.color == Some(true) {
+ match self.rgb_colors {
+ RgbColors::Always => ThemeStyles::rgb(),
+ _ => ThemeStyles::ansi(),
+ }
+ } else {
+ ThemeStyles::none()
+ };
+ let theme = self.theme.unwrap_or(GraphicalTheme { characters, styles });
+ let mut handler = GraphicalReportHandler::new()
+ .with_width(width)
+ .with_links(linkify)
+ .with_theme(theme);
+ if let Some(with_cause_chain) = self.with_cause_chain {
+ if with_cause_chain {
+ handler = handler.with_cause_chain();
+ } else {
+ handler = handler.without_cause_chain();
+ }
+ }
+ if let Some(footer) = self.footer {
+ handler = handler.with_footer(footer);
+ }
+ if let Some(context_lines) = self.context_lines {
+ handler = handler.with_context_lines(context_lines);
+ }
+ if let Some(w) = self.tab_width {
+ handler = handler.tab_width(w);
+ }
+ MietteHandler {
+ inner: Box::new(handler),
+ }
+ }
+ }
+
+ pub(crate) fn is_graphical(&self) -> bool {
+ if let Some(force_narrated) = self.force_narrated {
+ !force_narrated
+ } else if let Some(force_graphical) = self.force_graphical {
+ force_graphical
+ } else if let Ok(env) = std::env::var("NO_GRAPHICS") {
+ env == "0"
+ } else {
+ true
+ }
+ }
+
+ // Detects known terminal apps based on env variables and returns true if
+ // they support rendering links.
+ pub(crate) fn use_links(&self) -> bool {
+ if let Some(linkify) = self.linkify {
+ linkify
+ } else {
+ supports_hyperlinks::on(supports_hyperlinks::Stream::Stderr)
+ }
+ }
+
+ #[cfg(not(miri))]
+ pub(crate) fn get_width(&self) -> usize {
+ self.width.unwrap_or_else(|| {
+ terminal_size::terminal_size()
+ .unwrap_or((terminal_size::Width(80), terminal_size::Height(0)))
+ .0
+ .0 as usize
+ })
+ }
+
+ #[cfg(miri)]
+ // miri doesn't support a syscall (specifically ioctl)
+ // performed by terminal_size, which causes test execution to fail
+ // so when miri is running we'll just fallback to a constant
+ pub(crate) fn get_width(&self) -> usize {
+ self.width.unwrap_or(80)
+ }
+}
+
+/**
+A [`ReportHandler`] that displays a given [`Report`](crate::Report) in a
+quasi-graphical way, using terminal colors, unicode drawing characters, and
+other such things.
+
+This is the default reporter bundled with `miette`.
+
+This printer can be customized by using
+[`GraphicalReportHandler::new_themed()`] and handing it a [`GraphicalTheme`] of
+your own creation (or using one of its own defaults).
+
+See [`set_hook`](crate::set_hook) for more details on customizing your global
+printer.
+*/
+#[allow(missing_debug_implementations)]
+pub struct MietteHandler {
+ inner: Box<dyn ReportHandler + Send + Sync>,
+}
+
+impl MietteHandler {
+ /// Creates a new [`MietteHandler`] with default settings.
+ pub fn new() -> Self {
+ Default::default()
+ }
+}
+
+impl Default for MietteHandler {
+ fn default() -> Self {
+ MietteHandlerOpts::new().build()
+ }
+}
+
+impl ReportHandler for MietteHandler {
+ fn debug(&self, diagnostic: &(dyn Diagnostic), f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ if f.alternate() {
+ return fmt::Debug::fmt(diagnostic, f);
+ }
+
+ self.inner.debug(diagnostic, f)
+ }
+}
diff --git a/vendor/miette/src/handlers/debug.rs b/vendor/miette/src/handlers/debug.rs
new file mode 100644
index 0000000..50450a4
--- /dev/null
+++ b/vendor/miette/src/handlers/debug.rs
@@ -0,0 +1,71 @@
+use std::fmt;
+
+use crate::{protocol::Diagnostic, ReportHandler};
+
+/**
+[`ReportHandler`] that renders plain text and avoids extraneous graphics.
+It's optimized for screen readers and braille users, but is also used in any
+non-graphical environments, such as non-TTY output.
+*/
+#[derive(Debug, Clone)]
+pub struct DebugReportHandler;
+
+impl DebugReportHandler {
+ /// Create a new [`NarratableReportHandler`](crate::NarratableReportHandler)
+ /// There are no customization options.
+ pub const fn new() -> Self {
+ Self
+ }
+}
+
+impl Default for DebugReportHandler {
+ fn default() -> Self {
+ Self::new()
+ }
+}
+
+impl DebugReportHandler {
+ /// Render a [`Diagnostic`]. This function is mostly internal and meant to
+ /// be called by the toplevel [`ReportHandler`] handler, but is made public
+ /// to make it easier (possible) to test in isolation from global state.
+ pub fn render_report(
+ &self,
+ f: &mut fmt::Formatter<'_>,
+ diagnostic: &(dyn Diagnostic),
+ ) -> fmt::Result {
+ let mut diag = f.debug_struct("Diagnostic");
+ diag.field("message", &format!("{}", diagnostic));
+ if let Some(code) = diagnostic.code() {
+ diag.field("code", &code.to_string());
+ }
+ if let Some(severity) = diagnostic.severity() {
+ diag.field("severity", &format!("{:?}", severity));
+ }
+ if let Some(url) = diagnostic.url() {
+ diag.field("url", &url.to_string());
+ }
+ if let Some(help) = diagnostic.help() {
+ diag.field("help", &help.to_string());
+ }
+ if let Some(labels) = diagnostic.labels() {
+ let labels: Vec<_> = labels.collect();
+ diag.field("labels", &format!("{:?}", labels));
+ }
+ if let Some(cause) = diagnostic.diagnostic_source() {
+ diag.field("caused by", &format!("{:?}", cause));
+ }
+ diag.finish()?;
+ writeln!(f)?;
+ writeln!(f, "NOTE: If you're looking for the fancy error reports, install miette with the `fancy` feature, or write your own and hook it up with miette::set_hook().")
+ }
+}
+
+impl ReportHandler for DebugReportHandler {
+ fn debug(&self, diagnostic: &(dyn Diagnostic), f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ if f.alternate() {
+ return fmt::Debug::fmt(diagnostic, f);
+ }
+
+ self.render_report(f, diagnostic)
+ }
+}
diff --git a/vendor/miette/src/handlers/graphical.rs b/vendor/miette/src/handlers/graphical.rs
new file mode 100644
index 0000000..b5dd754
--- /dev/null
+++ b/vendor/miette/src/handlers/graphical.rs
@@ -0,0 +1,920 @@
+use std::fmt::{self, Write};
+
+use owo_colors::{OwoColorize, Style};
+use unicode_width::UnicodeWidthChar;
+
+use crate::diagnostic_chain::{DiagnosticChain, ErrorKind};
+use crate::handlers::theme::*;
+use crate::protocol::{Diagnostic, Severity};
+use crate::{LabeledSpan, MietteError, ReportHandler, SourceCode, SourceSpan, SpanContents};
+
+/**
+A [`ReportHandler`] that displays a given [`Report`](crate::Report) in a
+quasi-graphical way, using terminal colors, unicode drawing characters, and
+other such things.
+
+This is the default reporter bundled with `miette`.
+
+This printer can be customized by using [`new_themed()`](GraphicalReportHandler::new_themed) and handing it a
+[`GraphicalTheme`] of your own creation (or using one of its own defaults!)
+
+See [`set_hook()`](crate::set_hook) for more details on customizing your global
+printer.
+*/
+#[derive(Debug, Clone)]
+pub struct GraphicalReportHandler {
+ pub(crate) links: LinkStyle,
+ pub(crate) termwidth: usize,
+ pub(crate) theme: GraphicalTheme,
+ pub(crate) footer: Option<String>,
+ pub(crate) context_lines: usize,
+ pub(crate) tab_width: usize,
+ pub(crate) with_cause_chain: bool,
+}
+
+#[derive(Debug, Clone, Copy, PartialEq, Eq)]
+pub(crate) enum LinkStyle {
+ None,
+ Link,
+ Text,
+}
+
+impl GraphicalReportHandler {
+ /// Create a new `GraphicalReportHandler` with the default
+ /// [`GraphicalTheme`]. This will use both unicode characters and colors.
+ pub fn new() -> Self {
+ Self {
+ links: LinkStyle::Link,
+ termwidth: 200,
+ theme: GraphicalTheme::default(),
+ footer: None,
+ context_lines: 1,
+ tab_width: 4,
+ with_cause_chain: true,
+ }
+ }
+
+ ///Create a new `GraphicalReportHandler` with a given [`GraphicalTheme`].
+ pub fn new_themed(theme: GraphicalTheme) -> Self {
+ Self {
+ links: LinkStyle::Link,
+ termwidth: 200,
+ theme,
+ footer: None,
+ context_lines: 1,
+ tab_width: 4,
+ with_cause_chain: true,
+ }
+ }
+
+ /// Set the displayed tab width in spaces.
+ pub fn tab_width(mut self, width: usize) -> Self {
+ self.tab_width = width;
+ self
+ }
+
+ /// Whether to enable error code linkification using [`Diagnostic::url()`].
+ pub fn with_links(mut self, links: bool) -> Self {
+ self.links = if links {
+ LinkStyle::Link
+ } else {
+ LinkStyle::Text
+ };
+ self
+ }
+
+ /// Include the cause chain of the top-level error in the graphical output,
+ /// if available.
+ pub fn with_cause_chain(mut self) -> Self {
+ self.with_cause_chain = true;
+ self
+ }
+
+ /// Do not include the cause chain of the top-level error in the graphical
+ /// output.
+ pub fn without_cause_chain(mut self) -> Self {
+ self.with_cause_chain = false;
+ self
+ }
+
+ /// Whether to include [`Diagnostic::url()`] in the output.
+ ///
+ /// Disabling this is not recommended, but can be useful for more easily
+ /// reproducible tests, as `url(docsrs)` links are version-dependent.
+ pub fn with_urls(mut self, urls: bool) -> Self {
+ self.links = match (self.links, urls) {
+ (_, false) => LinkStyle::None,
+ (LinkStyle::None, true) => LinkStyle::Link,
+ (links, true) => links,
+ };
+ self
+ }
+
+ /// Set a theme for this handler.
+ pub fn with_theme(mut self, theme: GraphicalTheme) -> Self {
+ self.theme = theme;
+ self
+ }
+
+ /// Sets the width to wrap the report at.
+ pub fn with_width(mut self, width: usize) -> Self {
+ self.termwidth = width;
+ self
+ }
+
+ /// Sets the 'global' footer for this handler.
+ pub fn with_footer(mut self, footer: String) -> Self {
+ self.footer = Some(footer);
+ self
+ }
+
+ /// Sets the number of lines of context to show around each error.
+ pub fn with_context_lines(mut self, lines: usize) -> Self {
+ self.context_lines = lines;
+ self
+ }
+}
+
+impl Default for GraphicalReportHandler {
+ fn default() -> Self {
+ Self::new()
+ }
+}
+
+impl GraphicalReportHandler {
+ /// Render a [`Diagnostic`]. This function is mostly internal and meant to
+ /// be called by the toplevel [`ReportHandler`] handler, but is made public
+ /// to make it easier (possible) to test in isolation from global state.
+ pub fn render_report(
+ &self,
+ f: &mut impl fmt::Write,
+ diagnostic: &(dyn Diagnostic),
+ ) -> fmt::Result {
+ self.render_header(f, diagnostic)?;
+ self.render_causes(f, diagnostic)?;
+ let src = diagnostic.source_code();
+ self.render_snippets(f, diagnostic, src)?;
+ self.render_footer(f, diagnostic)?;
+ self.render_related(f, diagnostic, src)?;
+ if let Some(footer) = &self.footer {
+ writeln!(f)?;
+ let width = self.termwidth.saturating_sub(4);
+ let opts = textwrap::Options::new(width)
+ .initial_indent(" ")
+ .subsequent_indent(" ");
+ writeln!(f, "{}", textwrap::fill(footer, opts))?;
+ }
+ Ok(())
+ }
+
+ fn render_header(&self, f: &mut impl fmt::Write, diagnostic: &(dyn Diagnostic)) -> fmt::Result {
+ let severity_style = match diagnostic.severity() {
+ Some(Severity::Error) | None => self.theme.styles.error,
+ Some(Severity::Warning) => self.theme.styles.warning,
+ Some(Severity::Advice) => self.theme.styles.advice,
+ };
+ let mut header = String::new();
+ if self.links == LinkStyle::Link && diagnostic.url().is_some() {
+ let url = diagnostic.url().unwrap(); // safe
+ let code = if let Some(code) = diagnostic.code() {
+ format!("{} ", code)
+ } else {
+ "".to_string()
+ };
+ let link = format!(
+ "\u{1b}]8;;{}\u{1b}\\{}{}\u{1b}]8;;\u{1b}\\",
+ url,
+ code.style(severity_style),
+ "(link)".style(self.theme.styles.link)
+ );
+ write!(header, "{}", link)?;
+ writeln!(f, "{}", header)?;
+ writeln!(f)?;
+ } else if let Some(code) = diagnostic.code() {
+ write!(header, "{}", code.style(severity_style),)?;
+ if self.links == LinkStyle::Text && diagnostic.url().is_some() {
+ let url = diagnostic.url().unwrap(); // safe
+ write!(header, " ({})", url.style(self.theme.styles.link))?;
+ }
+ writeln!(f, "{}", header)?;
+ writeln!(f)?;
+ }
+ Ok(())
+ }
+
+ fn render_causes(&self, f: &mut impl fmt::Write, diagnostic: &(dyn Diagnostic)) -> fmt::Result {
+ let (severity_style, severity_icon) = match diagnostic.severity() {
+ Some(Severity::Error) | None => (self.theme.styles.error, &self.theme.characters.error),
+ Some(Severity::Warning) => (self.theme.styles.warning, &self.theme.characters.warning),
+ Some(Severity::Advice) => (self.theme.styles.advice, &self.theme.characters.advice),
+ };
+
+ let initial_indent = format!(" {} ", severity_icon.style(severity_style));
+ let rest_indent = format!(" {} ", self.theme.characters.vbar.style(severity_style));
+ let width = self.termwidth.saturating_sub(2);
+ let opts = textwrap::Options::new(width)
+ .initial_indent(&initial_indent)
+ .subsequent_indent(&rest_indent);
+
+ writeln!(f, "{}", textwrap::fill(&diagnostic.to_string(), opts))?;
+
+ if !self.with_cause_chain {
+ return Ok(());
+ }
+
+ if let Some(mut cause_iter) = diagnostic
+ .diagnostic_source()
+ .map(DiagnosticChain::from_diagnostic)
+ .or_else(|| diagnostic.source().map(DiagnosticChain::from_stderror))
+ .map(|it| it.peekable())
+ {
+ while let Some(error) = cause_iter.next() {
+ let is_last = cause_iter.peek().is_none();
+ let char = if !is_last {
+ self.theme.characters.lcross
+ } else {
+ self.theme.characters.lbot
+ };
+ let initial_indent = format!(
+ " {}{}{} ",
+ char, self.theme.characters.hbar, self.theme.characters.rarrow
+ )
+ .style(severity_style)
+ .to_string();
+ let rest_indent = format!(
+ " {} ",
+ if is_last {
+ ' '
+ } else {
+ self.theme.characters.vbar
+ }
+ )
+ .style(severity_style)
+ .to_string();
+ let opts = textwrap::Options::new(width)
+ .initial_indent(&initial_indent)
+ .subsequent_indent(&rest_indent);
+ match error {
+ ErrorKind::Diagnostic(diag) => {
+ let mut inner = String::new();
+
+ // Don't print footer for inner errors
+ let mut inner_renderer = self.clone();
+ inner_renderer.footer = None;
+ inner_renderer.with_cause_chain = false;
+ inner_renderer.render_report(&mut inner, diag)?;
+
+ writeln!(f, "{}", textwrap::fill(&inner, opts))?;
+ }
+ ErrorKind::StdError(err) => {
+ writeln!(f, "{}", textwrap::fill(&err.to_string(), opts))?;
+ }
+ }
+ }
+ }
+
+ Ok(())
+ }
+
+ fn render_footer(&self, f: &mut impl fmt::Write, diagnostic: &(dyn Diagnostic)) -> fmt::Result {
+ if let Some(help) = diagnostic.help() {
+ let width = self.termwidth.saturating_sub(4);
+ let initial_indent = " help: ".style(self.theme.styles.help).to_string();
+ let opts = textwrap::Options::new(width)
+ .initial_indent(&initial_indent)
+ .subsequent_indent(" ");
+ writeln!(f, "{}", textwrap::fill(&help.to_string(), opts))?;
+ }
+ Ok(())
+ }
+
+ fn render_related(
+ &self,
+ f: &mut impl fmt::Write,
+ diagnostic: &(dyn Diagnostic),
+ parent_src: Option<&dyn SourceCode>,
+ ) -> fmt::Result {
+ if let Some(related) = diagnostic.related() {
+ writeln!(f)?;
+ for rel in related {
+ match rel.severity() {
+ Some(Severity::Error) | None => write!(f, "Error: ")?,
+ Some(Severity::Warning) => write!(f, "Warning: ")?,
+ Some(Severity::Advice) => write!(f, "Advice: ")?,
+ };
+ self.render_header(f, rel)?;
+ self.render_causes(f, rel)?;
+ let src = rel.source_code().or(parent_src);
+ self.render_snippets(f, rel, src)?;
+ self.render_footer(f, rel)?;
+ self.render_related(f, rel, src)?;
+ }
+ }
+ Ok(())
+ }
+
+ fn render_snippets(
+ &self,
+ f: &mut impl fmt::Write,
+ diagnostic: &(dyn Diagnostic),
+ opt_source: Option<&dyn SourceCode>,
+ ) -> fmt::Result {
+ if let Some(source) = opt_source {
+ if let Some(labels) = diagnostic.labels() {
+ let mut labels = labels.collect::<Vec<_>>();
+ labels.sort_unstable_by_key(|l| l.inner().offset());
+ if !labels.is_empty() {
+ let contents = labels
+ .iter()
+ .map(|label| {
+ source.read_span(label.inner(), self.context_lines, self.context_lines)
+ })
+ .collect::<Result<Vec<Box<dyn SpanContents<'_>>>, MietteError>>()
+ .map_err(|_| fmt::Error)?;
+ let mut contexts = Vec::with_capacity(contents.len());
+ for (right, right_conts) in labels.iter().cloned().zip(contents.iter()) {
+ if contexts.is_empty() {
+ contexts.push((right, right_conts));
+ } else {
+ let (left, left_conts) = contexts.last().unwrap().clone();
+ let left_end = left.offset() + left.len();
+ let right_end = right.offset() + right.len();
+ if left_conts.line() + left_conts.line_count() >= right_conts.line() {
+ // The snippets will overlap, so we create one Big Chunky Boi
+ let new_span = LabeledSpan::new(
+ left.label().map(String::from),
+ left.offset(),
+ if right_end >= left_end {
+ // Right end goes past left end
+ right_end - left.offset()
+ } else {
+ // right is contained inside left
+ left.len()
+ },
+ );
+ if source
+ .read_span(
+ new_span.inner(),
+ self.context_lines,
+ self.context_lines,
+ )
+ .is_ok()
+ {
+ contexts.pop();
+ contexts.push((
+ // We'll throw this away later
+ new_span, left_conts,
+ ));
+ } else {
+ contexts.push((right, right_conts));
+ }
+ } else {
+ contexts.push((right, right_conts));
+ }
+ }
+ }
+ for (ctx, _) in contexts {
+ self.render_context(f, source, &ctx, &labels[..])?;
+ }
+ }
+ }
+ }
+ Ok(())
+ }
+
+ fn render_context<'a>(
+ &self,
+ f: &mut impl fmt::Write,
+ source: &'a dyn SourceCode,
+ context: &LabeledSpan,
+ labels: &[LabeledSpan],
+ ) -> fmt::Result {
+ let (contents, lines) = self.get_lines(source, context.inner())?;
+
+ // sorting is your friend
+ let labels = labels
+ .iter()
+ .zip(self.theme.styles.highlights.iter().cloned().cycle())
+ .map(|(label, st)| FancySpan::new(label.label().map(String::from), *label.inner(), st))
+ .collect::<Vec<_>>();
+
+ // The max number of gutter-lines that will be active at any given
+ // point. We need this to figure out indentation, so we do one loop
+ // over the lines to see what the damage is gonna be.
+ let mut max_gutter = 0usize;
+ for line in &lines {
+ let mut num_highlights = 0;
+ for hl in &labels {
+ if !line.span_line_only(hl) && line.span_applies(hl) {
+ num_highlights += 1;
+ }
+ }
+ max_gutter = std::cmp::max(max_gutter, num_highlights);
+ }
+
+ // Oh and one more thing: We need to figure out how much room our line
+ // numbers need!
+ let linum_width = lines[..]
+ .last()
+ .map(|line| line.line_number)
+ // It's possible for the source to be an empty string.
+ .unwrap_or(0)
+ .to_string()
+ .len();
+
+ // Header
+ write!(
+ f,
+ "{}{}{}",
+ " ".repeat(linum_width + 2),
+ self.theme.characters.ltop,
+ self.theme.characters.hbar,
+ )?;
+
+ if let Some(source_name) = contents.name() {
+ let source_name = source_name.style(self.theme.styles.link);
+ writeln!(
+ f,
+ "[{}:{}:{}]",
+ source_name,
+ contents.line() + 1,
+ contents.column() + 1
+ )?;
+ } else if lines.len() <= 1 {
+ writeln!(f, "{}", self.theme.characters.hbar.to_string().repeat(3))?;
+ } else {
+ writeln!(f, "[{}:{}]", contents.line() + 1, contents.column() + 1)?;
+ }
+
+ // Now it's time for the fun part--actually rendering everything!
+ for line in &lines {
+ // Line number, appropriately padded.
+ self.write_linum(f, linum_width, line.line_number)?;
+
+ // Then, we need to print the gutter, along with any fly-bys We
+ // have separate gutters depending on whether we're on the actual
+ // line, or on one of the "highlight lines" below it.
+ self.render_line_gutter(f, max_gutter, line, &labels)?;
+
+ // And _now_ we can print out the line text itself!
+ self.render_line_text(f, &line.text)?;
+
+ // Next, we write all the highlights that apply to this particular line.
+ let (single_line, multi_line): (Vec<_>, Vec<_>) = labels
+ .iter()
+ .filter(|hl| line.span_applies(hl))
+ .partition(|hl| line.span_line_only(hl));
+ if !single_line.is_empty() {
+ // no line number!
+ self.write_no_linum(f, linum_width)?;
+ // gutter _again_
+ self.render_highlight_gutter(f, max_gutter, line, &labels)?;
+ self.render_single_line_highlights(
+ f,
+ line,
+ linum_width,
+ max_gutter,
+ &single_line,
+ &labels,
+ )?;
+ }
+ for hl in multi_line {
+ if hl.label().is_some() && line.span_ends(hl) && !line.span_starts(hl) {
+ // no line number!
+ self.write_no_linum(f, linum_width)?;
+ // gutter _again_
+ self.render_highlight_gutter(f, max_gutter, line, &labels)?;
+ self.render_multi_line_end(f, hl)?;
+ }
+ }
+ }
+ writeln!(
+ f,
+ "{}{}{}",
+ " ".repeat(linum_width + 2),
+ self.theme.characters.lbot,
+ self.theme.characters.hbar.to_string().repeat(4),
+ )?;
+ Ok(())
+ }
+
+ fn render_line_gutter(
+ &self,
+ f: &mut impl fmt::Write,
+ max_gutter: usize,
+ line: &Line,
+ highlights: &[FancySpan],
+ ) -> fmt::Result {
+ if max_gutter == 0 {
+ return Ok(());
+ }
+ let chars = &self.theme.characters;
+ let mut gutter = String::new();
+ let applicable = highlights.iter().filter(|hl| line.span_applies(hl));
+ let mut arrow = false;
+ for (i, hl) in applicable.enumerate() {
+ if line.span_starts(hl) {
+ gutter.push_str(&chars.ltop.style(hl.style).to_string());
+ gutter.push_str(
+ &chars
+ .hbar
+ .to_string()
+ .repeat(max_gutter.saturating_sub(i))
+ .style(hl.style)
+ .to_string(),
+ );
+ gutter.push_str(&chars.rarrow.style(hl.style).to_string());
+ arrow = true;
+ break;
+ } else if line.span_ends(hl) {
+ if hl.label().is_some() {
+ gutter.push_str(&chars.lcross.style(hl.style).to_string());
+ } else {
+ gutter.push_str(&chars.lbot.style(hl.style).to_string());
+ }
+ gutter.push_str(
+ &chars
+ .hbar
+ .to_string()
+ .repeat(max_gutter.saturating_sub(i))
+ .style(hl.style)
+ .to_string(),
+ );
+ gutter.push_str(&chars.rarrow.style(hl.style).to_string());
+ arrow = true;
+ break;
+ } else if line.span_flyby(hl) {
+ gutter.push_str(&chars.vbar.style(hl.style).to_string());
+ } else {
+ gutter.push(' ');
+ }
+ }
+ write!(
+ f,
+ "{}{}",
+ gutter,
+ " ".repeat(
+ if arrow { 1 } else { 3 } + max_gutter.saturating_sub(gutter.chars().count())
+ )
+ )?;
+ Ok(())
+ }
+
+ fn render_highlight_gutter(
+ &self,
+ f: &mut impl fmt::Write,
+ max_gutter: usize,
+ line: &Line,
+ highlights: &[FancySpan],
+ ) -> fmt::Result {
+ if max_gutter == 0 {
+ return Ok(());
+ }
+ let chars = &self.theme.characters;
+ let mut gutter = String::new();
+ let applicable = highlights.iter().filter(|hl| line.span_applies(hl));
+ for (i, hl) in applicable.enumerate() {
+ if !line.span_line_only(hl) && line.span_ends(hl) {
+ gutter.push_str(&chars.lbot.style(hl.style).to_string());
+ gutter.push_str(
+ &chars
+ .hbar
+ .to_string()
+ .repeat(max_gutter.saturating_sub(i) + 2)
+ .style(hl.style)
+ .to_string(),
+ );
+ break;
+ } else {
+ gutter.push_str(&chars.vbar.style(hl.style).to_string());
+ }
+ }
+ write!(f, "{:width$}", gutter, width = max_gutter + 1)?;
+ Ok(())
+ }
+
+ fn write_linum(&self, f: &mut impl fmt::Write, width: usize, linum: usize) -> fmt::Result {
+ write!(
+ f,
+ " {:width$} {} ",
+ linum.style(self.theme.styles.linum),
+ self.theme.characters.vbar,
+ width = width
+ )?;
+ Ok(())
+ }
+
+ fn write_no_linum(&self, f: &mut impl fmt::Write, width: usize) -> fmt::Result {
+ write!(
+ f,
+ " {:width$} {} ",
+ "",
+ self.theme.characters.vbar_break,
+ width = width
+ )?;
+ Ok(())
+ }
+
+ /// Returns an iterator over the visual width of each character in a line.
+ fn line_visual_char_width<'a>(&self, text: &'a str) -> impl Iterator<Item = usize> + 'a {
+ let mut column = 0;
+ let tab_width = self.tab_width;
+ text.chars().map(move |c| {
+ let width = if c == '\t' {
+ // Round up to the next multiple of tab_width
+ tab_width - column % tab_width
+ } else {
+ c.width().unwrap_or(0)
+ };
+ column += width;
+ width
+ })
+ }
+
+ /// Returns the visual column position of a byte offset on a specific line.
+ fn visual_offset(&self, line: &Line, offset: usize) -> usize {
+ let line_range = line.offset..=(line.offset + line.length);
+ assert!(line_range.contains(&offset));
+
+ let text_index = offset - line.offset;
+ let text = &line.text[..text_index.min(line.text.len())];
+ let text_width = self.line_visual_char_width(text).sum();
+ if text_index > line.text.len() {
+ // Spans extending past the end of the line are always rendered as
+ // one column past the end of the visible line.
+ //
+ // This doesn't necessarily correspond to a specific byte-offset,
+ // since a span extending past the end of the line could contain:
+ // - an actual \n character (1 byte)
+ // - a CRLF (2 bytes)
+ // - EOF (0 bytes)
+ text_width + 1
+ } else {
+ text_width
+ }
+ }
+
+ /// Renders a line to the output formatter, replacing tabs with spaces.
+ fn render_line_text(&self, f: &mut impl fmt::Write, text: &str) -> fmt::Result {
+ for (c, width) in text.chars().zip(self.line_visual_char_width(text)) {
+ if c == '\t' {
+ for _ in 0..width {
+ f.write_char(' ')?
+ }
+ } else {
+ f.write_char(c)?
+ }
+ }
+ f.write_char('\n')?;
+ Ok(())
+ }
+
+ fn render_single_line_highlights(
+ &self,
+ f: &mut impl fmt::Write,
+ line: &Line,
+ linum_width: usize,
+ max_gutter: usize,
+ single_liners: &[&FancySpan],
+ all_highlights: &[FancySpan],
+ ) -> fmt::Result {
+ let mut underlines = String::new();
+ let mut highest = 0;
+
+ let chars = &self.theme.characters;
+ let vbar_offsets: Vec<_> = single_liners
+ .iter()
+ .map(|hl| {
+ let byte_start = hl.offset();
+ let byte_end = hl.offset() + hl.len();
+ let start = self.visual_offset(line, byte_start).max(highest);
+ let end = self.visual_offset(line, byte_end).max(start + 1);
+
+ let vbar_offset = (start + end) / 2;
+ let num_left = vbar_offset - start;
+ let num_right = end - vbar_offset - 1;
+ if start < end {
+ underlines.push_str(
+ &format!(
+ "{:width$}{}{}{}",
+ "",
+ chars.underline.to_string().repeat(num_left),
+ if hl.len() == 0 {
+ chars.uarrow
+ } else if hl.label().is_some() {
+ chars.underbar
+ } else {
+ chars.underline
+ },
+ chars.underline.to_string().repeat(num_right),
+ width = start.saturating_sub(highest),
+ )
+ .style(hl.style)
+ .to_string(),
+ );
+ }
+ highest = std::cmp::max(highest, end);
+
+ (hl, vbar_offset)
+ })
+ .collect();
+ writeln!(f, "{}", underlines)?;
+
+ for hl in single_liners.iter().rev() {
+ if let Some(label) = hl.label() {
+ self.write_no_linum(f, linum_width)?;
+ self.render_highlight_gutter(f, max_gutter, line, all_highlights)?;
+ let mut curr_offset = 1usize;
+ for (offset_hl, vbar_offset) in &vbar_offsets {
+ while curr_offset < *vbar_offset + 1 {
+ write!(f, " ")?;
+ curr_offset += 1;
+ }
+ if *offset_hl != hl {
+ write!(f, "{}", chars.vbar.to_string().style(offset_hl.style))?;
+ curr_offset += 1;
+ } else {
+ let lines = format!(
+ "{}{} {}",
+ chars.lbot,
+ chars.hbar.to_string().repeat(2),
+ label,
+ );
+ writeln!(f, "{}", lines.style(hl.style))?;
+ break;
+ }
+ }
+ }
+ }
+ Ok(())
+ }
+
+ fn render_multi_line_end(&self, f: &mut impl fmt::Write, hl: &FancySpan) -> fmt::Result {
+ writeln!(
+ f,
+ "{} {}",
+ self.theme.characters.hbar.style(hl.style),
+ hl.label().unwrap_or_else(|| "".into()),
+ )?;
+ Ok(())
+ }
+
+ fn get_lines<'a>(
+ &'a self,
+ source: &'a dyn SourceCode,
+ context_span: &'a SourceSpan,
+ ) -> Result<(Box<dyn SpanContents<'a> + 'a>, Vec<Line>), fmt::Error> {
+ let context_data = source
+ .read_span(context_span, self.context_lines, self.context_lines)
+ .map_err(|_| fmt::Error)?;
+ let context = std::str::from_utf8(context_data.data()).expect("Bad utf8 detected");
+ let mut line = context_data.line();
+ let mut column = context_data.column();
+ let mut offset = context_data.span().offset();
+ let mut line_offset = offset;
+ let mut iter = context.chars().peekable();
+ let mut line_str = String::new();
+ let mut lines = Vec::new();
+ while let Some(char) = iter.next() {
+ offset += char.len_utf8();
+ let mut at_end_of_file = false;
+ match char {
+ '\r' => {
+ if iter.next_if_eq(&'\n').is_some() {
+ offset += 1;
+ line += 1;
+ column = 0;
+ } else {
+ line_str.push(char);
+ column += 1;
+ }
+ at_end_of_file = iter.peek().is_none();
+ }
+ '\n' => {
+ at_end_of_file = iter.peek().is_none();
+ line += 1;
+ column = 0;
+ }
+ _ => {
+ line_str.push(char);
+ column += 1;
+ }
+ }
+
+ if iter.peek().is_none() && !at_end_of_file {
+ line += 1;
+ }
+
+ if column == 0 || iter.peek().is_none() {
+ lines.push(Line {
+ line_number: line,
+ offset: line_offset,
+ length: offset - line_offset,
+ text: line_str.clone(),
+ });
+ line_str.clear();
+ line_offset = offset;
+ }
+ }
+ Ok((context_data, lines))
+ }
+}
+
+impl ReportHandler for GraphicalReportHandler {
+ fn debug(&self, diagnostic: &(dyn Diagnostic), f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ if f.alternate() {
+ return fmt::Debug::fmt(diagnostic, f);
+ }
+
+ self.render_report(f, diagnostic)
+ }
+}
+
+/*
+Support types
+*/
+
+#[derive(Debug)]
+struct Line {
+ line_number: usize,
+ offset: usize,
+ length: usize,
+ text: String,
+}
+
+impl Line {
+ fn span_line_only(&self, span: &FancySpan) -> bool {
+ span.offset() >= self.offset && span.offset() + span.len() <= self.offset + self.length
+ }
+
+ fn span_applies(&self, span: &FancySpan) -> bool {
+ let spanlen = if span.len() == 0 { 1 } else { span.len() };
+ // Span starts in this line
+ (span.offset() >= self.offset && span.offset() < self.offset + self.length)
+ // Span passes through this line
+ || (span.offset() < self.offset && span.offset() + spanlen > self.offset + self.length) //todo
+ // Span ends on this line
+ || (span.offset() + spanlen > self.offset && span.offset() + spanlen <= self.offset + self.length)
+ }
+
+ // A 'flyby' is a multi-line span that technically covers this line, but
+ // does not begin or end within the line itself. This method is used to
+ // calculate gutters.
+ fn span_flyby(&self, span: &FancySpan) -> bool {
+ // The span itself starts before this line's starting offset (so, in a
+ // prev line).
+ span.offset() < self.offset
+ // ...and it stops after this line's end.
+ && span.offset() + span.len() > self.offset + self.length
+ }
+
+ // Does this line contain the *beginning* of this multiline span?
+ // This assumes self.span_applies() is true already.
+ fn span_starts(&self, span: &FancySpan) -> bool {
+ span.offset() >= self.offset
+ }
+
+ // Does this line contain the *end* of this multiline span?
+ // This assumes self.span_applies() is true already.
+ fn span_ends(&self, span: &FancySpan) -> bool {
+ span.offset() + span.len() >= self.offset
+ && span.offset() + span.len() <= self.offset + self.length
+ }
+}
+
+#[derive(Debug, Clone)]
+struct FancySpan {
+ label: Option<String>,
+ span: SourceSpan,
+ style: Style,
+}
+
+impl PartialEq for FancySpan {
+ fn eq(&self, other: &Self) -> bool {
+ self.label == other.label && self.span == other.span
+ }
+}
+
+impl FancySpan {
+ fn new(label: Option<String>, span: SourceSpan, style: Style) -> Self {
+ FancySpan { label, span, style }
+ }
+
+ fn style(&self) -> Style {
+ self.style
+ }
+
+ fn label(&self) -> Option<String> {
+ self.label
+ .as_ref()
+ .map(|l| l.style(self.style()).to_string())
+ }
+
+ fn offset(&self) -> usize {
+ self.span.offset()
+ }
+
+ fn len(&self) -> usize {
+ self.span.len()
+ }
+}
diff --git a/vendor/miette/src/handlers/json.rs b/vendor/miette/src/handlers/json.rs
new file mode 100644
index 0000000..29e21a0
--- /dev/null
+++ b/vendor/miette/src/handlers/json.rs
@@ -0,0 +1,182 @@
+use std::fmt::{self, Write};
+
+use crate::{
+ diagnostic_chain::DiagnosticChain, protocol::Diagnostic, ReportHandler, Severity, SourceCode,
+};
+
+/**
+[`ReportHandler`] that renders JSON output. It's a machine-readable output.
+*/
+#[derive(Debug, Clone)]
+pub struct JSONReportHandler;
+
+impl JSONReportHandler {
+ /// Create a new [`JSONReportHandler`]. There are no customization
+ /// options.
+ pub const fn new() -> Self {
+ Self
+ }
+}
+
+impl Default for JSONReportHandler {
+ fn default() -> Self {
+ Self::new()
+ }
+}
+
+struct Escape<'a>(&'a str);
+
+impl fmt::Display for Escape<'_> {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ for c in self.0.chars() {
+ let escape = match c {
+ '\\' => Some(r"\\"),
+ '"' => Some(r#"\""#),
+ '\r' => Some(r"\r"),
+ '\n' => Some(r"\n"),
+ '\t' => Some(r"\t"),
+ '\u{08}' => Some(r"\b"),
+ '\u{0c}' => Some(r"\f"),
+ _ => None,
+ };
+ if let Some(escape) = escape {
+ f.write_str(escape)?;
+ } else {
+ f.write_char(c)?;
+ }
+ }
+ Ok(())
+ }
+}
+
+const fn escape(input: &'_ str) -> Escape<'_> {
+ Escape(input)
+}
+
+impl JSONReportHandler {
+ /// Render a [`Diagnostic`]. This function is mostly internal and meant to
+ /// be called by the toplevel [`ReportHandler`] handler, but is made public
+ /// to make it easier (possible) to test in isolation from global state.
+ pub fn render_report(
+ &self,
+ f: &mut impl fmt::Write,
+ diagnostic: &(dyn Diagnostic),
+ ) -> fmt::Result {
+ self._render_report(f, diagnostic, None)
+ }
+
+ fn _render_report(
+ &self,
+ f: &mut impl fmt::Write,
+ diagnostic: &(dyn Diagnostic),
+ parent_src: Option<&dyn SourceCode>,
+ ) -> fmt::Result {
+ write!(f, r#"{{"message": "{}","#, escape(&diagnostic.to_string()))?;
+ if let Some(code) = diagnostic.code() {
+ write!(f, r#""code": "{}","#, escape(&code.to_string()))?;
+ }
+ let severity = match diagnostic.severity() {
+ Some(Severity::Error) | None => "error",
+ Some(Severity::Warning) => "warning",
+ Some(Severity::Advice) => "advice",
+ };
+ write!(f, r#""severity": "{:}","#, severity)?;
+ if let Some(cause_iter) = diagnostic
+ .diagnostic_source()
+ .map(DiagnosticChain::from_diagnostic)
+ .or_else(|| diagnostic.source().map(DiagnosticChain::from_stderror))
+ {
+ write!(f, r#""causes": ["#)?;
+ let mut add_comma = false;
+ for error in cause_iter {
+ if add_comma {
+ write!(f, ",")?;
+ } else {
+ add_comma = true;
+ }
+ write!(f, r#""{}""#, escape(&error.to_string()))?;
+ }
+ write!(f, "],")?
+ } else {
+ write!(f, r#""causes": [],"#)?;
+ }
+ if let Some(url) = diagnostic.url() {
+ write!(f, r#""url": "{}","#, &url.to_string())?;
+ }
+ if let Some(help) = diagnostic.help() {
+ write!(f, r#""help": "{}","#, escape(&help.to_string()))?;
+ }
+ let src = diagnostic.source_code().or(parent_src);
+ if let Some(src) = src {
+ self.render_snippets(f, diagnostic, src)?;
+ }
+ if let Some(labels) = diagnostic.labels() {
+ write!(f, r#""labels": ["#)?;
+ let mut add_comma = false;
+ for label in labels {
+ if add_comma {
+ write!(f, ",")?;
+ } else {
+ add_comma = true;
+ }
+ write!(f, "{{")?;
+ if let Some(label_name) = label.label() {
+ write!(f, r#""label": "{}","#, escape(label_name))?;
+ }
+ write!(f, r#""span": {{"#)?;
+ write!(f, r#""offset": {},"#, label.offset())?;
+ write!(f, r#""length": {}"#, label.len())?;
+
+ write!(f, "}}}}")?;
+ }
+ write!(f, "],")?;
+ } else {
+ write!(f, r#""labels": [],"#)?;
+ }
+ if let Some(relateds) = diagnostic.related() {
+ write!(f, r#""related": ["#)?;
+ let mut add_comma = false;
+ for related in relateds {
+ if add_comma {
+ write!(f, ",")?;
+ } else {
+ add_comma = true;
+ }
+ self._render_report(f, related, src)?;
+ }
+ write!(f, "]")?;
+ } else {
+ write!(f, r#""related": []"#)?;
+ }
+ write!(f, "}}")
+ }
+
+ fn render_snippets(
+ &self,
+ f: &mut impl fmt::Write,
+ diagnostic: &(dyn Diagnostic),
+ source: &dyn SourceCode,
+ ) -> fmt::Result {
+ if let Some(mut labels) = diagnostic.labels() {
+ if let Some(label) = labels.next() {
+ if let Ok(span_content) = source.read_span(label.inner(), 0, 0) {
+ let filename = span_content.name().unwrap_or_default();
+ return write!(f, r#""filename": "{}","#, escape(filename));
+ }
+ }
+ }
+ write!(f, r#""filename": "","#)
+ }
+}
+
+impl ReportHandler for JSONReportHandler {
+ fn debug(&self, diagnostic: &(dyn Diagnostic), f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ self.render_report(f, diagnostic)
+ }
+}
+
+#[test]
+fn test_escape() {
+ assert_eq!(escape("a\nb").to_string(), r"a\nb");
+ assert_eq!(escape("C:\\Miette").to_string(), r"C:\\Miette");
+}
diff --git a/vendor/miette/src/handlers/mod.rs b/vendor/miette/src/handlers/mod.rs
new file mode 100644
index 0000000..fde2dc9
--- /dev/null
+++ b/vendor/miette/src/handlers/mod.rs
@@ -0,0 +1,24 @@
+/*!
+Reporters included with `miette`.
+*/
+
+#[allow(unreachable_pub)]
+pub use debug::*;
+#[allow(unreachable_pub)]
+#[cfg(feature = "fancy-no-backtrace")]
+pub use graphical::*;
+#[allow(unreachable_pub)]
+pub use json::*;
+#[allow(unreachable_pub)]
+pub use narratable::*;
+#[allow(unreachable_pub)]
+#[cfg(feature = "fancy-no-backtrace")]
+pub use theme::*;
+
+mod debug;
+#[cfg(feature = "fancy-no-backtrace")]
+mod graphical;
+mod json;
+mod narratable;
+#[cfg(feature = "fancy-no-backtrace")]
+mod theme;
diff --git a/vendor/miette/src/handlers/narratable.rs b/vendor/miette/src/handlers/narratable.rs
new file mode 100644
index 0000000..c809124
--- /dev/null
+++ b/vendor/miette/src/handlers/narratable.rs
@@ -0,0 +1,423 @@
+use std::fmt;
+
+use unicode_width::{UnicodeWidthChar, UnicodeWidthStr};
+
+use crate::diagnostic_chain::DiagnosticChain;
+use crate::protocol::{Diagnostic, Severity};
+use crate::{LabeledSpan, MietteError, ReportHandler, SourceCode, SourceSpan, SpanContents};
+
+/**
+[`ReportHandler`] that renders plain text and avoids extraneous graphics.
+It's optimized for screen readers and braille users, but is also used in any
+non-graphical environments, such as non-TTY output.
+*/
+#[derive(Debug, Clone)]
+pub struct NarratableReportHandler {
+ context_lines: usize,
+ with_cause_chain: bool,
+ footer: Option<String>,
+}
+
+impl NarratableReportHandler {
+ /// Create a new [`NarratableReportHandler`]. There are no customization
+ /// options.
+ pub const fn new() -> Self {
+ Self {
+ footer: None,
+ context_lines: 1,
+ with_cause_chain: true,
+ }
+ }
+
+ /// Include the cause chain of the top-level error in the report, if
+ /// available.
+ pub const fn with_cause_chain(mut self) -> Self {
+ self.with_cause_chain = true;
+ self
+ }
+
+ /// Do not include the cause chain of the top-level error in the report.
+ pub const fn without_cause_chain(mut self) -> Self {
+ self.with_cause_chain = false;
+ self
+ }
+
+ /// Set the footer to be displayed at the end of the report.
+ pub fn with_footer(mut self, footer: String) -> Self {
+ self.footer = Some(footer);
+ self
+ }
+
+ /// Sets the number of lines of context to show around each error.
+ pub const fn with_context_lines(mut self, lines: usize) -> Self {
+ self.context_lines = lines;
+ self
+ }
+}
+
+impl Default for NarratableReportHandler {
+ fn default() -> Self {
+ Self::new()
+ }
+}
+
+impl NarratableReportHandler {
+ /// Render a [`Diagnostic`]. This function is mostly internal and meant to
+ /// be called by the toplevel [`ReportHandler`] handler, but is
+ /// made public to make it easier (possible) to test in isolation from
+ /// global state.
+ pub fn render_report(
+ &self,
+ f: &mut impl fmt::Write,
+ diagnostic: &(dyn Diagnostic),
+ ) -> fmt::Result {
+ self.render_header(f, diagnostic)?;
+ if self.with_cause_chain {
+ self.render_causes(f, diagnostic)?;
+ }
+ let src = diagnostic.source_code();
+ self.render_snippets(f, diagnostic, src)?;
+ self.render_footer(f, diagnostic)?;
+ self.render_related(f, diagnostic, src)?;
+ if let Some(footer) = &self.footer {
+ writeln!(f, "{}", footer)?;
+ }
+ Ok(())
+ }
+
+ fn render_header(&self, f: &mut impl fmt::Write, diagnostic: &(dyn Diagnostic)) -> fmt::Result {
+ writeln!(f, "{}", diagnostic)?;
+ let severity = match diagnostic.severity() {
+ Some(Severity::Error) | None => "error",
+ Some(Severity::Warning) => "warning",
+ Some(Severity::Advice) => "advice",
+ };
+ writeln!(f, " Diagnostic severity: {}", severity)?;
+ Ok(())
+ }
+
+ fn render_causes(&self, f: &mut impl fmt::Write, diagnostic: &(dyn Diagnostic)) -> fmt::Result {
+ if let Some(cause_iter) = diagnostic
+ .diagnostic_source()
+ .map(DiagnosticChain::from_diagnostic)
+ .or_else(|| diagnostic.source().map(DiagnosticChain::from_stderror))
+ {
+ for error in cause_iter {
+ writeln!(f, " Caused by: {}", error)?;
+ }
+ }
+
+ Ok(())
+ }
+
+ fn render_footer(&self, f: &mut impl fmt::Write, diagnostic: &(dyn Diagnostic)) -> fmt::Result {
+ if let Some(help) = diagnostic.help() {
+ writeln!(f, "diagnostic help: {}", help)?;
+ }
+ if let Some(code) = diagnostic.code() {
+ writeln!(f, "diagnostic code: {}", code)?;
+ }
+ if let Some(url) = diagnostic.url() {
+ writeln!(f, "For more details, see:\n{}", url)?;
+ }
+ Ok(())
+ }
+
+ fn render_related(
+ &self,
+ f: &mut impl fmt::Write,
+ diagnostic: &(dyn Diagnostic),
+ parent_src: Option<&dyn SourceCode>,
+ ) -> fmt::Result {
+ if let Some(related) = diagnostic.related() {
+ writeln!(f)?;
+ for rel in related {
+ match rel.severity() {
+ Some(Severity::Error) | None => write!(f, "Error: ")?,
+ Some(Severity::Warning) => write!(f, "Warning: ")?,
+ Some(Severity::Advice) => write!(f, "Advice: ")?,
+ };
+ self.render_header(f, rel)?;
+ writeln!(f)?;
+ self.render_causes(f, rel)?;
+ let src = rel.source_code().or(parent_src);
+ self.render_snippets(f, rel, src)?;
+ self.render_footer(f, rel)?;
+ self.render_related(f, rel, src)?;
+ }
+ }
+ Ok(())
+ }
+
+ fn render_snippets(
+ &self,
+ f: &mut impl fmt::Write,
+ diagnostic: &(dyn Diagnostic),
+ source_code: Option<&dyn SourceCode>,
+ ) -> fmt::Result {
+ if let Some(source) = source_code {
+ if let Some(labels) = diagnostic.labels() {
+ let mut labels = labels.collect::<Vec<_>>();
+ labels.sort_unstable_by_key(|l| l.inner().offset());
+ if !labels.is_empty() {
+ let contents = labels
+ .iter()
+ .map(|label| {
+ source.read_span(label.inner(), self.context_lines, self.context_lines)
+ })
+ .collect::<Result<Vec<Box<dyn SpanContents<'_>>>, MietteError>>()
+ .map_err(|_| fmt::Error)?;
+ let mut contexts = Vec::new();
+ for (right, right_conts) in labels.iter().cloned().zip(contents.iter()) {
+ if contexts.is_empty() {
+ contexts.push((right, right_conts));
+ } else {
+ let (left, left_conts) = contexts.last().unwrap().clone();
+ let left_end = left.offset() + left.len();
+ let right_end = right.offset() + right.len();
+ if left_conts.line() + left_conts.line_count() >= right_conts.line() {
+ // The snippets will overlap, so we create one Big Chunky Boi
+ let new_span = LabeledSpan::new(
+ left.label().map(String::from),
+ left.offset(),
+ if right_end >= left_end {
+ // Right end goes past left end
+ right_end - left.offset()
+ } else {
+ // right is contained inside left
+ left.len()
+ },
+ );
+ if source
+ .read_span(
+ new_span.inner(),
+ self.context_lines,
+ self.context_lines,
+ )
+ .is_ok()
+ {
+ contexts.pop();
+ contexts.push((
+ new_span, // We'll throw this away later
+ left_conts,
+ ));
+ } else {
+ contexts.push((right, right_conts));
+ }
+ } else {
+ contexts.push((right, right_conts));
+ }
+ }
+ }
+ for (ctx, _) in contexts {
+ self.render_context(f, source, &ctx, &labels[..])?;
+ }
+ }
+ }
+ }
+ Ok(())
+ }
+
+ fn render_context(
+ &self,
+ f: &mut impl fmt::Write,
+ source: &dyn SourceCode,
+ context: &LabeledSpan,
+ labels: &[LabeledSpan],
+ ) -> fmt::Result {
+ let (contents, lines) = self.get_lines(source, context.inner())?;
+ write!(f, "Begin snippet")?;
+ if let Some(filename) = contents.name() {
+ write!(f, " for {}", filename,)?;
+ }
+ writeln!(
+ f,
+ " starting at line {}, column {}",
+ contents.line() + 1,
+ contents.column() + 1
+ )?;
+ writeln!(f)?;
+ for line in &lines {
+ writeln!(f, "snippet line {}: {}", line.line_number, line.text)?;
+ let relevant = labels
+ .iter()
+ .filter_map(|l| line.span_attach(l.inner()).map(|a| (a, l)));
+ for (attach, label) in relevant {
+ match attach {
+ SpanAttach::Contained { col_start, col_end } if col_start == col_end => {
+ write!(
+ f,
+ " label at line {}, column {}",
+ line.line_number, col_start,
+ )?;
+ }
+ SpanAttach::Contained { col_start, col_end } => {
+ write!(
+ f,
+ " label at line {}, columns {} to {}",
+ line.line_number, col_start, col_end,
+ )?;
+ }
+ SpanAttach::Starts { col_start } => {
+ write!(
+ f,
+ " label starting at line {}, column {}",
+ line.line_number, col_start,
+ )?;
+ }
+ SpanAttach::Ends { col_end } => {
+ write!(
+ f,
+ " label ending at line {}, column {}",
+ line.line_number, col_end,
+ )?;
+ }
+ }
+ if let Some(label) = label.label() {
+ write!(f, ": {}", label)?;
+ }
+ writeln!(f)?;
+ }
+ }
+ Ok(())
+ }
+
+ fn get_lines<'a>(
+ &'a self,
+ source: &'a dyn SourceCode,
+ context_span: &'a SourceSpan,
+ ) -> Result<(Box<dyn SpanContents<'a> + 'a>, Vec<Line>), fmt::Error> {
+ let context_data = source
+ .read_span(context_span, self.context_lines, self.context_lines)
+ .map_err(|_| fmt::Error)?;
+ let context = std::str::from_utf8(context_data.data()).expect("Bad utf8 detected");
+ let mut line = context_data.line();
+ let mut column = context_data.column();
+ let mut offset = context_data.span().offset();
+ let mut line_offset = offset;
+ let mut iter = context.chars().peekable();
+ let mut line_str = String::new();
+ let mut lines = Vec::new();
+ while let Some(char) = iter.next() {
+ offset += char.len_utf8();
+ let mut at_end_of_file = false;
+ match char {
+ '\r' => {
+ if iter.next_if_eq(&'\n').is_some() {
+ offset += 1;
+ line += 1;
+ column = 0;
+ } else {
+ line_str.push(char);
+ column += 1;
+ }
+ at_end_of_file = iter.peek().is_none();
+ }
+ '\n' => {
+ at_end_of_file = iter.peek().is_none();
+ line += 1;
+ column = 0;
+ }
+ _ => {
+ line_str.push(char);
+ column += 1;
+ }
+ }
+
+ if iter.peek().is_none() && !at_end_of_file {
+ line += 1;
+ }
+
+ if column == 0 || iter.peek().is_none() {
+ lines.push(Line {
+ line_number: line,
+ offset: line_offset,
+ text: line_str.clone(),
+ at_end_of_file,
+ });
+ line_str.clear();
+ line_offset = offset;
+ }
+ }
+ Ok((context_data, lines))
+ }
+}
+
+impl ReportHandler for NarratableReportHandler {
+ fn debug(&self, diagnostic: &(dyn Diagnostic), f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ if f.alternate() {
+ return fmt::Debug::fmt(diagnostic, f);
+ }
+
+ self.render_report(f, diagnostic)
+ }
+}
+
+/*
+Support types
+*/
+
+struct Line {
+ line_number: usize,
+ offset: usize,
+ text: String,
+ at_end_of_file: bool,
+}
+
+enum SpanAttach {
+ Contained { col_start: usize, col_end: usize },
+ Starts { col_start: usize },
+ Ends { col_end: usize },
+}
+
+/// Returns column at offset, and nearest boundary if offset is in the middle of
+/// the character
+fn safe_get_column(text: &str, offset: usize, start: bool) -> usize {
+ let mut column = text.get(0..offset).map(|s| s.width()).unwrap_or_else(|| {
+ let mut column = 0;
+ for (idx, c) in text.char_indices() {
+ if offset <= idx {
+ break;
+ }
+ column += c.width().unwrap_or(0);
+ }
+ column
+ });
+ if start {
+ // Offset are zero-based, so plus one
+ column += 1;
+ } // On the other hand for end span, offset refers for the next column
+ // So we should do -1. column+1-1 == column
+ column
+}
+
+impl Line {
+ fn span_attach(&self, span: &SourceSpan) -> Option<SpanAttach> {
+ let span_end = span.offset() + span.len();
+ let line_end = self.offset + self.text.len();
+
+ let start_after = span.offset() >= self.offset;
+ let end_before = self.at_end_of_file || span_end <= line_end;
+
+ if start_after && end_before {
+ let col_start = safe_get_column(&self.text, span.offset() - self.offset, true);
+ let col_end = if span.is_empty() {
+ col_start
+ } else {
+ // span_end refers to the next character after token
+ // while col_end refers to the exact character, so -1
+ safe_get_column(&self.text, span_end - self.offset, false)
+ };
+ return Some(SpanAttach::Contained { col_start, col_end });
+ }
+ if start_after && span.offset() <= line_end {
+ let col_start = safe_get_column(&self.text, span.offset() - self.offset, true);
+ return Some(SpanAttach::Starts { col_start });
+ }
+ if end_before && span_end >= self.offset {
+ let col_end = safe_get_column(&self.text, span_end - self.offset, false);
+ return Some(SpanAttach::Ends { col_end });
+ }
+ None
+ }
+}
diff --git a/vendor/miette/src/handlers/theme.rs b/vendor/miette/src/handlers/theme.rs
new file mode 100644
index 0000000..1f5236a
--- /dev/null
+++ b/vendor/miette/src/handlers/theme.rs
@@ -0,0 +1,275 @@
+use is_terminal::IsTerminal;
+use owo_colors::Style;
+
+/**
+Theme used by [`GraphicalReportHandler`](crate::GraphicalReportHandler) to
+render fancy [`Diagnostic`](crate::Diagnostic) reports.
+
+A theme consists of two things: the set of characters to be used for drawing,
+and the
+[`owo_colors::Style`](https://docs.rs/owo-colors/latest/owo_colors/struct.Style.html)s to be used to paint various items.
+
+You can create your own custom graphical theme using this type, or you can use
+one of the predefined ones using the methods below.
+*/
+#[derive(Debug, Clone)]
+pub struct GraphicalTheme {
+ /// Characters to be used for drawing.
+ pub characters: ThemeCharacters,
+ /// Styles to be used for painting.
+ pub styles: ThemeStyles,
+}
+
+impl GraphicalTheme {
+ /// ASCII-art-based graphical drawing, with ANSI styling.
+ pub fn ascii() -> Self {
+ Self {
+ characters: ThemeCharacters::ascii(),
+ styles: ThemeStyles::ansi(),
+ }
+ }
+
+ /// Graphical theme that draws using both ansi colors and unicode
+ /// characters.
+ ///
+ /// Note that full rgb colors aren't enabled by default because they're
+ /// an accessibility hazard, especially in the context of terminal themes
+ /// that can change the background color and make hardcoded colors illegible.
+ /// Such themes typically remap ansi codes properly, treating them more
+ /// like CSS classes than specific colors.
+ pub fn unicode() -> Self {
+ Self {
+ characters: ThemeCharacters::unicode(),
+ styles: ThemeStyles::ansi(),
+ }
+ }
+
+ /// Graphical theme that draws in monochrome, while still using unicode
+ /// characters.
+ pub fn unicode_nocolor() -> Self {
+ Self {
+ characters: ThemeCharacters::unicode(),
+ styles: ThemeStyles::none(),
+ }
+ }
+
+ /// A "basic" graphical theme that skips colors and unicode characters and
+ /// just does monochrome ascii art. If you want a completely non-graphical
+ /// rendering of your `Diagnostic`s, check out
+ /// [crate::NarratableReportHandler], or write your own
+ /// [crate::ReportHandler]!
+ pub fn none() -> Self {
+ Self {
+ characters: ThemeCharacters::ascii(),
+ styles: ThemeStyles::none(),
+ }
+ }
+}
+
+impl Default for GraphicalTheme {
+ fn default() -> Self {
+ match std::env::var("NO_COLOR") {
+ _ if !std::io::stdout().is_terminal() || !std::io::stderr().is_terminal() => {
+ Self::ascii()
+ }
+ Ok(string) if string != "0" => Self::unicode_nocolor(),
+ _ => Self::unicode(),
+ }
+ }
+}
+
+/**
+Styles for various parts of graphical rendering for the [crate::GraphicalReportHandler].
+*/
+#[derive(Debug, Clone)]
+pub struct ThemeStyles {
+ /// Style to apply to things highlighted as "error".
+ pub error: Style,
+ /// Style to apply to things highlighted as "warning".
+ pub warning: Style,
+ /// Style to apply to things highlighted as "advice".
+ pub advice: Style,
+ /// Style to apply to the help text.
+ pub help: Style,
+ /// Style to apply to filenames/links/URLs.
+ pub link: Style,
+ /// Style to apply to line numbers.
+ pub linum: Style,
+ /// Styles to cycle through (using `.iter().cycle()`), to render the lines
+ /// and text for diagnostic highlights.
+ pub highlights: Vec<Style>,
+}
+
+fn style() -> Style {
+ Style::new()
+}
+
+impl ThemeStyles {
+ /// Nice RGB colors.
+ /// [Credit](http://terminal.sexy/#FRUV0NDQFRUVrEFCkKlZ9L91ap-1qnWfdbWq0NDQUFBQrEFCkKlZ9L91ap-1qnWfdbWq9fX1).
+ pub fn rgb() -> Self {
+ Self {
+ error: style().fg_rgb::<255, 30, 30>(),
+ warning: style().fg_rgb::<244, 191, 117>(),
+ advice: style().fg_rgb::<106, 159, 181>(),
+ help: style().fg_rgb::<106, 159, 181>(),
+ link: style().fg_rgb::<92, 157, 255>().underline().bold(),
+ linum: style().dimmed(),
+ highlights: vec![
+ style().fg_rgb::<246, 87, 248>(),
+ style().fg_rgb::<30, 201, 212>(),
+ style().fg_rgb::<145, 246, 111>(),
+ ],
+ }
+ }
+
+ /// ANSI color-based styles.
+ pub fn ansi() -> Self {
+ Self {
+ error: style().red(),
+ warning: style().yellow(),
+ advice: style().cyan(),
+ help: style().cyan(),
+ link: style().cyan().underline().bold(),
+ linum: style().dimmed(),
+ highlights: vec![
+ style().magenta().bold(),
+ style().yellow().bold(),
+ style().green().bold(),
+ ],
+ }
+ }
+
+ /// No styling. Just regular ol' monochrome.
+ pub fn none() -> Self {
+ Self {
+ error: style(),
+ warning: style(),
+ advice: style(),
+ help: style(),
+ link: style(),
+ linum: style(),
+ highlights: vec![style()],
+ }
+ }
+}
+
+// ----------------------------------------
+// Most of these characters were taken from
+// https://github.com/zesterer/ariadne/blob/e3cb394cb56ecda116a0a1caecd385a49e7f6662/src/draw.rs
+
+/// Characters to be used when drawing when using
+/// [crate::GraphicalReportHandler].
+#[allow(missing_docs)]
+#[derive(Debug, Clone, Eq, PartialEq)]
+pub struct ThemeCharacters {
+ pub hbar: char,
+ pub vbar: char,
+ pub xbar: char,
+ pub vbar_break: char,
+
+ pub uarrow: char,
+ pub rarrow: char,
+
+ pub ltop: char,
+ pub mtop: char,
+ pub rtop: char,
+ pub lbot: char,
+ pub rbot: char,
+ pub mbot: char,
+
+ pub lbox: char,
+ pub rbox: char,
+
+ pub lcross: char,
+ pub rcross: char,
+
+ pub underbar: char,
+ pub underline: char,
+
+ pub error: String,
+ pub warning: String,
+ pub advice: String,
+}
+
+impl ThemeCharacters {
+ /// Fancy unicode-based graphical elements.
+ pub fn unicode() -> Self {
+ Self {
+ hbar: '─',
+ vbar: '│',
+ xbar: '┼',
+ vbar_break: '·',
+ uarrow: '▲',
+ rarrow: '▶',
+ ltop: '╭',
+ mtop: '┬',
+ rtop: '╮',
+ lbot: '╰',
+ mbot: '┴',
+ rbot: '╯',
+ lbox: '[',
+ rbox: ']',
+ lcross: '├',
+ rcross: '┤',
+ underbar: '┬',
+ underline: '─',
+ error: "×".into(),
+ warning: "⚠".into(),
+ advice: "☞".into(),
+ }
+ }
+
+ /// Emoji-heavy unicode characters.
+ pub fn emoji() -> Self {
+ Self {
+ hbar: '─',
+ vbar: '│',
+ xbar: '┼',
+ vbar_break: '·',
+ uarrow: '▲',
+ rarrow: '▶',
+ ltop: '╭',
+ mtop: '┬',
+ rtop: '╮',
+ lbot: '╰',
+ mbot: '┴',
+ rbot: '╯',
+ lbox: '[',
+ rbox: ']',
+ lcross: '├',
+ rcross: '┤',
+ underbar: '┬',
+ underline: '─',
+ error: "💥".into(),
+ warning: "⚠️".into(),
+ advice: "💡".into(),
+ }
+ }
+ /// ASCII-art-based graphical elements. Works well on older terminals.
+ pub fn ascii() -> Self {
+ Self {
+ hbar: '-',
+ vbar: '|',
+ xbar: '+',
+ vbar_break: ':',
+ uarrow: '^',
+ rarrow: '>',
+ ltop: ',',
+ mtop: 'v',
+ rtop: '.',
+ lbot: '`',
+ mbot: '^',
+ rbot: '\'',
+ lbox: '[',
+ rbox: ']',
+ lcross: '|',
+ rcross: '|',
+ underbar: '|',
+ underline: '^',
+ error: "x".into(),
+ warning: "!".into(),
+ advice: ">".into(),
+ }
+ }
+}
diff --git a/vendor/miette/src/lib.rs b/vendor/miette/src/lib.rs
new file mode 100644
index 0000000..20589ef
--- /dev/null
+++ b/vendor/miette/src/lib.rs
@@ -0,0 +1,682 @@
+#![deny(missing_docs, missing_debug_implementations, nonstandard_style)]
+#![warn(unreachable_pub, rust_2018_idioms)]
+//! You run miette? You run her code like the software? Oh. Oh! Error code for
+//! coder! Error code for One Thousand Lines!
+//!
+//! ## About
+//!
+//! `miette` is a diagnostic library for Rust. It includes a series of
+//! traits/protocols that allow you to hook into its error reporting facilities,
+//! and even write your own error reports! It lets you define error types that
+//! can print out like this (or in any format you like!):
+//!
+//! <img src="https://raw.githubusercontent.com/zkat/miette/main/images/serde_json.png" alt="Hi! miette also includes a screen-reader-oriented diagnostic printer that's enabled in various situations, such as when you use NO_COLOR or CLICOLOR settings, or on CI. This behavior is also fully configurable and customizable. For example, this is what this particular diagnostic will look like when the narrated printer is enabled:
+//! \
+//! Error: Received some bad JSON from the source. Unable to parse.
+//! Caused by: missing field `foo` at line 1 column 1700
+//! \
+//! Begin snippet for https://api.nuget.org/v3/registration5-gz-semver2/json.net/index.json starting
+//! at line 1, column 1659
+//! \
+//! snippet line 1: gs&quot;:[&quot;json&quot;],&quot;title&quot;:&quot;&quot;,&quot;version&quot;:&quot;1.0.0&quot;},&quot;packageContent&quot;:&quot;https://api.nuget.o
+//! highlight starting at line 1, column 1699: last parsing location
+//! \
+//! diagnostic help: This is a bug. It might be in ruget, or it might be in the
+//! source you're using, but it's definitely a bug and should be reported.
+//! diagnostic error code: ruget::api::bad_json
+//! " />
+//!
+//! > **NOTE: You must enable the `"fancy"` crate feature to get fancy report
+//! output like in the screenshots above.** You should only do this in your
+//! toplevel crate, as the fancy feature pulls in a number of dependencies that
+//! libraries and such might not want.
+//!
+//! ## Table of Contents <!-- omit in toc -->
+//!
+//! - [About](#about)
+//! - [Features](#features)
+//! - [Installing](#installing)
+//! - [Example](#example)
+//! - [Using](#using)
+//! - [... in libraries](#-in-libraries)
+//! - [... in application code](#-in-application-code)
+//! - [... in `main()`](#-in-main)
+//! - [... diagnostic code URLs](#-diagnostic-code-urls)
+//! - [... snippets](#-snippets)
+//! - [... multiple related errors](#-multiple-related-errors)
+//! - [... delayed source code](#-delayed-source-code)
+//! - [... handler options](#-handler-options)
+//! - [... dynamic diagnostics](#-dynamic-diagnostics)
+//! - [Acknowledgements](#acknowledgements)
+//! - [License](#license)
+//!
+//! ## Features
+//!
+//! - Generic [`Diagnostic`] protocol, compatible (and dependent on)
+//! [`std::error::Error`].
+//! - Unique error codes on every [`Diagnostic`].
+//! - Custom links to get more details on error codes.
+//! - Super handy derive macro for defining diagnostic metadata.
+//! - Replacements for [`anyhow`](https://docs.rs/anyhow)/[`eyre`](https://docs.rs/eyre)
+//! types [`Result`], [`Report`] and the [`miette!`] macro for the
+//! `anyhow!`/`eyre!` macros.
+//! - Generic support for arbitrary [`SourceCode`]s for snippet data, with
+//! default support for `String`s included.
+//!
+//! The `miette` crate also comes bundled with a default [`ReportHandler`] with
+//! the following features:
+//!
+//! - Fancy graphical [diagnostic output](#about), using ANSI/Unicode text
+//! - single- and multi-line highlighting support
+//! - Screen reader/braille support, gated on [`NO_COLOR`](http://no-color.org/),
+//! and other heuristics.
+//! - Fully customizable graphical theming (or overriding the printers
+//! entirely).
+//! - Cause chain printing
+//! - Turns diagnostic codes into links in [supported terminals](https://gist.github.com/egmontkob/eb114294efbcd5adb1944c9f3cb5feda).
+//!
+//! ## Installing
+//!
+//! ```sh
+//! $ cargo add miette
+//! ```
+//!
+//! If you want to use the fancy printer in all these screenshots:
+//!
+//! ```sh
+//! $ cargo add miette --features fancy
+//! ```
+//!
+//! ## Example
+//!
+//! ```rust
+//! /*
+//! You can derive a `Diagnostic` from any `std::error::Error` type.
+//!
+//! `thiserror` is a great way to define them, and plays nicely with `miette`!
+//! */
+//! use miette::{Diagnostic, SourceSpan};
+//! use thiserror::Error;
+//!
+//! #[derive(Error, Debug, Diagnostic)]
+//! #[error("oops!")]
+//! #[diagnostic(
+//! code(oops::my::bad),
+//! url(docsrs),
+//! help("try doing it better next time?")
+//! )]
+//! struct MyBad {
+//! // The Source that we're gonna be printing snippets out of.
+//! // This can be a String if you don't have or care about file names.
+//! #[source_code]
+//! src: NamedSource,
+//! // Snippets and highlights can be included in the diagnostic!
+//! #[label("This bit here")]
+//! bad_bit: SourceSpan,
+//! }
+//!
+//! /*
+//! Now let's define a function!
+//!
+//! Use this `Result` type (or its expanded version) as the return type
+//! throughout your app (but NOT your libraries! Those should always return
+//! concrete types!).
+//! */
+//! use miette::{NamedSource, Result};
+//! fn this_fails() -> Result<()> {
+//! // You can use plain strings as a `Source`, or anything that implements
+//! // the one-method `Source` trait.
+//! let src = "source\n text\n here".to_string();
+//! let len = src.len();
+//!
+//! Err(MyBad {
+//! src: NamedSource::new("bad_file.rs", src),
+//! bad_bit: (9, 4).into(),
+//! })?;
+//!
+//! Ok(())
+//! }
+//!
+//! /*
+//! Now to get everything printed nicely, just return a `Result<()>`
+//! and you're all set!
+//!
+//! Note: You can swap out the default reporter for a custom one using
+//! `miette::set_hook()`
+//! */
+//! fn pretend_this_is_main() -> Result<()> {
+//! // kaboom~
+//! this_fails()?;
+//!
+//! Ok(())
+//! }
+//! ```
+//!
+//! And this is the output you'll get if you run this program:
+//!
+//! <img src="https://raw.githubusercontent.com/zkat/miette/main/images/single-line-example.png" alt="
+//! Narratable printout:
+//! \
+//! Error: Types mismatched for operation.
+//! Diagnostic severity: error
+//! Begin snippet starting at line 1, column 1
+//! \
+//! snippet line 1: 3 + &quot;5&quot;
+//! label starting at line 1, column 1: int
+//! label starting at line 1, column 1: doesn't support these values.
+//! label starting at line 1, column 1: string
+//! diagnostic help: Change int or string to be the right types and try again.
+//! diagnostic code: nu::parser::unsupported_operation
+//! For more details, see https://docs.rs/nu-parser/0.1.0/nu-parser/enum.ParseError.html#variant.UnsupportedOperation">
+//!
+//! ## Using
+//!
+//! ### ... in libraries
+//!
+//! `miette` is _fully compatible_ with library usage. Consumers who don't know
+//! about, or don't want, `miette` features can safely use its error types as
+//! regular [`std::error::Error`].
+//!
+//! We highly recommend using something like [`thiserror`](https://docs.rs/thiserror)
+//! to define unique error types and error wrappers for your library.
+//!
+//! While `miette` integrates smoothly with `thiserror`, it is _not required_.
+//! If you don't want to use the [`Diagnostic`] derive macro, you can implement
+//! the trait directly, just like with `std::error::Error`.
+//!
+//! ```rust
+//! // lib/error.rs
+//! use miette::{Diagnostic, SourceSpan};
+//! use thiserror::Error;
+//!
+//! #[derive(Error, Diagnostic, Debug)]
+//! pub enum MyLibError {
+//! #[error(transparent)]
+//! #[diagnostic(code(my_lib::io_error))]
+//! IoError(#[from] std::io::Error),
+//!
+//! #[error("Oops it blew up")]
+//! #[diagnostic(code(my_lib::bad_code))]
+//! BadThingHappened,
+//!
+//! #[error(transparent)]
+//! // Use `#[diagnostic(transparent)]` to wrap another [`Diagnostic`]. You won't see labels otherwise
+//! #[diagnostic(transparent)]
+//! AnotherError(#[from] AnotherError),
+//! }
+//!
+//! #[derive(Error, Diagnostic, Debug)]
+//! #[error("another error")]
+//! pub struct AnotherError {
+//! #[label("here")]
+//! pub at: SourceSpan
+//! }
+//! ```
+//!
+//! Then, return this error type from all your fallible public APIs. It's a best
+//! practice to wrap any "external" error types in your error `enum` instead of
+//! using something like [`Report`] in a library.
+//!
+//! ### ... in application code
+//!
+//! Application code tends to work a little differently than libraries. You
+//! don't always need or care to define dedicated error wrappers for errors
+//! coming from external libraries and tools.
+//!
+//! For this situation, `miette` includes two tools: [`Report`] and
+//! [`IntoDiagnostic`]. They work in tandem to make it easy to convert regular
+//! `std::error::Error`s into [`Diagnostic`]s. Additionally, there's a
+//! [`Result`] type alias that you can use to be more terse.
+//!
+//! When dealing with non-`Diagnostic` types, you'll want to
+//! `.into_diagnostic()` them:
+//!
+//! ```rust
+//! // my_app/lib/my_internal_file.rs
+//! use miette::{IntoDiagnostic, Result};
+//! use semver::Version;
+//!
+//! pub fn some_tool() -> Result<Version> {
+//! Ok("1.2.x".parse().into_diagnostic()?)
+//! }
+//! ```
+//!
+//! `miette` also includes an `anyhow`/`eyre`-style `Context`/`WrapErr` traits
+//! that you can import to add ad-hoc context messages to your `Diagnostic`s, as
+//! well, though you'll still need to use `.into_diagnostic()` to make use of
+//! it:
+//!
+//! ```rust
+//! // my_app/lib/my_internal_file.rs
+//! use miette::{IntoDiagnostic, Result, WrapErr};
+//! use semver::Version;
+//!
+//! pub fn some_tool() -> Result<Version> {
+//! Ok("1.2.x"
+//! .parse()
+//! .into_diagnostic()
+//! .wrap_err("Parsing this tool's semver version failed.")?)
+//! }
+//! ```
+//!
+//! To construct your own simple adhoc error use the [miette!] macro:
+//! ```rust
+//! // my_app/lib/my_internal_file.rs
+//! use miette::{miette, IntoDiagnostic, Result, WrapErr};
+//! use semver::Version;
+//!
+//! pub fn some_tool() -> Result<Version> {
+//! let version = "1.2.x";
+//! Ok(version
+//! .parse()
+//! .map_err(|_| miette!("Invalid version {}", version))?)
+//! }
+//! ```
+//! There are also similar [bail!] and [ensure!] macros.
+//!
+//! ### ... in `main()`
+//!
+//! `main()` is just like any other part of your application-internal code. Use
+//! `Result` as your return value, and it will pretty-print your diagnostics
+//! automatically.
+//!
+//! > **NOTE:** You must enable the `"fancy"` crate feature to get fancy report
+//! output like in the screenshots here.** You should only do this in your
+//! toplevel crate, as the fancy feature pulls in a number of dependencies that
+//! libraries and such might not want.
+//!
+//! ```rust
+//! use miette::{IntoDiagnostic, Result};
+//! use semver::Version;
+//!
+//! fn pretend_this_is_main() -> Result<()> {
+//! let version: Version = "1.2.x".parse().into_diagnostic()?;
+//! println!("{}", version);
+//! Ok(())
+//! }
+//! ```
+//!
+//! Please note: in order to get fancy diagnostic rendering with all the pretty
+//! colors and arrows, you should install `miette` with the `fancy` feature
+//! enabled:
+//!
+//! ```toml
+//! miette = { version = "X.Y.Z", features = ["fancy"] }
+//! ```
+//!
+//! ### ... diagnostic code URLs
+//!
+//! `miette` supports providing a URL for individual diagnostics. This URL will
+//! be displayed as an actual link in supported terminals, like so:
+//!
+//! <img
+//! src="https://raw.githubusercontent.com/zkat/miette/main/images/code_linking.png"
+//! alt=" Example showing the graphical report printer for miette
+//! pretty-printing an error code. The code is underlined and followed by text
+//! saying to 'click here'. A hover tooltip shows a full-fledged URL that can be
+//! Ctrl+Clicked to open in a browser.
+//! \
+//! This feature is also available in the narratable printer. It will add a line
+//! after printing the error code showing a plain URL that you can visit.
+//! ">
+//!
+//! To use this, you can add a `url()` sub-param to your `#[diagnostic]`
+//! attribute:
+//!
+//! ```rust
+//! use miette::Diagnostic;
+//! use thiserror::Error;
+//!
+//! #[derive(Error, Diagnostic, Debug)]
+//! #[error("kaboom")]
+//! #[diagnostic(
+//! code(my_app::my_error),
+//! // You can do formatting!
+//! url("https://my_website.com/error_codes#{}", self.code().unwrap())
+//! )]
+//! struct MyErr;
+//! ```
+//!
+//! Additionally, if you're developing a library and your error type is exported
+//! from your crate's top level, you can use a special `url(docsrs)` option
+//! instead of manually constructing the URL. This will automatically create a
+//! link to this diagnostic on `docs.rs`, so folks can just go straight to your
+//! (very high quality and detailed!) documentation on this diagnostic:
+//!
+//! ```rust
+//! use miette::Diagnostic;
+//! use thiserror::Error;
+//!
+//! #[derive(Error, Diagnostic, Debug)]
+//! #[diagnostic(
+//! code(my_app::my_error),
+//! // Will link users to https://docs.rs/my_crate/0.0.0/my_crate/struct.MyErr.html
+//! url(docsrs)
+//! )]
+//! #[error("kaboom")]
+//! struct MyErr;
+//! ```
+//!
+//! ### ... snippets
+//!
+//! Along with its general error handling and reporting features, `miette` also
+//! includes facilities for adding error spans/annotations/labels to your
+//! output. This can be very useful when an error is syntax-related, but you can
+//! even use it to print out sections of your own source code!
+//!
+//! To achieve this, `miette` defines its own lightweight [`SourceSpan`] type.
+//! This is a basic byte-offset and length into an associated [`SourceCode`]
+//! and, along with the latter, gives `miette` all the information it needs to
+//! pretty-print some snippets! You can also use your own `Into<SourceSpan>`
+//! types as label spans.
+//!
+//! The easiest way to define errors like this is to use the
+//! `derive(Diagnostic)` macro:
+//!
+//! ```rust
+//! use miette::{Diagnostic, SourceSpan};
+//! use thiserror::Error;
+//!
+//! #[derive(Diagnostic, Debug, Error)]
+//! #[error("oops")]
+//! #[diagnostic(code(my_lib::random_error))]
+//! pub struct MyErrorType {
+//! // The `Source` that miette will use.
+//! #[source_code]
+//! src: String,
+//!
+//! // This will underline/mark the specific code inside the larger
+//! // snippet context.
+//! #[label = "This is the highlight"]
+//! err_span: SourceSpan,
+//!
+//! // You can add as many labels as you want.
+//! // They'll be rendered sequentially.
+//! #[label("This is bad")]
+//! snip2: (usize, usize), // `(usize, usize)` is `Into<SourceSpan>`!
+//!
+//! // Snippets can be optional, by using Option:
+//! #[label("some text")]
+//! snip3: Option<SourceSpan>,
+//!
+//! // with or without label text
+//! #[label]
+//! snip4: Option<SourceSpan>,
+//! }
+//! ```
+//!
+//! #### ... help text
+//! `miette` provides two facilities for supplying help text for your errors:
+//!
+//! The first is the `#[help()]` format attribute that applies to structs or
+//! enum variants:
+//!
+//! ```rust
+//! use miette::Diagnostic;
+//! use thiserror::Error;
+//!
+//! #[derive(Debug, Diagnostic, Error)]
+//! #[error("welp")]
+//! #[diagnostic(help("try doing this instead"))]
+//! struct Foo;
+//! ```
+//!
+//! The other is by programmatically supplying the help text as a field to
+//! your diagnostic:
+//!
+//! ```rust
+//! use miette::Diagnostic;
+//! use thiserror::Error;
+//!
+//! #[derive(Debug, Diagnostic, Error)]
+//! #[error("welp")]
+//! #[diagnostic()]
+//! struct Foo {
+//! #[help]
+//! advice: Option<String>, // Can also just be `String`
+//! }
+//!
+//! let err = Foo {
+//! advice: Some("try doing this instead".to_string()),
+//! };
+//! ```
+//!
+//! ### ... multiple related errors
+//!
+//! `miette` supports collecting multiple errors into a single diagnostic, and
+//! printing them all together nicely.
+//!
+//! To do so, use the `#[related]` tag on any `IntoIter` field in your
+//! `Diagnostic` type:
+//!
+//! ```rust
+//! use miette::Diagnostic;
+//! use thiserror::Error;
+//!
+//! #[derive(Debug, Error, Diagnostic)]
+//! #[error("oops")]
+//! struct MyError {
+//! #[related]
+//! others: Vec<MyError>,
+//! }
+//! ```
+//!
+//! ### ... delayed source code
+//!
+//! Sometimes it makes sense to add source code to the error message later.
+//! One option is to use [`with_source_code()`](Report::with_source_code)
+//! method for that:
+//!
+//! ```rust,no_run
+//! use miette::{Diagnostic, SourceSpan};
+//! use thiserror::Error;
+//!
+//! #[derive(Diagnostic, Debug, Error)]
+//! #[error("oops")]
+//! #[diagnostic()]
+//! pub struct MyErrorType {
+//! // Note: label but no source code
+//! #[label]
+//! err_span: SourceSpan,
+//! }
+//!
+//! fn do_something() -> miette::Result<()> {
+//! // This function emits actual error with label
+//! return Err(MyErrorType {
+//! err_span: (7..11).into(),
+//! })?;
+//! }
+//!
+//! fn main() -> miette::Result<()> {
+//! do_something().map_err(|error| {
+//! // And this code provides the source code for inner error
+//! error.with_source_code(String::from("source code"))
+//! })
+//! }
+//! ```
+//!
+//! Also source code can be provided by a wrapper type. This is especially
+//! useful in combination with `related`, when multiple errors should be
+//! emitted at the same time:
+//!
+//! ```rust,no_run
+//! use miette::{Diagnostic, Report, SourceSpan};
+//! use thiserror::Error;
+//!
+//! #[derive(Diagnostic, Debug, Error)]
+//! #[error("oops")]
+//! #[diagnostic()]
+//! pub struct InnerError {
+//! // Note: label but no source code
+//! #[label]
+//! err_span: SourceSpan,
+//! }
+//!
+//! #[derive(Diagnostic, Debug, Error)]
+//! #[error("oops: multiple errors")]
+//! #[diagnostic()]
+//! pub struct MultiError {
+//! // Note source code by no labels
+//! #[source_code]
+//! source_code: String,
+//! // The source code above is used for these errors
+//! #[related]
+//! related: Vec<InnerError>,
+//! }
+//!
+//! fn do_something() -> Result<(), Vec<InnerError>> {
+//! Err(vec![
+//! InnerError {
+//! err_span: (0..6).into(),
+//! },
+//! InnerError {
+//! err_span: (7..11).into(),
+//! },
+//! ])
+//! }
+//!
+//! fn main() -> miette::Result<()> {
+//! do_something().map_err(|err_list| MultiError {
+//! source_code: "source code".into(),
+//! related: err_list,
+//! })?;
+//! Ok(())
+//! }
+//! ```
+//!
+//! ### ... Diagnostic-based error sources.
+//!
+//! When one uses the `#[source]` attribute on a field, that usually comes
+//! from `thiserror`, and implements a method for
+//! [`std::error::Error::source`]. This works in many cases, but it's lossy:
+//! if the source of the diagnostic is a diagnostic itself, the source will
+//! simply be treated as an `std::error::Error`.
+//!
+//! While this has no effect on the existing _reporters_, since they don't use
+//! that information right now, APIs who might want this information will have
+//! no access to it.
+//!
+//! If it's important for you for this information to be available to users,
+//! you can use `#[diagnostic_source]` alongside `#[source]`. Not that you
+//! will likely want to use _both_:
+//!
+//! ```rust
+//! use miette::Diagnostic;
+//! use thiserror::Error;
+//!
+//! #[derive(Debug, Diagnostic, Error)]
+//! #[error("MyError")]
+//! struct MyError {
+//! #[source]
+//! #[diagnostic_source]
+//! the_cause: OtherError,
+//! }
+//!
+//! #[derive(Debug, Diagnostic, Error)]
+//! #[error("OtherError")]
+//! struct OtherError;
+//! ```
+//!
+//! ### ... handler options
+//!
+//! [`MietteHandler`] is the default handler, and is very customizable. In
+//! most cases, you can simply use [`MietteHandlerOpts`] to tweak its behavior
+//! instead of falling back to your own custom handler.
+//!
+//! Usage is like so:
+//!
+//! ```rust,ignore
+//! miette::set_hook(Box::new(|_| {
+//! Box::new(
+//! miette::MietteHandlerOpts::new()
+//! .terminal_links(true)
+//! .unicode(false)
+//! .context_lines(3)
+//! .tab_width(4)
+//! .build(),
+//! )
+//! }))
+//!
+//! # .unwrap()
+//! ```
+//!
+//! See the docs for [`MietteHandlerOpts`] for more details on what you can
+//! customize!
+//!
+//! ### ... dynamic diagnostics
+//!
+//! If you...
+//! - ...don't know all the possible errors upfront
+//! - ...need to serialize/deserialize errors
+//! then you may want to use [`miette!`], [`diagnostic!`] macros or
+//! [`MietteDiagnostic`] directly to create diagnostic on the fly.
+//!
+//! ```rust,ignore
+//! # use miette::{miette, LabeledSpan, Report};
+//!
+//! let source = "2 + 2 * 2 = 8".to_string();
+//! let report = miette!(
+//! labels = vec[
+//! LabeledSpan::at(12..13, "this should be 6"),
+//! ],
+//! help = "'*' has greater precedence than '+'",
+//! "Wrong answer"
+//! ).with_source_code(source);
+//! println!("{:?}", report)
+//! ```
+//!
+//! ## Acknowledgements
+//!
+//! `miette` was not developed in a void. It owes enormous credit to various
+//! other projects and their authors:
+//!
+//! - [`anyhow`](http://crates.io/crates/anyhow) and [`color-eyre`](https://crates.io/crates/color-eyre):
+//! these two enormously influential error handling libraries have pushed
+//! forward the experience of application-level error handling and error
+//! reporting. `miette`'s `Report` type is an attempt at a very very rough
+//! version of their `Report` types.
+//! - [`thiserror`](https://crates.io/crates/thiserror) for setting the standard
+//! for library-level error definitions, and for being the inspiration behind
+//! `miette`'s derive macro.
+//! - `rustc` and [@estebank](https://github.com/estebank) for their
+//! state-of-the-art work in compiler diagnostics.
+//! - [`ariadne`](https://crates.io/crates/ariadne) for pushing forward how
+//! _pretty_ these diagnostics can really look!
+//!
+//! ## License
+//!
+//! `miette` is released to the Rust community under the [Apache license
+//! 2.0](./LICENSE).
+//!
+//! It also includes code taken from [`eyre`](https://github.com/yaahc/eyre),
+//! and some from [`thiserror`](https://github.com/dtolnay/thiserror), also
+//! under the Apache License. Some code is taken from
+//! [`ariadne`](https://github.com/zesterer/ariadne), which is MIT licensed.
+pub use miette_derive::*;
+
+pub use error::*;
+pub use eyreish::*;
+#[cfg(feature = "fancy-no-backtrace")]
+pub use handler::*;
+pub use handlers::*;
+pub use miette_diagnostic::*;
+pub use named_source::*;
+#[cfg(feature = "fancy")]
+pub use panic::*;
+pub use protocol::*;
+
+mod chain;
+mod diagnostic_chain;
+mod error;
+mod eyreish;
+#[cfg(feature = "fancy-no-backtrace")]
+mod handler;
+mod handlers;
+#[doc(hidden)]
+pub mod macro_helpers;
+mod miette_diagnostic;
+mod named_source;
+#[cfg(feature = "fancy")]
+mod panic;
+mod protocol;
+mod source_impls;
diff --git a/vendor/miette/src/macro_helpers.rs b/vendor/miette/src/macro_helpers.rs
new file mode 100644
index 0000000..5520899
--- /dev/null
+++ b/vendor/miette/src/macro_helpers.rs
@@ -0,0 +1,38 @@
+// Huge thanks to @jam1gamer for this hack:
+// https://twitter.com/jam1garner/status/1515887996444323840
+
+#[doc(hidden)]
+pub trait IsOption {}
+impl<T> IsOption for Option<T> {}
+
+#[doc(hidden)]
+#[derive(Debug, Default)]
+pub struct OptionalWrapper<T>(pub core::marker::PhantomData<T>);
+
+impl<T> OptionalWrapper<T> {
+ pub fn new() -> Self {
+ Self(core::marker::PhantomData)
+ }
+}
+
+#[doc(hidden)]
+pub trait ToOption {
+ #[doc(hidden)]
+ fn to_option<T>(self, value: T) -> Option<T>;
+}
+
+impl<T> OptionalWrapper<T>
+where
+ T: IsOption,
+{
+ #[doc(hidden)]
+ pub fn to_option(self, value: &T) -> &T {
+ value
+ }
+}
+
+impl<T> ToOption for &OptionalWrapper<T> {
+ fn to_option<U>(self, value: U) -> Option<U> {
+ Some(value)
+ }
+}
diff --git a/vendor/miette/src/miette_diagnostic.rs b/vendor/miette/src/miette_diagnostic.rs
new file mode 100644
index 0000000..67b75d0
--- /dev/null
+++ b/vendor/miette/src/miette_diagnostic.rs
@@ -0,0 +1,365 @@
+use std::{
+ error::Error,
+ fmt::{Debug, Display},
+};
+
+#[cfg(feature = "serde")]
+use serde::{Deserialize, Serialize};
+
+use crate::{Diagnostic, LabeledSpan, Severity};
+
+/// Diagnostic that can be created at runtime.
+#[derive(Debug, Clone, PartialEq, Eq)]
+#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
+pub struct MietteDiagnostic {
+ /// Displayed diagnostic message
+ pub message: String,
+ /// Unique diagnostic code to look up more information
+ /// about this Diagnostic. Ideally also globally unique, and documented
+ /// in the toplevel crate's documentation for easy searching.
+ /// Rust path format (`foo::bar::baz`) is recommended, but more classic
+ /// codes like `E0123` will work just fine
+ #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
+ pub code: Option<String>,
+ /// [`Diagnostic`] severity. Intended to be used by
+ /// [`ReportHandler`](crate::ReportHandler)s to change the way different
+ /// [`Diagnostic`]s are displayed. Defaults to [`Severity::Error`]
+ #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
+ pub severity: Option<Severity>,
+ /// Additional help text related to this Diagnostic
+ #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
+ pub help: Option<String>,
+ /// URL to visit for a more detailed explanation/help about this
+ /// [`Diagnostic`].
+ #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
+ pub url: Option<String>,
+ /// Labels to apply to this `Diagnostic`'s [`Diagnostic::source_code`]
+ #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
+ pub labels: Option<Vec<LabeledSpan>>,
+}
+
+impl Display for MietteDiagnostic {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ write!(f, "{}", &self.message)
+ }
+}
+
+impl Error for MietteDiagnostic {}
+
+impl Diagnostic for MietteDiagnostic {
+ fn code<'a>(&'a self) -> Option<Box<dyn Display + 'a>> {
+ self.code
+ .as_ref()
+ .map(Box::new)
+ .map(|c| c as Box<dyn Display>)
+ }
+
+ fn severity(&self) -> Option<Severity> {
+ self.severity
+ }
+
+ fn help<'a>(&'a self) -> Option<Box<dyn Display + 'a>> {
+ self.help
+ .as_ref()
+ .map(Box::new)
+ .map(|c| c as Box<dyn Display>)
+ }
+
+ fn url<'a>(&'a self) -> Option<Box<dyn Display + 'a>> {
+ self.url
+ .as_ref()
+ .map(Box::new)
+ .map(|c| c as Box<dyn Display>)
+ }
+
+ fn labels(&self) -> Option<Box<dyn Iterator<Item = LabeledSpan> + '_>> {
+ self.labels
+ .as_ref()
+ .map(|ls| ls.iter().cloned())
+ .map(Box::new)
+ .map(|b| b as Box<dyn Iterator<Item = LabeledSpan>>)
+ }
+}
+
+impl MietteDiagnostic {
+ /// Create a new dynamic diagnostic with the given message.
+ ///
+ /// # Examples
+ /// ```
+ /// use miette::{Diagnostic, MietteDiagnostic, Severity};
+ ///
+ /// let diag = MietteDiagnostic::new("Oops, something went wrong!");
+ /// assert_eq!(diag.to_string(), "Oops, something went wrong!");
+ /// assert_eq!(diag.message, "Oops, something went wrong!");
+ /// ```
+ pub fn new(message: impl Into<String>) -> Self {
+ Self {
+ message: message.into(),
+ labels: None,
+ severity: None,
+ code: None,
+ help: None,
+ url: None,
+ }
+ }
+
+ /// Return new diagnostic with the given code.
+ ///
+ /// # Examples
+ /// ```
+ /// use miette::{Diagnostic, MietteDiagnostic};
+ ///
+ /// let diag = MietteDiagnostic::new("Oops, something went wrong!").with_code("foo::bar::baz");
+ /// assert_eq!(diag.message, "Oops, something went wrong!");
+ /// assert_eq!(diag.code, Some("foo::bar::baz".to_string()));
+ /// ```
+ pub fn with_code(mut self, code: impl Into<String>) -> Self {
+ self.code = Some(code.into());
+ self
+ }
+
+ /// Return new diagnostic with the given severity.
+ ///
+ /// # Examples
+ /// ```
+ /// use miette::{Diagnostic, MietteDiagnostic, Severity};
+ ///
+ /// let diag = MietteDiagnostic::new("I warn you to stop!").with_severity(Severity::Warning);
+ /// assert_eq!(diag.message, "I warn you to stop!");
+ /// assert_eq!(diag.severity, Some(Severity::Warning));
+ /// ```
+ pub fn with_severity(mut self, severity: Severity) -> Self {
+ self.severity = Some(severity);
+ self
+ }
+
+ /// Return new diagnostic with the given help message.
+ ///
+ /// # Examples
+ /// ```
+ /// use miette::{Diagnostic, MietteDiagnostic};
+ ///
+ /// let diag = MietteDiagnostic::new("PC is not working").with_help("Try to reboot it again");
+ /// assert_eq!(diag.message, "PC is not working");
+ /// assert_eq!(diag.help, Some("Try to reboot it again".to_string()));
+ /// ```
+ pub fn with_help(mut self, help: impl Into<String>) -> Self {
+ self.help = Some(help.into());
+ self
+ }
+
+ /// Return new diagnostic with the given URL.
+ ///
+ /// # Examples
+ /// ```
+ /// use miette::{Diagnostic, MietteDiagnostic};
+ ///
+ /// let diag = MietteDiagnostic::new("PC is not working")
+ /// .with_url("https://letmegooglethat.com/?q=Why+my+pc+doesn%27t+work");
+ /// assert_eq!(diag.message, "PC is not working");
+ /// assert_eq!(
+ /// diag.url,
+ /// Some("https://letmegooglethat.com/?q=Why+my+pc+doesn%27t+work".to_string())
+ /// );
+ /// ```
+ pub fn with_url(mut self, url: impl Into<String>) -> Self {
+ self.url = Some(url.into());
+ self
+ }
+
+ /// Return new diagnostic with the given label.
+ ///
+ /// Discards previous labels
+ ///
+ /// # Examples
+ /// ```
+ /// use miette::{Diagnostic, LabeledSpan, MietteDiagnostic};
+ ///
+ /// let source = "cpp is the best language";
+ ///
+ /// let label = LabeledSpan::at(0..3, "This should be Rust");
+ /// let diag = MietteDiagnostic::new("Wrong best language").with_label(label.clone());
+ /// assert_eq!(diag.message, "Wrong best language");
+ /// assert_eq!(diag.labels, Some(vec![label]));
+ /// ```
+ pub fn with_label(mut self, label: impl Into<LabeledSpan>) -> Self {
+ self.labels = Some(vec![label.into()]);
+ self
+ }
+
+ /// Return new diagnostic with the given labels.
+ ///
+ /// Discards previous labels
+ ///
+ /// # Examples
+ /// ```
+ /// use miette::{Diagnostic, LabeledSpan, MietteDiagnostic};
+ ///
+ /// let source = "helo wrld";
+ ///
+ /// let labels = vec![
+ /// LabeledSpan::at_offset(3, "add 'l'"),
+ /// LabeledSpan::at_offset(6, "add 'r'"),
+ /// ];
+ /// let diag = MietteDiagnostic::new("Typos in 'hello world'").with_labels(labels.clone());
+ /// assert_eq!(diag.message, "Typos in 'hello world'");
+ /// assert_eq!(diag.labels, Some(labels));
+ /// ```
+ pub fn with_labels(mut self, labels: impl IntoIterator<Item = LabeledSpan>) -> Self {
+ self.labels = Some(labels.into_iter().collect());
+ self
+ }
+
+ /// Return new diagnostic with new label added to the existing ones.
+ ///
+ /// # Examples
+ /// ```
+ /// use miette::{Diagnostic, LabeledSpan, MietteDiagnostic};
+ ///
+ /// let source = "helo wrld";
+ ///
+ /// let label1 = LabeledSpan::at_offset(3, "add 'l'");
+ /// let label2 = LabeledSpan::at_offset(6, "add 'r'");
+ /// let diag = MietteDiagnostic::new("Typos in 'hello world'")
+ /// .and_label(label1.clone())
+ /// .and_label(label2.clone());
+ /// assert_eq!(diag.message, "Typos in 'hello world'");
+ /// assert_eq!(diag.labels, Some(vec![label1, label2]));
+ /// ```
+ pub fn and_label(mut self, label: impl Into<LabeledSpan>) -> Self {
+ let mut labels = self.labels.unwrap_or_default();
+ labels.push(label.into());
+ self.labels = Some(labels);
+ self
+ }
+
+ /// Return new diagnostic with new labels added to the existing ones.
+ ///
+ /// # Examples
+ /// ```
+ /// use miette::{Diagnostic, LabeledSpan, MietteDiagnostic};
+ ///
+ /// let source = "helo wrld";
+ ///
+ /// let label1 = LabeledSpan::at_offset(3, "add 'l'");
+ /// let label2 = LabeledSpan::at_offset(6, "add 'r'");
+ /// let label3 = LabeledSpan::at_offset(9, "add '!'");
+ /// let diag = MietteDiagnostic::new("Typos in 'hello world!'")
+ /// .and_label(label1.clone())
+ /// .and_labels([label2.clone(), label3.clone()]);
+ /// assert_eq!(diag.message, "Typos in 'hello world!'");
+ /// assert_eq!(diag.labels, Some(vec![label1, label2, label3]));
+ /// ```
+ pub fn and_labels(mut self, labels: impl IntoIterator<Item = LabeledSpan>) -> Self {
+ let mut all_labels = self.labels.unwrap_or_default();
+ all_labels.extend(labels.into_iter());
+ self.labels = Some(all_labels);
+ self
+ }
+}
+
+#[cfg(feature = "serde")]
+#[test]
+fn test_serialize_miette_diagnostic() {
+ use serde_json::json;
+
+ use crate::diagnostic;
+
+ let diag = diagnostic!("message");
+ let json = json!({ "message": "message" });
+ assert_eq!(json!(diag), json);
+
+ let diag = diagnostic!(
+ code = "code",
+ help = "help",
+ url = "url",
+ labels = [
+ LabeledSpan::at_offset(0, "label1"),
+ LabeledSpan::at(1..3, "label2")
+ ],
+ severity = Severity::Warning,
+ "message"
+ );
+ let json = json!({
+ "message": "message",
+ "code": "code",
+ "help": "help",
+ "url": "url",
+ "severity": "Warning",
+ "labels": [
+ {
+ "span": {
+ "offset": 0,
+ "length": 0
+ },
+ "label": "label1"
+ },
+ {
+ "span": {
+ "offset": 1,
+ "length": 2
+ },
+ "label": "label2"
+ }
+ ]
+ });
+ assert_eq!(json!(diag), json);
+}
+
+#[cfg(feature = "serde")]
+#[test]
+fn test_deserialize_miette_diagnostic() {
+ use serde_json::json;
+
+ use crate::diagnostic;
+
+ let json = json!({ "message": "message" });
+ let diag = diagnostic!("message");
+ assert_eq!(diag, serde_json::from_value(json).unwrap());
+
+ let json = json!({
+ "message": "message",
+ "help": null,
+ "code": null,
+ "severity": null,
+ "url": null,
+ "labels": null
+ });
+ assert_eq!(diag, serde_json::from_value(json).unwrap());
+
+ let diag = diagnostic!(
+ code = "code",
+ help = "help",
+ url = "url",
+ labels = [
+ LabeledSpan::at_offset(0, "label1"),
+ LabeledSpan::at(1..3, "label2")
+ ],
+ severity = Severity::Warning,
+ "message"
+ );
+ let json = json!({
+ "message": "message",
+ "code": "code",
+ "help": "help",
+ "url": "url",
+ "severity": "Warning",
+ "labels": [
+ {
+ "span": {
+ "offset": 0,
+ "length": 0
+ },
+ "label": "label1"
+ },
+ {
+ "span": {
+ "offset": 1,
+ "length": 2
+ },
+ "label": "label2"
+ }
+ ]
+ });
+ assert_eq!(diag, serde_json::from_value(json).unwrap());
+}
diff --git a/vendor/miette/src/named_source.rs b/vendor/miette/src/named_source.rs
new file mode 100644
index 0000000..31ad1d1
--- /dev/null
+++ b/vendor/miette/src/named_source.rs
@@ -0,0 +1,61 @@
+use crate::{MietteError, MietteSpanContents, SourceCode, SpanContents};
+
+/// Utility struct for when you have a regular [`SourceCode`] type that doesn't
+/// implement `name`. For example [`String`]. Or if you want to override the
+/// `name` returned by the `SourceCode`.
+pub struct NamedSource {
+ source: Box<dyn SourceCode + 'static>,
+ name: String,
+}
+
+impl std::fmt::Debug for NamedSource {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ f.debug_struct("NamedSource")
+ .field("name", &self.name)
+ .field("source", &"<redacted>");
+ Ok(())
+ }
+}
+
+impl NamedSource {
+ /// Create a new `NamedSource` using a regular [`SourceCode`] and giving
+ /// its returned [`SpanContents`] a name.
+ pub fn new(name: impl AsRef<str>, source: impl SourceCode + Send + Sync + 'static) -> Self {
+ Self {
+ source: Box::new(source),
+ name: name.as_ref().to_string(),
+ }
+ }
+
+ /// Gets the name of this `NamedSource`.
+ pub fn name(&self) -> &str {
+ &self.name
+ }
+
+ /// Returns a reference the inner [`SourceCode`] type for this
+ /// `NamedSource`.
+ pub fn inner(&self) -> &(dyn SourceCode + 'static) {
+ &*self.source
+ }
+}
+
+impl SourceCode for NamedSource {
+ fn read_span<'a>(
+ &'a self,
+ span: &crate::SourceSpan,
+ context_lines_before: usize,
+ context_lines_after: usize,
+ ) -> Result<Box<dyn SpanContents<'a> + 'a>, MietteError> {
+ let contents = self
+ .inner()
+ .read_span(span, context_lines_before, context_lines_after)?;
+ Ok(Box::new(MietteSpanContents::new_named(
+ self.name.clone(),
+ contents.data(),
+ *contents.span(),
+ contents.line(),
+ contents.column(),
+ contents.line_count(),
+ )))
+ }
+}
diff --git a/vendor/miette/src/panic.rs b/vendor/miette/src/panic.rs
new file mode 100644
index 0000000..ad98cac
--- /dev/null
+++ b/vendor/miette/src/panic.rs
@@ -0,0 +1,86 @@
+use backtrace::Backtrace;
+use thiserror::Error;
+
+use crate::{self as miette, Context, Diagnostic, Result};
+
+/// Tells miette to render panics using its rendering engine.
+pub fn set_panic_hook() {
+ std::panic::set_hook(Box::new(move |info| {
+ let mut message = "Something went wrong".to_string();
+ let payload = info.payload();
+ if let Some(msg) = payload.downcast_ref::<&str>() {
+ message = msg.to_string();
+ }
+ if let Some(msg) = payload.downcast_ref::<String>() {
+ message = msg.clone();
+ }
+ let mut report: Result<()> = Err(Panic(message).into());
+ if let Some(loc) = info.location() {
+ report = report
+ .with_context(|| format!("at {}:{}:{}", loc.file(), loc.line(), loc.column()));
+ }
+ if let Err(err) = report.with_context(|| "Main thread panicked.".to_string()) {
+ eprintln!("Error: {:?}", err);
+ }
+ }));
+}
+
+#[derive(Debug, Error, Diagnostic)]
+#[error("{0}{}", Panic::backtrace())]
+#[diagnostic(help("set the `RUST_BACKTRACE=1` environment variable to display a backtrace."))]
+struct Panic(String);
+
+impl Panic {
+ fn backtrace() -> String {
+ use std::fmt::Write;
+ if let Ok(var) = std::env::var("RUST_BACKTRACE") {
+ if !var.is_empty() && var != "0" {
+ const HEX_WIDTH: usize = std::mem::size_of::<usize>() + 2;
+ // Padding for next lines after frame's address
+ const NEXT_SYMBOL_PADDING: usize = HEX_WIDTH + 6;
+ let mut backtrace = String::new();
+ let trace = Backtrace::new();
+ let frames = backtrace_ext::short_frames_strict(&trace).enumerate();
+ for (idx, (frame, sub_frames)) in frames {
+ let ip = frame.ip();
+ let _ = write!(backtrace, "\n{:4}: {:2$?}", idx, ip, HEX_WIDTH);
+
+ let symbols = frame.symbols();
+ if symbols.is_empty() {
+ let _ = write!(backtrace, " - <unresolved>");
+ continue;
+ }
+
+ for (idx, symbol) in symbols[sub_frames].iter().enumerate() {
+ // Print symbols from this address,
+ // if there are several addresses
+ // we need to put it on next line
+ if idx != 0 {
+ let _ = write!(backtrace, "\n{:1$}", "", NEXT_SYMBOL_PADDING);
+ }
+
+ if let Some(name) = symbol.name() {
+ let _ = write!(backtrace, " - {}", name);
+ } else {
+ let _ = write!(backtrace, " - <unknown>");
+ }
+
+ // See if there is debug information with file name and line
+ if let (Some(file), Some(line)) = (symbol.filename(), symbol.lineno()) {
+ let _ = write!(
+ backtrace,
+ "\n{:3$}at {}:{}",
+ "",
+ file.display(),
+ line,
+ NEXT_SYMBOL_PADDING
+ );
+ }
+ }
+ }
+ return backtrace;
+ }
+ }
+ "".into()
+ }
+}
diff --git a/vendor/miette/src/protocol.rs b/vendor/miette/src/protocol.rs
new file mode 100644
index 0000000..f516984
--- /dev/null
+++ b/vendor/miette/src/protocol.rs
@@ -0,0 +1,697 @@
+/*!
+This module defines the core of the miette protocol: a series of types and
+traits that you can implement to get access to miette's (and related library's)
+full reporting and such features.
+*/
+use std::{
+ fmt::{self, Display},
+ fs,
+ panic::Location,
+};
+
+#[cfg(feature = "serde")]
+use serde::{Deserialize, Serialize};
+
+use crate::MietteError;
+
+/// Adds rich metadata to your Error that can be used by
+/// [`Report`](crate::Report) to print really nice and human-friendly error
+/// messages.
+pub trait Diagnostic: std::error::Error {
+ /// Unique diagnostic code that can be used to look up more information
+ /// about this `Diagnostic`. Ideally also globally unique, and documented
+ /// in the toplevel crate's documentation for easy searching. Rust path
+ /// format (`foo::bar::baz`) is recommended, but more classic codes like
+ /// `E0123` or enums will work just fine.
+ fn code<'a>(&'a self) -> Option<Box<dyn Display + 'a>> {
+ None
+ }
+
+ /// Diagnostic severity. This may be used by
+ /// [`ReportHandler`](crate::ReportHandler)s to change the display format
+ /// of this diagnostic.
+ ///
+ /// If `None`, reporters should treat this as [`Severity::Error`].
+ fn severity(&self) -> Option<Severity> {
+ None
+ }
+
+ /// Additional help text related to this `Diagnostic`. Do you have any
+ /// advice for the poor soul who's just run into this issue?
+ fn help<'a>(&'a self) -> Option<Box<dyn Display + 'a>> {
+ None
+ }
+
+ /// URL to visit for a more detailed explanation/help about this
+ /// `Diagnostic`.
+ fn url<'a>(&'a self) -> Option<Box<dyn Display + 'a>> {
+ None
+ }
+
+ /// Source code to apply this `Diagnostic`'s [`Diagnostic::labels`] to.
+ fn source_code(&self) -> Option<&dyn SourceCode> {
+ None
+ }
+
+ /// Labels to apply to this `Diagnostic`'s [`Diagnostic::source_code`]
+ fn labels(&self) -> Option<Box<dyn Iterator<Item = LabeledSpan> + '_>> {
+ None
+ }
+
+ /// Additional related `Diagnostic`s.
+ fn related<'a>(&'a self) -> Option<Box<dyn Iterator<Item = &'a dyn Diagnostic> + 'a>> {
+ None
+ }
+
+ /// The cause of the error.
+ fn diagnostic_source(&self) -> Option<&dyn Diagnostic> {
+ None
+ }
+}
+
+macro_rules! box_impls {
+ ($($box_type:ty),*) => {
+ $(
+ impl std::error::Error for $box_type {
+ fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
+ (**self).source()
+ }
+
+ fn cause(&self) -> Option<&dyn std::error::Error> {
+ self.source()
+ }
+ }
+ )*
+ }
+}
+
+box_impls! {
+ Box<dyn Diagnostic>,
+ Box<dyn Diagnostic + Send>,
+ Box<dyn Diagnostic + Send + Sync>
+}
+
+impl<T: Diagnostic + Send + Sync + 'static> From<T>
+ for Box<dyn Diagnostic + Send + Sync + 'static>
+{
+ fn from(diag: T) -> Self {
+ Box::new(diag)
+ }
+}
+
+impl<T: Diagnostic + Send + Sync + 'static> From<T> for Box<dyn Diagnostic + Send + 'static> {
+ fn from(diag: T) -> Self {
+ Box::<dyn Diagnostic + Send + Sync>::from(diag)
+ }
+}
+
+impl<T: Diagnostic + Send + Sync + 'static> From<T> for Box<dyn Diagnostic + 'static> {
+ fn from(diag: T) -> Self {
+ Box::<dyn Diagnostic + Send + Sync>::from(diag)
+ }
+}
+
+impl From<&str> for Box<dyn Diagnostic> {
+ fn from(s: &str) -> Self {
+ From::from(String::from(s))
+ }
+}
+
+impl<'a> From<&str> for Box<dyn Diagnostic + Send + Sync + 'a> {
+ fn from(s: &str) -> Self {
+ From::from(String::from(s))
+ }
+}
+
+impl From<String> for Box<dyn Diagnostic> {
+ fn from(s: String) -> Self {
+ let err1: Box<dyn Diagnostic + Send + Sync> = From::from(s);
+ let err2: Box<dyn Diagnostic> = err1;
+ err2
+ }
+}
+
+impl From<String> for Box<dyn Diagnostic + Send + Sync> {
+ fn from(s: String) -> Self {
+ struct StringError(String);
+
+ impl std::error::Error for StringError {}
+ impl Diagnostic for StringError {}
+
+ impl Display for StringError {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ Display::fmt(&self.0, f)
+ }
+ }
+
+ // Purposefully skip printing "StringError(..)"
+ impl fmt::Debug for StringError {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ fmt::Debug::fmt(&self.0, f)
+ }
+ }
+
+ Box::new(StringError(s))
+ }
+}
+
+impl From<Box<dyn std::error::Error + Send + Sync>> for Box<dyn Diagnostic + Send + Sync> {
+ fn from(s: Box<dyn std::error::Error + Send + Sync>) -> Self {
+ #[derive(thiserror::Error)]
+ #[error(transparent)]
+ struct BoxedDiagnostic(Box<dyn std::error::Error + Send + Sync>);
+ impl fmt::Debug for BoxedDiagnostic {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ fmt::Debug::fmt(&self.0, f)
+ }
+ }
+
+ impl Diagnostic for BoxedDiagnostic {}
+
+ Box::new(BoxedDiagnostic(s))
+ }
+}
+
+/**
+[`Diagnostic`] severity. Intended to be used by
+[`ReportHandler`](crate::ReportHandler)s to change the way different
+[`Diagnostic`]s are displayed. Defaults to [`Severity::Error`].
+*/
+#[derive(Copy, Clone, Debug, Eq, Ord, PartialEq, PartialOrd)]
+#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
+pub enum Severity {
+ /// Just some help. Here's how you could be doing it better.
+ Advice,
+ /// Warning. Please take note.
+ Warning,
+ /// Critical failure. The program cannot continue.
+ /// This is the default severity, if you don't specify another one.
+ Error,
+}
+
+impl Default for Severity {
+ fn default() -> Self {
+ Severity::Error
+ }
+}
+
+#[cfg(feature = "serde")]
+#[test]
+fn test_serialize_severity() {
+ use serde_json::json;
+
+ assert_eq!(json!(Severity::Advice), json!("Advice"));
+ assert_eq!(json!(Severity::Warning), json!("Warning"));
+ assert_eq!(json!(Severity::Error), json!("Error"));
+}
+
+#[cfg(feature = "serde")]
+#[test]
+fn test_deserialize_severity() {
+ use serde_json::json;
+
+ let severity: Severity = serde_json::from_value(json!("Advice")).unwrap();
+ assert_eq!(severity, Severity::Advice);
+
+ let severity: Severity = serde_json::from_value(json!("Warning")).unwrap();
+ assert_eq!(severity, Severity::Warning);
+
+ let severity: Severity = serde_json::from_value(json!("Error")).unwrap();
+ assert_eq!(severity, Severity::Error);
+}
+
+/**
+Represents readable source code of some sort.
+
+This trait is able to support simple `SourceCode` types like [`String`]s, as
+well as more involved types like indexes into centralized `SourceMap`-like
+types, file handles, and even network streams.
+
+If you can read it, you can source it, and it's not necessary to read the
+whole thing--meaning you should be able to support `SourceCode`s which are
+gigabytes or larger in size.
+*/
+pub trait SourceCode: Send + Sync {
+ /// Read the bytes for a specific span from this SourceCode, keeping a
+ /// certain number of lines before and after the span as context.
+ fn read_span<'a>(
+ &'a self,
+ span: &SourceSpan,
+ context_lines_before: usize,
+ context_lines_after: usize,
+ ) -> Result<Box<dyn SpanContents<'a> + 'a>, MietteError>;
+}
+
+/// A labeled [`SourceSpan`].
+#[derive(Debug, Clone, PartialEq, Eq)]
+#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
+pub struct LabeledSpan {
+ #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
+ label: Option<String>,
+ span: SourceSpan,
+}
+
+impl LabeledSpan {
+ /// Makes a new labeled span.
+ pub const fn new(label: Option<String>, offset: ByteOffset, len: usize) -> Self {
+ Self {
+ label,
+ span: SourceSpan::new(SourceOffset(offset), SourceOffset(len)),
+ }
+ }
+
+ /// Makes a new labeled span using an existing span.
+ pub fn new_with_span(label: Option<String>, span: impl Into<SourceSpan>) -> Self {
+ Self {
+ label,
+ span: span.into(),
+ }
+ }
+
+ /// Makes a new label at specified span
+ ///
+ /// # Examples
+ /// ```
+ /// use miette::LabeledSpan;
+ ///
+ /// let source = "Cpp is the best";
+ /// let label = LabeledSpan::at(0..3, "should be Rust");
+ /// assert_eq!(
+ /// label,
+ /// LabeledSpan::new(Some("should be Rust".to_string()), 0, 3)
+ /// )
+ /// ```
+ pub fn at(span: impl Into<SourceSpan>, label: impl Into<String>) -> Self {
+ Self::new_with_span(Some(label.into()), span)
+ }
+
+ /// Makes a new label that points at a specific offset.
+ ///
+ /// # Examples
+ /// ```
+ /// use miette::LabeledSpan;
+ ///
+ /// let source = "(2 + 2";
+ /// let label = LabeledSpan::at_offset(4, "expected a closing parenthesis");
+ /// assert_eq!(
+ /// label,
+ /// LabeledSpan::new(Some("expected a closing parenthesis".to_string()), 4, 0)
+ /// )
+ /// ```
+ pub fn at_offset(offset: ByteOffset, label: impl Into<String>) -> Self {
+ Self::new(Some(label.into()), offset, 0)
+ }
+
+ /// Makes a new label without text, that underlines a specific span.
+ ///
+ /// # Examples
+ /// ```
+ /// use miette::LabeledSpan;
+ ///
+ /// let source = "You have an eror here";
+ /// let label = LabeledSpan::underline(12..16);
+ /// assert_eq!(label, LabeledSpan::new(None, 12, 4))
+ /// ```
+ pub fn underline(span: impl Into<SourceSpan>) -> Self {
+ Self::new_with_span(None, span)
+ }
+
+ /// Gets the (optional) label string for this `LabeledSpan`.
+ pub fn label(&self) -> Option<&str> {
+ self.label.as_deref()
+ }
+
+ /// Returns a reference to the inner [`SourceSpan`].
+ pub const fn inner(&self) -> &SourceSpan {
+ &self.span
+ }
+
+ /// Returns the 0-based starting byte offset.
+ pub const fn offset(&self) -> usize {
+ self.span.offset()
+ }
+
+ /// Returns the number of bytes this `LabeledSpan` spans.
+ pub const fn len(&self) -> usize {
+ self.span.len()
+ }
+
+ /// True if this `LabeledSpan` is empty.
+ pub const fn is_empty(&self) -> bool {
+ self.span.is_empty()
+ }
+}
+
+#[cfg(feature = "serde")]
+#[test]
+fn test_serialize_labeled_span() {
+ use serde_json::json;
+
+ assert_eq!(
+ json!(LabeledSpan::new(None, 0, 0)),
+ json!({
+ "span": { "offset": 0, "length": 0 }
+ })
+ );
+
+ assert_eq!(
+ json!(LabeledSpan::new(Some("label".to_string()), 0, 0)),
+ json!({
+ "label": "label",
+ "span": { "offset": 0, "length": 0 }
+ })
+ )
+}
+
+#[cfg(feature = "serde")]
+#[test]
+fn test_deserialize_labeled_span() {
+ use serde_json::json;
+
+ let span: LabeledSpan = serde_json::from_value(json!({
+ "label": null,
+ "span": { "offset": 0, "length": 0 }
+ }))
+ .unwrap();
+ assert_eq!(span, LabeledSpan::new(None, 0, 0));
+
+ let span: LabeledSpan = serde_json::from_value(json!({
+ "span": { "offset": 0, "length": 0 }
+ }))
+ .unwrap();
+ assert_eq!(span, LabeledSpan::new(None, 0, 0));
+
+ let span: LabeledSpan = serde_json::from_value(json!({
+ "label": "label",
+ "span": { "offset": 0, "length": 0 }
+ }))
+ .unwrap();
+ assert_eq!(span, LabeledSpan::new(Some("label".to_string()), 0, 0))
+}
+
+/**
+Contents of a [`SourceCode`] covered by [`SourceSpan`].
+
+Includes line and column information to optimize highlight calculations.
+*/
+pub trait SpanContents<'a> {
+ /// Reference to the data inside the associated span, in bytes.
+ fn data(&self) -> &'a [u8];
+ /// [`SourceSpan`] representing the span covered by this `SpanContents`.
+ fn span(&self) -> &SourceSpan;
+ /// An optional (file?) name for the container of this `SpanContents`.
+ fn name(&self) -> Option<&str> {
+ None
+ }
+ /// The 0-indexed line in the associated [`SourceCode`] where the data
+ /// begins.
+ fn line(&self) -> usize;
+ /// The 0-indexed column in the associated [`SourceCode`] where the data
+ /// begins, relative to `line`.
+ fn column(&self) -> usize;
+ /// Total number of lines covered by this `SpanContents`.
+ fn line_count(&self) -> usize;
+}
+
+/**
+Basic implementation of the [`SpanContents`] trait, for convenience.
+*/
+#[derive(Clone, Debug)]
+pub struct MietteSpanContents<'a> {
+ // Data from a [`SourceCode`], in bytes.
+ data: &'a [u8],
+ // span actually covered by this SpanContents.
+ span: SourceSpan,
+ // The 0-indexed line where the associated [`SourceSpan`] _starts_.
+ line: usize,
+ // The 0-indexed column where the associated [`SourceSpan`] _starts_.
+ column: usize,
+ // Number of line in this snippet.
+ line_count: usize,
+ // Optional filename
+ name: Option<String>,
+}
+
+impl<'a> MietteSpanContents<'a> {
+ /// Make a new [`MietteSpanContents`] object.
+ pub const fn new(
+ data: &'a [u8],
+ span: SourceSpan,
+ line: usize,
+ column: usize,
+ line_count: usize,
+ ) -> MietteSpanContents<'a> {
+ MietteSpanContents {
+ data,
+ span,
+ line,
+ column,
+ line_count,
+ name: None,
+ }
+ }
+
+ /// Make a new [`MietteSpanContents`] object, with a name for its 'file'.
+ pub const fn new_named(
+ name: String,
+ data: &'a [u8],
+ span: SourceSpan,
+ line: usize,
+ column: usize,
+ line_count: usize,
+ ) -> MietteSpanContents<'a> {
+ MietteSpanContents {
+ data,
+ span,
+ line,
+ column,
+ line_count,
+ name: Some(name),
+ }
+ }
+}
+
+impl<'a> SpanContents<'a> for MietteSpanContents<'a> {
+ fn data(&self) -> &'a [u8] {
+ self.data
+ }
+ fn span(&self) -> &SourceSpan {
+ &self.span
+ }
+ fn line(&self) -> usize {
+ self.line
+ }
+ fn column(&self) -> usize {
+ self.column
+ }
+ fn line_count(&self) -> usize {
+ self.line_count
+ }
+ fn name(&self) -> Option<&str> {
+ self.name.as_deref()
+ }
+}
+
+/// Span within a [`SourceCode`]
+#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)]
+#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
+pub struct SourceSpan {
+ /// The start of the span.
+ offset: SourceOffset,
+ /// The total length of the span
+ length: usize,
+}
+
+impl SourceSpan {
+ /// Create a new [`SourceSpan`].
+ pub const fn new(start: SourceOffset, length: SourceOffset) -> Self {
+ Self {
+ offset: start,
+ length: length.offset(),
+ }
+ }
+
+ /// The absolute offset, in bytes, from the beginning of a [`SourceCode`].
+ pub const fn offset(&self) -> usize {
+ self.offset.offset()
+ }
+
+ /// Total length of the [`SourceSpan`], in bytes.
+ pub const fn len(&self) -> usize {
+ self.length
+ }
+
+ /// Whether this [`SourceSpan`] has a length of zero. It may still be useful
+ /// to point to a specific point.
+ pub const fn is_empty(&self) -> bool {
+ self.length == 0
+ }
+}
+
+impl From<(ByteOffset, usize)> for SourceSpan {
+ fn from((start, len): (ByteOffset, usize)) -> Self {
+ Self {
+ offset: start.into(),
+ length: len,
+ }
+ }
+}
+
+impl From<(SourceOffset, SourceOffset)> for SourceSpan {
+ fn from((start, len): (SourceOffset, SourceOffset)) -> Self {
+ Self::new(start, len)
+ }
+}
+
+impl From<std::ops::Range<ByteOffset>> for SourceSpan {
+ fn from(range: std::ops::Range<ByteOffset>) -> Self {
+ Self {
+ offset: range.start.into(),
+ length: range.len(),
+ }
+ }
+}
+
+impl From<SourceOffset> for SourceSpan {
+ fn from(offset: SourceOffset) -> Self {
+ Self { offset, length: 0 }
+ }
+}
+
+impl From<ByteOffset> for SourceSpan {
+ fn from(offset: ByteOffset) -> Self {
+ Self {
+ offset: offset.into(),
+ length: 0,
+ }
+ }
+}
+
+#[cfg(feature = "serde")]
+#[test]
+fn test_serialize_source_span() {
+ use serde_json::json;
+
+ assert_eq!(
+ json!(SourceSpan::from(0)),
+ json!({ "offset": 0, "length": 0})
+ )
+}
+
+#[cfg(feature = "serde")]
+#[test]
+fn test_deserialize_source_span() {
+ use serde_json::json;
+
+ let span: SourceSpan = serde_json::from_value(json!({ "offset": 0, "length": 0})).unwrap();
+ assert_eq!(span, SourceSpan::from(0))
+}
+
+/**
+"Raw" type for the byte offset from the beginning of a [`SourceCode`].
+*/
+pub type ByteOffset = usize;
+
+/**
+Newtype that represents the [`ByteOffset`] from the beginning of a [`SourceCode`]
+*/
+#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)]
+#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
+pub struct SourceOffset(ByteOffset);
+
+impl SourceOffset {
+ /// Actual byte offset.
+ pub const fn offset(&self) -> ByteOffset {
+ self.0
+ }
+
+ /// Little utility to help convert 1-based line/column locations into
+ /// miette-compatible Spans
+ ///
+ /// This function is infallible: Giving an out-of-range line/column pair
+ /// will return the offset of the last byte in the source.
+ pub fn from_location(source: impl AsRef<str>, loc_line: usize, loc_col: usize) -> Self {
+ let mut line = 0usize;
+ let mut col = 0usize;
+ let mut offset = 0usize;
+ for char in source.as_ref().chars() {
+ if line + 1 >= loc_line && col + 1 >= loc_col {
+ break;
+ }
+ if char == '\n' {
+ col = 0;
+ line += 1;
+ } else {
+ col += 1;
+ }
+ offset += char.len_utf8();
+ }
+
+ SourceOffset(offset)
+ }
+
+ /// Returns an offset for the _file_ location of wherever this function is
+ /// called. If you want to get _that_ caller's location, mark this
+ /// function's caller with `#[track_caller]` (and so on and so forth).
+ ///
+ /// Returns both the filename that was given and the offset of the caller
+ /// as a [`SourceOffset`].
+ ///
+ /// Keep in mind that this fill only work if the file your Rust source
+ /// file was compiled from is actually available at that location. If
+ /// you're shipping binaries for your application, you'll want to ignore
+ /// the Err case or otherwise report it.
+ #[track_caller]
+ pub fn from_current_location() -> Result<(String, Self), MietteError> {
+ let loc = Location::caller();
+ Ok((
+ loc.file().into(),
+ fs::read_to_string(loc.file())
+ .map(|txt| Self::from_location(txt, loc.line() as usize, loc.column() as usize))?,
+ ))
+ }
+}
+
+impl From<ByteOffset> for SourceOffset {
+ fn from(bytes: ByteOffset) -> Self {
+ SourceOffset(bytes)
+ }
+}
+
+#[test]
+fn test_source_offset_from_location() {
+ let source = "f\n\noo\r\nbar";
+
+ assert_eq!(SourceOffset::from_location(source, 1, 1).offset(), 0);
+ assert_eq!(SourceOffset::from_location(source, 1, 2).offset(), 1);
+ assert_eq!(SourceOffset::from_location(source, 2, 1).offset(), 2);
+ assert_eq!(SourceOffset::from_location(source, 3, 1).offset(), 3);
+ assert_eq!(SourceOffset::from_location(source, 3, 2).offset(), 4);
+ assert_eq!(SourceOffset::from_location(source, 3, 3).offset(), 5);
+ assert_eq!(SourceOffset::from_location(source, 3, 4).offset(), 6);
+ assert_eq!(SourceOffset::from_location(source, 4, 1).offset(), 7);
+ assert_eq!(SourceOffset::from_location(source, 4, 2).offset(), 8);
+ assert_eq!(SourceOffset::from_location(source, 4, 3).offset(), 9);
+ assert_eq!(SourceOffset::from_location(source, 4, 4).offset(), 10);
+
+ // Out-of-range
+ assert_eq!(
+ SourceOffset::from_location(source, 5, 1).offset(),
+ source.len()
+ );
+}
+
+#[cfg(feature = "serde")]
+#[test]
+fn test_serialize_source_offset() {
+ use serde_json::json;
+
+ assert_eq!(json!(SourceOffset::from(0)), 0)
+}
+
+#[cfg(feature = "serde")]
+#[test]
+fn test_deserialize_source_offset() {
+ let offset: SourceOffset = serde_json::from_str("0").unwrap();
+ assert_eq!(offset, SourceOffset::from(0))
+}
diff --git a/vendor/miette/src/source_impls.rs b/vendor/miette/src/source_impls.rs
new file mode 100644
index 0000000..e43a665
--- /dev/null
+++ b/vendor/miette/src/source_impls.rs
@@ -0,0 +1,301 @@
+/*!
+Default trait implementations for [`SourceCode`].
+*/
+use std::{
+ borrow::{Cow, ToOwned},
+ collections::VecDeque,
+ fmt::Debug,
+ sync::Arc,
+};
+
+use crate::{MietteError, MietteSpanContents, SourceCode, SourceSpan, SpanContents};
+
+fn context_info<'a>(
+ input: &'a [u8],
+ span: &SourceSpan,
+ context_lines_before: usize,
+ context_lines_after: usize,
+) -> Result<MietteSpanContents<'a>, MietteError> {
+ let mut offset = 0usize;
+ let mut line_count = 0usize;
+ let mut start_line = 0usize;
+ let mut start_column = 0usize;
+ let mut before_lines_starts = VecDeque::new();
+ let mut current_line_start = 0usize;
+ let mut end_lines = 0usize;
+ let mut post_span = false;
+ let mut post_span_got_newline = false;
+ let mut iter = input.iter().copied().peekable();
+ while let Some(char) = iter.next() {
+ if matches!(char, b'\r' | b'\n') {
+ line_count += 1;
+ if char == b'\r' && iter.next_if_eq(&b'\n').is_some() {
+ offset += 1;
+ }
+ if offset < span.offset() {
+ // We're before the start of the span.
+ start_column = 0;
+ before_lines_starts.push_back(current_line_start);
+ if before_lines_starts.len() > context_lines_before {
+ start_line += 1;
+ before_lines_starts.pop_front();
+ }
+ } else if offset >= span.offset() + span.len().saturating_sub(1) {
+ // We're after the end of the span, but haven't necessarily
+ // started collecting end lines yet (we might still be
+ // collecting context lines).
+ if post_span {
+ start_column = 0;
+ if post_span_got_newline {
+ end_lines += 1;
+ } else {
+ post_span_got_newline = true;
+ }
+ if end_lines >= context_lines_after {
+ offset += 1;
+ break;
+ }
+ }
+ }
+ current_line_start = offset + 1;
+ } else if offset < span.offset() {
+ start_column += 1;
+ }
+
+ if offset >= (span.offset() + span.len()).saturating_sub(1) {
+ post_span = true;
+ if end_lines >= context_lines_after {
+ offset += 1;
+ break;
+ }
+ }
+
+ offset += 1;
+ }
+
+ if offset >= (span.offset() + span.len()).saturating_sub(1) {
+ let starting_offset = before_lines_starts.front().copied().unwrap_or_else(|| {
+ if context_lines_before == 0 {
+ span.offset()
+ } else {
+ 0
+ }
+ });
+ Ok(MietteSpanContents::new(
+ &input[starting_offset..offset],
+ (starting_offset, offset - starting_offset).into(),
+ start_line,
+ if context_lines_before == 0 {
+ start_column
+ } else {
+ 0
+ },
+ line_count,
+ ))
+ } else {
+ Err(MietteError::OutOfBounds)
+ }
+}
+
+impl SourceCode for [u8] {
+ fn read_span<'a>(
+ &'a self,
+ span: &SourceSpan,
+ context_lines_before: usize,
+ context_lines_after: usize,
+ ) -> Result<Box<dyn SpanContents<'a> + 'a>, MietteError> {
+ let contents = context_info(self, span, context_lines_before, context_lines_after)?;
+ Ok(Box::new(contents))
+ }
+}
+
+impl<'src> SourceCode for &'src [u8] {
+ fn read_span<'a>(
+ &'a self,
+ span: &SourceSpan,
+ context_lines_before: usize,
+ context_lines_after: usize,
+ ) -> Result<Box<dyn SpanContents<'a> + 'a>, MietteError> {
+ <[u8] as SourceCode>::read_span(self, span, context_lines_before, context_lines_after)
+ }
+}
+
+impl SourceCode for Vec<u8> {
+ fn read_span<'a>(
+ &'a self,
+ span: &SourceSpan,
+ context_lines_before: usize,
+ context_lines_after: usize,
+ ) -> Result<Box<dyn SpanContents<'a> + 'a>, MietteError> {
+ <[u8] as SourceCode>::read_span(self, span, context_lines_before, context_lines_after)
+ }
+}
+
+impl SourceCode for str {
+ fn read_span<'a>(
+ &'a self,
+ span: &SourceSpan,
+ context_lines_before: usize,
+ context_lines_after: usize,
+ ) -> Result<Box<dyn SpanContents<'a> + 'a>, MietteError> {
+ <[u8] as SourceCode>::read_span(
+ self.as_bytes(),
+ span,
+ context_lines_before,
+ context_lines_after,
+ )
+ }
+}
+
+/// Makes `src: &'static str` or `struct S<'a> { src: &'a str }` usable.
+impl<'s> SourceCode for &'s str {
+ fn read_span<'a>(
+ &'a self,
+ span: &SourceSpan,
+ context_lines_before: usize,
+ context_lines_after: usize,
+ ) -> Result<Box<dyn SpanContents<'a> + 'a>, MietteError> {
+ <str as SourceCode>::read_span(self, span, context_lines_before, context_lines_after)
+ }
+}
+
+impl SourceCode for String {
+ fn read_span<'a>(
+ &'a self,
+ span: &SourceSpan,
+ context_lines_before: usize,
+ context_lines_after: usize,
+ ) -> Result<Box<dyn SpanContents<'a> + 'a>, MietteError> {
+ <str as SourceCode>::read_span(self, span, context_lines_before, context_lines_after)
+ }
+}
+
+impl<T: ?Sized + SourceCode> SourceCode for Arc<T> {
+ fn read_span<'a>(
+ &'a self,
+ span: &SourceSpan,
+ context_lines_before: usize,
+ context_lines_after: usize,
+ ) -> Result<Box<dyn SpanContents<'a> + 'a>, MietteError> {
+ self.as_ref()
+ .read_span(span, context_lines_before, context_lines_after)
+ }
+}
+
+impl<T: ?Sized + SourceCode + ToOwned> SourceCode for Cow<'_, T>
+where
+ // The minimal bounds are used here.
+ // `T::Owned` need not be
+ // `SourceCode`, because `&T`
+ // can always be obtained from
+ // `Cow<'_, T>`.
+ T::Owned: Debug + Send + Sync,
+{
+ fn read_span<'a>(
+ &'a self,
+ span: &SourceSpan,
+ context_lines_before: usize,
+ context_lines_after: usize,
+ ) -> Result<Box<dyn SpanContents<'a> + 'a>, MietteError> {
+ self.as_ref()
+ .read_span(span, context_lines_before, context_lines_after)
+ }
+}
+
+#[cfg(test)]
+mod tests {
+ use super::*;
+
+ #[test]
+ fn basic() -> Result<(), MietteError> {
+ let src = String::from("foo\n");
+ let contents = src.read_span(&(0, 4).into(), 0, 0)?;
+ assert_eq!("foo\n", std::str::from_utf8(contents.data()).unwrap());
+ assert_eq!(0, contents.line());
+ assert_eq!(0, contents.column());
+ Ok(())
+ }
+
+ #[test]
+ fn shifted() -> Result<(), MietteError> {
+ let src = String::from("foobar");
+ let contents = src.read_span(&(3, 3).into(), 1, 1)?;
+ assert_eq!("foobar", std::str::from_utf8(contents.data()).unwrap());
+ assert_eq!(0, contents.line());
+ assert_eq!(0, contents.column());
+ Ok(())
+ }
+
+ #[test]
+ fn middle() -> Result<(), MietteError> {
+ let src = String::from("foo\nbar\nbaz\n");
+ let contents = src.read_span(&(4, 4).into(), 0, 0)?;
+ assert_eq!("bar\n", std::str::from_utf8(contents.data()).unwrap());
+ assert_eq!(1, contents.line());
+ assert_eq!(0, contents.column());
+ Ok(())
+ }
+
+ #[test]
+ fn middle_of_line() -> Result<(), MietteError> {
+ let src = String::from("foo\nbarbar\nbaz\n");
+ let contents = src.read_span(&(7, 4).into(), 0, 0)?;
+ assert_eq!("bar\n", std::str::from_utf8(contents.data()).unwrap());
+ assert_eq!(1, contents.line());
+ assert_eq!(3, contents.column());
+ Ok(())
+ }
+
+ #[test]
+ fn with_crlf() -> Result<(), MietteError> {
+ let src = String::from("foo\r\nbar\r\nbaz\r\n");
+ let contents = src.read_span(&(5, 5).into(), 0, 0)?;
+ assert_eq!("bar\r\n", std::str::from_utf8(contents.data()).unwrap());
+ assert_eq!(1, contents.line());
+ assert_eq!(0, contents.column());
+ Ok(())
+ }
+
+ #[test]
+ fn with_context() -> Result<(), MietteError> {
+ let src = String::from("xxx\nfoo\nbar\nbaz\n\nyyy\n");
+ let contents = src.read_span(&(8, 3).into(), 1, 1)?;
+ assert_eq!(
+ "foo\nbar\nbaz\n",
+ std::str::from_utf8(contents.data()).unwrap()
+ );
+ assert_eq!(1, contents.line());
+ assert_eq!(0, contents.column());
+ Ok(())
+ }
+
+ #[test]
+ fn multiline_with_context() -> Result<(), MietteError> {
+ let src = String::from("aaa\nxxx\n\nfoo\nbar\nbaz\n\nyyy\nbbb\n");
+ let contents = src.read_span(&(9, 11).into(), 1, 1)?;
+ assert_eq!(
+ "\nfoo\nbar\nbaz\n\n",
+ std::str::from_utf8(contents.data()).unwrap()
+ );
+ assert_eq!(2, contents.line());
+ assert_eq!(0, contents.column());
+ let span: SourceSpan = (8, 14).into();
+ assert_eq!(&span, contents.span());
+ Ok(())
+ }
+
+ #[test]
+ fn multiline_with_context_line_start() -> Result<(), MietteError> {
+ let src = String::from("one\ntwo\n\nthree\nfour\nfive\n\nsix\nseven\n");
+ let contents = src.read_span(&(2, 0).into(), 2, 2)?;
+ assert_eq!(
+ "one\ntwo\n\n",
+ std::str::from_utf8(contents.data()).unwrap()
+ );
+ assert_eq!(0, contents.line());
+ assert_eq!(0, contents.column());
+ let span: SourceSpan = (0, 9).into();
+ assert_eq!(&span, contents.span());
+ Ok(())
+ }
+}