1*5afb6030SNick Fitzgerald use crate::error::{Error, ErrorExt, OutOfMemory, Result, boxed::try_new_uninit_box};
28325e1ecSAlex Crichton use core::any::TypeId;
38325e1ecSAlex Crichton use core::fmt;
48325e1ecSAlex Crichton use core::ptr::NonNull;
58325e1ecSAlex Crichton use std_alloc::boxed::Box;
68325e1ecSAlex Crichton 
78325e1ecSAlex Crichton mod sealed {
88325e1ecSAlex Crichton     use super::*;
98325e1ecSAlex Crichton     pub trait Sealed {}
108325e1ecSAlex Crichton     impl<T, E> Sealed for Result<T, E> {}
118325e1ecSAlex Crichton     impl<T> Sealed for Option<T> {}
128325e1ecSAlex Crichton }
138325e1ecSAlex Crichton 
148325e1ecSAlex Crichton /// Extension trait to add error context to results.
158325e1ecSAlex Crichton ///
168325e1ecSAlex Crichton /// This extension trait, and its methods, are the primary way to create error
178325e1ecSAlex Crichton /// chains. An error's debug output will include the full chain of
188325e1ecSAlex Crichton /// errors. Errors in these chains are accessible via the
19bc4582c3SAlex Crichton /// [`Error::chain`] and [`Error::root_cause`] methods.
208325e1ecSAlex Crichton ///
218325e1ecSAlex Crichton /// After applying error context of type `C`, calling
22bc4582c3SAlex Crichton /// [`error.is::<C>()`](Error::is) will return `true` for the new error
238325e1ecSAlex Crichton /// (unless there was a memory allocation failure) in addition to any other
248325e1ecSAlex Crichton /// types `T` for which it was already the case that `error.is::<T>()`.
258325e1ecSAlex Crichton ///
268325e1ecSAlex Crichton /// This boxes the inner `C` type, but if that box allocation fails, then this
278325e1ecSAlex Crichton /// trait's functions return an `Error` where
28bc4582c3SAlex Crichton /// [`error.is::<OutOfMemory>()`](OutOfMemory) is true.
298325e1ecSAlex Crichton ///
308325e1ecSAlex Crichton /// # Example
318325e1ecSAlex Crichton ///
328325e1ecSAlex Crichton /// ```
338325e1ecSAlex Crichton /// # use wasmtime_internal_core::error as wasmtime;
348325e1ecSAlex Crichton /// use wasmtime::{Context as _, Result};
358325e1ecSAlex Crichton /// # #[cfg(feature = "backtrace")]
368325e1ecSAlex Crichton /// # wasmtime_internal_core::error::disable_backtrace();
378325e1ecSAlex Crichton ///
388325e1ecSAlex Crichton /// fn u32_to_u8(x: u32) -> Result<u8> {
398325e1ecSAlex Crichton ///     let y = u8::try_from(x).with_context(|| {
408325e1ecSAlex Crichton ///         format!("failed to convert `{x}` into a `u8` (max = `{}`)", u8::MAX)
418325e1ecSAlex Crichton ///     })?;
428325e1ecSAlex Crichton ///     Ok(y)
438325e1ecSAlex Crichton /// }
448325e1ecSAlex Crichton ///
458325e1ecSAlex Crichton /// let x = u32_to_u8(42).unwrap();
468325e1ecSAlex Crichton /// assert_eq!(x, 42);
478325e1ecSAlex Crichton ///
488325e1ecSAlex Crichton /// let error = u32_to_u8(999).unwrap_err();
498325e1ecSAlex Crichton ///
508325e1ecSAlex Crichton /// // The error is a `String` because of our added context.
518325e1ecSAlex Crichton /// assert!(error.is::<String>());
528325e1ecSAlex Crichton /// assert_eq!(
538325e1ecSAlex Crichton ///     error.to_string(),
548325e1ecSAlex Crichton ///     "failed to convert `999` into a `u8` (max = `255`)",
558325e1ecSAlex Crichton /// );
568325e1ecSAlex Crichton ///
578325e1ecSAlex Crichton /// // But it is also a `TryFromIntError` because of the inner error.
588325e1ecSAlex Crichton /// assert!(error.is::<std::num::TryFromIntError>());
598325e1ecSAlex Crichton /// assert_eq!(
608325e1ecSAlex Crichton ///     error.root_cause().to_string(),
618325e1ecSAlex Crichton ///     "out of range integral type conversion attempted",
628325e1ecSAlex Crichton /// );
638325e1ecSAlex Crichton ///
648325e1ecSAlex Crichton /// // The debug output of the error contains the full error chain.
658325e1ecSAlex Crichton /// assert_eq!(
668325e1ecSAlex Crichton ///     format!("{error:?}").trim(),
678325e1ecSAlex Crichton ///     r#"
688325e1ecSAlex Crichton /// failed to convert `999` into a `u8` (max = `255`)
698325e1ecSAlex Crichton ///
708325e1ecSAlex Crichton /// Caused by:
718325e1ecSAlex Crichton ///     out of range integral type conversion attempted
728325e1ecSAlex Crichton ///     "#.trim(),
738325e1ecSAlex Crichton /// );
748325e1ecSAlex Crichton /// ```
758325e1ecSAlex Crichton ///
768325e1ecSAlex Crichton /// # Example with `Option<T>`
778325e1ecSAlex Crichton ///
788325e1ecSAlex Crichton /// You can also use this trait to create the initial, root-cause `Error` when a
798325e1ecSAlex Crichton /// fallible function returns an `Option`:
808325e1ecSAlex Crichton ///
818325e1ecSAlex Crichton /// ```
828325e1ecSAlex Crichton /// # use wasmtime_internal_core as wasmtime;
838325e1ecSAlex Crichton /// use wasmtime::error::{Context as _, Result};
848325e1ecSAlex Crichton ///
858325e1ecSAlex Crichton /// fn try_get<T>(slice: &[T], i: usize) -> Result<&T> {
868325e1ecSAlex Crichton ///     let elem: Option<&T> = slice.get(i);
878325e1ecSAlex Crichton ///     elem.with_context(|| {
888325e1ecSAlex Crichton ///         format!("out of bounds access: index is {i} but length is {}", slice.len())
898325e1ecSAlex Crichton ///     })
908325e1ecSAlex Crichton /// }
918325e1ecSAlex Crichton ///
928325e1ecSAlex Crichton /// let arr = [921, 36, 123, 42, 785];
938325e1ecSAlex Crichton ///
948325e1ecSAlex Crichton /// let x = try_get(&arr, 2).unwrap();
958325e1ecSAlex Crichton /// assert_eq!(*x, 123);
968325e1ecSAlex Crichton ///
978325e1ecSAlex Crichton /// let error = try_get(&arr, 9999).unwrap_err();
988325e1ecSAlex Crichton /// assert_eq!(
998325e1ecSAlex Crichton ///     error.to_string(),
1008325e1ecSAlex Crichton ///     "out of bounds access: index is 9999 but length is 5",
1018325e1ecSAlex Crichton /// );
1028325e1ecSAlex Crichton /// ```
1038325e1ecSAlex Crichton pub trait Context<T, E>: sealed::Sealed {
1048325e1ecSAlex Crichton     /// Add additional, already-computed error context to this result.
1058325e1ecSAlex Crichton     ///
1068325e1ecSAlex Crichton     /// Because this method requires that the error context is already computed,
1078325e1ecSAlex Crichton     /// it should only be used when the `context` is already available or is
1088325e1ecSAlex Crichton     /// effectively a constant. Otherwise, it effectively forces computation of
1098325e1ecSAlex Crichton     /// the context, even when we aren't on an error path. The
110bc4582c3SAlex Crichton     /// [`Context::with_context`](Context::with_context) method is
1118325e1ecSAlex Crichton     /// preferred in these scenarios, as it lazily computes the error context,
1128325e1ecSAlex Crichton     /// only doing so when we are actually on an error path.
context<C>(self, context: C) -> Result<T, Error> where C: fmt::Display + Send + Sync + 'static1138325e1ecSAlex Crichton     fn context<C>(self, context: C) -> Result<T, Error>
1148325e1ecSAlex Crichton     where
1158325e1ecSAlex Crichton         C: fmt::Display + Send + Sync + 'static;
1168325e1ecSAlex Crichton 
1178325e1ecSAlex Crichton     /// Add additional, lazily-computed error context to this result.
1188325e1ecSAlex Crichton     ///
1198325e1ecSAlex Crichton     /// Only invokes `f` to compute the error context when we are actually on an
1208325e1ecSAlex Crichton     /// error path. Does not invoke `f` if we are not on an error path.
with_context<C, F>(self, f: F) -> Result<T, Error> where C: fmt::Display + Send + Sync + 'static, F: FnOnce() -> C1218325e1ecSAlex Crichton     fn with_context<C, F>(self, f: F) -> Result<T, Error>
1228325e1ecSAlex Crichton     where
1238325e1ecSAlex Crichton         C: fmt::Display + Send + Sync + 'static,
1248325e1ecSAlex Crichton         F: FnOnce() -> C;
1258325e1ecSAlex Crichton }
1268325e1ecSAlex Crichton 
1278325e1ecSAlex Crichton impl<T, E> Context<T, E> for Result<T, E>
1288325e1ecSAlex Crichton where
1298325e1ecSAlex Crichton     E: core::error::Error + Send + Sync + 'static,
1308325e1ecSAlex Crichton {
1318325e1ecSAlex Crichton     #[inline]
context<C>(self, context: C) -> Result<T> where C: fmt::Display + Send + Sync + 'static,1328325e1ecSAlex Crichton     fn context<C>(self, context: C) -> Result<T>
1338325e1ecSAlex Crichton     where
1348325e1ecSAlex Crichton         C: fmt::Display + Send + Sync + 'static,
1358325e1ecSAlex Crichton     {
1368325e1ecSAlex Crichton         match self {
1378325e1ecSAlex Crichton             Ok(x) => Ok(x),
1388325e1ecSAlex Crichton             Err(e) => Err(Error::new(e).context(context)),
1398325e1ecSAlex Crichton         }
1408325e1ecSAlex Crichton     }
1418325e1ecSAlex Crichton 
1428325e1ecSAlex Crichton     #[inline]
with_context<C, F>(self, f: F) -> Result<T> where C: fmt::Display + Send + Sync + 'static, F: FnOnce() -> C,1438325e1ecSAlex Crichton     fn with_context<C, F>(self, f: F) -> Result<T>
1448325e1ecSAlex Crichton     where
1458325e1ecSAlex Crichton         C: fmt::Display + Send + Sync + 'static,
1468325e1ecSAlex Crichton         F: FnOnce() -> C,
1478325e1ecSAlex Crichton     {
1488325e1ecSAlex Crichton         match self {
1498325e1ecSAlex Crichton             Ok(x) => Ok(x),
1508325e1ecSAlex Crichton             Err(e) => Err(Error::new(e).context(f())),
1518325e1ecSAlex Crichton         }
1528325e1ecSAlex Crichton     }
1538325e1ecSAlex Crichton }
1548325e1ecSAlex Crichton 
1558325e1ecSAlex Crichton impl<T> Context<T, Error> for Result<T> {
context<C>(self, context: C) -> Result<T, Error> where C: fmt::Display + Send + Sync + 'static,1568325e1ecSAlex Crichton     fn context<C>(self, context: C) -> Result<T, Error>
1578325e1ecSAlex Crichton     where
1588325e1ecSAlex Crichton         C: fmt::Display + Send + Sync + 'static,
1598325e1ecSAlex Crichton     {
1608325e1ecSAlex Crichton         match self {
1618325e1ecSAlex Crichton             Ok(x) => Ok(x),
1628325e1ecSAlex Crichton             Err(e) => Err(e.context(context)),
1638325e1ecSAlex Crichton         }
1648325e1ecSAlex Crichton     }
1658325e1ecSAlex Crichton 
with_context<C, F>(self, f: F) -> Result<T, Error> where C: fmt::Display + Send + Sync + 'static, F: FnOnce() -> C,1668325e1ecSAlex Crichton     fn with_context<C, F>(self, f: F) -> Result<T, Error>
1678325e1ecSAlex Crichton     where
1688325e1ecSAlex Crichton         C: fmt::Display + Send + Sync + 'static,
1698325e1ecSAlex Crichton         F: FnOnce() -> C,
1708325e1ecSAlex Crichton     {
1718325e1ecSAlex Crichton         match self {
1728325e1ecSAlex Crichton             Ok(x) => Ok(x),
1738325e1ecSAlex Crichton             Err(e) => Err(e.context(f())),
1748325e1ecSAlex Crichton         }
1758325e1ecSAlex Crichton     }
1768325e1ecSAlex Crichton }
1778325e1ecSAlex Crichton 
1788325e1ecSAlex Crichton impl<T> Context<T, core::convert::Infallible> for Option<T> {
context<C>(self, context: C) -> Result<T> where C: fmt::Display + Send + Sync + 'static,1798325e1ecSAlex Crichton     fn context<C>(self, context: C) -> Result<T>
1808325e1ecSAlex Crichton     where
1818325e1ecSAlex Crichton         C: fmt::Display + Send + Sync + 'static,
1828325e1ecSAlex Crichton     {
1838325e1ecSAlex Crichton         match self {
1848325e1ecSAlex Crichton             Some(x) => Ok(x),
1858325e1ecSAlex Crichton             None => Err(Error::from_error_ext(ContextError {
1868325e1ecSAlex Crichton                 context,
1878325e1ecSAlex Crichton                 error: None,
1888325e1ecSAlex Crichton             })),
1898325e1ecSAlex Crichton         }
1908325e1ecSAlex Crichton     }
1918325e1ecSAlex Crichton 
with_context<C, F>(self, f: F) -> Result<T> where C: fmt::Display + Send + Sync + 'static, F: FnOnce() -> C,1928325e1ecSAlex Crichton     fn with_context<C, F>(self, f: F) -> Result<T>
1938325e1ecSAlex Crichton     where
1948325e1ecSAlex Crichton         C: fmt::Display + Send + Sync + 'static,
1958325e1ecSAlex Crichton         F: FnOnce() -> C,
1968325e1ecSAlex Crichton     {
1978325e1ecSAlex Crichton         match self {
1988325e1ecSAlex Crichton             Some(x) => Ok(x),
1998325e1ecSAlex Crichton             None => Err(Error::from_error_ext(ContextError {
2008325e1ecSAlex Crichton                 context: f(),
2018325e1ecSAlex Crichton                 error: None,
2028325e1ecSAlex Crichton             })),
2038325e1ecSAlex Crichton         }
2048325e1ecSAlex Crichton     }
2058325e1ecSAlex Crichton }
2068325e1ecSAlex Crichton 
2078325e1ecSAlex Crichton // NB: The `repr(C)` is required for safety of the `ErrorExt::ext_is`
2088325e1ecSAlex Crichton // implementation and the casts that are performed using that method's
2098325e1ecSAlex Crichton // return value.
2108325e1ecSAlex Crichton #[repr(C)]
2118325e1ecSAlex Crichton pub(crate) struct ContextError<C> {
2128325e1ecSAlex Crichton     // NB: This must be the first field for safety of the `ErrorExt::ext_is`
2138325e1ecSAlex Crichton     // implementation and the casts that are performed using that method's
2148325e1ecSAlex Crichton     // return value.
2158325e1ecSAlex Crichton     pub(crate) context: C,
2168325e1ecSAlex Crichton 
2178325e1ecSAlex Crichton     pub(crate) error: Option<Error>,
2188325e1ecSAlex Crichton }
2198325e1ecSAlex Crichton 
2208325e1ecSAlex Crichton impl<C> fmt::Debug for ContextError<C>
2218325e1ecSAlex Crichton where
2228325e1ecSAlex Crichton     C: fmt::Display,
2238325e1ecSAlex Crichton {
fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result2248325e1ecSAlex Crichton     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2258325e1ecSAlex Crichton         fmt::Display::fmt(self, f)
2268325e1ecSAlex Crichton     }
2278325e1ecSAlex Crichton }
2288325e1ecSAlex Crichton 
2298325e1ecSAlex Crichton impl<C> fmt::Display for ContextError<C>
2308325e1ecSAlex Crichton where
2318325e1ecSAlex Crichton     C: fmt::Display,
2328325e1ecSAlex Crichton {
fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result2338325e1ecSAlex Crichton     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2348325e1ecSAlex Crichton         self.context.fmt(f)
2358325e1ecSAlex Crichton     }
2368325e1ecSAlex Crichton }
2378325e1ecSAlex Crichton 
2388325e1ecSAlex Crichton impl<C> core::error::Error for ContextError<C>
2398325e1ecSAlex Crichton where
2408325e1ecSAlex Crichton     C: fmt::Display + Send + Sync + 'static,
2418325e1ecSAlex Crichton {
source(&self) -> Option<&(dyn core::error::Error + 'static)>2428325e1ecSAlex Crichton     fn source(&self) -> Option<&(dyn core::error::Error + 'static)> {
2438325e1ecSAlex Crichton         let source = self.ext_source()?;
244*5afb6030SNick Fitzgerald         Some(source.inner.as_dyn_core_error())
2458325e1ecSAlex Crichton     }
2468325e1ecSAlex Crichton }
2478325e1ecSAlex Crichton 
2488325e1ecSAlex Crichton unsafe impl<C> ErrorExt for ContextError<C>
2498325e1ecSAlex Crichton where
2508325e1ecSAlex Crichton     C: fmt::Display + Send + Sync + 'static,
2518325e1ecSAlex Crichton {
ext_as_dyn_core_error(&self) -> &(dyn core::error::Error + Send + Sync + 'static)2528325e1ecSAlex Crichton     fn ext_as_dyn_core_error(&self) -> &(dyn core::error::Error + Send + Sync + 'static) {
2538325e1ecSAlex Crichton         self
2548325e1ecSAlex Crichton     }
2558325e1ecSAlex Crichton 
ext_into_boxed_dyn_core_error( self, ) -> Result<Box<dyn core::error::Error + Send + Sync + 'static>, OutOfMemory>2568325e1ecSAlex Crichton     fn ext_into_boxed_dyn_core_error(
2578325e1ecSAlex Crichton         self,
2588325e1ecSAlex Crichton     ) -> Result<Box<dyn core::error::Error + Send + Sync + 'static>, OutOfMemory> {
2598325e1ecSAlex Crichton         let boxed = try_new_uninit_box()?;
2608325e1ecSAlex Crichton         Ok(Box::write(boxed, self) as _)
2618325e1ecSAlex Crichton     }
2628325e1ecSAlex Crichton 
ext_source(&self) -> Option<&Error>263*5afb6030SNick Fitzgerald     fn ext_source(&self) -> Option<&Error> {
264*5afb6030SNick Fitzgerald         self.error.as_ref()
2658325e1ecSAlex Crichton     }
2668325e1ecSAlex Crichton 
ext_source_mut(&mut self) -> Option<&mut Error>267*5afb6030SNick Fitzgerald     fn ext_source_mut(&mut self) -> Option<&mut Error> {
268*5afb6030SNick Fitzgerald         self.error.as_mut()
2698325e1ecSAlex Crichton     }
2708325e1ecSAlex Crichton 
ext_is(&self, type_id: TypeId) -> bool2718325e1ecSAlex Crichton     fn ext_is(&self, type_id: TypeId) -> bool {
2728325e1ecSAlex Crichton         // NB: need to check type id of `C`, not `Self` aka
2738325e1ecSAlex Crichton         // `ContextError<C>`.
2748325e1ecSAlex Crichton         type_id == TypeId::of::<C>()
2758325e1ecSAlex Crichton     }
2768325e1ecSAlex Crichton 
ext_move(self, to: NonNull<u8>)2778325e1ecSAlex Crichton     unsafe fn ext_move(self, to: NonNull<u8>) {
2788325e1ecSAlex Crichton         // Safety: implied by this trait method's contract.
2798325e1ecSAlex Crichton         unsafe {
2808325e1ecSAlex Crichton             to.cast::<C>().write(self.context);
2818325e1ecSAlex Crichton         }
2828325e1ecSAlex Crichton     }
2838325e1ecSAlex Crichton 
2848325e1ecSAlex Crichton     #[cfg(feature = "backtrace")]
take_backtrace(&mut self) -> Option<std::backtrace::Backtrace>2858325e1ecSAlex Crichton     fn take_backtrace(&mut self) -> Option<std::backtrace::Backtrace> {
286*5afb6030SNick Fitzgerald         self.error.as_mut()?.take_backtrace()
2878325e1ecSAlex Crichton     }
2884fd25c07SAlex Crichton 
2894fd25c07SAlex Crichton     #[cfg(feature = "anyhow")]
ext_into_anyhow(mut self) -> anyhow::Error2904fd25c07SAlex Crichton     fn ext_into_anyhow(mut self) -> anyhow::Error {
2914fd25c07SAlex Crichton         match self.error.take() {
2924fd25c07SAlex Crichton             Some(error) => anyhow::Error::from(error).context(self.context),
2934fd25c07SAlex Crichton             None => anyhow::Error::msg(self),
2944fd25c07SAlex Crichton         }
2954fd25c07SAlex Crichton     }
2968325e1ecSAlex Crichton }
297