rootcause/report/owned.rs
1use core::{
2 any::{Any, TypeId},
3 marker::PhantomData,
4};
5
6use rootcause_internals::{
7 RawReport,
8 handlers::{ContextFormattingStyle, FormattingFunction},
9};
10
11use crate::{
12 ReportConversion, ReportIter, ReportMut, ReportRef,
13 handlers::{self, ContextHandler},
14 markers::{
15 self, Cloneable, Dynamic, Local, Mutable, ReportOwnershipMarker, SendSync, Uncloneable,
16 },
17 report::iter::DowncastIterator,
18 report_attachment::ReportAttachment,
19 report_attachments::ReportAttachments,
20 report_collection::ReportCollection,
21 util::ErrorNoSourceWrapper,
22};
23
24/// FIXME: Once rust-lang/rust#132922 gets resolved, we can make the `raw` field
25/// an unsafe field and remove this module.
26mod limit_field_access {
27 use core::marker::PhantomData;
28
29 use rootcause_internals::{RawReport, RawReportMut, RawReportRef};
30
31 use crate::markers::{self, Dynamic, Mutable, SendSync};
32
33 /// An error report that contains a context, child reports, and attachments.
34 ///
35 /// [`Report`] is the main type for creating and working with error reports
36 /// in this library. It can contain a root context (typically an error),
37 /// zero or more child reports, and zero or more attachments.
38 ///
39 /// # Type Parameters
40 ///
41 /// [`Report`] has three type parameters that control its behavior:
42 ///
43 /// - **Context (`C`)**: The type of the root error or context (defaults to
44 /// [`Dynamic`])
45 /// - **Ownership (`O`)**: Controls whether the report can be cloned
46 /// - [`Mutable`]: Unique ownership, can modify but cannot clone (default)
47 /// - [`Cloneable`]: Shared ownership via [`Arc`], can clone but cannot
48 /// modify root
49 /// - **Thread Safety (`T`)**: Controls whether the report can be sent
50 /// across threads
51 /// - [`SendSync`]: Can be sent across threads (default, requires all data
52 /// is [`Send`]+[`Sync`])
53 /// - [`Local`]: Cannot be sent across threads (allows non-thread-safe
54 /// data)
55 ///
56 /// # Common Usage
57 ///
58 /// The easiest way to create a [`Report`] is with the [`report!()`] macro:
59 ///
60 /// ```
61 /// # use rootcause::prelude::*;
62 /// let report: Report = report!("file missing");
63 /// println!("{report}");
64 /// ```
65 ///
66 /// You can add context and attachments using method chaining:
67 ///
68 /// ```
69 /// # use rootcause::prelude::*;
70 /// let report = report!("database query failed")
71 /// .context("failed to fetch user data")
72 /// .attach("user_id: 12345");
73 /// println!("{report}");
74 /// ```
75 ///
76 /// [`Arc`]: triomphe::Arc
77 /// [`Local`]: crate::markers::Local
78 /// [`Mutable`]: crate::markers::Mutable
79 /// [`Cloneable`]: crate::markers::Cloneable
80 /// [`SendSync`]: crate::markers::SendSync
81 /// [`report!()`]: crate::report!
82 #[repr(transparent)]
83 pub struct Report<
84 Context: ?Sized + 'static = Dynamic,
85 Ownership: 'static = Mutable,
86 ThreadSafety: 'static = SendSync,
87 > {
88 /// # Safety
89 ///
90 /// The following safety invariants are guaranteed to be upheld as long
91 /// as this struct exists:
92 ///
93 /// 1. `C` must either be a type bounded by `Sized`, or `Dynamic`.
94 /// 2. `O` must either be `Mutable` or `Cloneable`.
95 /// 3. `T` must either be `SendSync` or `Local`.
96 /// 4. If `C` is a `Sized` type: The context embedded in the report must
97 /// be of type `C`
98 /// 5. If `O = Mutable`: This is the unique owner of the report. More
99 /// specifically this means that the strong count of the underlying
100 /// `triomphe::Arc` is exactly 1.
101 /// 6. If `O = Cloneable`: All other references to this report are
102 /// compatible with shared ownership. Specifically there are no
103 /// references with an assumption that the strong_count is `1`.
104 /// 7. All references to any sub-reports of this report are compatible
105 /// with shared ownership. Specifically there are no references with
106 /// an assumption that the strong_count is `1`.
107 /// 8. If `T = SendSync`: All contexts and attachments in the report and
108 /// all sub-reports must be `Send+Sync`.
109 raw: RawReport,
110 _context: PhantomData<Context>,
111 _ownership: PhantomData<Ownership>,
112 _thread_safety: PhantomData<ThreadSafety>,
113 }
114
115 impl<C: ?Sized, O, T> Report<C, O, T> {
116 /// Creates a new [`Report`] from a [`RawReport`]
117 ///
118 /// # Safety
119 ///
120 /// The caller must ensure:
121 ///
122 /// 1. `C` must either be a type bounded by `Sized`, or `Dynamic`.
123 /// 2. `O` must either be `Mutable` or `Cloneable`.
124 /// 3. `T` must either be `SendSync` or `Local`.
125 /// 4. If `C` is a `Sized` type: The context embedded in the report must
126 /// be of type `C`
127 /// 5. If `O = Mutable`: This is the unique owner of the report. More
128 /// specifically this means that the strong count of the underlying
129 /// `triomphe::Arc` is exactly 1.
130 /// 6. If `O = Cloneable`: All other references to this report are
131 /// compatible with shared ownership. Specifically there are no
132 /// references with an assumption that the strong_count is `1`.
133 /// 7. All references to any sub-reports of this report are compatible
134 /// with shared ownership. Specifically there are no references with
135 /// an assumption that the strong_count is `1`.
136 /// 8. If `T = SendSync`: All contexts and attachments in the report and
137 /// all sub-reports must be `Send+Sync`.
138 #[must_use]
139 pub(crate) unsafe fn from_raw(raw: RawReport) -> Self {
140 // SAFETY: We must uphold the safety invariants of the raw field:
141 // 1. Guaranteed by the caller
142 // 2. Guaranteed by the caller
143 // 3. Guaranteed by the caller
144 // 4. Guaranteed by the caller
145 // 5. Guaranteed by the caller
146 // 6. Guaranteed by the caller
147 // 7. Guaranteed by the caller
148 // 8. Guaranteed by the caller
149 Self {
150 raw,
151 _context: PhantomData,
152 _ownership: PhantomData,
153 _thread_safety: PhantomData,
154 }
155 }
156
157 /// Consumes the [`Report`] and returns the inner [`RawReport`].
158 #[must_use]
159 pub(crate) fn into_raw(self) -> RawReport {
160 // SAFETY: We are destroying `self`, so we no longer
161 // need to uphold any safety invariants.
162 self.raw
163 }
164
165 /// Creates a lifetime-bound [`RawReportRef`] from the inner
166 /// [`RawReport`].
167 #[must_use]
168 pub(crate) fn as_raw_ref(&self) -> RawReportRef<'_> {
169 // SAFETY: We must uphold the safety invariants of the raw field:
170 // 1. Upheld as the type parameters do not change.
171 // 2. Upheld as the type parameters do not change.
172 // 3. Upheld as the type parameters do not change.
173 // 4. Trivially upheld, as no mutation occurs
174 // 5. The only way to break this would be to call `RawReportRef::clone_arc`, but
175 // that method has a `safety` requirement that the caller must ensure that no
176 // owners exist which are incompatible with shared ownership. Since `self` is
177 // incompatible with shared ownership when `O=Mutable`, this cannot happen.
178 // 6. Trivially upheld, as no mutation occurs
179 // 7. Upheld, as this does not create any such references.
180 // 8. Trivially upheld, as no mutation occurs
181 let raw = &self.raw;
182
183 raw.as_ref()
184 }
185 }
186
187 impl<C: ?Sized, T> Report<C, markers::Mutable, T> {
188 /// Creates a lifetime-bound [`RawReportMut`] from the inner
189 /// [`RawReport`].
190 ///
191 /// # Safety
192 ///
193 /// The caller must ensure:
194 ///
195 /// 1. If `T = SendSync`, no objects are added to the report through
196 /// this that are not `Send+Sync`
197 #[must_use]
198 pub(crate) unsafe fn as_raw_mut(&mut self) -> RawReportMut<'_> {
199 // SAFETY: We need to uphold the safety invariants of the raw field:
200 // 1. Upheld as the type parameters do not change.
201 // 2. Upheld as the type parameters do not change.
202 // 3. Upheld as the type parameters do not change.
203 // 4. While mutation of the context is possible through this reference, it is
204 // not possible to change the type of the context. Therefore this invariant
205 // is upheld.
206 // 5. The only way to break this would be to call `RawReportRef::clone_arc`, but
207 // that method has a `safety` requirement that the caller must ensure that no
208 // owners exist which are incompatible with shared ownership. Since `self` is
209 // the unique owner, this cannot happen.
210 // 6. `O = Mutable`, so this is trivially upheld.
211 // 7. Upheld, as this does not create any such references.
212 // 8. The caller guarantees that the current report is not modified in an
213 // incompatible way and it is not possible to mutate the sub-reports.
214 let raw = &mut self.raw;
215
216 // SAFETY:
217 // 1. This method is in an impl for `Report<C, Mutable, T>`, which means that we
218 // can invoke our own safety invariant to show that this is indeed the unique
219 // owner of the report.
220 unsafe { raw.as_mut() }
221 }
222 }
223}
224
225pub use limit_field_access::Report;
226
227impl<C: Sized, T> Report<C, Mutable, T> {
228 /// Creates a new [`Report`] with the given context.
229 ///
230 /// This method is generic over the thread safety marker `T`. The context
231 /// will use the [`handlers::Error`] handler for formatting.
232 ///
233 /// See also:
234 ///
235 /// - The [`report!()`] macro will also create a new [`Report`], but can
236 /// auto-detect the thread safety marker and handler.
237 /// - [`Report::new_sendsync`] and [`Report::new_local`] are more
238 /// restrictive variants of this function that might help avoid type
239 /// inference issues.
240 /// - [`Report::new_custom`] also allows you to manually specify the
241 /// handler.
242 ///
243 /// [`report!()`]: crate::report!
244 ///
245 /// # Examples
246 /// ```
247 /// # use rootcause::{prelude::*, markers::{SendSync, Mutable, Local}};
248 /// # #[derive(Debug)]
249 /// # struct MyError;
250 /// # impl core::error::Error for MyError {}
251 /// # impl core::fmt::Display for MyError { fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result { unimplemented!() }}
252 /// let report_sendsync: Report<MyError, Mutable, SendSync> = Report::new(MyError);
253 /// let report_local: Report<MyError, Mutable, Local> = Report::new(MyError);
254 /// ```
255 #[track_caller]
256 #[must_use]
257 pub fn new(context: C) -> Self
258 where
259 C: markers::ObjectMarkerFor<T> + core::error::Error,
260 {
261 Self::new_custom::<handlers::Error>(context)
262 }
263
264 /// Creates a new [`Report`] with the given context and handler.
265 ///
266 /// This method is generic over the thread safety marker `T`.
267 ///
268 /// If you're having trouble with type inference for the thread safety
269 /// parameter, consider using [`Report::new_sendsync_custom`] or
270 /// [`Report::new_local_custom`] instead.
271 ///
272 /// # Examples
273 /// ```
274 /// # use rootcause::{prelude::*, markers::{SendSync, Local}};
275 /// # #[derive(Debug)]
276 /// # struct MyError;
277 /// # impl core::error::Error for MyError {}
278 /// # impl core::fmt::Display for MyError { fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result { unimplemented!() }}
279 /// let report_sendsync: Report<MyError> = Report::new_custom::<handlers::Debug>(MyError);
280 /// let report_local: Report<MyError> = Report::new_custom::<handlers::Display>(MyError);
281 /// ```
282 #[track_caller]
283 #[must_use]
284 pub fn new_custom<H>(context: C) -> Self
285 where
286 C: markers::ObjectMarkerFor<T>,
287 H: ContextHandler<C>,
288 {
289 Self::from_parts::<H>(context, ReportCollection::new(), ReportAttachments::new())
290 }
291
292 /// Creates a new [`Report`] with the given context, children, and
293 /// attachments.
294 ///
295 /// This method processes hooks during report creation. If you want to skip
296 /// hook processing, use [`Report::from_parts_unhooked`] instead.
297 ///
298 /// # Examples
299 /// ```
300 /// # use rootcause::{prelude::*, report_collection::ReportCollection, report_attachments::ReportAttachments, markers::{SendSync}};
301 /// let report: Report<String, _, SendSync> = Report::from_parts::<handlers::Display>(
302 /// "error".to_string(),
303 /// ReportCollection::new(),
304 /// ReportAttachments::new(),
305 /// );
306 /// ```
307 #[track_caller]
308 #[must_use]
309 pub fn from_parts<H>(
310 context: C,
311 children: ReportCollection<Dynamic, T>,
312 attachments: ReportAttachments<T>,
313 ) -> Self
314 where
315 C: markers::ObjectMarkerFor<T>,
316 H: ContextHandler<C>,
317 {
318 let mut report: Self = Self::from_parts_unhooked::<H>(context, children, attachments);
319 C::run_creation_hooks(report.as_mut().into_dynamic());
320 report
321 }
322
323 /// Creates a new [`Report`] with the given context, children, and
324 /// attachments without hook processing.
325 ///
326 /// This method skips hook processing during report creation. If you want
327 /// hooks to be processed, use [`Report::from_parts`] instead.
328 ///
329 /// # Examples
330 /// ```
331 /// # use rootcause::{prelude::*, report_collection::ReportCollection, report_attachments::ReportAttachments, markers::SendSync};
332 /// let report: Report<String, _, SendSync> = Report::from_parts_unhooked::<handlers::Display>(
333 /// "error".to_string(),
334 /// ReportCollection::new(),
335 /// ReportAttachments::new(),
336 /// );
337 /// ```
338 #[track_caller]
339 #[must_use]
340 pub fn from_parts_unhooked<H>(
341 context: C,
342 children: ReportCollection<Dynamic, T>,
343 attachments: ReportAttachments<T>,
344 ) -> Self
345 where
346 C: markers::ObjectMarkerFor<T>,
347 H: ContextHandler<C>,
348 {
349 let raw = RawReport::new::<C, H>(context, children.into_raw(), attachments.into_raw());
350
351 // SAFETY:
352 // 1. `C` is bounded by `Sized`, so this is upheld.
353 // 2. `O=Mutable`, so this is trivially upheld.
354 // 3. `C` is bounded by `markers::ObjectMarkerFor<T>` and this can only be
355 // implemented for `T=Local` and `T=SendSync`, so this is
356 // upheld.
357 // 4. We just created the report and the `C` does indeed match.
358 // 5. We just created the report and we are the unique owner.
359 // 6. `O=Mutable`, so this is trivially upheld.
360 // 7. This is guaranteed by the invariants of the `ReportCollection` we used to
361 // create the raw report.
362 // 8. If `T=Local`, then this is trivially true. If `T=SendSync`, then we have
363 // `C: ObjectMarkerFor<SendSync>`, so the context is `Send+Sync`.
364 // Additionally the invariants of the `ReportCollection` and
365 // `ReportAttachments` guarantee that the children and attachments are
366 // `Send+Sync` as well.
367 unsafe {
368 // @add-unsafe-context: ReportCollection
369 // @add-unsafe-context: ReportAttachments
370 // @add-unsafe-context: markers::ObjectMarkerFor
371 Report::<C, Mutable, T>::from_raw(raw)
372 }
373 }
374
375 /// Decomposes the [`Report`] into its constituent parts.
376 ///
377 /// Returns a tuple containing the context, the children collection and the
378 /// attachments collection in that order. This is the inverse operation
379 /// of [`Report::from_parts`] and [`Report::from_parts_unhooked`].
380 ///
381 /// This method can be useful when you need to:
382 /// - Extract and modify individual components of a report
383 /// - Rebuild a report with different components
384 /// - Transfer components between different reports
385 /// - Perform custom processing on specific parts
386 ///
387 /// Note that to exactly reconstruct the original report, you will also need
388 /// to use the same handler as was used for the original report.
389 ///
390 /// # Examples
391 /// ```
392 /// # use rootcause::{prelude::*, report_collection::ReportCollection, report_attachments::ReportAttachments};
393 /// // Create a report with some children and attachments
394 /// let mut report: Report<String> = Report::from_parts::<handlers::Display>(
395 /// "main error".to_string(),
396 /// ReportCollection::new(),
397 /// ReportAttachments::new(),
398 /// );
399 ///
400 /// // Add some content
401 /// let child_report = report!("child error").into_dynamic().into_cloneable();
402 /// report.children_mut().push(child_report);
403 /// report.attachments_mut().push("debug info".into());
404 ///
405 /// // Decompose into parts
406 /// let (context, children, attachments) = report.into_parts();
407 ///
408 /// assert_eq!(context, "main error");
409 /// assert_eq!(children.len(), 1);
410 /// assert!(attachments.len() >= 1); // "debug info" + potential automatic attachments
411 ///
412 /// // Can rebuild with the same or different parts
413 /// let rebuilt: Report<String> = Report::from_parts::<handlers::Display>(
414 /// context,
415 /// children,
416 /// attachments,
417 /// );
418 /// ```
419 #[must_use]
420 pub fn into_parts(self) -> (C, ReportCollection<Dynamic, T>, ReportAttachments<T>) {
421 let raw = self.into_raw();
422
423 // SAFETY:
424 // 1. This is guaranteed by the invariants of this type.
425 // 2. Since `O=Mutable` and we are consuming `self`, then this is guaranteed to
426 // be the unique owner of the report. We also know that there are no other
427 // references such as `ReportRef` or `ReportMut` active, as those would
428 // require a borrow of `self`.
429 let (context, children, attachments) = unsafe { raw.into_parts() };
430
431 // SAFETY:
432 // 1. `C=Dynamic` for the created collection, so this is trivially true.
433 // 2. The invariants of this type guarantee that `T` is either `Local` or
434 // `SendSync`.
435 // 3. `C=Dynamic` for the created collection, so this is trivially true.
436 // 4. This is guaranteed by the invariants of this type.
437 // 5. If `T=Local`, then this is trivially true. If `T=SendSync`, then this is
438 // guaranteed by the invariants of this type.
439 let children = unsafe { ReportCollection::<Dynamic, T>::from_raw(children) };
440
441 // SAFETY:
442 // 1. `T` is guaranteed to either be `Local` or `SendSync` by the invariants of
443 // this type.
444 // 2. If `T=Local`, then this is trivially true. If `T=SendSync`, then this is
445 // guaranteed by the invariants of this type.
446 let attachments = unsafe { ReportAttachments::<T>::from_raw(attachments) };
447
448 (context, children, attachments)
449 }
450
451 /// Extracts and returns the context value from the [`Report`].
452 ///
453 /// This is a convenience method that consumes the [`Report`] and returns
454 /// only the context, discarding the children and attachments. It's
455 /// equivalent to calling `report.into_parts().0`.
456 ///
457 /// This method can be useful when:
458 /// - You only need the underlying error or context value
459 /// - Converting from a [`Report`] back to the original error type
460 /// - Extracting context for logging or forwarding to other systems
461 /// - Implementing error conversion traits
462 ///
463 /// # Examples
464 /// ```
465 /// # use rootcause::prelude::*;
466 /// #[derive(Debug, PartialEq, Clone)]
467 /// struct MyError {
468 /// message: String,
469 /// code: u32,
470 /// }
471 ///
472 /// impl std::fmt::Display for MyError {
473 /// fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
474 /// write!(f, "Error {}: {}", self.code, self.message)
475 /// }
476 /// }
477 ///
478 /// // Create a report with a custom error context
479 /// let original_error = MyError {
480 /// message: "database connection failed".to_string(),
481 /// code: 500,
482 /// };
483 /// let report: Report<MyError> = report!(original_error.clone());
484 ///
485 /// // Extract just the context, discarding report structure
486 /// let extracted_error = report.into_current_context();
487 /// assert_eq!(extracted_error, original_error);
488 /// assert_eq!(extracted_error.code, 500);
489 /// assert_eq!(extracted_error.message, "database connection failed");
490 /// ```
491 #[must_use]
492 pub fn into_current_context(self) -> C {
493 self.into_parts().0
494 }
495
496 /// Returns a mutable reference to the current context.
497 ///
498 /// # Examples
499 /// ```
500 /// use rootcause::prelude::*;
501 /// let mut report: Report<String> = report!(String::from("An error occurred"));
502 /// let context: &mut String = report.current_context_mut();
503 /// context.push_str(" and that's bad");
504 /// ```
505 #[must_use]
506 pub fn current_context_mut(&mut self) -> &mut C {
507 self.as_mut().into_current_context_mut()
508 }
509
510 /// Transforms the context type by applying a function, preserving report
511 /// structure.
512 ///
513 /// Converts the context type in-place without creating new nodes. Children,
514 /// attachments, and hook data (backtraces, locations) are preserved.
515 ///
516 /// # Examples
517 ///
518 /// ```
519 /// # use rootcause::prelude::*;
520 /// # #[derive(Debug)]
521 /// # struct LibError;
522 /// # impl std::fmt::Display for LibError {
523 /// # fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { write!(f, "lib error") }
524 /// # }
525 /// # #[derive(Debug)]
526 /// enum AppError {
527 /// Lib(LibError)
528 /// }
529 /// # impl std::fmt::Display for AppError {
530 /// # fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { write!(f, "app error") }
531 /// # }
532 ///
533 /// let lib_report: Report<LibError> = report!(LibError);
534 /// let app_report: Report<AppError> = lib_report.context_transform(AppError::Lib);
535 /// ```
536 ///
537 /// # See Also
538 ///
539 /// - [`ContextTransformNestedExt::context_transform_nested`] - Wraps original as preformatted child
540 /// - [`context()`](Report::context) - Adds new parent context
541 /// - [`context_to()`](Report::context_to) - Uses
542 /// [`ReportConversion`](crate::ReportConversion) trait
543 /// - [`examples/context_methods.rs`] - Comparison guide
544 ///
545 /// [`ContextTransformNestedExt::context_transform_nested`]: https://docs.rs/rootcause-preformat/latest/rootcause_preformat/trait.ContextTransformNestedExt.html#method.context_transform_nested
546 /// [`examples/context_methods.rs`]: https://github.com/rootcause-rs/rootcause/blob/main/examples/context_methods.rs
547 #[track_caller]
548 pub fn context_transform<F, D>(self, f: F) -> Report<D, Mutable, T>
549 where
550 F: FnOnce(C) -> D,
551 D: markers::ObjectMarkerFor<T> + core::fmt::Display + core::fmt::Debug,
552 {
553 let (context, children, attachments) = self.into_parts();
554 let new_context = f(context);
555
556 Report::from_parts_unhooked::<handlers::Display>(new_context, children, attachments)
557 }
558}
559
560impl<C: ?Sized, T> Report<C, Mutable, T> {
561 /// Returns a mutable reference to the report.
562 ///
563 /// # Examples
564 /// ```
565 /// use rootcause::{ReportMut, prelude::*};
566 /// let mut report: Report = report!("error message");
567 /// let report_mut: ReportMut<'_> = report.as_mut();
568 /// ```
569 #[must_use]
570 pub fn as_mut(&mut self) -> ReportMut<'_, C, T> {
571 // SAFETY:
572 // 1. If `T=Local`, then this is trivially true. If `T=SendSync`, then we are
573 // not allowed to mutate the returned raw report in a way that adds
574 // non-`Send+Sync` objects. However the invariants of the created `ReportMut`
575 // guarantee that no such mutation can occur.
576 let raw = unsafe { self.as_raw_mut() };
577
578 // SAFETY:
579 // 1. This is guaranteed by the invariants of this type.
580 // 2. This is guaranteed by the invariants of this type.
581 // 3. This is guaranteed by the invariants of this type.
582 // 4. This is guaranteed by the invariants of this type.
583 // 5. This is guaranteed by the invariants of this type.
584 // 6. This is guaranteed by the invariants of this type.
585 // 7. We have a `&mut self`. This means that there are no other borrows active
586 // to `self`. We also know that this is the unique owner of the report, so
587 // there are no other references to it through different ownership. This
588 // means that there are no other references to this report at all, so there
589 // cannot be any incompatible references.
590 unsafe { ReportMut::from_raw(raw) }
591 }
592
593 /// Adds a new attachment to the [`Report`].
594 ///
595 /// This is a convenience method used for chaining method calls; it consumes
596 /// the [`Report`] and returns it.
597 ///
598 /// If you want more direct control over the attachments, you can use the
599 /// [`Report::attachments_mut`].
600 ///
601 /// # Examples
602 /// ```
603 /// # use rootcause::prelude::*;
604 /// let report: Report = report!("error message");
605 /// let with_attachment = report.attach("additional info");
606 /// ```
607 #[must_use]
608 pub fn attach<A>(mut self, attachment: A) -> Self
609 where
610 A: markers::ObjectMarkerFor<T> + core::fmt::Display + core::fmt::Debug,
611 {
612 self.attachments_mut()
613 .push(ReportAttachment::new(attachment).into_dynamic());
614 self
615 }
616
617 /// Adds a new attachment to the [`Report`].
618 ///
619 /// This is a convenience method used for chaining method calls; it consumes
620 /// the [`Report`] and returns it.
621 ///
622 /// If you want more direct control over the attachments, you can use the
623 /// [`Report::attachments_mut`].
624 ///
625 /// # Examples
626 /// ```
627 /// # use rootcause::prelude::*;
628 /// let report: Report = report!("error message");
629 /// let with_attachment = report.attach_custom::<handlers::Display, _>("info");
630 /// ```
631 #[must_use]
632 pub fn attach_custom<H, A>(mut self, attachment: A) -> Self
633 where
634 A: markers::ObjectMarkerFor<T>,
635 H: handlers::AttachmentHandler<A>,
636 {
637 self.attachments_mut()
638 .push(ReportAttachment::new_custom::<H>(attachment).into_dynamic());
639 self
640 }
641
642 /// Returns a mutable reference to the child reports.
643 ///
644 /// # Examples
645 /// ```
646 /// # use rootcause::{prelude::*, report_collection::ReportCollection};
647 /// let mut report: Report = report!("error message");
648 /// let children_mut: &mut ReportCollection = report.children_mut();
649 /// ```
650 #[must_use]
651 pub fn children_mut(&mut self) -> &mut ReportCollection<Dynamic, T> {
652 self.as_mut().into_children_mut()
653 }
654
655 /// Returns a mutable reference to the attachments.
656 ///
657 /// # Examples
658 /// ```
659 /// # use rootcause::{prelude::*, report_attachments::ReportAttachments};
660 /// let mut report: Report = report!("error message");
661 /// let attachments_mut: &mut ReportAttachments = report.attachments_mut();
662 /// ```
663 #[must_use]
664 pub fn attachments_mut(&mut self) -> &mut ReportAttachments<T> {
665 self.as_mut().into_attachments_mut()
666 }
667
668 /// Returns a [`&mut dyn Any`](Any) view of the current context.
669 ///
670 /// This works whether the context type `C` is known at compile time or
671 /// erased to [`Dynamic`]. The returned reference can be downcast using
672 /// `<dyn Any>::downcast_mut`.
673 ///
674 /// [`Dynamic`]: crate::markers::Dynamic
675 ///
676 /// # Examples
677 /// ```
678 /// # use rootcause::prelude::*;
679 /// # use core::any::Any;
680 /// let mut report: Report<String> = report!(String::from("An error occurred"));
681 /// let any: &mut dyn Any = report.current_context_as_any_mut();
682 /// if let Some(s) = any.downcast_mut::<String>() {
683 /// s.push_str(" and that's bad");
684 /// }
685 /// ```
686 #[must_use]
687 pub fn current_context_as_any_mut(&mut self) -> &mut (dyn Any + 'static) {
688 self.as_mut().into_current_context_as_any_mut()
689 }
690}
691
692impl<C: ?Sized, O, T> Report<C, O, T> {
693 /// Creates a new [`Report`] with the given context and sets the current
694 /// report as a child of the new report.
695 ///
696 /// The new context will use the [`handlers::Display`] handler to format the
697 /// context.
698 ///
699 /// This is a convenience method used for chaining method calls; it consumes
700 /// the [`Report`] and returns it.
701 ///
702 /// If you want a different context handler, you can use
703 /// [`Report::context_custom`].
704 ///
705 /// If you want to more directly control the allocation of the new report,
706 /// you can use [`Report::from_parts`], which is the underlying method
707 /// used to implement this method.
708 ///
709 /// # Examples
710 /// ```
711 /// # use rootcause::prelude::*;
712 /// let report: Report = report!("initial error");
713 /// let contextual_report: Report<&str> = report.context("additional context");
714 /// ```
715 #[track_caller]
716 #[must_use]
717 pub fn context<D>(self, context: D) -> Report<D, Mutable, T>
718 where
719 D: markers::ObjectMarkerFor<T> + core::fmt::Display + core::fmt::Debug,
720 {
721 self.context_custom::<handlers::Display, _>(context)
722 }
723
724 /// Creates a new [`Report`] with the given context and sets the current
725 /// report as a child of the new report.
726 ///
727 /// This is a convenience method used for chaining method calls; it consumes
728 /// the [`Report`] and returns it.
729 ///
730 /// If you want to more directly control the allocation of the new report,
731 /// you can use [`Report::from_parts`], which is the underlying method
732 /// used to implement this method.
733 ///
734 /// # Examples
735 /// ```
736 /// # use rootcause::prelude::*;
737 /// let report: Report = report!("initial error");
738 /// let contextual_report: Report<&str> = report.context_custom::<handlers::Debug, _>("context");
739 /// ```
740 #[track_caller]
741 #[must_use]
742 pub fn context_custom<H, D>(self, context: D) -> Report<D, Mutable, T>
743 where
744 D: markers::ObjectMarkerFor<T>,
745 H: ContextHandler<D>,
746 {
747 Report::from_parts::<H>(
748 context,
749 ReportCollection::from([self.into_dynamic().into_cloneable()]),
750 ReportAttachments::<T>::new(),
751 )
752 }
753
754 /// Converts this report to a different context type using
755 /// [`ReportConversion`].
756 ///
757 /// Implement [`ReportConversion`] once to define conversion logic, then use
758 /// [`context_to`](Self::context_to) at call sites. Useful for consistent
759 /// error type coercion across your codebase, especially when integrating
760 /// with external libraries. You typically need to specify the target type
761 /// (`::<Type>`).
762 ///
763 /// See also: [`context_transform`](Self::context_transform) for direct
764 /// conversion, `context_transform_nested` (in the
765 /// [`rootcause-preformat`](https://docs.rs/rootcause-preformat) crate) for
766 /// wrapping, [`examples/thiserror_interop.rs`] for integration patterns.
767 ///
768 /// [`examples/thiserror_interop.rs`]: https://github.com/rootcause-rs/rootcause/blob/main/examples/thiserror_interop.rs
769 ///
770 /// # Examples
771 ///
772 /// ```
773 /// # use rootcause::{ReportConversion, markers::Mutable, prelude::*};
774 /// # #[derive(Debug)]
775 /// enum AppError { Parse }
776 /// # impl std::fmt::Display for AppError {
777 /// # fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { write!(f, "error") }
778 /// # }
779 /// impl<T> ReportConversion<std::num::ParseIntError, Mutable, T> for AppError
780 /// where AppError: markers::ObjectMarkerFor<T>
781 /// {
782 /// fn convert_report(report: Report<std::num::ParseIntError, Mutable, T>) -> Report<Self, Mutable, T>
783 /// {
784 /// report.context(AppError::Parse)
785 /// }
786 /// }
787 /// // After implementing ReportConversion, use at call sites:
788 /// let result: Result<i32, Report<AppError>> = "abc".parse::<i32>().context_to();
789 /// ```
790 #[track_caller]
791 #[must_use]
792 pub fn context_to<D: ReportConversion<C, O, T>>(self) -> Report<D, Mutable, T> {
793 D::convert_report(self)
794 }
795
796 /// Returns a reference to the child reports.
797 ///
798 /// # Examples
799 /// ```
800 /// # use rootcause::{prelude::*, report_collection::ReportCollection};
801 /// let report: Report = report!("error message");
802 /// let children: &ReportCollection = report.children();
803 /// assert_eq!(children.len(), 0); // The report has just been created, so it has no children
804 /// ```
805 #[must_use]
806 pub fn children(&self) -> &ReportCollection<Dynamic, T> {
807 self.as_uncloneable_ref().children()
808 }
809
810 /// Returns a reference to the attachments.
811 ///
812 /// # Examples
813 /// ```
814 /// # use rootcause::{prelude::*, report_attachments::ReportAttachments};
815 /// let report: Report = report!("error message");
816 /// let attachments: &ReportAttachments = report.attachments();
817 /// ```
818 #[must_use]
819 pub fn attachments(&self) -> &ReportAttachments<T> {
820 self.as_uncloneable_ref().attachments()
821 }
822
823 /// Changes the context type of the [`Report`] to [`Dynamic`].
824 ///
825 /// Calling this method is equivalent to calling `report.into()`, however
826 /// this method has been restricted to only change the context mode to
827 /// [`Dynamic`].
828 ///
829 /// This method can be useful to help with type inference or to improve code
830 /// readability, as it more clearly communicates intent.
831 ///
832 /// This method does not actually modify the report in any way. It only has
833 /// the effect of "forgetting" that the context actually has the type
834 /// `C`.
835 ///
836 /// To get back the report with a concrete `C` you can use the method
837 /// [`Report::downcast_report`].
838 ///
839 /// # Examples
840 /// ```
841 /// # use rootcause::{prelude::*, markers::Dynamic};
842 /// # struct MyError;
843 /// # let my_error = MyError;
844 /// let report: Report<MyError> = report!(my_error);
845 /// let dyn_report: Report<Dynamic> = report.into_dynamic();
846 /// ```
847 #[must_use]
848 pub fn into_dynamic(self) -> Report<Dynamic, O, T> {
849 let raw = self.into_raw();
850
851 // SAFETY:
852 // 1. `C=Dynamic`, so this is trivially true.
853 // 2. This is guaranteed by the invariants of this type.
854 // 3. This is guaranteed by the invariants of this type.
855 // 4. `C=Dynamic`, so this is trivially true.
856 // 5. This is guaranteed by the invariants of this type.
857 // 6. This is guaranteed by the invariants of this type.
858 // 7. This is guaranteed by the invariants of this type.
859 // 8. This is guaranteed by the invariants of this type.
860 unsafe {
861 // @add-unsafe-context: Dynamic
862 Report::<Dynamic, O, T>::from_raw(raw)
863 }
864 }
865
866 /// Changes the ownership of the [`Report`] to [`Cloneable`].
867 ///
868 /// Calling this method is equivalent to calling `report.into()`, however
869 /// this method has been restricted to only change the ownership mode to
870 /// [`Cloneable`].
871 ///
872 /// This method can be useful to help with type inference or to improve code
873 /// readability, as it more clearly communicates intent.
874 ///
875 /// This method does not actually modify the report in any way. It only has
876 /// the effect of "forgetting" that the [`Report`] only has a single
877 /// owner.
878 ///
879 /// After calling this method, you can clone the [`Report`], but you can no
880 /// longer add attachments to the [`Report`] or otherwise modify the
881 /// root node.
882 ///
883 /// To get back a [`Mutable`] you need to either:
884 /// - Allocate a new root node using e.g. [`Report::context`].
885 /// - If there is a single unique owner of the report, you can use
886 /// [`Report::try_into_mutable`].
887 /// - Preformat the root node using [`PreformatReportExt::preformat`].
888 ///
889 /// [`PreformatReportExt::preformat`]: https://docs.rs/rootcause-preformat/latest/rootcause_preformat/trait.PreformatReportExt.html#method.preformat
890 ///
891 /// # Examples
892 /// ```
893 /// # use rootcause::{prelude::*, markers::{Mutable, Cloneable}};
894 /// # let my_error = "error message";
895 /// let report: Report<_, Mutable> = report!(my_error);
896 /// let cloneable_report: Report<_, Cloneable> = report.into_cloneable();
897 /// let cloned = cloneable_report.clone();
898 /// ```
899 #[must_use]
900 pub fn into_cloneable(self) -> Report<C, Cloneable, T> {
901 let raw = self.into_raw();
902
903 // SAFETY:
904 // 1. This is guaranteed by the invariants of `self`.
905 // 2. `O=Cloneable`, so this is trivially true.
906 // 3. This is guaranteed by the invariants of `self`.
907 // 4. This is guaranteed by the invariants of `self`.
908 // 5. `O=Cloneable`, so this is trivially true.
909 // 6. If the ownership of `self` is already `Cloneable`, then this is guaranteed
910 // by the invariants of `self`. If the ownership of `self` is `Mutable`, then
911 // the invariants of `self` guarantee that we are the only owner and we are
912 // consuming `self` in this method, so there are no other owners.
913 // 7. This is guaranteed by the invariants of `self`.
914 // 8. This is guaranteed by the invariants of `self`.
915 unsafe { Report::<C, Cloneable, T>::from_raw(raw) }
916 }
917
918 /// Changes the thread safety mode of the [`Report`] to [`Local`].
919 ///
920 /// Calling this method is equivalent to calling `report.into()`, however
921 /// this method has been restricted to only change the thread safety
922 /// mode to [`Local`].
923 ///
924 /// This method can be useful to help with type inference or to improve code
925 /// readability, as it more clearly communicates intent.
926 ///
927 /// This method does not actually modify the report in any way. It only has
928 /// the effect of "forgetting" that all objects in the [`Report`] might
929 /// actually be [`Send`] and [`Sync`].
930 ///
931 /// After calling this method, you can add objects to the [`Report`] that
932 /// are neither [`Send`] nor [`Sync`], but the report itself will no
933 /// longer be [`Send`]+[`Sync`].
934 ///
935 /// # Examples
936 /// ```
937 /// # use rootcause::{prelude::*, markers::{Local, SendSync}};
938 /// # let my_error = "error message";
939 /// let report: Report<_, _, SendSync> = report!(my_error);
940 /// let local_report: Report<_, _, Local> = report.into_local();
941 /// ```
942 #[must_use]
943 pub fn into_local(self) -> Report<C, O, Local> {
944 let raw = self.into_raw();
945
946 // SAFETY:
947 // 1. This is guaranteed by the invariants of this type.
948 // 2. This is guaranteed by the invariants of this type.
949 // 3. `T=Local`, so this is trivially upheld.
950 // 4. This is guaranteed by the invariants of this type.
951 // 5. This is guaranteed by the invariants of this type.
952 // 6. This is guaranteed by the invariants of this type.
953 // 7. This is guaranteed by the invariants of this type.
954 // 8. `T=Local`, so this is trivially true.
955 unsafe { Report::<C, O, Local>::from_raw(raw) }
956 }
957
958 /// Checks if there is only a single unique owner of the root node of the
959 /// [`Report`].
960 ///
961 /// If there is only a single unique owner, this method
962 /// marks the current [`Report`] as [`Mutable`] and returns `Ok`,
963 /// otherwise it returns `Err` with the original [`Report`].
964 ///
965 /// This method does not actually modify the report in any way. It only has
966 /// the effect of checking for unique ownership and returns the same
967 /// report (with different type parameters) no matter the outcome of the
968 /// check.
969 ///
970 /// # Examples
971 /// ```
972 /// # use rootcause::{prelude::*, markers::{Mutable, Cloneable}};
973 /// # let some_report = report!("error message").into_cloneable();
974 /// let cloneable: Report<_, Cloneable> = some_report;
975 /// match cloneable.try_into_mutable() {
976 /// Ok(mutable) => println!("Converted to mutable"),
977 /// Err(cloneable) => println!("Still cloneable"),
978 /// }
979 /// ```
980 pub fn try_into_mutable(self) -> Result<Report<C, Mutable, T>, Report<C, O, T>> {
981 if self.strong_count() == 1 {
982 let raw = self.into_raw();
983
984 // SAFETY:
985 // 1. This is guaranteed by the invariants of this type.
986 // 2. `O=Mutable`, so this is trivially true.
987 // 3. This is guaranteed by the invariants of this type.
988 // 4. This is guaranteed by the invariants of this type.
989 // 5. We just checked that the strong count is `1`, and we are taking ownership
990 // of `self`, so we are the unique owner.
991 // 6. `O=Mutable`, so this is trivially upheld.
992 // 7. This is guaranteed by the invariants of this type.
993 // 8. This is guaranteed by the invariants of this type.
994 let report = unsafe { Report::<C, Mutable, T>::from_raw(raw) };
995 Ok(report)
996 } else {
997 Err(self)
998 }
999 }
1000
1001 pub(crate) fn as_uncloneable_ref(&self) -> ReportRef<'_, C, Uncloneable, T> {
1002 let raw = self.as_raw_ref();
1003
1004 // SAFETY:
1005 // 1. This is guaranteed by the invariants of this type.
1006 // 2. `O=Uncloneable`, so this is trivially true.
1007 // 3. This is guaranteed by the invariants of this type.
1008 // 4. This is guaranteed by the invariants of this type.
1009 // 5. `O=Uncloneable`, so this is trivially true.
1010 // 6. This is guaranteed by the invariants of this type.
1011 // 7. This is guaranteed by the invariants of this type.
1012 unsafe {
1013 // @add-unsafe-context: markers::ReportOwnershipMarker
1014 ReportRef::<C, Uncloneable, T>::from_raw(raw)
1015 }
1016 }
1017
1018 /// Returns an immutable reference to the report.
1019 ///
1020 /// # Examples
1021 /// ```
1022 /// # use rootcause::{prelude::*, ReportRef, markers::{Cloneable, Mutable, Uncloneable}};
1023 /// let report: Report<_, Mutable> = report!("error message");
1024 /// let report_ref: ReportRef<'_, _, Uncloneable> = report.as_ref();
1025 ///
1026 /// let report: Report<_, Cloneable> = report!("error message").into_cloneable();
1027 /// let report_ref: ReportRef<'_, _, Cloneable> = report.as_ref();
1028 /// ```
1029 #[must_use]
1030 pub fn as_ref(&self) -> ReportRef<'_, C, O::RefMarker, T>
1031 where
1032 O: markers::ReportOwnershipMarker,
1033 {
1034 let raw = self.as_raw_ref();
1035
1036 // SAFETY:
1037 // 1. This is guaranteed by the invariants of this type.
1038 // 2. If the ownership of `self` is `Mutable`, then the `O=Uncloneable`, which
1039 // means that this is trivially true. On the other hand, if the ownership of
1040 // `self` is `Cloneable`, then the `O=Cloneable`, which is also trivially
1041 // true.
1042 // 3. This is guaranteed by the invariants of this type.
1043 // 4. This is guaranteed by the invariants of this type.
1044 // 5. If the ownership of `self` is `Mutable`, then the `O=Uncloneable`, which
1045 // means that this is trivially true. On the other hand, if the ownership of
1046 // `self` is `Cloneable`, then the `O=Cloneable`. However in that case, the
1047 // invariants of this type guarantee that all references are compatible.
1048 // 6. This is guaranteed by the invariants of this type.
1049 // 7. This is guaranteed by the invariants of this type.
1050 unsafe {
1051 // @add-unsafe-context: markers::ReportOwnershipMarker
1052 ReportRef::<C, O::RefMarker, T>::from_raw(raw)
1053 }
1054 }
1055
1056 /// Returns an iterator over the complete report hierarchy including this
1057 /// report.
1058 ///
1059 /// The iterator visits reports in a depth-first order: it first visits the
1060 /// current report, then recursively visits each child report and all of
1061 /// their descendants before moving to the next sibling. Unlike
1062 /// [`Report::iter_sub_reports`], this method includes the report on
1063 /// which it was called as the first item in the iteration.
1064 ///
1065 /// The ownership marker of the returned iterator references matches the
1066 /// ownership of this report. For mutable reports, the references may
1067 /// not be cloneable, which can limit how you can use them. If you need
1068 /// cloneable references, consider using [`Report::iter_sub_reports`]
1069 /// instead, which only iterates over children but guarantees
1070 /// cloneable references.
1071 ///
1072 /// See also: [`Report::iter_sub_reports`] for iterating only over child
1073 /// reports with cloneable references.
1074 ///
1075 /// # Examples
1076 /// ```
1077 /// # use rootcause::prelude::*;
1078 /// // Create base reports
1079 /// let error1: Report = report!("error 1");
1080 /// let error2: Report = report!("error 2");
1081 ///
1082 /// // Build hierarchy using .context() which creates new nodes
1083 /// let with_context1 = error1.context("context for error 1"); // Creates new node with error1 as child
1084 /// let with_context2 = error2.context("context for error 2"); // Creates new node with error2 as child
1085 ///
1086 /// // Create root that contains both context nodes as children
1087 /// let mut root = report!("root error").context("context for root error");
1088 /// root.children_mut().push(with_context1.into_dynamic().into_cloneable());
1089 /// root.children_mut().push(with_context2.into_dynamic().into_cloneable());
1090 ///
1091 /// // At this point our report tree looks like this:
1092 /// // - context for root error
1093 /// // - root error
1094 /// // - context for error 1
1095 /// // - error 1
1096 /// // - context for error 2
1097 /// // - error 2
1098 ///
1099 /// let all_reports: Vec<String> = root
1100 /// .iter_reports()
1101 /// .map(|report| report.format_current_context().to_string())
1102 /// .collect();
1103 ///
1104 /// assert_eq!(all_reports[0], "context for root error"); // Current report is included
1105 /// assert_eq!(all_reports[1], "root error");
1106 /// assert_eq!(all_reports.len(), 6);
1107 /// ```
1108 pub fn iter_reports(&self) -> ReportIter<'_, O::RefMarker, T>
1109 where
1110 O: markers::ReportOwnershipMarker,
1111 {
1112 self.as_ref().iter_reports()
1113 }
1114
1115 /// Returns an iterator over child reports in the report hierarchy
1116 /// (excluding this report).
1117 ///
1118 /// The iterator visits reports in a depth-first order: it first visits the
1119 /// current report's children, then recursively visits each child report
1120 /// and all of their descendants before moving to the next sibling.
1121 /// Unlike [`Report::iter_reports`], this method does NOT include the
1122 /// report on which it was called - only its descendants.
1123 ///
1124 /// This method always returns cloneable report references, making it
1125 /// suitable for scenarios where you need to store or pass around the
1126 /// report references. This is different from [`Report::iter_reports`],
1127 /// which returns references that match the ownership marker of the
1128 /// current report and may not be cloneable for mutable reports.
1129 ///
1130 /// See also: [`Report::iter_reports`] for iterating over all reports
1131 /// including the current one.
1132 ///
1133 /// # Examples
1134 /// ```
1135 /// # use rootcause::{prelude::*, markers::Cloneable};
1136 /// // Create base reports
1137 /// let error1: Report = report!("error 1");
1138 /// let error2: Report = report!("error 2");
1139 ///
1140 /// // Build hierarchy using .context() which creates new nodes
1141 /// let with_context1 = error1.context("context for error 1"); // Creates new node with error1 as child
1142 /// let with_context2 = error2.context("context for error 2"); // Creates new node with error2 as child
1143 ///
1144 /// // Create root that contains both context nodes as children
1145 /// let mut root = report!("root error").context("context for root error");
1146 /// root.children_mut().push(with_context1.into_dynamic().into_cloneable());
1147 /// root.children_mut().push(with_context2.into_dynamic().into_cloneable());
1148 ///
1149 /// let sub_reports: Vec<String> = root
1150 /// .iter_sub_reports() // Note: using iter_sub_reports, not iter_reports
1151 /// .map(|report| report.format_current_context().to_string())
1152 /// .collect();
1153 ///
1154 /// // Current "root" report is NOT included in the results
1155 /// assert_eq!(sub_reports[0], "root error");
1156 /// assert_eq!(sub_reports[1], "context for error 1");
1157 /// assert_eq!(sub_reports.len(), 5);
1158 /// ```
1159 pub fn iter_sub_reports(&self) -> ReportIter<'_, Cloneable, T>
1160 where
1161 O: markers::ReportOwnershipMarker,
1162 {
1163 self.as_uncloneable_ref().iter_sub_reports()
1164 }
1165
1166 /// Returns the [`TypeId`] of the current context.
1167 ///
1168 /// # Examples
1169 /// ```
1170 /// # use rootcause::{prelude::*, markers::Dynamic};
1171 /// # use core::any::TypeId;
1172 /// # struct MyError;
1173 /// let report: Report<MyError> = report!(MyError);
1174 /// let type_id = report.current_context_type_id();
1175 /// assert_eq!(type_id, TypeId::of::<MyError>());
1176 ///
1177 /// let report: Report<Dynamic> = report.into_dynamic();
1178 /// let type_id = report.current_context_type_id();
1179 /// assert_eq!(type_id, TypeId::of::<MyError>());
1180 /// ```
1181 #[must_use]
1182 pub fn current_context_type_id(&self) -> TypeId {
1183 self.as_uncloneable_ref().current_context_type_id()
1184 }
1185
1186 /// Returns the [`core::any::type_name`] of the current context.
1187 ///
1188 /// # Examples
1189 /// ```
1190 /// # use rootcause::{prelude::*, markers::Dynamic};
1191 /// # use core::any::TypeId;
1192 /// # struct MyError;
1193 /// # let report = report!(MyError).into_cloneable();
1194 /// let report: Report<MyError> = report!(MyError);
1195 /// let type_name = report.current_context_type_name();
1196 /// assert_eq!(type_name, core::any::type_name::<MyError>());
1197 ///
1198 /// let report: Report<Dynamic> = report.into_dynamic();
1199 /// let type_name = report.current_context_type_name();
1200 /// assert_eq!(type_name, core::any::type_name::<MyError>());
1201 /// ```
1202 #[must_use]
1203 pub fn current_context_type_name(&self) -> &'static str {
1204 self.as_uncloneable_ref().current_context_type_name()
1205 }
1206
1207 /// Returns the [`TypeId`] of the handler used for the current context.
1208 ///
1209 /// This can be useful for debugging or introspection to understand which
1210 /// handler was used to format the context.
1211 ///
1212 /// # Examples
1213 /// ```
1214 /// # use rootcause::{prelude::*, markers::SendSync};
1215 /// # use core::any::TypeId;
1216 /// let report : Report<&'static str> = Report::new_custom::<handlers::Debug>("error message");
1217 /// let handler_type = report.current_context_handler_type_id();
1218 /// assert_eq!(handler_type, TypeId::of::<handlers::Debug>());
1219 /// ```
1220 #[must_use]
1221 pub fn current_context_handler_type_id(&self) -> TypeId {
1222 self.as_uncloneable_ref().current_context_handler_type_id()
1223 }
1224
1225 /// Returns a [`&dyn Any`](Any) view of the current context.
1226 ///
1227 /// This is the most general accessor for the current context: it works
1228 /// whether the context type `C` is known at compile time or erased to
1229 /// [`Dynamic`]. The returned reference can be downcast using
1230 /// `<dyn Any>::downcast_ref` and interoperates with
1231 /// any code that accepts `&dyn Any`.
1232 ///
1233 /// [`Dynamic`]: crate::markers::Dynamic
1234 ///
1235 /// # Examples
1236 /// ```
1237 /// # use rootcause::prelude::*;
1238 /// # use core::any::Any;
1239 /// # struct MyError;
1240 /// let report: Report<MyError> = report!(MyError);
1241 /// let any: &dyn Any = report.current_context_as_any();
1242 /// assert!(any.is::<MyError>());
1243 ///
1244 /// // Also works for Dynamic reports
1245 /// let report: Report = report.into_dynamic();
1246 /// let any: &dyn Any = report.current_context_as_any();
1247 /// assert!(any.is::<MyError>());
1248 /// ```
1249 #[must_use]
1250 pub fn current_context_as_any(&self) -> &(dyn Any + 'static) {
1251 self.as_uncloneable_ref().current_context_as_any()
1252 }
1253
1254 /// Returns the error source if the context implements [`Error`].
1255 ///
1256 /// [`Error`]: core::error::Error
1257 ///
1258 /// # Examples
1259 /// ```
1260 /// # use rootcause::prelude::*;
1261 /// # use core::any::TypeId;
1262 /// let report: Report = report!("error message");
1263 /// let source: Option<&dyn core::error::Error> = report.current_context_error_source();
1264 /// assert!(source.is_none()); // The context does not implement Error, so no source
1265 ///
1266 /// #[derive(Debug, thiserror::Error)]
1267 /// enum MyError {
1268 /// #[error("Io error: {0}")]
1269 /// Io(#[from] std::io::Error),
1270 /// // ...
1271 /// }
1272 ///
1273 /// let report: Report<MyError> = report!(MyError::Io(std::io::Error::other("My inner error")));
1274 /// let source: Option<&dyn std::error::Error> = report.current_context_error_source();
1275 /// assert_eq!(format!("{}", source.unwrap()), "My inner error");
1276 /// ```
1277 #[must_use]
1278 pub fn current_context_error_source(&self) -> Option<&(dyn core::error::Error + 'static)> {
1279 self.as_uncloneable_ref().current_context_error_source()
1280 }
1281
1282 /// Formats the current context with hook processing.
1283 ///
1284 /// # Examples
1285 /// ```
1286 /// # use rootcause::prelude::*;
1287 /// let report: Report = report!("error message");
1288 /// let formatted = report.format_current_context();
1289 /// println!("{formatted}");
1290 /// ```
1291 #[must_use]
1292 pub fn format_current_context(&self) -> impl core::fmt::Display + core::fmt::Debug {
1293 self.as_uncloneable_ref().format_current_context()
1294 }
1295
1296 /// Formats the current context without hook processing.
1297 ///
1298 /// # Examples
1299 /// ```
1300 /// # use rootcause::prelude::*;
1301 /// let report: Report = report!("error message");
1302 /// let formatted = report.format_current_context_unhooked();
1303 /// println!("{formatted}");
1304 /// ```
1305 #[must_use]
1306 pub fn format_current_context_unhooked(&self) -> impl core::fmt::Display + core::fmt::Debug {
1307 self.as_uncloneable_ref().format_current_context_unhooked()
1308 }
1309
1310 /// Formats the entire report using a specific report formatting hook.
1311 ///
1312 /// This method allows you to format a report with a custom formatter
1313 /// without globally registering it. This is useful for:
1314 /// - One-off custom formatting
1315 /// - Testing different formatters
1316 /// - Using different formatters in different parts of your application
1317 ///
1318 /// Unlike the default [`Display`](core::fmt::Display) and
1319 /// [`Debug`](core::fmt::Debug) implementations which use the
1320 /// globally registered hook, this method uses the hook you provide
1321 /// directly.
1322 ///
1323 /// # Examples
1324 ///
1325 /// ```
1326 /// use rootcause::{hooks::builtin_hooks::report_formatter::DefaultReportFormatter, prelude::*};
1327 ///
1328 /// let report = report!("error message");
1329 ///
1330 /// // Format with ASCII-only output (no Unicode or ANSI colors)
1331 /// let formatted = report.format_with(&DefaultReportFormatter::ASCII);
1332 /// println!("{}", formatted);
1333 /// ```
1334 #[must_use]
1335 pub fn format_with<H>(&self, hook: &H) -> impl core::fmt::Display + core::fmt::Debug
1336 where
1337 H: crate::hooks::report_formatter::ReportFormatter,
1338 {
1339 self.as_uncloneable_ref().format_with(hook)
1340 }
1341
1342 /// Gets the preferred formatting style for the context with hook
1343 /// processing.
1344 ///
1345 /// # Arguments
1346 ///
1347 /// - `report_formatting_function`: Whether the report in which this context
1348 /// will be embedded is being formatted using [`Display`] formatting or
1349 /// [`Debug`]
1350 ///
1351 /// [`Display`]: core::fmt::Display
1352 /// [`Debug`]: core::fmt::Debug
1353 ///
1354 /// See also [`Report::preferred_context_formatting_style_unhooked`].
1355 ///
1356 /// # Examples
1357 /// ```
1358 /// # use rootcause::prelude::*;
1359 /// let report: Report = report!("error message");
1360 /// let style = report.preferred_context_formatting_style(handlers::FormattingFunction::Display);
1361 /// ```
1362 #[must_use]
1363 pub fn preferred_context_formatting_style(
1364 &self,
1365 report_formatting_function: FormattingFunction,
1366 ) -> ContextFormattingStyle {
1367 let report: ReportRef<'_, Dynamic, Uncloneable, Local> = self
1368 .as_uncloneable_ref()
1369 .into_dynamic()
1370 .into_uncloneable()
1371 .into_local();
1372 crate::hooks::context_formatter::get_preferred_context_formatting_style(
1373 report,
1374 report_formatting_function,
1375 )
1376 }
1377
1378 /// Gets the preferred formatting style for the context without hook
1379 /// processing.
1380 ///
1381 /// # Arguments
1382 ///
1383 /// - `report_formatting_function`: Whether the report in which this context
1384 /// will be embedded is being formatted using [`Display`] formatting or
1385 /// [`Debug`]
1386 ///
1387 /// [`Display`]: core::fmt::Display
1388 /// [`Debug`]: core::fmt::Debug
1389 ///
1390 /// # Examples
1391 /// ```
1392 /// # use rootcause::prelude::*;
1393 /// let report: Report = report!("error message");
1394 /// let style =
1395 /// report.preferred_context_formatting_style_unhooked(handlers::FormattingFunction::Display);
1396 /// ```
1397 #[must_use]
1398 pub fn preferred_context_formatting_style_unhooked(
1399 &self,
1400 report_formatting_function: FormattingFunction,
1401 ) -> ContextFormattingStyle {
1402 self.as_uncloneable_ref()
1403 .preferred_context_formatting_style_unhooked(report_formatting_function)
1404 }
1405
1406 /// Returns the number of references to this report.
1407 ///
1408 /// # Examples
1409 /// ```
1410 /// # use rootcause::prelude::*;
1411 /// let report: Report = report!("error message");
1412 /// assert_eq!(report.strong_count(), 1); // We just created the report so it has a single owner
1413 /// ```
1414 #[must_use]
1415 pub fn strong_count(&self) -> usize {
1416 self.as_uncloneable_ref().strong_count()
1417 }
1418}
1419
1420impl<C: Sized, O, T> Report<C, O, T> {
1421 /// Returns a reference to the current context.
1422 ///
1423 /// # Examples
1424 /// ```
1425 /// # use rootcause::prelude::*;
1426 /// # struct MyError;
1427 /// # let my_error = MyError;
1428 /// let report: Report<MyError> = report!(my_error);
1429 /// let context: &MyError = report.current_context();
1430 /// ```
1431 #[must_use]
1432 pub fn current_context(&self) -> &C {
1433 self.as_uncloneable_ref().current_context()
1434 }
1435}
1436
1437impl<O, T> Report<Dynamic, O, T> {
1438 /// Attempts to downcast the current context to a specific type.
1439 ///
1440 /// Returns `Some(&C)` if the current context is of type `C`, otherwise
1441 /// returns `None`.
1442 ///
1443 /// # Examples
1444 /// ```
1445 /// # use rootcause::{prelude::*, markers::Dynamic};
1446 /// # struct MyError;
1447 /// let report: Report<MyError> = report!(MyError);
1448 /// let dyn_report: Report<Dynamic> = report.into_dynamic();
1449 /// let context: Option<&MyError> = dyn_report.downcast_current_context();
1450 /// assert!(context.is_some());
1451 /// ```
1452 #[must_use]
1453 pub fn downcast_current_context<C>(&self) -> Option<&C>
1454 where
1455 C: Sized + 'static,
1456 {
1457 self.as_uncloneable_ref().downcast_current_context()
1458 }
1459
1460 /// Downcasts the current context to a specific type without checking.
1461 ///
1462 /// # Safety
1463 ///
1464 /// The caller must ensure:
1465 ///
1466 /// 1. The current context is actually of type `C` (can be verified by
1467 /// calling [`current_context_type_id()`] first)
1468 ///
1469 /// [`current_context_type_id()`]: Report::current_context_type_id
1470 ///
1471 /// # Examples
1472 /// ```
1473 /// # use rootcause::prelude::*;
1474 /// # use core::any::TypeId;
1475 /// # struct MyError;
1476 /// let report: Report<MyError> = report!(MyError);
1477 /// let dyn_report: Report = report.into_dynamic();
1478 ///
1479 /// // Verify the type first
1480 /// if dyn_report.current_context_type_id() == TypeId::of::<MyError>() {
1481 /// // SAFETY: We verified the type matches
1482 /// let context: &MyError = unsafe { dyn_report.downcast_current_context_unchecked() };
1483 /// }
1484 /// ```
1485 #[must_use]
1486 pub unsafe fn downcast_current_context_unchecked<C>(&self) -> &C
1487 where
1488 C: Sized + 'static,
1489 {
1490 let report = self.as_uncloneable_ref();
1491
1492 // SAFETY:
1493 // 1. Guaranteed by the caller
1494 unsafe { report.downcast_current_context_unchecked() }
1495 }
1496
1497 /// Attempts to downcast the report to a specific context type.
1498 ///
1499 /// Returns `Ok(report)` if the current context is of type `C`,
1500 /// otherwise returns `Err(self)` with the original report.
1501 ///
1502 /// # Examples
1503 /// ```
1504 /// # use rootcause::prelude::*;
1505 /// # struct MyError;
1506 /// let report: Report<MyError> = report!(MyError);
1507 /// let dyn_report: Report = report.into_dynamic();
1508 /// let downcasted: Result<Report<MyError>, _> = dyn_report.downcast_report();
1509 /// assert!(downcasted.is_ok());
1510 /// ```
1511 pub fn downcast_report<C>(self) -> Result<Report<C, O, T>, Self>
1512 where
1513 C: Sized + 'static,
1514 {
1515 if TypeId::of::<C>() == self.current_context_type_id() {
1516 // SAFETY:
1517 // 1. We just checked that the type IDs match.
1518 let report = unsafe { self.downcast_report_unchecked() };
1519
1520 Ok(report)
1521 } else {
1522 Err(self)
1523 }
1524 }
1525
1526 /// Downcasts the report to a specific context type without checking.
1527 ///
1528 /// # Safety
1529 ///
1530 /// The caller must ensure:
1531 ///
1532 /// 1. The current context is actually of type `C` (can be verified by
1533 /// calling [`current_context_type_id()`] first)
1534 ///
1535 /// [`current_context_type_id()`]: Report::current_context_type_id
1536 ///
1537 /// # Examples
1538 /// ```
1539 /// # use rootcause::prelude::*;
1540 /// # use core::any::TypeId;
1541 /// # struct MyError;
1542 /// let report: Report<MyError> = report!(MyError);
1543 /// let dyn_report: Report = report.into_dynamic();
1544 ///
1545 /// // Verify the type first
1546 /// if dyn_report.current_context_type_id() == TypeId::of::<MyError>() {
1547 /// // SAFETY: We verified the type matches
1548 /// let downcasted: Report<MyError> = unsafe { dyn_report.downcast_report_unchecked() };
1549 /// }
1550 /// ```
1551 #[must_use]
1552 pub unsafe fn downcast_report_unchecked<C>(self) -> Report<C, O, T>
1553 where
1554 C: Sized + 'static,
1555 {
1556 let raw = self.into_raw();
1557
1558 // SAFETY:
1559 // 1. `C` is bounded by `Sized` in the function signature.
1560 // 2. This is guaranteed by the invariants of this type.
1561 // 3. This is guaranteed by the invariants of this type.
1562 // 4. Guaranteed by the caller
1563 // 5. This is guaranteed by the invariants of this type.
1564 // 6. This is guaranteed by the invariants of this type.
1565 // 7. This is guaranteed by the invariants of this type.
1566 // 8. This is guaranteed by the invariants of this type.
1567 unsafe { Report::from_raw(raw) }
1568 }
1569
1570 /// Returns an iterator over all contexts in the report hierarchy that can
1571 /// be downcast to the specified type `D`.
1572 ///
1573 /// Iterates over the complete report hierarchy (including this report)
1574 /// using [`iter_reports`](Self::iter_reports) and yields references to
1575 /// contexts that successfully downcast to `D`.
1576 ///
1577 /// This is a convenience method combining
1578 /// [`iter_reports`](Self::iter_reports) with
1579 /// [`downcast_current_context`](Report::downcast_current_context).
1580 ///
1581 /// See also: [`iter_reports`](Self::iter_reports) for iterating over all
1582 /// reports, [`downcast_current_context`](Report::downcast_current_context)
1583 /// for downcasting a single report's context.
1584 ///
1585 /// # Examples
1586 ///
1587 /// ```
1588 /// # use rootcause::prelude::*;
1589 /// # #[derive(Debug)]
1590 /// struct MyError {
1591 /// code: u32,
1592 /// }
1593 /// # impl std::fmt::Display for MyError {
1594 /// # fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { write!(f, "error {}", self.code) }
1595 /// # }
1596 ///
1597 /// let child = report!(MyError { code: 404 }).into_dynamic();
1598 /// let mut root = report!(MyError { code: 500 }).into_dynamic();
1599 /// root.children_mut().push(child.into_cloneable());
1600 ///
1601 /// let codes: Vec<u32> = root
1602 /// .iter_downcast_context::<MyError>()
1603 /// .map(|e| e.code)
1604 /// .collect();
1605 ///
1606 /// assert_eq!(codes, vec![500, 404]);
1607 /// ```
1608 pub fn iter_downcast_context<D>(&self) -> DowncastIterator<'_, D, O::RefMarker, T>
1609 where
1610 O: ReportOwnershipMarker,
1611 D: 'static,
1612 {
1613 DowncastIterator {
1614 iter: self.iter_reports(),
1615 _phantom: PhantomData,
1616 }
1617 }
1618}
1619
1620impl<C: Sized + Send + Sync> Report<C, Mutable, SendSync> {
1621 /// Creates a new [`Report`] with [`SendSync`] thread safety.
1622 ///
1623 /// This is a convenience method that calls [`Report::new`] with explicit
1624 /// [`SendSync`] thread safety. Use this method when you're having
1625 /// trouble with type inference for the thread safety parameter.
1626 ///
1627 /// The context will use the [`handlers::Error`] handler to format the
1628 /// context.
1629 ///
1630 /// # Examples
1631 /// ```
1632 /// # use rootcause::prelude::*;
1633 /// # #[derive(Debug)]
1634 /// # struct MyError;
1635 /// # impl core::error::Error for MyError {}
1636 /// # impl core::fmt::Display for MyError { fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result { unimplemented!() }}
1637 /// let report = Report::new_sendsync(MyError);
1638 /// ```
1639 #[track_caller]
1640 #[must_use]
1641 pub fn new_sendsync(context: C) -> Self
1642 where
1643 C: core::error::Error,
1644 {
1645 Self::new(context)
1646 }
1647
1648 /// Creates a new [`Report`] with [`SendSync`] thread safety and the given
1649 /// handler.
1650 ///
1651 /// This is a convenience method that calls [`Report::new_custom`] with
1652 /// explicit [`SendSync`] thread safety. Use this method when you're
1653 /// having trouble with type inference for the thread safety parameter.
1654 ///
1655 /// # Examples
1656 /// ```
1657 /// # use rootcause::prelude::*;
1658 /// let report = Report::new_sendsync_custom::<handlers::Display>("error");
1659 /// ```
1660 #[track_caller]
1661 #[must_use]
1662 pub fn new_sendsync_custom<H>(context: C) -> Self
1663 where
1664 H: ContextHandler<C>,
1665 {
1666 Self::new_custom::<H>(context)
1667 }
1668}
1669
1670impl<C: Sized> Report<C, Mutable, Local> {
1671 /// Creates a new [`Report`] with [`Local`] thread safety.
1672 ///
1673 /// This is a convenience method that calls [`Report::new`] with explicit
1674 /// [`Local`] thread safety. Use this method when you're having trouble
1675 /// with type inference for the thread safety parameter.
1676 ///
1677 /// The context will use the [`handlers::Error`] handler to format the
1678 /// context.
1679 ///
1680 /// # Examples
1681 /// ```
1682 /// # use rootcause::prelude::*;
1683 /// # #[derive(Debug)]
1684 /// # struct MyError;
1685 /// # impl core::error::Error for MyError {}
1686 /// # impl core::fmt::Display for MyError { fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result { unimplemented!() }}
1687 /// let report = Report::new_local(MyError);
1688 /// ```
1689 #[track_caller]
1690 #[must_use]
1691 pub fn new_local(context: C) -> Self
1692 where
1693 C: core::error::Error,
1694 {
1695 Self::new(context)
1696 }
1697
1698 /// Creates a new [`Report`] with [`Local`] thread safety and the given
1699 /// handler.
1700 ///
1701 /// This is a convenience method that calls [`Report::new_custom`] with
1702 /// explicit [`Local`] thread safety. Use this method when you're having
1703 /// trouble with type inference for the thread safety parameter.
1704 ///
1705 /// # Examples
1706 /// ```
1707 /// # use rootcause::prelude::*;
1708 /// let report = Report::new_local_custom::<handlers::Display>("error");
1709 /// ```
1710 #[track_caller]
1711 #[must_use]
1712 pub fn new_local_custom<H>(context: C) -> Self
1713 where
1714 H: ContextHandler<C>,
1715 {
1716 Self::new_custom::<H>(context)
1717 }
1718}
1719
1720// SAFETY: The `SendSync` marker indicates that all objects in the report are
1721// `Send`+`Sync`. Therefore it is safe to implement `Send`+`Sync` for the report
1722// itself.
1723unsafe impl<C: ?Sized, O> Send for Report<C, O, SendSync> {}
1724
1725// SAFETY: The `SendSync` marker indicates that all objects in the report are
1726// `Send`+`Sync`. Therefore it is safe to implement `Send`+`Sync` for the report
1727// itself.
1728unsafe impl<C: ?Sized, O> Sync for Report<C, O, SendSync> {}
1729
1730impl<C: Sized, T> From<C> for Report<C, Mutable, T>
1731where
1732 C: markers::ObjectMarkerFor<T> + core::error::Error,
1733{
1734 #[track_caller]
1735 fn from(context: C) -> Self {
1736 Report::new(context)
1737 }
1738}
1739
1740impl<C: Sized, T> From<C> for Report<C, Cloneable, T>
1741where
1742 C: markers::ObjectMarkerFor<T> + core::error::Error,
1743{
1744 #[track_caller]
1745 fn from(context: C) -> Self {
1746 Report::new(context).into_cloneable()
1747 }
1748}
1749
1750impl<C: Sized, T> From<C> for Report<Dynamic, Mutable, T>
1751where
1752 C: markers::ObjectMarkerFor<T> + core::error::Error,
1753{
1754 #[track_caller]
1755 fn from(context: C) -> Self {
1756 Report::new(context).into_dynamic()
1757 }
1758}
1759
1760impl<C: Sized, T> From<C> for Report<Dynamic, Cloneable, T>
1761where
1762 C: markers::ObjectMarkerFor<T> + core::error::Error,
1763{
1764 #[track_caller]
1765 fn from(context: C) -> Self {
1766 Report::new(context).into_dynamic().into_cloneable()
1767 }
1768}
1769
1770impl<C: ?Sized, T> Clone for Report<C, Cloneable, T> {
1771 fn clone(&self) -> Self {
1772 self.as_ref().clone_arc()
1773 }
1774}
1775
1776impl<C: ?Sized, O, T> core::fmt::Display for Report<C, O, T> {
1777 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
1778 core::fmt::Display::fmt(&self.as_uncloneable_ref(), f)
1779 }
1780}
1781
1782impl<C: ?Sized, O, T> core::fmt::Debug for Report<C, O, T> {
1783 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
1784 core::fmt::Debug::fmt(&self.as_uncloneable_ref(), f)
1785 }
1786}
1787
1788impl<C: ?Sized, O> core::ops::Deref for Report<C, O, SendSync> {
1789 type Target = dyn core::error::Error + Send + Sync + 'static;
1790
1791 fn deref(&self) -> &Self::Target {
1792 ErrorNoSourceWrapper::new(self)
1793 }
1794}
1795
1796impl<C: ?Sized, O> core::ops::Deref for Report<C, O, Local> {
1797 type Target = dyn core::error::Error + 'static;
1798
1799 fn deref(&self) -> &Self::Target {
1800 ErrorNoSourceWrapper::new(self)
1801 }
1802}
1803
1804impl<C: ?Sized, O> AsRef<dyn core::error::Error + Send + Sync> for Report<C, O, SendSync> {
1805 #[inline(always)]
1806 fn as_ref(&self) -> &(dyn core::error::Error + Send + Sync + 'static) {
1807 ErrorNoSourceWrapper::new(self)
1808 }
1809}
1810
1811impl<C: ?Sized, O> AsRef<dyn core::error::Error> for Report<C, O, Local> {
1812 #[inline(always)]
1813 fn as_ref(&self) -> &(dyn core::error::Error + 'static) {
1814 ErrorNoSourceWrapper::new(self)
1815 }
1816}
1817
1818impl<C: ?Sized, O, T> Unpin for Report<C, O, T> {}
1819
1820macro_rules! from_impls {
1821 ($(
1822 <
1823 $($param:ident),*
1824 >:
1825 $context1:ty => $context2:ty,
1826 $ownership1:ty => $ownership2:ty,
1827 $thread_safety1:ty => $thread_safety2:ty,
1828 [$($op:ident),*]
1829 ),* $(,)?) => {
1830 $(
1831 impl<$($param),*> From<Report<$context1, $ownership1, $thread_safety1>> for Report<$context2, $ownership2, $thread_safety2>
1832 {
1833 #[track_caller]
1834 fn from(report: Report<$context1, $ownership1, $thread_safety1>) -> Self {
1835 report
1836 $(.$op())*
1837 }
1838 }
1839 )*
1840 };
1841}
1842
1843from_impls!(
1844 <C>: C => C, Mutable => Mutable, SendSync => Local, [into_local],
1845 <C>: C => C, Mutable => Cloneable, SendSync => SendSync, [into_cloneable],
1846 <C>: C => C, Mutable => Cloneable, SendSync => Local, [into_cloneable, into_local],
1847 <C>: C => C, Mutable => Cloneable, Local => Local, [into_cloneable],
1848 <C>: C => C, Cloneable => Cloneable, SendSync => Local, [into_local],
1849 <C>: C => Dynamic, Mutable => Mutable, SendSync => SendSync, [into_dynamic],
1850 <C>: C => Dynamic, Mutable => Mutable, SendSync => Local, [into_dynamic, into_local],
1851 <C>: C => Dynamic, Mutable => Mutable, Local => Local, [into_dynamic],
1852 <C>: C => Dynamic, Mutable => Cloneable, SendSync => SendSync, [into_dynamic, into_cloneable],
1853 <C>: C => Dynamic, Mutable => Cloneable, SendSync => Local, [into_dynamic, into_cloneable, into_local],
1854 <C>: C => Dynamic, Mutable => Cloneable, Local => Local, [into_dynamic, into_cloneable],
1855 <C>: C => Dynamic, Cloneable => Cloneable, SendSync => SendSync, [into_dynamic, into_cloneable],
1856 <C>: C => Dynamic, Cloneable => Cloneable, SendSync => Local, [into_dynamic, into_cloneable, into_local],
1857 <C>: C => Dynamic, Cloneable => Cloneable, Local => Local, [into_dynamic, into_cloneable],
1858 <>: Dynamic => Dynamic, Mutable => Mutable, SendSync => Local, [into_local],
1859 <>: Dynamic => Dynamic, Mutable => Cloneable, SendSync => SendSync, [into_cloneable],
1860 <>: Dynamic => Dynamic, Mutable => Cloneable, SendSync => Local, [into_cloneable, into_local],
1861 <>: Dynamic => Dynamic, Mutable => Cloneable, Local => Local, [into_cloneable],
1862 <>: Dynamic => Dynamic, Cloneable => Cloneable, SendSync => Local, [into_local],
1863);
1864
1865#[cfg(test)]
1866mod tests {
1867 use alloc::string::{String, ToString};
1868 use core::error::Error as StdError;
1869 use core::ops::Deref;
1870 use thiserror::Error;
1871
1872 use super::*;
1873
1874 #[allow(dead_code)]
1875 struct NonSend(*const ());
1876 static_assertions::assert_not_impl_any!(NonSend: Send, Sync);
1877
1878 #[test]
1879 fn test_report_send_sync() {
1880 static_assertions::assert_impl_all!(Report<(), Mutable, SendSync>: Send, Sync);
1881 static_assertions::assert_impl_all!(Report<(), Cloneable, SendSync>: Send, Sync);
1882 static_assertions::assert_impl_all!(Report<String, Mutable, SendSync>: Send, Sync);
1883 static_assertions::assert_impl_all!(Report<String, Cloneable, SendSync>: Send, Sync);
1884 static_assertions::assert_impl_all!(Report<NonSend, Mutable, SendSync>: Send, Sync); // This still makes sense, since you won't actually be able to construct this report
1885 static_assertions::assert_impl_all!(Report<NonSend, Cloneable, SendSync>: Send, Sync);
1886 static_assertions::assert_impl_all!(Report<Dynamic, Mutable, SendSync>: Send, Sync);
1887 static_assertions::assert_impl_all!(Report<Dynamic, Cloneable, SendSync>: Send, Sync);
1888
1889 static_assertions::assert_not_impl_any!(Report<(), Mutable, Local>: Send, Sync);
1890 static_assertions::assert_not_impl_any!(Report<(), Cloneable, Local>: Send, Sync);
1891 static_assertions::assert_not_impl_any!(Report<String, Mutable, Local>: Send, Sync);
1892 static_assertions::assert_not_impl_any!(Report<String, Cloneable, Local>: Send, Sync);
1893 static_assertions::assert_not_impl_any!(Report<NonSend, Mutable, Local>: Send, Sync);
1894 static_assertions::assert_not_impl_any!(Report<NonSend, Cloneable, Local>: Send, Sync);
1895 static_assertions::assert_not_impl_any!(Report<Dynamic, Mutable, Local>: Send, Sync);
1896 static_assertions::assert_not_impl_any!(Report<Dynamic, Cloneable, Local>: Send, Sync);
1897 }
1898
1899 #[test]
1900 fn test_report_unpin() {
1901 static_assertions::assert_impl_all!(Report<(), Mutable, SendSync>: Unpin);
1902 static_assertions::assert_impl_all!(Report<(), Cloneable, SendSync>: Unpin);
1903 static_assertions::assert_impl_all!(Report<String, Mutable, SendSync>: Unpin);
1904 static_assertions::assert_impl_all!(Report<String, Cloneable, SendSync>: Unpin);
1905 static_assertions::assert_impl_all!(Report<NonSend, Mutable, SendSync>: Unpin); // This still makes sense, since you won't actually be able to construct this report
1906 static_assertions::assert_impl_all!(Report<NonSend, Cloneable, SendSync>: Unpin);
1907 static_assertions::assert_impl_all!(Report<Dynamic, Mutable, SendSync>: Unpin);
1908 static_assertions::assert_impl_all!(Report<Dynamic, Cloneable, SendSync>: Unpin);
1909
1910 static_assertions::assert_impl_all!(Report<(), Mutable, Local>: Unpin);
1911 static_assertions::assert_impl_all!(Report<(), Cloneable, Local>: Unpin);
1912 static_assertions::assert_impl_all!(Report<String, Mutable, Local>: Unpin);
1913 static_assertions::assert_impl_all!(Report<String, Cloneable, Local>: Unpin);
1914 static_assertions::assert_impl_all!(Report<NonSend, Mutable, Local>: Unpin);
1915 static_assertions::assert_impl_all!(Report<NonSend, Cloneable, Local>: Unpin);
1916 static_assertions::assert_impl_all!(Report<Dynamic, Mutable, Local>: Unpin);
1917 static_assertions::assert_impl_all!(Report<Dynamic, Cloneable, Local>: Unpin);
1918 }
1919
1920 #[test]
1921 fn test_report_copy_clone() {
1922 static_assertions::assert_not_impl_any!(Report<(), Mutable, SendSync>: Copy, Clone);
1923 static_assertions::assert_not_impl_any!(Report<(), Mutable, Local>: Copy, Clone);
1924 static_assertions::assert_not_impl_any!(Report<String, Mutable, SendSync>: Copy, Clone);
1925 static_assertions::assert_not_impl_any!(Report<String, Mutable, Local>: Copy, Clone);
1926 static_assertions::assert_not_impl_any!(Report<NonSend, Mutable, SendSync>: Copy, Clone);
1927 static_assertions::assert_not_impl_any!(Report<NonSend, Mutable, Local>: Copy, Clone);
1928 static_assertions::assert_not_impl_any!(Report<Dynamic, Mutable, SendSync>: Copy, Clone);
1929 static_assertions::assert_not_impl_any!(Report<Dynamic, Mutable, Local>: Copy, Clone);
1930
1931 static_assertions::assert_impl_all!(Report<(), Cloneable, SendSync>: Clone);
1932 static_assertions::assert_impl_all!(Report<(), Cloneable, Local>: Clone);
1933 static_assertions::assert_impl_all!(Report<String, Cloneable, SendSync>: Clone);
1934 static_assertions::assert_impl_all!(Report<String, Cloneable, Local>: Clone);
1935 static_assertions::assert_impl_all!(Report<NonSend, Cloneable, SendSync>: Clone);
1936 static_assertions::assert_impl_all!(Report<NonSend, Cloneable, Local>: Clone);
1937 static_assertions::assert_impl_all!(Report<Dynamic, Cloneable, SendSync>: Clone);
1938 static_assertions::assert_impl_all!(Report<Dynamic, Cloneable, Local>: Clone);
1939
1940 static_assertions::assert_not_impl_any!(Report<(), Cloneable, SendSync>: Copy);
1941 static_assertions::assert_not_impl_any!(Report<(), Cloneable, Local>: Copy);
1942 static_assertions::assert_not_impl_any!(Report<String, Cloneable, SendSync>: Copy);
1943 static_assertions::assert_not_impl_any!(Report<String, Cloneable, Local>: Copy);
1944 static_assertions::assert_not_impl_any!(Report<NonSend, Cloneable, SendSync>: Copy);
1945 static_assertions::assert_not_impl_any!(Report<NonSend, Cloneable, Local>: Copy);
1946 static_assertions::assert_not_impl_any!(Report<Dynamic, Cloneable, SendSync>: Copy);
1947 static_assertions::assert_not_impl_any!(Report<Dynamic, Cloneable, Local>: Copy);
1948 }
1949
1950 #[derive(Debug, Error)]
1951 #[error("boom")]
1952 struct Boom;
1953
1954 #[derive(Debug, Error)]
1955 enum Outer {
1956 #[error(transparent)]
1957 Inner(#[from] Report<Boom>),
1958 }
1959
1960 fn make_report() -> Report<Boom> {
1961 Report::new(Boom)
1962 }
1963
1964 fn make_dynamic_report() -> Report<Dynamic> {
1965 make_report().into_dynamic()
1966 }
1967
1968 fn make_cloneable_report() -> Report<Boom, Cloneable> {
1969 make_report().into_cloneable()
1970 }
1971
1972 fn make_local_report() -> Report<Boom, Mutable, Local> {
1973 make_report().into_local()
1974 }
1975
1976 #[test]
1977 fn report_derefs_to_dyn_error() {
1978 let report = make_report();
1979
1980 let err: &(dyn StdError + Send + Sync) = report.deref();
1981
1982 assert!(err.to_string().contains("boom"));
1983 }
1984
1985 #[test]
1986 fn report_asrefs_to_dyn_error() {
1987 let report = make_report();
1988
1989 fn takes_asref(err: impl AsRef<dyn StdError + Send + Sync>) {
1990 assert!(err.as_ref().to_string().contains("boom"));
1991 }
1992
1993 takes_asref(&report);
1994 }
1995
1996 #[test]
1997 fn dynamic_report_derefs_to_dyn_error() {
1998 let report = make_dynamic_report();
1999
2000 let err: &dyn StdError = report.deref();
2001
2002 assert!(err.to_string().contains("boom"));
2003 }
2004
2005 #[test]
2006 fn dynamic_report_asrefs_to_dyn_error() {
2007 let report = make_dynamic_report();
2008
2009 fn takes_asref(err: impl AsRef<dyn StdError + Send + Sync>) {
2010 assert!(err.as_ref().to_string().contains("boom"));
2011 }
2012
2013 takes_asref(&report);
2014 }
2015
2016 #[test]
2017 fn cloneable_report_derefs_to_dyn_error() {
2018 let report = make_cloneable_report();
2019
2020 let err: &dyn StdError = report.deref();
2021
2022 assert!(err.to_string().contains("boom"));
2023 }
2024
2025 #[test]
2026 fn cloneable_report_asrefs_to_dyn_error() {
2027 let report = make_cloneable_report();
2028
2029 fn takes_asref(err: impl AsRef<dyn StdError + Send + Sync>) {
2030 assert!(err.as_ref().to_string().contains("boom"));
2031 }
2032
2033 takes_asref(&report);
2034 }
2035
2036 #[test]
2037 fn local_report_derefs_to_dyn_error() {
2038 let report = make_local_report();
2039
2040 let err: &dyn StdError = report.deref();
2041
2042 assert!(err.to_string().contains("boom"));
2043 }
2044
2045 #[test]
2046 fn local_report_asrefs_to_dyn_error() {
2047 let report = make_local_report();
2048
2049 fn takes_asref(err: impl AsRef<dyn StdError>) {
2050 assert!(err.as_ref().to_string().contains("boom"));
2051 }
2052
2053 takes_asref(&report);
2054 }
2055
2056 #[test]
2057 fn report_deref_supports_error_methods() {
2058 let report = make_report();
2059
2060 assert!(report.source().is_none());
2061 }
2062
2063 #[test]
2064 fn thiserror_from_works_for_report() {
2065 let report = make_report();
2066
2067 let outer: Outer = report.into();
2068
2069 match outer {
2070 Outer::Inner(inner) => {
2071 assert!(inner.to_string().contains("boom"));
2072 }
2073 }
2074 }
2075
2076 #[test]
2077 fn thiserror_question_mark_works_for_report() {
2078 fn inner() -> Result<(), Report<Boom>> {
2079 Err(make_report())
2080 }
2081
2082 fn outer() -> Result<(), Outer> {
2083 inner()?;
2084 Ok(())
2085 }
2086
2087 let err = outer().unwrap_err();
2088 assert!(err.to_string().contains("boom"));
2089 }
2090
2091 #[test]
2092 fn report_is_usable_where_dyn_error_is_expected() {
2093 fn takes_error(err: &dyn StdError) -> String {
2094 err.to_string()
2095 }
2096
2097 let report = make_report();
2098 assert!(takes_error(report.deref()).contains("boom"));
2099 }
2100}