oopsie_core/
diagnostic.rs1use std::sync::Arc;
4
5use crate::{Backtrace, ErrorCode, HelpText, SpanTrace};
6
7pub trait Diagnostic: std::error::Error {
13 #[inline]
15 fn oopsie_backtrace(&self) -> Option<&Backtrace> {
16 None
17 }
18
19 #[inline]
21 fn oopsie_spantrace(&self) -> Option<&SpanTrace> {
22 None
23 }
24
25 #[inline]
27 fn oopsie_location(&self) -> Option<&'static std::panic::Location<'static>> {
28 None
29 }
30
31 #[inline]
33 fn oopsie_error_code(&self) -> Option<ErrorCode> {
34 None
35 }
36
37 #[inline]
39 fn oopsie_help_text(&self) -> Option<HelpText> {
40 None
41 }
42
43 #[inline]
50 fn oopsie_exit_code(&self) -> Option<core::num::NonZeroU8> {
51 None
52 }
53}
54
55impl<T: Diagnostic> Diagnostic for Box<T> {
56 #[inline]
57 fn oopsie_backtrace(&self) -> Option<&Backtrace> {
58 (**self).oopsie_backtrace()
59 }
60
61 #[inline]
62 fn oopsie_spantrace(&self) -> Option<&SpanTrace> {
63 (**self).oopsie_spantrace()
64 }
65
66 #[inline]
67 fn oopsie_location(&self) -> Option<&'static std::panic::Location<'static>> {
68 (**self).oopsie_location()
69 }
70
71 #[inline]
72 fn oopsie_error_code(&self) -> Option<ErrorCode> {
73 (**self).oopsie_error_code()
74 }
75
76 #[inline]
77 fn oopsie_help_text(&self) -> Option<HelpText> {
78 (**self).oopsie_help_text()
79 }
80
81 #[inline]
82 fn oopsie_exit_code(&self) -> Option<core::num::NonZeroU8> {
83 (**self).oopsie_exit_code()
84 }
85}
86
87impl<T: Diagnostic> Diagnostic for Arc<T> {
91 #[inline]
92 fn oopsie_backtrace(&self) -> Option<&Backtrace> {
93 (**self).oopsie_backtrace()
94 }
95
96 #[inline]
97 fn oopsie_spantrace(&self) -> Option<&SpanTrace> {
98 (**self).oopsie_spantrace()
99 }
100
101 #[inline]
102 fn oopsie_location(&self) -> Option<&'static std::panic::Location<'static>> {
103 (**self).oopsie_location()
104 }
105
106 #[inline]
107 fn oopsie_error_code(&self) -> Option<ErrorCode> {
108 (**self).oopsie_error_code()
109 }
110
111 #[inline]
112 fn oopsie_help_text(&self) -> Option<HelpText> {
113 (**self).oopsie_help_text()
114 }
115
116 #[inline]
117 fn oopsie_exit_code(&self) -> Option<core::num::NonZeroU8> {
118 (**self).oopsie_exit_code()
119 }
120}
121
122#[cfg(test)]
123mod tests {
124 use super::*;
125 use crate::Capturable;
126 use std::fmt;
127
128 #[derive(Debug)]
129 struct Src {
130 backtrace: Backtrace,
131 spantrace: SpanTrace,
132 }
133
134 impl fmt::Display for Src {
135 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
136 f.write_str("src")
137 }
138 }
139
140 impl std::error::Error for Src {}
141
142 impl Diagnostic for Src {
143 fn oopsie_backtrace(&self) -> Option<&Backtrace> {
144 Some(&self.backtrace)
145 }
146
147 fn oopsie_spantrace(&self) -> Option<&SpanTrace> {
148 Some(&self.spantrace)
149 }
150 }
151
152 #[test]
153 fn box_delegates_diagnostic_accessors() {
154 let src = Src {
155 backtrace: Backtrace::capture(),
156 spantrace: SpanTrace::capture(),
157 };
158 let boxed = Box::new(src);
159 assert!(boxed.oopsie_backtrace().is_some());
160 assert!(boxed.oopsie_spantrace().is_some());
161 }
162
163 #[test]
164 fn box_diagnostic_extraction_reuses_source_frames() {
165 use crate::{RustBacktrace, with_rust_backtrace_override};
166
167 with_rust_backtrace_override(RustBacktrace::Enabled, || {
168 let src = Src {
169 backtrace: Backtrace::capture(),
170 spantrace: SpanTrace::capture(),
171 };
172 let expected_frames = src.backtrace.frames().len();
173 assert!(
174 expected_frames > 0,
175 "backtrace must be enabled for this test to be probative"
176 );
177 let boxed = Box::new(src);
178 let extracted = <(Backtrace, SpanTrace) as Capturable>::capture_or_extract(&boxed);
179 assert_eq!(extracted.0.frames().len(), expected_frames);
180 });
181 }
182
183 #[test]
184 fn arc_delegates_diagnostic_accessors() {
185 let src = Src {
186 backtrace: Backtrace::capture(),
187 spantrace: SpanTrace::capture(),
188 };
189 let arced = Arc::new(src);
190 assert!(arced.oopsie_backtrace().is_some());
191 assert!(arced.oopsie_spantrace().is_some());
192 }
193
194 #[test]
195 fn arc_diagnostic_extraction_reuses_source_frames() {
196 use crate::{RustBacktrace, with_rust_backtrace_override};
197
198 with_rust_backtrace_override(RustBacktrace::Enabled, || {
199 let src = Src {
200 backtrace: Backtrace::capture(),
201 spantrace: SpanTrace::capture(),
202 };
203 let expected_frames = src.backtrace.frames().len();
204 assert!(
205 expected_frames > 0,
206 "backtrace must be enabled for this test to be probative"
207 );
208 let arced = Arc::new(src);
209 let extracted = <(Backtrace, SpanTrace) as Capturable>::capture_or_extract(&arced);
210 assert_eq!(extracted.0.frames().len(), expected_frames);
211 });
212 }
213}