rootcause_internals/report/
raw.rs

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