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