rootcause_internals/report/
raw.rs

1//! This module encapsulates the fields of the [`RawReport`], [`RawReportRef`],
2//! and [`RawReportMut`]. Since this is the only place they are visible, this
3//! means that the `ptr` field of all three types is always guaranteed to come
4//! from a [`triomphe::Arc<ReportData<C>>`]. This follows from the fact that
5//! there are no places where the `ptr` field is altered after creation (besides
6//! invalidating it after it should no longer be used).
7
8use alloc::vec::Vec;
9use core::{any::TypeId, ptr::NonNull};
10
11use crate::{
12    attachment::RawAttachment,
13    handlers::{ContextFormattingStyle, ContextHandler, FormattingFunction},
14    report::data::ReportData,
15    util::{CastTo, Erased},
16};
17
18/// A pointer to a [`ReportData`] that is guaranteed to point to an initialized
19/// instance of a [`ReportData<C>`] for some specific `C`, though we do not know
20/// which actual `C` it is.
21///
22/// However, the pointer is allowed to transition into a non-initialized state
23/// inside the [`RawReport::drop`] method.
24///
25/// The pointer is guaranteed to have been created using
26/// [`triomphe::Arc::into_raw`].
27///
28/// We cannot use a [`triomphe::OffsetArc<ReportData<C>>`] directly, because
29/// that does not allow us to type-erase the `C`.
30#[repr(transparent)]
31pub struct RawReport {
32    /// Pointer to the inner report data
33    ptr: NonNull<ReportData<Erased>>,
34}
35
36impl RawReport {
37    /// Creates a new [`RawReport`] from a [`triomphe::Arc<ReportData<C>>`].
38    #[inline]
39    pub(super) fn from_arc<C: 'static>(data: triomphe::Arc<ReportData<C>>) -> Self {
40        let ptr: *const ReportData<C> = triomphe::Arc::into_raw(data);
41        let ptr: *mut ReportData<Erased> = ptr as _;
42
43        // SAFETY: Triomphe guarantees that `Arc::into_raw` returns a non-null pointer
44        let ptr: NonNull<ReportData<Erased>> = unsafe { NonNull::new_unchecked(ptr) };
45
46        Self { ptr }
47    }
48
49    /// Consumes the RawReport without decrementing the reference count and
50    /// returns the inner pointer.
51    #[inline]
52    pub(super) fn into_non_null(self) -> NonNull<ReportData<Erased>> {
53        let ptr = self.ptr;
54        core::mem::forget(self);
55        ptr
56    }
57
58    /// Creates a new [`RawReport`] with the specified handler, context,
59    /// children, and attachments.
60    #[inline]
61    pub fn new<C, H>(context: C, children: Vec<RawReport>, attachments: Vec<RawAttachment>) -> Self
62    where
63        C: 'static,
64        H: ContextHandler<C>,
65    {
66        let data = triomphe::Arc::new(ReportData::new::<H>(context, children, attachments));
67        Self::from_arc(data)
68    }
69
70    /// Returns a reference to the [`ReportData`] instance.
71    #[inline]
72    pub fn as_ref(&self) -> RawReportRef<'_> {
73        RawReportRef {
74            ptr: self.ptr,
75            _marker: core::marker::PhantomData,
76        }
77    }
78
79    /// Returns a mutable reference to the [`ReportData`] instance.
80    ///
81    /// # Safety
82    ///
83    /// The caller must ensure that this is the only existing reference pointing
84    /// to the inner [`ReportData`].
85    #[inline]
86    pub unsafe fn as_mut(&mut self) -> RawReportMut<'_> {
87        RawReportMut {
88            ptr: self.ptr,
89            _marker: core::marker::PhantomData,
90        }
91    }
92}
93
94impl core::ops::Drop for RawReport {
95    #[inline]
96    fn drop(&mut self) {
97        let vtable = self.as_ref().vtable();
98
99        // SAFETY: The vtable drop method has three safety requirements:
100        // - The pointer must come from `triomphe::Arc<ReportData<C>>` via
101        //   `triomphe::Arc::into_raw`
102        // - The `C` type in `ReportData<C>` must match the vtable's `C` type
103        // - The pointer must not be used after this call
104        //
105        // These are satisfied because:
106        // - The only way to construct or alter a `RawReport` is through the
107        //   `RawReport::new` method
108        // - The only way to construct or alter a `ReportData` is through the
109        //   `ReportData::new` method
110        // - This is guaranteed by the fact that we are in the `drop()` function
111        unsafe {
112            vtable.drop(self.ptr);
113        }
114    }
115}
116
117/// A lifetime-bound pointer to a [`ReportData`] that is guaranteed to point
118/// to an initialized instance of a [`ReportData<C>`] for some specific `C`,
119/// though we do not know which actual `C` it is.
120///
121/// We cannot use a [`&'a ReportData<C>`] directly, because that would require
122/// us to know the actual type of the context, which we do not.
123///
124/// [`&'a ReportData<C>`]: ReportData
125#[derive(Clone, Copy)]
126#[repr(transparent)]
127pub struct RawReportRef<'a> {
128    /// Pointer to the inner report data
129    ptr: NonNull<ReportData<Erased>>,
130    /// Marker to tell the compiler that we should
131    /// behave the same as a `&'a ReportData<Erased>`
132    _marker: core::marker::PhantomData<&'a ReportData<Erased>>,
133}
134
135impl<'a> RawReportRef<'a> {
136    /// Casts the [`RawReportRef`] to a [`ReportData<C>`] reference.
137    ///
138    /// # Safety
139    ///
140    /// The caller must ensure that the type `C` matches the actual context type
141    /// stored in the [`ReportData`].
142    #[inline]
143    pub(super) unsafe fn cast_inner<C: CastTo>(self) -> &'a ReportData<C::Target> {
144        // Debug assertion to catch type mismatches in case of bugs
145        debug_assert_eq!(self.vtable().type_id(), TypeId::of::<C>());
146
147        let this = self.ptr.cast::<ReportData<C::Target>>();
148        // SAFETY: Our caller guarantees that we point to a ReportData<C>, so it is safe
149        // to turn the NonNull pointer into a reference with the same lifetime
150        unsafe { this.as_ref() }
151    }
152
153    /// Returns a [`NonNull`] pointer to the [`ReportData`] instance.
154    #[inline]
155    pub(super) fn as_ptr(self) -> *const ReportData<Erased> {
156        self.ptr.as_ptr()
157    }
158
159    /// Returns the [`TypeId`] of the context.
160    #[inline]
161    pub fn context_type_id(self) -> TypeId {
162        self.vtable().type_id()
163    }
164
165    /// Returns the [`TypeId`] of the context.
166    #[inline]
167    pub fn context_handler_type_id(self) -> TypeId {
168        self.vtable().handler_type_id()
169    }
170
171    /// Checks if the type of the context matches the specified type and returns
172    /// a reference to it if it does.
173    #[inline]
174    pub fn context_downcast<C: 'static>(self) -> Option<&'a C> {
175        if self.context_type_id() == core::any::TypeId::of::<C>() {
176            // SAFETY: We must ensure that the `C` in the ReportData matches the `C` we are
177            // using as an argument. However, we have just checked that the
178            // types match, so that is fine.
179            unsafe { Some(self.context_downcast_unchecked::<C>()) }
180        } else {
181            None
182        }
183    }
184
185    /// Returns the source of the context using the [`ContextHandler::source`]
186    /// method specified when the [`ReportData`] was created.
187    #[inline]
188    pub fn context_source(self) -> Option<&'a (dyn core::error::Error + 'static)> {
189        let vtable = self.vtable();
190        // SAFETY: We must ensure that the `C` of the `ReportData` matches the `C` of
191        // the `ReportVtable`. However, the only way to construct a `ReportData`
192        // is through the `ReportData::new` method, which ensures this fact.
193        unsafe { vtable.source(self) }
194    }
195
196    /// Formats the context by using the [`ContextHandler::display`] method
197    /// specified by the handler used to create the [`ReportData`].
198    #[inline]
199    pub fn context_display(self, formatter: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
200        let vtable = self.vtable();
201        // SAFETY: We must ensure that the `C` of the `ReportData` matches the `C` of
202        // the `ReportVtable`. However, the only way to construct a `ReportData`
203        // is through the `ReportData::new` method, which ensures this fact.
204        unsafe { vtable.display(self, formatter) }
205    }
206
207    /// Formats the context by using the [`ContextHandler::debug`] method
208    /// specified by the handler used to create the [`ReportData`].
209    #[inline]
210    pub fn context_debug(self, formatter: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
211        let vtable = self.vtable();
212        // SAFETY: We must ensure that the `C` of the `ReportData` matches the `C` of
213        // the `ReportVtable`. However, the only way to construct a `ReportData`
214        // is through the `ReportData::new` method, which ensures this fact.
215        unsafe { vtable.debug(self, formatter) }
216    }
217
218    /// The formatting style preferred by the context when formatted as part of
219    /// a report.
220    ///
221    /// # Arguments
222    ///
223    /// - `report_formatting_function`: Whether the report in which this
224    ///   attachment will be embedded is being formatted using [`Display`]
225    ///   formatting or [`Debug`]
226    ///
227    /// [`Display`]: core::fmt::Display
228    /// [`Debug`]: core::fmt::Debug
229    #[inline]
230    pub fn preferred_context_formatting_style(
231        self,
232        report_formatting_function: FormattingFunction,
233    ) -> ContextFormattingStyle {
234        let vtable = self.vtable();
235        // SAFETY: We must ensure that the `C` of the `ReportData` matches the `C` of
236        // the `ReportVtable`. However, the only way to construct a `ReportData`
237        // is through the `ReportData::new` method, which ensures this fact.
238        unsafe { vtable.preferred_context_formatting_style(self, report_formatting_function) }
239    }
240
241    /// Clones the inner [`triomphe::Arc`] and returns a new [`RawReport`]
242    /// pointing to the same data.
243    ///
244    /// # Safety
245    ///
246    /// There must be no external assumptions that there is unique ownership of
247    /// the [`triomphe::Arc`].
248    #[inline]
249    pub unsafe fn clone_arc(self) -> RawReport {
250        let vtable = self.vtable();
251        // SAFETY: We must ensure that the `C` of the `ReportData` matches the `C` of
252        // the `ReportVtable`. However, the only way to construct a `ReportData`
253        // is through the `ReportData::new` method, which ensures this fact.
254        //
255        // We must also ensure that there are no external assumptions that
256        // there is unique ownership of the `Arc`. However, this is guaranteed by
257        // our caller.
258        unsafe { vtable.clone_arc(self.ptr) }
259    }
260
261    /// Gets the strong_count of the inner [`triomphe::Arc`].
262    #[inline]
263    pub fn strong_count(self) -> usize {
264        let vtable = self.vtable();
265        // SAFETY: We must ensure that the `C` of the `ReportData` matches the `C` of
266        // the `ReportVtable`. However, the only way to construct a `ReportData`
267        // is through the `ReportData::new` method, which ensures this fact.
268        unsafe { vtable.strong_count(self.ptr) }
269    }
270}
271
272/// A mutable lifetime-bound pointer to a [`ReportData`] that is guaranteed to
273/// point to an initialized instance of a [`ReportData<C>`] for some specific
274/// `C`, though we do not know which actual `C` it is.
275///
276/// We cannot use a [`&'a mut ReportData<C>`] directly, because that would
277/// require us to know the actual type of the context, which we do not.
278///
279/// [`&'a mut ReportData<C>`]: ReportData
280#[repr(transparent)]
281pub struct RawReportMut<'a> {
282    /// Pointer to the inner report data
283    ptr: NonNull<ReportData<Erased>>,
284    /// Marker to tell the compiler that we should
285    /// behave the same as a `&'a mut ReportData<Erased>`
286    _marker: core::marker::PhantomData<&'a mut ReportData<Erased>>,
287}
288
289impl<'a> RawReportMut<'a> {
290    /// Casts the [`RawReportMut`] to a mutable [`ReportData<C>`] reference.
291    ///
292    /// # Safety
293    ///
294    /// The caller must ensure that the type `C` matches the actual context type
295    /// stored in the [`ReportData`].
296    #[inline]
297    pub(super) unsafe fn cast_inner<C: CastTo>(self) -> &'a mut ReportData<C::Target> {
298        // Debug assertion to catch type mismatches in case of bugs
299        debug_assert_eq!(self.as_ref().vtable().type_id(), TypeId::of::<C>());
300
301        let mut this = self.ptr.cast::<ReportData<C::Target>>();
302        // SAFETY: Our caller guarantees that we point to a ReportData<C>, so it is safe
303        // to turn the NonNull pointer into a reference with the same lifetime
304        unsafe { this.as_mut() }
305    }
306
307    /// Reborrows the mutable reference to the [`ReportData`] with a shorter
308    /// lifetime.
309    #[inline]
310    pub fn reborrow<'b>(&'b mut self) -> RawReportMut<'b> {
311        RawReportMut {
312            ptr: self.ptr,
313            _marker: core::marker::PhantomData,
314        }
315    }
316
317    /// Returns a reference to the [`ReportData`] instance.
318    #[inline]
319    pub fn as_ref(&self) -> RawReportRef<'_> {
320        RawReportRef {
321            ptr: self.ptr,
322            _marker: core::marker::PhantomData,
323        }
324    }
325
326    /// Consumes the mutable reference and returns an immutable one with the
327    /// same lifetime.
328    #[inline]
329    pub fn into_ref(self) -> RawReportRef<'a> {
330        RawReportRef {
331            ptr: self.ptr,
332            _marker: core::marker::PhantomData,
333        }
334    }
335
336    /// Consumes this [`RawReportMut`] and returns a raw mutable pointer to the
337    /// underlying [`ReportData`].
338    ///
339    /// This method is primarily used for internal operations that require
340    /// direct pointer access.
341    #[inline]
342    pub(super) fn into_mut_ptr(self) -> *mut ReportData<Erased> {
343        self.ptr.as_ptr()
344    }
345}
346
347#[cfg(test)]
348mod tests {
349    use alloc::{string::String, vec};
350    use core::{error::Error, fmt};
351
352    use super::*;
353    use crate::handlers::ContextHandler;
354
355    struct HandlerI32;
356    impl ContextHandler<i32> for HandlerI32 {
357        fn source(_value: &i32) -> Option<&(dyn Error + 'static)> {
358            None
359        }
360
361        fn display(value: &i32, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
362            fmt::Display::fmt(value, formatter)
363        }
364
365        fn debug(value: &i32, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
366            fmt::Debug::fmt(value, formatter)
367        }
368    }
369
370    struct HandlerString;
371    impl ContextHandler<String> for HandlerString {
372        fn source(_value: &String) -> Option<&(dyn Error + 'static)> {
373            None
374        }
375
376        fn display(value: &String, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
377            fmt::Display::fmt(value, formatter)
378        }
379
380        fn debug(value: &String, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
381            fmt::Debug::fmt(value, formatter)
382        }
383    }
384
385    #[test]
386    fn test_raw_report_size() {
387        assert_eq!(
388            core::mem::size_of::<RawReport>(),
389            core::mem::size_of::<usize>()
390        );
391        assert_eq!(
392            core::mem::size_of::<Option<RawReport>>(),
393            core::mem::size_of::<usize>()
394        );
395        assert_eq!(
396            core::mem::size_of::<Result<(), RawReport>>(),
397            core::mem::size_of::<usize>()
398        );
399        assert_eq!(
400            core::mem::size_of::<Result<String, RawReport>>(),
401            core::mem::size_of::<String>()
402        );
403        assert_eq!(
404            core::mem::size_of::<Option<Option<RawReport>>>(),
405            core::mem::size_of::<Option<usize>>()
406        );
407
408        assert_eq!(
409            core::mem::size_of::<RawReportRef<'_>>(),
410            core::mem::size_of::<usize>()
411        );
412        assert_eq!(
413            core::mem::size_of::<Option<RawReportRef<'_>>>(),
414            core::mem::size_of::<usize>()
415        );
416        assert_eq!(
417            core::mem::size_of::<Result<(), RawReportRef<'_>>>(),
418            core::mem::size_of::<usize>()
419        );
420        assert_eq!(
421            core::mem::size_of::<Result<String, RawReportRef<'_>>>(),
422            core::mem::size_of::<String>()
423        );
424        assert_eq!(
425            core::mem::size_of::<Option<Option<RawReportRef<'_>>>>(),
426            core::mem::size_of::<Option<usize>>()
427        );
428
429        assert_eq!(
430            core::mem::size_of::<RawReportMut<'_>>(),
431            core::mem::size_of::<usize>()
432        );
433        assert_eq!(
434            core::mem::size_of::<Option<RawReportMut<'_>>>(),
435            core::mem::size_of::<usize>()
436        );
437        assert_eq!(
438            core::mem::size_of::<Result<(), RawReportMut<'_>>>(),
439            core::mem::size_of::<usize>()
440        );
441        assert_eq!(
442            core::mem::size_of::<Result<String, RawReportMut<'_>>>(),
443            core::mem::size_of::<String>()
444        );
445        assert_eq!(
446            core::mem::size_of::<Option<Option<RawReportMut<'_>>>>(),
447            core::mem::size_of::<Option<usize>>()
448        );
449    }
450
451    #[test]
452    fn test_raw_report_get_refs() {
453        let report = RawReport::new::<i32, HandlerI32>(789, vec![], vec![]);
454        let report_ref = report.as_ref();
455
456        // Accessing the pointer multiple times should be safe and consistent
457        let ptr1 = report_ref.as_ptr();
458        let ptr2 = report_ref.as_ptr();
459        assert_eq!(ptr1, ptr2);
460    }
461
462    #[test]
463    fn test_raw_report_clone_arc() {
464        // Test that Arc cloning maintains safety
465        let report = RawReport::new::<i32, HandlerI32>(123, vec![], vec![]);
466        let report_ref = report.as_ref();
467
468        assert_eq!(report_ref.strong_count(), 1);
469
470        // Original should have valid data
471        assert_eq!(report_ref.context_type_id(), TypeId::of::<i32>());
472
473        // Clone should work and maintain same type
474        // SAFETY: There are no assumptions on single ownership
475        let cloned = unsafe { report_ref.clone_arc() };
476        let cloned_ref = cloned.as_ref();
477
478        assert_eq!(report_ref.strong_count(), 2);
479        assert_eq!(cloned_ref.strong_count(), 2);
480
481        // Both should have same type and vtable
482        assert_eq!(report_ref.context_type_id(), cloned_ref.context_type_id());
483        assert!(core::ptr::eq(report_ref.vtable(), cloned_ref.vtable()));
484
485        core::mem::drop(cloned);
486
487        // After dropping the strong count should go back down
488        assert_eq!(report_ref.strong_count(), 1);
489    }
490
491    #[test]
492    fn test_raw_attachment_downcast() {
493        let int_report = RawReport::new::<i32, HandlerI32>(42, vec![], vec![]);
494        let string_report =
495            RawReport::new::<String, HandlerString>(String::from("test"), vec![], vec![]);
496
497        let int_ref = int_report.as_ref();
498        let string_ref = string_report.as_ref();
499
500        // Are TypeIds what we expect?
501        assert_eq!(int_ref.context_type_id(), TypeId::of::<i32>());
502        assert_eq!(string_ref.context_type_id(), TypeId::of::<String>());
503
504        // The vtables should be different
505        assert!(!core::ptr::eq(int_ref.vtable(), string_ref.vtable()));
506
507        // Cross-type downcasting should fail safely
508        assert!(int_ref.context_downcast::<String>().is_none());
509        assert!(string_ref.context_downcast::<i32>().is_none());
510
511        // Correct downcasting should work
512        assert_eq!(int_ref.context_downcast::<i32>().unwrap(), &42);
513        assert_eq!(string_ref.context_downcast::<String>().unwrap(), "test");
514    }
515
516    #[test]
517    fn test_raw_report_children() {
518        let child = RawReport::new::<i32, HandlerI32>(1, vec![], vec![]);
519        let parent = RawReport::new::<i32, HandlerI32>(0, vec![child], vec![]);
520
521        let parent_ref = parent.as_ref();
522        assert_eq!(parent_ref.context_downcast::<i32>().unwrap(), &0);
523
524        // Parent should have one child
525        let children = parent_ref.children();
526        assert_eq!(children.len(), 1);
527
528        // Child should be accessible safely
529        let child_ref = children[0].as_ref();
530        assert_eq!(child_ref.context_type_id(), TypeId::of::<i32>());
531        assert_eq!(child_ref.children().len(), 0);
532        assert_eq!(child_ref.context_downcast::<i32>().unwrap(), &1);
533
534        // Both should have same vtable (same type)
535        assert!(core::ptr::eq(parent_ref.vtable(), child_ref.vtable()));
536    }
537
538    #[test]
539    fn test_raw_report_with_attachments() {
540        use crate::{attachment::RawAttachment, handlers::AttachmentHandler};
541
542        // Create a simple attachment handler for i32
543        struct AttachmentHandlerI32;
544        impl AttachmentHandler<i32> for AttachmentHandlerI32 {
545            fn display(value: &i32, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
546                fmt::Display::fmt(value, formatter)
547            }
548
549            fn debug(value: &i32, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
550                fmt::Debug::fmt(value, formatter)
551            }
552        }
553
554        // Create some attachments
555        let attachment1 = RawAttachment::new::<i32, AttachmentHandlerI32>(100);
556        let attachment2 = RawAttachment::new::<i32, AttachmentHandlerI32>(200);
557
558        // Create a child report with one attachment
559        let child = RawReport::new::<i32, HandlerI32>(1, vec![], vec![attachment1]);
560
561        // Create a parent report with the child and another attachment
562        let parent = RawReport::new::<i32, HandlerI32>(0, vec![child], vec![attachment2]);
563
564        let parent_ref = parent.as_ref();
565        assert_eq!(parent_ref.context_downcast::<i32>().unwrap(), &0);
566
567        // Parent should have one child and one attachment
568        let children = parent_ref.children();
569        let attachments = parent_ref.attachments();
570        assert_eq!(children.len(), 1);
571        assert_eq!(attachments.len(), 1);
572
573        // Child should be accessible safely and have one attachment
574        let child_ref = children[0].as_ref();
575        assert_eq!(child_ref.context_type_id(), TypeId::of::<i32>());
576        assert_eq!(child_ref.context_downcast::<i32>().unwrap(), &1);
577        assert_eq!(child_ref.children().len(), 0);
578        assert_eq!(child_ref.attachments().len(), 1);
579
580        // Check attachment downcasting works
581        let parent_attachment_ref = attachments[0].as_ref();
582        let child_attachment_ref = child_ref.attachments()[0].as_ref();
583
584        assert_eq!(
585            parent_attachment_ref.attachment_type_id(),
586            TypeId::of::<i32>()
587        );
588        assert_eq!(
589            child_attachment_ref.attachment_type_id(),
590            TypeId::of::<i32>()
591        );
592
593        // Downcast attachments and verify values
594        assert_eq!(
595            *parent_attachment_ref.attachment_downcast::<i32>().unwrap(),
596            200
597        );
598        assert_eq!(
599            *child_attachment_ref.attachment_downcast::<i32>().unwrap(),
600            100
601        );
602
603        // Both reports should have same vtable (same context type)
604        assert!(core::ptr::eq(parent_ref.vtable(), child_ref.vtable()));
605    }
606
607    #[test]
608    fn test_raw_report_mut_basic() {
609        let mut report = RawReport::new::<i32, HandlerI32>(789, vec![], vec![]);
610
611        // SAFETY: We have unique ownership of the report
612        let mut report_mut = unsafe { report.as_mut() };
613
614        // Test that we can get a reference from the mutable reference
615        let report_ref = report_mut.as_ref();
616        assert_eq!(report_ref.context_type_id(), TypeId::of::<i32>());
617        assert_eq!(report_ref.context_downcast::<i32>().unwrap(), &789);
618
619        // Test reborrow functionality
620        let reborrowed = report_mut.reborrow();
621        let ref_from_reborrow = reborrowed.as_ref();
622        assert_eq!(ref_from_reborrow.context_type_id(), TypeId::of::<i32>());
623        assert_eq!(ref_from_reborrow.context_downcast::<i32>().unwrap(), &789);
624
625        // Test into_mut_ptr
626        let ptr = report_mut.into_mut_ptr();
627        assert!(!ptr.is_null());
628    }
629
630    #[test]
631    fn test_raw_report_mut_reborrow_lifetime() {
632        let mut report =
633            RawReport::new::<String, HandlerString>(String::from("test"), vec![], vec![]);
634
635        // SAFETY: We have unique ownership of the report
636        let mut report_mut = unsafe { report.as_mut() };
637
638        // Test that reborrow works with different lifetimes
639        {
640            let short_reborrow = report_mut.reborrow();
641            let ref_from_short = short_reborrow.as_ref();
642            assert_eq!(ref_from_short.context_downcast::<String>().unwrap(), "test");
643        }
644
645        // Original mutable reference should still be usable
646        let final_ref = report_mut.as_ref();
647        assert_eq!(final_ref.context_downcast::<String>().unwrap(), "test");
648    }
649
650    #[test]
651    fn test_raw_report_mut_with_children() {
652        let child = RawReport::new::<i32, HandlerI32>(1, vec![], vec![]);
653        let mut parent = RawReport::new::<i32, HandlerI32>(0, vec![child], vec![]);
654
655        // SAFETY: We have unique ownership of the parent report
656        let mut parent_mut = unsafe { parent.as_mut() };
657
658        let parent_ref = parent_mut.as_ref();
659        assert_eq!(parent_ref.context_downcast::<i32>().unwrap(), &0);
660
661        // Check that children are still accessible through the reference
662        let children = parent_ref.children();
663        assert_eq!(children.len(), 1);
664
665        let child_ref = children[0].as_ref();
666        assert_eq!(child_ref.context_downcast::<i32>().unwrap(), &1);
667
668        // Test reborrow with children
669        let reborrowed = parent_mut.reborrow();
670        let reborrow_ref = reborrowed.as_ref();
671        let reborrow_children = reborrow_ref.children();
672        assert_eq!(reborrow_children.len(), 1);
673        assert_eq!(
674            reborrow_children[0]
675                .as_ref()
676                .context_downcast::<i32>()
677                .unwrap(),
678            &1
679        );
680    }
681
682    #[test]
683    fn test_raw_report_mut_ptr_consistency() {
684        let mut report = RawReport::new::<i32, HandlerI32>(42, vec![], vec![]);
685
686        // Get immutable reference pointer first
687        let immut_ref = report.as_ref();
688        let immut_ptr = immut_ref.as_ptr() as usize;
689        // SAFETY: We have unique ownership of the report
690        let report_mut = unsafe { report.as_mut() };
691
692        // Get mutable pointer
693        let mut_ptr = report_mut.into_mut_ptr();
694
695        // Both pointers should point to the same location
696        assert_eq!(immut_ptr, mut_ptr as *const _ as usize);
697    }
698    #[test]
699    fn test_send_sync() {
700        static_assertions::assert_not_impl_any!(RawReport: Send, Sync);
701        static_assertions::assert_not_impl_any!(RawReportRef<'_>: Send, Sync);
702        static_assertions::assert_not_impl_any!(RawReportMut<'_>: Send, Sync);
703    }
704}