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