diff --git a/library/std/src/error.rs b/library/std/src/error.rs index 87f213b1608..3d7d8191770 100644 --- a/library/std/src/error.rs +++ b/library/std/src/error.rs @@ -156,7 +156,7 @@ use core::array; use core::convert::Infallible; use crate::alloc::{AllocError, LayoutError}; -use crate::any::TypeId; +use crate::any::{Demand, Provider, TypeId}; use crate::backtrace::Backtrace; use crate::borrow::Cow; use crate::cell; @@ -295,6 +295,84 @@ pub trait Error: Debug + Display { fn cause(&self) -> Option<&dyn Error> { self.source() } + + /// Provides type based access to context intended for error reports. + /// + /// Used in conjunction with [`context`] and [`context_ref`] to extract + /// references to member variables from `dyn Error` trait objects. + /// + /// # Example + /// + /// ```rust + /// #![feature(provide_any)] + /// #![feature(error_in_core)] + /// use core::fmt; + /// use core::any::Demand; + /// + /// #[derive(Debug)] + /// struct MyBacktrace { + /// // ... + /// } + /// + /// impl MyBacktrace { + /// fn new() -> MyBacktrace { + /// // ... + /// # MyBacktrace {} + /// } + /// } + /// + /// #[derive(Debug)] + /// struct SourceError { + /// // ... + /// } + /// + /// impl fmt::Display for SourceError { + /// fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + /// write!(f, "Example Source Error") + /// } + /// } + /// + /// impl std::error::Error for SourceError {} + /// + /// #[derive(Debug)] + /// struct Error { + /// source: SourceError, + /// backtrace: MyBacktrace, + /// } + /// + /// impl fmt::Display for Error { + /// fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + /// write!(f, "Example Error") + /// } + /// } + /// + /// impl std::error::Error for Error { + /// fn provide<'a>(&'a self, req: &mut Demand<'a>) { + /// req + /// .provide_ref::(&self.backtrace) + /// .provide_ref::(&self.source); + /// } + /// } + /// + /// fn main() { + /// let backtrace = MyBacktrace::new(); + /// let source = SourceError {}; + /// let error = Error { source, backtrace }; + /// let dyn_error = &error as &dyn std::error::Error; + /// let backtrace_ref = dyn_error.request_ref::().unwrap(); + /// + /// assert!(core::ptr::eq(&error.backtrace, backtrace_ref)); + /// } + /// ``` + #[unstable(feature = "generic_member_access", issue = "none")] + fn provide<'a>(&'a self, _req: &mut Demand<'a>) {} +} + +#[unstable(feature = "generic_member_access", issue = "none")] +impl Provider for dyn Error + 'static { + fn provide<'a>(&'a self, req: &mut Demand<'a>) { + self.provide(req) + } } mod private { @@ -831,6 +909,18 @@ impl dyn Error + 'static { None } } + + /// Request a reference to context of type `T`. + #[unstable(feature = "generic_member_access", issue = "none")] + pub fn request_ref(&self) -> Option<&T> { + core::any::request_ref(self) + } + + /// Request a value to context of type `T`. + #[unstable(feature = "generic_member_access", issue = "none")] + pub fn request_value(&self) -> Option { + core::any::request_value(self) + } } impl dyn Error + 'static + Send { @@ -854,6 +944,18 @@ impl dyn Error + 'static + Send { pub fn downcast_mut(&mut self) -> Option<&mut T> { ::downcast_mut::(self) } + + /// Request a reference to context of type `T`. + #[unstable(feature = "generic_member_access", issue = "none")] + pub fn request_ref(&self) -> Option<&T> { + ::request_ref(self) + } + + /// Request a value to context of type `T`. + #[unstable(feature = "generic_member_access", issue = "none")] + pub fn request_value(&self) -> Option { + ::request_value(self) + } } impl dyn Error + 'static + Send + Sync { @@ -877,6 +979,18 @@ impl dyn Error + 'static + Send + Sync { pub fn downcast_mut(&mut self) -> Option<&mut T> { ::downcast_mut::(self) } + + /// Request a reference to context of type `T`. + #[unstable(feature = "generic_member_access", issue = "none")] + pub fn request_ref(&self) -> Option<&T> { + ::request_ref(self) + } + + /// Request a value to context of type `T`. + #[unstable(feature = "generic_member_access", issue = "none")] + pub fn request_value(&self) -> Option { + ::request_value(self) + } } impl dyn Error { diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs index 7da9f248c87..c46752cc6f9 100644 --- a/library/std/src/lib.rs +++ b/library/std/src/lib.rs @@ -284,6 +284,7 @@ #![feature(panic_internals)] #![feature(portable_simd)] #![feature(prelude_2024)] +#![feature(provide_any)] #![feature(ptr_as_uninit)] #![feature(raw_os_nonzero)] #![feature(slice_internals)]