1#![warn(missing_docs)]
4#![cfg_attr(
5 feature = "unstable-error-generic-member-access",
6 feature(error_generic_member_access)
7)]
8#![cfg_attr(
12 feature = "unstable-error-generic-member-access",
13 doc(test(attr(feature(error_generic_member_access))))
14)]
15
16mod backtrace;
17mod chain;
18mod diagnostic;
19#[cfg(feature = "serde")]
20pub mod erased;
21#[cfg(feature = "extras")]
22pub mod extras;
23mod marker;
24mod spantrace;
25#[cfg(feature = "test-utils")]
26pub mod test_utils;
27mod traits;
28mod welp;
29
30use std::borrow::{Borrow, Cow};
31use std::ops::Deref;
32
33pub use backtrace::{
34 Backtrace, RustBacktrace, clear_rust_backtrace_override, rust_backtrace, rust_panic_backtrace,
35 set_rust_backtrace_override, with_rust_backtrace_override,
36};
37pub use chain::{Chain, ErrorChainExt};
38pub use diagnostic::Diagnostic;
39#[doc(hidden)]
41pub mod __private {
42 pub use crate::backtrace::CORE_SRC_PATH;
43 pub struct CaptureProbe<'a, T: ?Sized>(pub &'a T);
50
51 pub trait CaptureFromExt {
53 fn resolve<C: crate::Capturable>(&self) -> C;
54 }
55
56 impl<T: crate::Diagnostic> CaptureFromExt for CaptureProbe<'_, T> {
57 #[inline]
58 #[track_caller]
59 fn resolve<C: crate::Capturable>(&self) -> C {
60 C::capture_or_extract(self.0)
61 }
62 }
63
64 pub trait CaptureFromFallback {
66 fn resolve<C: crate::Capturable>(&self) -> C;
67 }
68
69 impl<T: ?Sized> CaptureFromFallback for &CaptureProbe<'_, T> {
70 #[inline]
71 #[track_caller]
72 fn resolve<C: crate::Capturable>(&self) -> C {
73 C::capture()
74 }
75 }
76
77 pub struct DiagProbe<'a, T: ?Sized>(pub &'a T);
88
89 pub trait DiagForwardExt<'a> {
91 fn fwd_code(&self) -> Option<crate::ErrorCode>;
92 fn fwd_help(&self) -> Option<crate::HelpText>;
93 fn fwd_backtrace(&self) -> Option<&'a crate::Backtrace>;
94 fn fwd_spantrace(&self) -> Option<&'a crate::SpanTrace>;
95 fn fwd_location(&self) -> Option<&'static std::panic::Location<'static>>;
96 fn fwd_exit_code(&self) -> Option<core::num::NonZeroU8>;
97 }
98
99 impl<'a, T: crate::Diagnostic + ?Sized> DiagForwardExt<'a> for DiagProbe<'a, T> {
100 #[inline]
101 fn fwd_code(&self) -> Option<crate::ErrorCode> {
102 self.0.oopsie_error_code()
103 }
104 #[inline]
105 fn fwd_help(&self) -> Option<crate::HelpText> {
106 self.0.oopsie_help_text()
107 }
108 #[inline]
109 fn fwd_backtrace(&self) -> Option<&'a crate::Backtrace> {
110 self.0.oopsie_backtrace()
111 }
112 #[inline]
113 fn fwd_spantrace(&self) -> Option<&'a crate::SpanTrace> {
114 self.0.oopsie_spantrace()
115 }
116 #[inline]
117 fn fwd_location(&self) -> Option<&'static std::panic::Location<'static>> {
118 self.0.oopsie_location()
119 }
120 #[inline]
121 fn fwd_exit_code(&self) -> Option<core::num::NonZeroU8> {
122 self.0.oopsie_exit_code()
123 }
124 }
125
126 pub trait DiagForwardFallback<'a> {
128 #[inline]
129 fn fwd_code(&self) -> Option<crate::ErrorCode> {
130 None
131 }
132 #[inline]
133 fn fwd_help(&self) -> Option<crate::HelpText> {
134 None
135 }
136 #[inline]
137 fn fwd_backtrace(&self) -> Option<&'a crate::Backtrace> {
138 None
139 }
140 #[inline]
141 fn fwd_spantrace(&self) -> Option<&'a crate::SpanTrace> {
142 None
143 }
144 #[inline]
145 fn fwd_location(&self) -> Option<&'static std::panic::Location<'static>> {
146 None
147 }
148 #[inline]
149 fn fwd_exit_code(&self) -> Option<core::num::NonZeroU8> {
150 None
151 }
152 }
153
154 impl<'a, T: ?Sized> DiagForwardFallback<'a> for &DiagProbe<'a, T> {}
155
156 #[inline]
169 #[must_use]
170 pub fn source_trace<'a, T: 'static>(
171 source: &'a (dyn std::error::Error + 'static),
172 ) -> Option<&'a T> {
173 #[cfg(feature = "unstable-error-generic-member-access")]
174 {
175 core::error::request_ref::<T>(source)
176 }
177 #[cfg(not(feature = "unstable-error-generic-member-access"))]
178 {
179 let _ = source;
180 None
181 }
182 }
183
184 #[inline]
188 #[must_use]
189 pub fn source_backtrace<'a>(
190 source: &'a (dyn std::error::Error + 'static),
191 ) -> Option<&'a crate::Backtrace> {
192 source_trace::<crate::Backtrace>(source).filter(|bt| bt.is_captured())
193 }
194
195 #[inline]
197 #[must_use]
198 pub fn source_spantrace<'a>(
199 source: &'a (dyn std::error::Error + 'static),
200 ) -> Option<&'a crate::SpanTrace> {
201 source_trace::<crate::SpanTrace>(source).filter(|st| st.is_captured())
202 }
203
204 pub use crate::marker::{TraceMarker, restore_marker, set_marker};
205
206 #[inline]
210 #[must_use]
211 pub fn source_exit_code(
212 source: &(dyn std::error::Error + 'static),
213 ) -> Option<core::num::NonZeroU8> {
214 #[cfg(feature = "unstable-error-generic-member-access")]
215 {
216 core::error::request_value::<core::num::NonZeroU8>(source)
217 }
218 #[cfg(not(feature = "unstable-error-generic-member-access"))]
219 {
220 let _ = source;
221 None
222 }
223 }
224
225 #[inline]
229 #[must_use]
230 pub const fn nonzero_u8_unchecked(value: u8) -> core::num::NonZeroU8 {
231 match core::num::NonZeroU8::new(value) {
232 Some(n) => n,
233 None => panic!("exit code must be non-zero"),
234 }
235 }
236
237 #[cfg(feature = "chrono")]
238 pub use chrono;
239}
240
241pub use spantrace::{OptionalSpanTrace, SpanTrace};
242#[cfg(all(feature = "tracing", feature = "serde"))]
243use tracing_error::ErrorLayer;
244#[cfg(all(feature = "tracing", feature = "serde"))]
245use tracing_subscriber::fmt::format::JsonFields;
246#[cfg(all(feature = "tracing", feature = "serde"))]
247use tracing_subscriber::registry::LookupSpan;
248pub use traits::*;
249pub use welp::{Welp, WelpOptionExt, WelpResultExt};
250
251macro_rules! impl_string_newtypes {
252 ($($(#[$meta:meta])* $ident:ident,)* $(,)?) => { $(
253 #[derive(Clone, Debug, Hash, PartialEq, Eq, PartialOrd, Ord)]
254 #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
255 #[cfg_attr(feature = "serde", serde(transparent))]
256 #[repr(transparent)]
257 $(#[$meta])*
258 pub struct $ident(Cow<'static, str>);
259
260 impl $ident {
261 #[doc = concat!("Build a new `", stringify!($ident), "` from a `&'static str`.")]
262 #[must_use]
263 #[inline]
264 pub const fn from_static(s: &'static str) -> Self {
265 Self(Cow::Borrowed(s))
266 }
267
268 #[doc = concat!("Build a new `", stringify!($ident), "` from a `String`.")]
269 #[must_use]
270 #[inline]
271 pub const fn from_string(s: String) -> Self {
272 Self(Cow::Owned(s))
273 }
274
275 #[must_use]
277 #[inline]
278 pub const fn as_str(&self) -> &str {
279 match &self.0 {
280 Cow::Borrowed(s) => s,
281 Cow::Owned(s) => s.as_str(),
282 }
283 }
284
285 #[doc = concat!("Consume the `", stringify!($ident), "` and return the underlying `Cow`.")]
286 #[must_use]
287 #[inline]
288 pub fn into_inner(self) -> Cow<'static, str> {
289 self.0
290 }
291 }
292
293 impl Deref for $ident {
294 type Target = str;
295
296 #[inline]
297 fn deref(&self) -> &Self::Target {
298 self.as_str()
299 }
300 }
301
302 impl Borrow<str> for $ident {
303 #[inline]
304 fn borrow(&self) -> &str {
305 self.as_str()
306 }
307 }
308
309 impl From<&'static str> for $ident {
310 #[inline]
311 fn from(s: &'static str) -> Self {
312 Self::from_static(s)
313 }
314 }
315
316 impl From<String> for $ident {
317 #[inline]
318 fn from(s: String) -> Self {
319 Self::from_string(s)
320 }
321 }
322
323 impl std::fmt::Display for $ident {
324 #[inline]
325 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
326 self.0.fmt(f)
327 }
328 }
329
330 )* };
331}
332
333impl_string_newtypes!(
334 ErrorCode,
336 HelpText,
338);
339
340#[cfg(all(feature = "tracing", feature = "serde"))]
346#[inline]
347#[must_use]
348pub fn json_error_layer<S>() -> ErrorLayer<S, JsonFields>
349where
350 S: tracing::Subscriber + for<'span> LookupSpan<'span>,
351{
352 ErrorLayer::new(JsonFields::default())
353}