rootcause/markers.rs
1//! Marker types and traits for defining ownership and thread-safety semantics.
2//!
3//! This module provides type-level markers that control how reports and
4//! attachments behave with respect to ownership, cloning, and thread safety.
5//! These markers are used as generic parameters in types like [`Report<C, O,
6//! T>`](crate::Report) to encode compile-time guarantees about how data can be
7//! accessed and shared.
8//!
9//! # Design Philosophy
10//!
11//! The constraints encoded by these markers are enforced at construction time.
12//! It is impossible to construct a [`Report`](crate::Report),
13//! [`ReportRef`], or
14//! [`ReportCollection`] that violates the invariants
15//! associated with its marker types. This means you can trust that a
16//! `Report<_, _, SendSync>` truly is `Send + Sync`, and that a `Report<_,
17//! Mutable>` truly has unique ownership.
18//!
19//! [`ReportRef`]: crate::ReportRef
20//! [`ReportCollection`]: crate::report_collection::ReportCollection
21//!
22//! # Context Marker
23//!
24//! The context marker is the first type parameter (`C`) in [`Report<C, O,
25//! T>`](crate::Report) and determines what type of error is stored at the root:
26//!
27//! - [`Dynamic`]: Type-erased context - the root error can be any type (like
28//! [`anyhow::Error`]). This is the default when you write just [`Report`].
29//! - Any concrete type: Typed context - the root error must be that specific
30//! type (like [`error-stack`]).
31//!
32//! See the [`Dynamic`] documentation for a detailed comparison and usage
33//! examples.
34//!
35//! [`anyhow::Error`]: https://docs.rs/anyhow
36//! [`error-stack`]: https://docs.rs/error-stack
37//! [`Report`]: crate::Report
38//!
39//! # Ownership Markers
40//!
41//! Ownership markers control whether reports and report references can be
42//! mutated and cloned.
43//!
44//! For owned reports ([`Report<C, O, T>`](crate::Report)), the ownership marker
45//! `O` can be:
46//! - [`Mutable`]: Unique ownership - the report can be mutated but not cloned
47//! - [`Cloneable`]: Shared ownership - the report can be cloned but not mutated
48//!
49//! For report references ([`ReportRef<C, O>`](crate::ReportRef)), the ownership
50//! marker `O` can be:
51//! - [`Cloneable`]: Enables [`clone_arc`](crate::ReportRef::clone_arc) to get
52//! an owned report
53//! - [`Uncloneable`]: Does not provide
54//! [`clone_arc`](crate::ReportRef::clone_arc)
55//!
56//! # Thread Safety Markers
57//!
58//! Thread safety markers control whether reports can be sent between threads or
59//! shared across threads. These appear as the third type parameter (`T`) in
60//! [`Report<C, O, T>`](crate::Report):
61//!
62//! - [`SendSync`]: The report and all its contents are `Send + Sync`, allowing
63//! the report to cross thread boundaries.
64//! - [`Local`]: The report contains non-thread-safe data (like `Rc` or raw
65//! pointers) and cannot be sent between threads.
66//!
67//! # Examples
68//!
69//! ## Creating Reports with Different Ownership Semantics
70//!
71//! ```
72//! use rootcause::prelude::*;
73//!
74//! // Mutable report - can be modified by adding context and attachments
75//! let mut report: Report<String, markers::Mutable> = report!("Error".to_string());
76//! let report: Report<String, markers::Mutable> = report.attach("Additional context");
77//!
78//! // Convert to cloneable report - can be cloned but not mutated
79//! let cloneable: Report<String, markers::Cloneable> = report.into_cloneable();
80//! let cloned: Report<String, markers::Cloneable> = cloneable.clone();
81//! assert_eq!(format!("{}", cloneable), format!("{}", cloned));
82//! ```
83//!
84//! ## Working with Thread Safety
85//!
86//! ```
87//! use std::rc::Rc;
88//!
89//! use rootcause::prelude::*;
90//!
91//! // Thread-safe report with String (String is Send + Sync)
92//! let thread_safe: Report<String, markers::Mutable, markers::SendSync> =
93//! report!("Thread-safe error".to_string());
94//!
95//! // Can be sent to another thread
96//! std::thread::spawn(move || {
97//! println!("{}", thread_safe);
98//! });
99//!
100//! // Local report with Rc (Rc is !Send + !Sync)
101//! let local_data: Rc<String> = Rc::new("Not thread-safe".to_string());
102//! let local_report: Report<Rc<String>, markers::Mutable, markers::Local> = report!(local_data);
103//! // local_report cannot be sent to another thread - won't compile
104//! ```
105
106use crate::ReportMut;
107
108/// Marker type for reports with dynamic (type-erased) context.
109///
110/// [`Dynamic`] is used as the context type parameter in
111/// [`Report<Dynamic, O, T>`](crate::Report) to indicate that the actual error
112/// type at the root is not known at compile time. This is the default behavior
113/// and is similar to [`anyhow::Error`] - any error type
114/// can be stored and the `?` operator works automatically.
115///
116/// # Key Properties
117///
118/// - **Zero-cost type erasure**: No actual instance of [`Dynamic`] is ever
119/// stored. It's purely a marker type used at the type level.
120/// - **Automatic conversions**: The `?` operator automatically converts any
121/// error type into `Report<Dynamic>`.
122/// - **Flexible propagation**: When you just need errors to propagate upward
123/// with context, [`Dynamic`] is the right choice.
124///
125/// # When to Use Dynamic
126///
127/// Use `Report<Dynamic>` (or just [`Report`](crate::Report), which defaults to
128/// [`Dynamic`]) when:
129/// - You're propagating errors upward and don't need to pattern match on
130/// specific error types
131/// - You want the flexibility to return different error types from the same
132/// function
133/// - You're building applications where error handling is about logging and
134/// displaying, not recovery
135///
136/// Use `Report<YourErrorType>` instead when:
137/// - Callers need to pattern match on specific error variants for recovery
138/// - You want compile-time guarantees about which errors a function can return
139/// - You're building libraries with well-defined error types
140///
141/// See [`examples/typed_reports.rs`] for when typed errors are appropriate.
142///
143/// [`examples/typed_reports.rs`]: https://github.com/rootcause-rs/rootcause/blob/main/examples/typed_reports.rs
144///
145/// # Examples
146///
147/// ## Basic Usage
148///
149/// ```
150/// use rootcause::prelude::*;
151///
152/// // Report<Dynamic> is the default - these are equivalent:
153/// fn might_fail() -> Result<(), Report> {
154/// // Can return any error type via ?
155/// std::fs::read_to_string("/nonexistent")?;
156/// Ok(())
157/// }
158///
159/// fn might_fail_explicit() -> Result<(), Report<markers::Dynamic>> {
160/// std::fs::read_to_string("/nonexistent")?;
161/// Ok(())
162/// }
163/// ```
164///
165/// ## Mixing Error Types
166///
167/// ```
168/// use std::{fs, io};
169///
170/// use rootcause::prelude::*;
171///
172/// #[derive(Debug)]
173/// struct ConfigError(String);
174/// impl std::fmt::Display for ConfigError {
175/// fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
176/// write!(f, "Config error: {}", self.0)
177/// }
178/// }
179/// impl std::error::Error for ConfigError {}
180///
181/// fn load_and_parse(path: &str) -> Result<u32, Report> {
182/// // io::Error from fs operations
183/// let contents = fs::read_to_string(path)?;
184///
185/// // Custom ConfigError
186/// if contents.is_empty() {
187/// Err(ConfigError("empty file".into()))?;
188/// }
189///
190/// // ParseIntError from parse
191/// let value: u32 = contents.trim().parse()?;
192///
193/// Ok(value)
194/// }
195/// ```
196///
197/// ## Converting Between Typed and Dynamic
198///
199/// ```
200/// use rootcause::prelude::*;
201///
202/// #[derive(Debug)]
203/// struct MyError;
204/// impl std::fmt::Display for MyError {
205/// fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
206/// write!(f, "MyError")
207/// }
208/// }
209/// impl std::error::Error for MyError {}
210///
211/// fn typed_error() -> Result<(), Report<MyError>> {
212/// Err(report!(MyError))
213/// }
214///
215/// fn dynamic_error() -> Result<(), Report> {
216/// // Typed report automatically coerces to dynamic via ?
217/// typed_error()?;
218/// Ok(())
219/// }
220///
221/// // Or convert explicitly:
222/// fn explicit_conversion() -> Result<(), Report> {
223/// let typed: Report<MyError> = report!(MyError);
224/// let dynamic: Report = typed.into_dynamic();
225/// Err(dynamic)
226/// }
227/// ```
228///
229/// See [`examples/error_coercion.rs`] for a complete guide to type conversions.
230///
231/// [`examples/error_coercion.rs`]: https://github.com/rootcause-rs/rootcause/blob/main/examples/error_coercion.rs
232pub struct Dynamic {
233 /// This field ensures [`Dynamic`] is an unsized type.
234 ///
235 /// Since the [`Dynamic`] type itself is never instantiated, the choice
236 /// of an unsized type here is purely to enforce that property at the type
237 /// level.
238 _phantom_unsized: [()],
239}
240
241/// Marker type for owned reports with unique ownership.
242///
243/// This marker is used exclusively with [`Report<C, Mutable, T>`] (not
244/// [`ReportRef`]). It indicates that the report has unique ownership of its
245/// data, which allows mutation operations but prevents cloning.
246///
247/// [`Report<C, Mutable, T>`]: crate::Report
248/// [`ReportRef`]: crate::ReportRef
249///
250/// # Available Operations
251///
252/// With [`Mutable`] ownership, you can:
253/// - Add attachments with [`attach`](crate::Report::attach)
254/// - Add parent context with [`context`](crate::Report::context)
255/// - Get mutable access with [`as_mut`](crate::Report::as_mut)
256/// - Convert to [`Cloneable`] with
257/// [`into_cloneable`](crate::Report::into_cloneable)
258///
259/// # Examples
260///
261/// ```
262/// use rootcause::prelude::*;
263///
264/// let report: Report<String, markers::Mutable> = report!("Database error".to_string());
265///
266/// // Can add attachments (consumes and returns the report)
267/// let report: Report<String, markers::Mutable> = report.attach("connection timeout");
268///
269/// // Can add parent context
270/// let report: Report<String, markers::Mutable> =
271/// report.context("Failed to fetch user data".to_string());
272///
273/// // Cannot clone - Mutable reports don't implement Clone
274/// // let cloned = report.clone(); // ❌ Won't compile
275/// ```
276#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Default, Hash)]
277pub struct Mutable;
278
279/// Marker type for cloneable reports and report references.
280///
281/// This marker is used with both [`Report<C, Cloneable, T>`](crate::Report) and
282/// [`ReportRef<C, Cloneable>`](crate::ReportRef). It indicates shared ownership
283/// using reference counting (`Arc` internally), which allows cheap cloning but
284/// prevents mutation.
285///
286/// # Usage with Report
287///
288/// For [`Report<C, Cloneable, T>`](crate::Report), this marker means the report
289/// itself implements `Clone`, allowing you to cheaply clone the entire report
290/// (shallow copy via `Arc`).
291///
292/// # Usage with ReportRef
293///
294/// For [`ReportRef<C, Cloneable>`](crate::ReportRef), the marker enables the
295/// [`clone_arc`](crate::ReportRef::clone_arc) method, which clones the
296/// underlying `Arc` to produce an owned [`Report<C, Cloneable,
297/// T>`](crate::Report). Note that [`ReportRef`](crate::ReportRef) itself is
298/// always `Copy` and `Clone` regardless of the ownership marker - the
299/// [`Cloneable`] marker specifically enables converting the reference back to
300/// an owned report.
301///
302/// # When to Use
303///
304/// Use [`Cloneable`] reports when you need to:
305/// - Share an error report across multiple code paths
306/// - Store reports in collections that require `Clone`
307/// - Return the same error from multiple places without deep copying
308///
309/// # Converting to Cloneable
310///
311/// Convert a [`Mutable`] report to [`Cloneable`] using
312/// [`into_cloneable`](crate::Report::into_cloneable):
313///
314/// ```
315/// use rootcause::prelude::*;
316///
317/// let report: Report<String, markers::Mutable> = report!("Error".to_string());
318///
319/// // Convert to cloneable
320/// let cloneable: Report<String, markers::Cloneable> = report.into_cloneable();
321///
322/// // Now can clone cheaply (shallow clone via Arc)
323/// let clone1: Report<String, markers::Cloneable> = cloneable.clone();
324/// let clone2: Report<String, markers::Cloneable> = cloneable.clone();
325/// ```
326///
327/// # Examples
328///
329/// Cloning owned reports:
330///
331/// ```
332/// use rootcause::prelude::*;
333///
334/// fn process_error(error: Report<String, markers::Cloneable>) {
335/// // Can clone the error to pass to multiple handlers
336/// let for_logging = error.clone();
337/// let for_metrics = error.clone();
338///
339/// println!("Logging: {}", for_logging);
340/// println!("Metrics: {}", for_metrics);
341/// }
342///
343/// let report: Report<String> = report!("An error occurred".to_string());
344/// process_error(report.into_cloneable());
345/// ```
346///
347/// Using [`clone_arc`](crate::ReportRef::clone_arc) on report references:
348///
349/// ```
350/// use rootcause::{ReportRef, prelude::*};
351///
352/// let report: Report<String, markers::Cloneable> = report!("Error".to_string()).into_cloneable();
353///
354/// // Get a reference (ReportRef is Copy, so this is cheap)
355/// let report_ref: ReportRef<String, markers::Cloneable> = report.as_ref();
356///
357/// // Clone the underlying Arc to get an owned Report
358/// let owned: Report<String, markers::Cloneable> = report_ref.clone_arc();
359/// ```
360#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Default, Hash)]
361pub struct Cloneable;
362
363/// Marker type for non-cloneable report references.
364///
365/// This marker is used exclusively with [`ReportRef<C,
366/// Uncloneable>`](crate::ReportRef) (not [`Report`](crate::Report)). It
367/// indicates that the reference does not provide the
368/// [`clone_arc`](crate::ReportRef::clone_arc) method to obtain an owned report.
369///
370/// Note that [`ReportRef`](crate::ReportRef) itself is always `Copy` and
371/// `Clone` - you can always copy the reference itself. The [`Uncloneable`]
372/// marker only prevents cloning the underlying `Arc` to get an owned
373/// [`Report`](crate::Report).
374///
375/// # Common Uses
376///
377/// [`Uncloneable`] references typically arise in two situations:
378///
379/// 1. **Taking a reference to a [`Mutable`] report**: When you call
380/// [`as_ref`](crate::Report::as_ref) on a `Report<C, Mutable>`, you get a
381/// `ReportRef<C, Uncloneable>` because the underlying report has unique
382/// ownership.
383///
384/// 2. **Explicitly restricting cloneability**: You can convert a `ReportRef<C,
385/// Cloneable>` to `ReportRef<C, Uncloneable>` when you want to pass a
386/// reference that explicitly cannot use
387/// [`clone_arc`](crate::ReportRef::clone_arc), ensuring the recipient
388/// can only inspect the report without obtaining ownership. This can be
389/// useful in APIs that need to accept both cloneable and uncloneable
390/// references.
391///
392///
393/// # Examples
394///
395/// Taking a reference to a [`Mutable`] report:
396///
397/// ```
398/// use rootcause::{ReportRef, prelude::*};
399///
400/// let report: Report<String, markers::Mutable> = report!("An error occurred".to_string());
401///
402/// // Taking a reference to a Mutable report gives an Uncloneable reference
403/// let report_ref: ReportRef<String, markers::Uncloneable> = report.as_ref();
404///
405/// // The reference itself can be copied (ReportRef is Copy)
406/// let copy = report_ref;
407///
408/// // But you cannot clone the underlying Arc to get an owned Report
409/// // let owned = report_ref.clone_arc(); // ❌ Method not available
410/// ```
411///
412/// Explicitly converting to [`Uncloneable`]:
413///
414/// ```
415/// use rootcause::{ReportRef, prelude::*};
416///
417/// let report: Report<String, markers::Cloneable> = report!("Error".to_string()).into_cloneable();
418///
419/// let cloneable_ref: ReportRef<String, markers::Cloneable> = report.as_ref();
420///
421/// // Convert to uncloneable to restrict the recipient's ability to clone
422/// let uncloneable_ref: ReportRef<String, markers::Uncloneable> = cloneable_ref.into_uncloneable();
423/// ```
424#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Default, Hash)]
425pub struct Uncloneable;
426
427/// Marker type indicating that a report and all its contents are `Send + Sync`.
428///
429/// This is the default thread-safety marker for reports. When all the context
430/// objects and attachments in a report implement `Send + Sync`, the report
431/// itself can be safely sent to other threads and shared between threads.
432///
433/// # When to Use
434///
435/// Most standard types in Rust are `Send + Sync`, including:
436/// - Primitive types (`i32`, `String`, `Vec`, etc.)
437/// - Most standard library types
438/// - Types explicitly designed for concurrent use
439///
440/// Use [`SendSync`] (the default) unless you have a specific need for
441/// thread-local data.
442///
443/// # Examples
444///
445/// ```
446/// use std::thread;
447///
448/// use rootcause::prelude::*;
449///
450/// // String is Send + Sync, so the report is too
451/// let report: Report<String, markers::Mutable, markers::SendSync> =
452/// report!("Thread-safe error".to_string());
453///
454/// // Can send to another thread
455/// thread::spawn(move || {
456/// println!("Error in thread: {}", report);
457/// })
458/// .join()
459/// .unwrap();
460/// ```
461#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Default, Hash)]
462pub struct SendSync;
463
464/// Marker type indicating that a report is not `Send` or `Sync`.
465///
466/// This marker is used when a report contains thread-local data that cannot be
467/// safely sent between threads or shared across threads. Common examples
468/// include `Rc`, raw pointers, or types that explicitly opt out of
469/// `Send`/`Sync`.
470///
471/// # When to Use
472///
473/// Use [`Local`] when your error context or attachments contain:
474/// - `Rc<T>` or `Weak<T>` (use `Arc<T>` for thread-safe alternative)
475/// - Raw pointers (`*const T`, `*mut T`)
476/// - Types that wrap thread-local storage
477/// - Any type that is `!Send` or `!Sync`
478///
479/// # Converting to Local
480///
481/// You can convert a thread-safe report to a local one using
482/// [`into_local`](crate::Report::into_local), or create a local report directly
483/// when the context type is not `Send + Sync`.
484///
485/// # Examples
486///
487/// ```
488/// use std::rc::Rc;
489///
490/// use rootcause::prelude::*;
491///
492/// // Rc is not Send or Sync, so the report must be Local
493/// let local_data: Rc<String> = Rc::new("Thread-local error".to_string());
494/// let report: Report<Rc<String>, markers::Mutable, markers::Local> = report!(local_data);
495///
496/// // This report cannot be sent to another thread
497/// // std::thread::spawn(move || {
498/// // println!("{}", report); // ❌ Won't compile
499/// // });
500/// ```
501///
502/// Converting a thread-safe report to local:
503///
504/// ```
505/// use std::rc::Rc;
506///
507/// use rootcause::prelude::*;
508///
509/// let report: Report<String> = report!("Error".to_string());
510///
511/// // Convert to local report so we can use thread-local data
512/// let local_report: Report<String, markers::Mutable, markers::Local> = report.into_local();
513/// ```
514#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Default, Hash)]
515pub struct Local;
516
517mod sealed_report_ownership_marker {
518 use super::*;
519
520 pub trait Sealed: 'static {}
521
522 impl Sealed for Mutable {}
523 impl Sealed for Cloneable {}
524}
525
526mod sealed_object_marker {
527 pub trait Sealed: 'static {}
528
529 impl<C: Sized + 'static> Sealed for C {}
530}
531
532/// Marker trait for ownership semantics of owned reports.
533///
534/// This trait is implemented for [`Mutable`] and [`Cloneable`], the two
535/// ownership markers that can be used with [`Report<C, O, T>`](crate::Report).
536/// It exists primarily to enable the associated type `RefMarker`, which
537/// determines the ownership marker used when creating a reference to the
538/// report.
539///
540/// # Relationship to Report Construction
541///
542/// While this trait defines the ownership modes, the actual enforcement of
543/// ownership invariants happens at report construction time. It is impossible
544/// to construct a `Report<_, Mutable>` that doesn't have unique ownership, or a
545/// `Report<_, Cloneable>` that hasn't been properly set up for shared
546/// ownership.
547///
548/// # Ownership Modes
549///
550/// - [`Mutable`]: Indicates unique ownership. The report can be mutated but not
551/// cloned. Methods like [`attach`](crate::Report::attach) and
552/// [`as_mut`](crate::Report::as_mut) are only available in this mode.
553///
554/// - [`Cloneable`]: Indicates shared ownership via reference counting. The
555/// report can be cloned cheaply but cannot be mutated since there may be
556/// multiple references.
557///
558/// # Associated Types
559///
560/// The `RefMarker` associated type determines what kind of reference you get
561/// when calling [`as_ref`](crate::Report::as_ref):
562/// - For [`Mutable`], this is [`Uncloneable`] (the reference cannot use
563/// [`clone_arc`](crate::ReportRef::clone_arc))
564/// - For [`Cloneable`], this is [`Cloneable`] (the reference can use
565/// [`clone_arc`](crate::ReportRef::clone_arc))
566///
567/// # Implementation
568///
569/// This trait is sealed and cannot be implemented outside of this crate. You
570/// should use the provided implementations for [`Mutable`] and [`Cloneable`].
571///
572/// # Examples
573///
574/// [`ReportOwnershipMarker`] is typically used as a bound to write functions
575/// that accept both [`Mutable`] and [`Cloneable`] reports:
576///
577/// ```
578/// use rootcause::{
579/// markers::{Cloneable, Mutable, ReportOwnershipMarker},
580/// prelude::*,
581/// };
582///
583/// fn describe<O: ReportOwnershipMarker>(report: Report<&'static str, O>) -> String {
584/// report.current_context().to_string()
585/// }
586///
587/// let context: &'static str = "oops";
588/// let mutable: Report<&str, Mutable> = report!(context);
589/// assert_eq!(describe(mutable), "oops");
590///
591/// let cloneable: Report<&str, Cloneable> = report!(context).into_cloneable();
592/// assert_eq!(describe(cloneable), "oops");
593/// ```
594pub trait ReportOwnershipMarker: sealed_report_ownership_marker::Sealed {
595 /// The ownership marker for references to this report type.
596 ///
597 /// This determines what type of reference is created when you call
598 /// [`Report::as_ref`](crate::Report::as_ref):
599 ///
600 /// - For [`Mutable`]: Returns [`ReportRef<C,
601 /// Uncloneable>`](crate::ReportRef) because the underlying report has
602 /// unique ownership
603 /// - For [`Cloneable`]: Returns [`ReportRef<C,
604 /// Cloneable>`](crate::ReportRef) because the underlying report already
605 /// uses shared ownership
606 type RefMarker;
607}
608impl ReportOwnershipMarker for Mutable {
609 type RefMarker = Uncloneable;
610}
611impl ReportOwnershipMarker for Cloneable {
612 type RefMarker = Cloneable;
613}
614
615/// Marker trait combining object and thread-safety requirements.
616///
617/// This trait enforces thread-safety constraints for context and attachment
618/// data at report construction time. Reports can only be constructed when their
619/// context and attachments satisfy the requirements of the thread-safety
620/// marker.
621///
622/// # Implementations
623///
624/// - For `T = Local`: Implemented for all `Sized + 'static` types, regardless
625/// of their `Send`/`Sync` status. This allows using types like `Rc` in local
626/// reports.
627///
628/// - For `T = SendSync`: Implemented only for `Sized + 'static` types that are
629/// also `Send + Sync`. This ensures thread-safe reports can only be
630/// constructed with thread-safe data.
631///
632/// # Enforcement at Construction
633///
634/// The key insight is that this trait is used as a bound during report
635/// construction. You cannot create a `Report<C, _, SendSync>` unless `C:
636/// ObjectMarkerFor<SendSync>`, which requires `C: Send + Sync`. This makes it
637/// impossible to accidentally create an invalid report:
638///
639/// ```compile_fail
640/// use std::rc::Rc;
641/// use rootcause::prelude::*;
642///
643/// // This won't compile because Rc is not Send + Sync
644/// let rc_data: Rc<String> = Rc::new("error".to_string());
645/// let report: Report<Rc<String>, markers::Mutable, markers::SendSync> = report!(rc_data);
646/// ```
647///
648/// Use [`Local`] instead for non-thread-safe data:
649///
650/// ```
651/// use std::rc::Rc;
652///
653/// use rootcause::prelude::*;
654///
655/// let rc_data: Rc<String> = Rc::new("error".to_string());
656/// let report: Report<Rc<String>, markers::Mutable, markers::Local> = report!(rc_data);
657/// ```
658//
659// # Safety:
660//
661// This trait is sealed and cannot be implemented outside of this crate. It is
662// guaranteed to only be implemented for the combinations of types and
663// thread-safety markers listed above.
664pub trait ObjectMarkerFor<T>: sealed_object_marker::Sealed + Sized + 'static {
665 /// Runs report creation hooks specific to this thread-safety marker.
666 #[doc(hidden)]
667 #[track_caller]
668 fn run_creation_hooks(report: ReportMut<'_, Dynamic, T>);
669}
670
671impl<O: Sized + 'static> ObjectMarkerFor<Local> for O {
672 #[inline(always)]
673 fn run_creation_hooks(report: ReportMut<'_, Dynamic, Local>) {
674 crate::hooks::report_creation::run_creation_hooks_local(report);
675 }
676}
677
678impl<O: Sized + 'static> ObjectMarkerFor<SendSync> for O
679where
680 O: Send + Sync,
681{
682 #[inline(always)]
683 fn run_creation_hooks(report: ReportMut<'_, Dynamic, SendSync>) {
684 crate::hooks::report_creation::run_creation_hooks_sendsync(report);
685 }
686}