From 1b6a04ca5504955c571d1c97504fb45ea0befee4 Mon Sep 17 00:00:00 2001 From: Valentin Popov Date: Mon, 8 Jan 2024 01:21:28 +0400 Subject: Initial vendor packages Signed-off-by: Valentin Popov --- vendor/miette/src/eyreish/context.rs | 217 +++++++ vendor/miette/src/eyreish/error.rs | 810 +++++++++++++++++++++++++++ vendor/miette/src/eyreish/fmt.rs | 20 + vendor/miette/src/eyreish/into_diagnostic.rs | 33 ++ vendor/miette/src/eyreish/kind.rs | 111 ++++ vendor/miette/src/eyreish/macros.rs | 300 ++++++++++ vendor/miette/src/eyreish/mod.rs | 485 ++++++++++++++++ vendor/miette/src/eyreish/ptr.rs | 188 +++++++ vendor/miette/src/eyreish/wrapper.rs | 234 ++++++++ 9 files changed, 2398 insertions(+) create mode 100644 vendor/miette/src/eyreish/context.rs create mode 100644 vendor/miette/src/eyreish/error.rs create mode 100644 vendor/miette/src/eyreish/fmt.rs create mode 100644 vendor/miette/src/eyreish/into_diagnostic.rs create mode 100644 vendor/miette/src/eyreish/kind.rs create mode 100644 vendor/miette/src/eyreish/macros.rs create mode 100644 vendor/miette/src/eyreish/mod.rs create mode 100644 vendor/miette/src/eyreish/ptr.rs create mode 100644 vendor/miette/src/eyreish/wrapper.rs (limited to 'vendor/miette/src/eyreish') 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(self, msg: D) -> Report + where + D: Display + Send + Sync + 'static; + } + + impl Diag for E + where + E: Diagnostic + Send + Sync + 'static, + { + fn ext_report(self, msg: D) -> Report + where + D: Display + Send + Sync + 'static, + { + Report::from_msg(msg, self) + } + } + + impl Diag for Report { + fn ext_report(self, msg: D) -> Report + where + D: Display + Send + Sync + 'static, + { + self.wrap_err(msg) + } + } +} + +impl WrapErr for Result +where + E: ext::Diag + Send + Sync + 'static, +{ + fn wrap_err(self, msg: D) -> Result + where + D: Display + Send + Sync + 'static, + { + match self { + Ok(t) => Ok(t), + Err(e) => Err(e.ext_report(msg)), + } + } + + fn wrap_err_with(self, msg: F) -> Result + where + D: Display + Send + Sync + 'static, + F: FnOnce() -> D, + { + match self { + Ok(t) => Ok(t), + Err(e) => Err(e.ext_report(msg())), + } + } + + fn context(self, msg: D) -> Result + where + D: Display + Send + Sync + 'static, + { + self.wrap_err(msg) + } + + fn with_context(self, msg: F) -> Result + where + D: Display + Send + Sync + 'static, + F: FnOnce() -> D, + { + self.wrap_err_with(msg) + } +} + +impl Debug for ContextError +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 Display for ContextError +where + D: Display, +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + Display::fmt(&self.msg, f) + } +} + +impl StdError for ContextError +where + D: Display, + E: StdError + 'static, +{ + fn source(&self) -> Option<&(dyn StdError + 'static)> { + Some(&self.error) + } +} + +impl StdError for ContextError +where + D: Display, +{ + fn source(&self) -> Option<&(dyn StdError + 'static)> { + unsafe { Some(ErrorImpl::error(self.error.inner.by_ref())) } + } +} + +impl Diagnostic for ContextError +where + D: Display, + E: Diagnostic + 'static, +{ + fn code<'a>(&'a self) -> Option> { + self.error.code() + } + + fn severity(&self) -> Option { + self.error.severity() + } + + fn help<'a>(&'a self) -> Option> { + self.error.help() + } + + fn url<'a>(&'a self) -> Option> { + self.error.url() + } + + fn labels<'a>(&'a self) -> Option + 'a>> { + self.error.labels() + } + + fn source_code(&self) -> Option<&dyn crate::SourceCode> { + self.error.source_code() + } + + fn related<'a>(&'a self) -> Option + 'a>> { + self.error.related() + } +} + +impl Diagnostic for ContextError +where + D: Display, +{ + fn code<'a>(&'a self) -> Option> { + unsafe { ErrorImpl::diagnostic(self.error.inner.by_ref()).code() } + } + + fn severity(&self) -> Option { + unsafe { ErrorImpl::diagnostic(self.error.inner.by_ref()).severity() } + } + + fn help<'a>(&'a self) -> Option> { + unsafe { ErrorImpl::diagnostic(self.error.inner.by_ref()).help() } + } + + fn url<'a>(&'a self) -> Option> { + unsafe { ErrorImpl::diagnostic(self.error.inner.by_ref()).url() } + } + + fn labels<'a>(&'a self) -> Option + '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 + 'a>> { + self.error.related() + } +} + +struct Quoted(D); + +impl Debug for Quoted +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 Sealed for Result where E: ext::Diag {} + impl Sealed for Option {} +} 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(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 { + /// # unimplemented!() + /// # } + /// # } + /// # + /// # use ffi::{Input, Output}; + /// # + /// use futures::stream::{Stream, StreamExt, TryStreamExt}; + /// use miette::{Report, Result}; + /// + /// async fn demo(stream: S) -> Result> + /// where + /// S: Stream, + /// { + /// stream + /// .then(ffi::do_some_work) // returns Result + /// .map_err(Report::msg) + /// .try_collect() + /// .await + /// } + /// ``` + #[cfg_attr(track_caller, track_caller)] + pub fn msg(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) -> Self { + Report::from_boxed(error) + } + + #[cfg_attr(track_caller, track_caller)] + pub(crate) fn from_std(error: E) -> Self + where + E: Diagnostic + Send + Sync + 'static, + { + let vtable = &ErrorVTable { + object_drop: object_drop::, + object_ref: object_ref::, + object_ref_stderr: object_ref_stderr::, + object_boxed: object_boxed::, + object_boxed_stderr: object_boxed_stderr::, + object_downcast: object_downcast::, + object_drop_rest: object_drop_front::, + }; + + // 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(message: M) -> Self + where + M: Display + Debug + Send + Sync + 'static, + { + use super::wrapper::MessageError; + let error: MessageError = MessageError(message); + let vtable = &ErrorVTable { + object_drop: object_drop::>, + object_ref: object_ref::>, + object_ref_stderr: object_ref_stderr::>, + object_boxed: object_boxed::>, + object_boxed_stderr: object_boxed_stderr::>, + object_downcast: object_downcast::, + object_drop_rest: object_drop_front::, + }; + + // Safety: MessageError is repr(transparent) so it is okay for the + // vtable to allow casting the MessageError 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(msg: D, error: E) -> Self + where + D: Display + Send + Sync + 'static, + E: Diagnostic + Send + Sync + 'static, + { + let error: ContextError = ContextError { msg, error }; + + let vtable = &ErrorVTable { + object_drop: object_drop::>, + object_ref: object_ref::>, + object_ref_stderr: object_ref_stderr::>, + object_boxed: object_boxed::>, + object_boxed_stderr: object_boxed_stderr::>, + object_downcast: context_downcast::, + object_drop_rest: context_drop_rest::, + }; + + // 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) -> Self { + use super::wrapper::BoxedError; + let error = BoxedError(error); + let handler = Some(super::capture_handler(&error)); + + let vtable = &ErrorVTable { + object_drop: object_drop::, + object_ref: object_ref::, + object_ref_stderr: object_ref_stderr::, + object_boxed: object_boxed::, + object_boxed_stderr: object_boxed_stderr::, + object_downcast: object_downcast::>, + object_drop_rest: object_drop_front::>, + }; + + // Safety: BoxedError is repr(transparent) so it is okay for the vtable + // to allow casting to Box. + 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( + error: E, + vtable: &'static ErrorVTable, + handler: Option>, + ) -> 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> to + // Box> except that the + // result is a thin pointer. The necessary behavior for manipulating the + // underlying ErrorImpl is preserved in the vtable provided by the + // caller rather than a builtin fat pointer vtable. + let inner = Own::new(inner).cast::(); + 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(self, msg: D) -> Self + where + D: Display + Send + Sync + 'static, + { + let handler = unsafe { self.inner.by_mut().deref_mut().handler.take() }; + let error: ContextError = ContextError { msg, error: self }; + + let vtable = &ErrorVTable { + object_drop: object_drop::>, + object_ref: object_ref::>, + object_ref_stderr: object_ref_stderr::>, + object_boxed: object_boxed::>, + object_boxed_stderr: object_boxed_stderr::>, + object_downcast: context_chain_downcast::, + object_drop_rest: context_chain_drop_rest::, + }; + + // 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(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 { + /// for cause in error.chain() { + /// if let Some(io_error) = cause.downcast_ref::() { + /// 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 — 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(&self) -> bool + where + E: Display + Debug + Send + Sync + 'static, + { + self.downcast_ref::().is_some() + } + + /// Attempt to downcast the error object to a concrete type. + pub fn downcast(self) -> Result + where + E: Display + Debug + Send + Sync + 'static, + { + let target = TypeId::of::(); + 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::().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::() { + /// Some(DataStoreError::Censored(_)) => Ok(Poll::Ready(REDACTED_CONTENT)), + /// None => Err(error), + /// } + /// # ; + /// ``` + pub fn downcast_ref(&self) -> Option<&E> + where + E: Display + Debug + Send + Sync + 'static, + { + let target = TypeId::of::(); + 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::().deref()) + } + } + + /// Downcast this error object by mutable reference. + pub fn downcast_mut(&mut self) -> Option<&mut E> + where + E: Display + Debug + Send + Sync + 'static, + { + let target = TypeId::of::(); + 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::().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 From 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), + 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) -> Box, + #[allow(clippy::type_complexity)] + object_boxed_stderr: + unsafe fn(Own) -> Box, + object_downcast: unsafe fn(Ref<'_, ErasedErrorImpl>, TypeId) -> Option>, + object_drop_rest: unsafe fn(Own, TypeId), +} + +// Safety: requires layout of *e to match ErrorImpl. +unsafe fn object_drop(e: Own) { + // Cast back to ErrorImpl so that the allocator receives the correct + // Layout to deallocate the Box's memory. + let unerased = e.cast::>().boxed(); + drop(unerased); +} + +// Safety: requires layout of *e to match ErrorImpl. +unsafe fn object_drop_front(e: Own, 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::>>().boxed(); + drop(unerased); +} + +// Safety: requires layout of *e to match ErrorImpl. +unsafe fn object_ref( + 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::>(); + + Ref::from_raw(NonNull::new_unchecked( + ptr::addr_of!((*unerased.as_ptr())._object) as *mut E, + )) +} + +// Safety: requires layout of *e to match ErrorImpl. +unsafe fn object_ref_stderr( + 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::>(); + + Ref::from_raw(NonNull::new_unchecked( + ptr::addr_of!((*unerased.as_ptr())._object) as *mut E, + )) +} + +// Safety: requires layout of *e to match ErrorImpl. +unsafe fn object_boxed(e: Own) -> Box +where + E: Diagnostic + Send + Sync + 'static, +{ + // Attach ErrorImpl's native StdError vtable. The StdError impl is below. + e.cast::>().boxed() +} + +// Safety: requires layout of *e to match ErrorImpl. +unsafe fn object_boxed_stderr( + e: Own, +) -> Box +where + E: StdError + Send + Sync + 'static, +{ + // Attach ErrorImpl's native StdError vtable. The StdError impl is below. + e.cast::>().boxed() +} + +// Safety: requires layout of *e to match ErrorImpl. +unsafe fn object_downcast(e: Ref<'_, ErasedErrorImpl>, target: TypeId) -> Option> +where + E: 'static, +{ + if TypeId::of::() == target { + // Caller is looking for an E pointer and e is ErrorImpl, take a + // pointer to its E field. + let unerased = e.cast::>(); + + 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>. +unsafe fn context_downcast(e: Ref<'_, ErasedErrorImpl>, target: TypeId) -> Option> +where + D: 'static, + E: 'static, +{ + if TypeId::of::() == target { + let unerased = e.cast::>>().deref(); + Some(Ref::new(&unerased._object.msg).cast::<()>()) + } else if TypeId::of::() == target { + let unerased = e.cast::>>().deref(); + Some(Ref::new(&unerased._object.error).cast::<()>()) + } else { + None + } +} + +// Safety: requires layout of *e to match ErrorImpl>. +unsafe fn context_drop_rest(e: Own, 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::() == target { + let unerased = e + .cast::, E>>>() + .boxed(); + drop(unerased); + } else { + let unerased = e + .cast::>>>() + .boxed(); + drop(unerased); + } +} + +// Safety: requires layout of *e to match ErrorImpl>. +unsafe fn context_chain_downcast( + e: Ref<'_, ErasedErrorImpl>, + target: TypeId, +) -> Option> +where + D: 'static, +{ + let unerased = e.cast::>>().deref(); + if TypeId::of::() == 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>. +unsafe fn context_chain_drop_rest(e: Own, 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::() == target { + let unerased = e + .cast::, Report>>>() + .boxed(); + // Drop the entire rest of the data structure rooted in the next Report. + drop(unerased); + } else { + let unerased = e + .cast::>>>() + .boxed(); + // Read out a ManuallyDrop> 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 { + vtable: &'static ErrorVTable, + pub(crate) handler: Option>, + // NOTE: Don't use directly. Use only through vtable. Erased type may have + // different alignment. + _object: E, +} + +// repr C to ensure that ContextError has the same layout as +// ContextError, E> and ContextError>. +#[repr(C)] +pub(crate) struct ContextError { + 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) -> &'static ErrorVTable { + (p.as_ptr() as *const &'static ErrorVTable).read() +} + +impl ErrorImpl { + 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::() + } +} + +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 StdError for ErrorImpl +where + E: StdError, +{ + fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { + unsafe { ErrorImpl::diagnostic(self.erase()).source() } + } +} + +impl Diagnostic for ErrorImpl where E: Diagnostic {} + +impl Debug for ErrorImpl +where + E: Debug, +{ + fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { + unsafe { ErrorImpl::debug(self.erase(), formatter) } + } +} + +impl Display for ErrorImpl +where + E: Display, +{ + fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { + unsafe { Display::fmt(ErrorImpl::diagnostic(self.erase()), formatter) } + } +} + +impl From for Box { + fn from(error: Report) -> Self { + let outer = ManuallyDrop::new(error); + unsafe { + // Use vtable to attach ErrorImpl's native StdError vtable for + // the right original type E. + (vtable(outer.inner.ptr).object_boxed)(outer.inner) + } + } +} + +impl From for Box { + fn from(error: Report) -> Self { + let outer = ManuallyDrop::new(error); + unsafe { + // Use vtable to attach ErrorImpl's native StdError vtable for + // the right original type E. + (vtable(outer.inner.ptr).object_boxed_stderr)(outer.inner) + } + } +} + +impl From for Box { + fn from(error: Report) -> Self { + Box::::from(error) + } +} + +impl From for Box { + fn from(error: Report) -> Self { + Box::::from(error) + } +} + +impl AsRef for Report { + fn as_ref(&self) -> &(dyn Diagnostic + Send + Sync + 'static) { + &**self + } +} + +impl AsRef for Report { + fn as_ref(&self) -> &(dyn Diagnostic + 'static) { + &**self + } +} + +impl AsRef for Report { + fn as_ref(&self) -> &(dyn StdError + Send + Sync + 'static) { + unsafe { ErrorImpl::error(self.inner.by_ref()) } + } +} + +impl AsRef for Report { + fn as_ref(&self) -> &(dyn StdError + 'static) { + unsafe { ErrorImpl::error(self.inner.by_ref()) } + } +} + +impl std::borrow::Borrow 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); +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`]. + +## 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 { + /// Converts [`Result`] types that return regular [`std::error::Error`]s + /// into a [`Result`] that returns a [`Diagnostic`]. + fn into_diagnostic(self) -> Result; +} + +impl IntoDiagnostic for Result { + fn into_diagnostic(self) -> Result { + 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 EyreNew for T +// where +// T: Display + Debug + Send + Sync + 'static, +// { +// default fn new(self) -> Report { +// /* no std error impl */ +// } +// } +// +// impl 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 AdhocKind for &T where T: ?Sized + Display + Debug + Send + Sync + 'static {} + +impl Adhoc { + #[cfg_attr(track_caller, track_caller)] + pub fn new(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 TraitKind for E where E: Into {} + +impl Trait { + #[cfg_attr(track_caller, track_caller)] + pub fn new(self, error: E) -> Report + where + E: Into, + { + error.into() + } +} + +pub struct Boxed; + +pub trait BoxedKind: Sized { + #[inline] + fn miette_kind(&self) -> Boxed { + Boxed + } +} + +impl BoxedKind for Box {} + +impl Boxed { + #[cfg_attr(track_caller, track_caller)] + pub fn new(self, error: Box) -> 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 { +/// 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 { +/// 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>, +} + +unsafe impl Sync for Report {} +unsafe impl Send for Report {} + +/// +pub type ErrorHook = + Box Box + Sync + Send + 'static>; + +static HOOK: OnceCell = 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 { + 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 { + #[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(&self) -> bool { + // Get `TypeId` of the type this function is instantiated with. + let t = core::any::TypeId::of::(); + + // 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(&self) -> Option<&T> { + if self.is::() { + unsafe { Some(&*(self as *const dyn ReportHandler as *const T)) } + } else { + None + } + } + + /// + pub fn downcast_mut(&mut self) -> Option<&mut T> { + if self.is::() { + 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` +/// +/// 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 {...} +/// // ^ equivalent to std::result::Result +/// +/// fn demo2() -> Result {...} +/// // ^ equivalent to std::result::Result +/// # }; +/// ``` +/// +/// # Example +/// +/// ``` +/// # pub trait Deserialize {} +/// # +/// # mod serde_json { +/// # use super::Deserialize; +/// # use std::io; +/// # +/// # pub fn from_str(json: &str) -> io::Result { +/// # 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 = core::result::Result; + +/// 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> { +/// 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`. +/// +/// 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>) +/// -> 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>) -> 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::() { +/// // 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::() { +/// // 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: context::private::Sealed { + /// Wrap the error value with a new adhoc error + #[cfg_attr(track_caller, track_caller)] + fn wrap_err(self, msg: D) -> Result + 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(self, f: F) -> Result + 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(self, msg: D) -> Result + 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(self, f: F) -> Result + 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(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 +where + T: ?Sized, +{ + pub(crate) ptr: NonNull, +} + +unsafe impl Send for Own where T: ?Sized {} +unsafe impl Sync for Own where T: ?Sized {} + +impl Copy for Own where T: ?Sized {} + +impl Clone for Own +where + T: ?Sized, +{ + fn clone(&self) -> Self { + *self + } +} + +impl Own +where + T: ?Sized, +{ + pub(crate) fn new(ptr: Box) -> Self { + Own { + ptr: unsafe { NonNull::new_unchecked(Box::into_raw(ptr)) }, + } + } + + pub(crate) fn cast(self) -> Own { + Own { + ptr: self.ptr.cast(), + } + } + + pub(crate) unsafe fn boxed(self) -> Box { + 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, + 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) -> Self { + Ref { + ptr, + lifetime: PhantomData, + } + } + + pub(crate) fn cast(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, + 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(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 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(pub(crate) M); + +#[repr(transparent)] +pub(crate) struct MessageError(pub(crate) M); + +pub(crate) struct NoneError; + +impl Debug for DisplayError +where + M: Display, +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + Display::fmt(&self.0, f) + } +} + +impl Display for DisplayError +where + M: Display, +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + Display::fmt(&self.0, f) + } +} + +impl StdError for DisplayError where M: Display + 'static {} +impl Diagnostic for DisplayError where M: Display + 'static {} + +impl Debug for MessageError +where + M: Display + Debug, +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + Debug::fmt(&self.0, f) + } +} + +impl Display for MessageError +where + M: Display + Debug, +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + Display::fmt(&self.0, f) + } +} + +impl StdError for MessageError where M: Display + Debug + 'static {} +impl Diagnostic for MessageError 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); + +impl Diagnostic for BoxedError { + fn code<'a>(&'a self) -> Option> { + self.0.code() + } + + fn severity(&self) -> Option { + self.0.severity() + } + + fn help<'a>(&'a self) -> Option> { + self.0.help() + } + + fn url<'a>(&'a self) -> Option> { + self.0.url() + } + + fn labels<'a>(&'a self) -> Option + 'a>> { + self.0.labels() + } + + fn source_code(&self) -> Option<&dyn miette::SourceCode> { + self.0.source_code() + } + + fn related<'a>(&'a self) -> Option + '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 { + pub(crate) error: E, + pub(crate) source_code: C, +} + +impl Diagnostic for WithSourceCode { + fn code<'a>(&'a self) -> Option> { + self.error.code() + } + + fn severity(&self) -> Option { + self.error.severity() + } + + fn help<'a>(&'a self) -> Option> { + self.error.help() + } + + fn url<'a>(&'a self) -> Option> { + self.error.url() + } + + fn labels<'a>(&'a self) -> Option + 'a>> { + self.error.labels() + } + + fn source_code(&self) -> Option<&dyn miette::SourceCode> { + Some(&self.source_code) + } + + fn related<'a>(&'a self) -> Option + 'a>> { + self.error.related() + } + + fn diagnostic_source(&self) -> Option<&dyn Diagnostic> { + self.error.diagnostic_source() + } +} + +impl Diagnostic for WithSourceCode { + fn code<'a>(&'a self) -> Option> { + self.error.code() + } + + fn severity(&self) -> Option { + self.error.severity() + } + + fn help<'a>(&'a self) -> Option> { + self.error.help() + } + + fn url<'a>(&'a self) -> Option> { + self.error.url() + } + + fn labels<'a>(&'a self) -> Option + 'a>> { + self.error.labels() + } + + fn source_code(&self) -> Option<&dyn miette::SourceCode> { + Some(&self.source_code) + } + + fn related<'a>(&'a self) -> Option + 'a>> { + self.error.related() + } + + fn diagnostic_source(&self) -> Option<&dyn Diagnostic> { + self.error.diagnostic_source() + } +} + +impl Debug for WithSourceCode { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + Debug::fmt(&self.error, f) + } +} + +impl Display for WithSourceCode { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + Display::fmt(&self.error, f) + } +} + +impl StdError for WithSourceCode { + fn source(&self) -> Option<&(dyn StdError + 'static)> { + self.error.source() + } +} + +impl StdError for WithSourceCode { + fn source(&self) -> Option<&(dyn StdError + 'static)> { + self.error.source() + } +} -- cgit v1.2.3