rootcause_internals/report/
raw.rs1use alloc::vec::Vec;
33use core::{any::TypeId, ptr::NonNull};
34
35use crate::{
36 attachment::RawAttachment,
37 handlers::{ContextFormattingStyle, ContextHandler, FormattingFunction},
38 report::data::ReportData,
39 util::{CastTo, Erased},
40};
41
42#[repr(transparent)]
55pub struct RawReport {
56 ptr: NonNull<ReportData<Erased>>,
58}
59
60impl RawReport {
61 #[inline]
63 pub(super) fn from_arc<C: 'static>(data: triomphe::Arc<ReportData<C>>) -> Self {
64 let ptr: *const ReportData<C> = triomphe::Arc::into_raw(data);
65 let ptr: *mut ReportData<Erased> = ptr as _;
66
67 let ptr: NonNull<ReportData<Erased>> = unsafe { NonNull::new_unchecked(ptr) };
69
70 Self { ptr }
71 }
72
73 #[inline]
76 pub(super) fn into_non_null(self) -> NonNull<ReportData<Erased>> {
77 let ptr = self.ptr;
78 core::mem::forget(self);
79 ptr
80 }
81
82 #[inline]
85 pub fn new<C, H>(context: C, children: Vec<RawReport>, attachments: Vec<RawAttachment>) -> Self
86 where
87 C: 'static,
88 H: ContextHandler<C>,
89 {
90 let data = triomphe::Arc::new(ReportData::new::<H>(context, children, attachments));
91 Self::from_arc(data)
92 }
93
94 #[inline]
96 pub fn as_ref(&self) -> RawReportRef<'_> {
97 RawReportRef {
98 ptr: self.ptr,
99 _marker: core::marker::PhantomData,
100 }
101 }
102
103 #[inline]
110 pub unsafe fn as_mut(&mut self) -> RawReportMut<'_> {
111 RawReportMut {
112 ptr: self.ptr,
113 _marker: core::marker::PhantomData,
114 }
115 }
116}
117
118impl core::ops::Drop for RawReport {
119 #[inline]
120 fn drop(&mut self) {
121 let vtable = self.as_ref().vtable();
122
123 unsafe {
136 vtable.drop(self.ptr);
137 }
138 }
139}
140
141#[derive(Clone, Copy)]
150#[repr(transparent)]
151pub struct RawReportRef<'a> {
152 ptr: NonNull<ReportData<Erased>>,
154 _marker: core::marker::PhantomData<&'a ReportData<Erased>>,
157}
158
159impl<'a> RawReportRef<'a> {
160 #[inline]
167 pub(super) unsafe fn cast_inner<C: CastTo>(self) -> &'a ReportData<C::Target> {
168 debug_assert_eq!(self.vtable().type_id(), TypeId::of::<C>());
170
171 let this = self.ptr.cast::<ReportData<C::Target>>();
172 unsafe { this.as_ref() }
178 }
179
180 #[inline]
182 pub(super) fn as_ptr(self) -> *const ReportData<Erased> {
183 self.ptr.as_ptr()
184 }
185
186 #[inline]
188 pub fn context_type_id(self) -> TypeId {
189 self.vtable().type_id()
190 }
191
192 #[inline]
194 pub fn context_handler_type_id(self) -> TypeId {
195 self.vtable().handler_type_id()
196 }
197
198 #[inline]
201 pub fn context_downcast<C: 'static>(self) -> Option<&'a C> {
202 if self.context_type_id() == core::any::TypeId::of::<C>() {
203 unsafe { Some(self.context_downcast_unchecked::<C>()) }
207 } else {
208 None
209 }
210 }
211
212 #[inline]
215 pub fn context_source(self) -> Option<&'a (dyn core::error::Error + 'static)> {
216 let vtable = self.vtable();
217 unsafe { vtable.source(self) }
221 }
222
223 #[inline]
226 pub fn context_display(self, formatter: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
227 let vtable = self.vtable();
228 unsafe { vtable.display(self, formatter) }
232 }
233
234 #[inline]
237 pub fn context_debug(self, formatter: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
238 let vtable = self.vtable();
239 unsafe { vtable.debug(self, formatter) }
243 }
244
245 #[inline]
257 pub fn preferred_context_formatting_style(
258 self,
259 report_formatting_function: FormattingFunction,
260 ) -> ContextFormattingStyle {
261 let vtable = self.vtable();
262 unsafe { vtable.preferred_context_formatting_style(self, report_formatting_function) }
266 }
267
268 #[inline]
276 pub unsafe fn clone_arc(self) -> RawReport {
277 let vtable = self.vtable();
278 unsafe { vtable.clone_arc(self.ptr) }
286 }
287
288 #[inline]
290 pub fn strong_count(self) -> usize {
291 let vtable = self.vtable();
292 unsafe { vtable.strong_count(self.ptr) }
296 }
297}
298
299#[repr(transparent)]
308pub struct RawReportMut<'a> {
309 ptr: NonNull<ReportData<Erased>>,
311 _marker: core::marker::PhantomData<&'a mut ReportData<Erased>>,
314}
315
316impl<'a> RawReportMut<'a> {
317 #[inline]
324 pub(super) unsafe fn cast_inner<C: CastTo>(self) -> &'a mut ReportData<C::Target> {
325 debug_assert_eq!(self.as_ref().vtable().type_id(), TypeId::of::<C>());
327
328 let mut this = self.ptr.cast::<ReportData<C::Target>>();
329 unsafe { this.as_mut() }
335 }
336
337 #[inline]
340 pub fn reborrow<'b>(&'b mut self) -> RawReportMut<'b> {
341 RawReportMut {
342 ptr: self.ptr,
343 _marker: core::marker::PhantomData,
344 }
345 }
346
347 #[inline]
349 pub fn as_ref(&self) -> RawReportRef<'_> {
350 RawReportRef {
351 ptr: self.ptr,
352 _marker: core::marker::PhantomData,
353 }
354 }
355
356 #[inline]
359 pub fn into_ref(self) -> RawReportRef<'a> {
360 RawReportRef {
361 ptr: self.ptr,
362 _marker: core::marker::PhantomData,
363 }
364 }
365
366 #[inline]
372 pub(super) fn into_mut_ptr(self) -> *mut ReportData<Erased> {
373 self.ptr.as_ptr()
374 }
375}
376
377#[cfg(test)]
378mod tests {
379 use alloc::{string::String, vec};
380 use core::{error::Error, fmt};
381
382 use super::*;
383 use crate::handlers::ContextHandler;
384
385 struct HandlerI32;
386 impl ContextHandler<i32> for HandlerI32 {
387 fn source(_value: &i32) -> Option<&(dyn Error + 'static)> {
388 None
389 }
390
391 fn display(value: &i32, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
392 fmt::Display::fmt(value, formatter)
393 }
394
395 fn debug(value: &i32, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
396 fmt::Debug::fmt(value, formatter)
397 }
398 }
399
400 struct HandlerString;
401 impl ContextHandler<String> for HandlerString {
402 fn source(_value: &String) -> Option<&(dyn Error + 'static)> {
403 None
404 }
405
406 fn display(value: &String, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
407 fmt::Display::fmt(value, formatter)
408 }
409
410 fn debug(value: &String, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
411 fmt::Debug::fmt(value, formatter)
412 }
413 }
414
415 #[test]
416 fn test_raw_report_size() {
417 assert_eq!(
418 core::mem::size_of::<RawReport>(),
419 core::mem::size_of::<usize>()
420 );
421 assert_eq!(
422 core::mem::size_of::<Option<RawReport>>(),
423 core::mem::size_of::<usize>()
424 );
425 assert_eq!(
426 core::mem::size_of::<Result<(), RawReport>>(),
427 core::mem::size_of::<usize>()
428 );
429 assert_eq!(
430 core::mem::size_of::<Result<String, RawReport>>(),
431 core::mem::size_of::<String>()
432 );
433 assert_eq!(
434 core::mem::size_of::<Option<Option<RawReport>>>(),
435 core::mem::size_of::<Option<usize>>()
436 );
437
438 assert_eq!(
439 core::mem::size_of::<RawReportRef<'_>>(),
440 core::mem::size_of::<usize>()
441 );
442 assert_eq!(
443 core::mem::size_of::<Option<RawReportRef<'_>>>(),
444 core::mem::size_of::<usize>()
445 );
446 assert_eq!(
447 core::mem::size_of::<Result<(), RawReportRef<'_>>>(),
448 core::mem::size_of::<usize>()
449 );
450 assert_eq!(
451 core::mem::size_of::<Result<String, RawReportRef<'_>>>(),
452 core::mem::size_of::<String>()
453 );
454 assert_eq!(
455 core::mem::size_of::<Option<Option<RawReportRef<'_>>>>(),
456 core::mem::size_of::<Option<usize>>()
457 );
458
459 assert_eq!(
460 core::mem::size_of::<RawReportMut<'_>>(),
461 core::mem::size_of::<usize>()
462 );
463 assert_eq!(
464 core::mem::size_of::<Option<RawReportMut<'_>>>(),
465 core::mem::size_of::<usize>()
466 );
467 assert_eq!(
468 core::mem::size_of::<Result<(), RawReportMut<'_>>>(),
469 core::mem::size_of::<usize>()
470 );
471 assert_eq!(
472 core::mem::size_of::<Result<String, RawReportMut<'_>>>(),
473 core::mem::size_of::<String>()
474 );
475 assert_eq!(
476 core::mem::size_of::<Option<Option<RawReportMut<'_>>>>(),
477 core::mem::size_of::<Option<usize>>()
478 );
479 }
480
481 #[test]
482 fn test_raw_report_get_refs() {
483 let report = RawReport::new::<i32, HandlerI32>(789, vec![], vec![]);
484 let report_ref = report.as_ref();
485
486 let ptr1 = report_ref.as_ptr();
488 let ptr2 = report_ref.as_ptr();
489 assert_eq!(ptr1, ptr2);
490 }
491
492 #[test]
493 fn test_raw_report_clone_arc() {
494 let report = RawReport::new::<i32, HandlerI32>(123, vec![], vec![]);
496 let report_ref = report.as_ref();
497
498 assert_eq!(report_ref.strong_count(), 1);
499
500 assert_eq!(report_ref.context_type_id(), TypeId::of::<i32>());
502
503 let cloned = unsafe { report_ref.clone_arc() };
506 let cloned_ref = cloned.as_ref();
507
508 assert_eq!(report_ref.strong_count(), 2);
509 assert_eq!(cloned_ref.strong_count(), 2);
510
511 assert_eq!(report_ref.context_type_id(), cloned_ref.context_type_id());
513 assert!(core::ptr::eq(report_ref.vtable(), cloned_ref.vtable()));
514
515 core::mem::drop(cloned);
516
517 assert_eq!(report_ref.strong_count(), 1);
519 }
520
521 #[test]
522 fn test_raw_attachment_downcast() {
523 let int_report = RawReport::new::<i32, HandlerI32>(42, vec![], vec![]);
524 let string_report =
525 RawReport::new::<String, HandlerString>(String::from("test"), vec![], vec![]);
526
527 let int_ref = int_report.as_ref();
528 let string_ref = string_report.as_ref();
529
530 assert_eq!(int_ref.context_type_id(), TypeId::of::<i32>());
532 assert_eq!(string_ref.context_type_id(), TypeId::of::<String>());
533
534 assert!(!core::ptr::eq(int_ref.vtable(), string_ref.vtable()));
536
537 assert!(int_ref.context_downcast::<String>().is_none());
539 assert!(string_ref.context_downcast::<i32>().is_none());
540
541 assert_eq!(int_ref.context_downcast::<i32>().unwrap(), &42);
543 assert_eq!(string_ref.context_downcast::<String>().unwrap(), "test");
544 }
545
546 #[test]
547 fn test_raw_report_children() {
548 let child = RawReport::new::<i32, HandlerI32>(1, vec![], vec![]);
549 let parent = RawReport::new::<i32, HandlerI32>(0, vec![child], vec![]);
550
551 let parent_ref = parent.as_ref();
552 assert_eq!(parent_ref.context_downcast::<i32>().unwrap(), &0);
553
554 let children = parent_ref.children();
556 assert_eq!(children.len(), 1);
557
558 let child_ref = children[0].as_ref();
560 assert_eq!(child_ref.context_type_id(), TypeId::of::<i32>());
561 assert_eq!(child_ref.children().len(), 0);
562 assert_eq!(child_ref.context_downcast::<i32>().unwrap(), &1);
563
564 assert!(core::ptr::eq(parent_ref.vtable(), child_ref.vtable()));
566 }
567
568 #[test]
569 fn test_raw_report_with_attachments() {
570 use crate::{attachment::RawAttachment, handlers::AttachmentHandler};
571
572 struct AttachmentHandlerI32;
574 impl AttachmentHandler<i32> for AttachmentHandlerI32 {
575 fn display(value: &i32, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
576 fmt::Display::fmt(value, formatter)
577 }
578
579 fn debug(value: &i32, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
580 fmt::Debug::fmt(value, formatter)
581 }
582 }
583
584 let attachment1 = RawAttachment::new::<i32, AttachmentHandlerI32>(100);
586 let attachment2 = RawAttachment::new::<i32, AttachmentHandlerI32>(200);
587
588 let child = RawReport::new::<i32, HandlerI32>(1, vec![], vec![attachment1]);
590
591 let parent = RawReport::new::<i32, HandlerI32>(0, vec![child], vec![attachment2]);
593
594 let parent_ref = parent.as_ref();
595 assert_eq!(parent_ref.context_downcast::<i32>().unwrap(), &0);
596
597 let children = parent_ref.children();
599 let attachments = parent_ref.attachments();
600 assert_eq!(children.len(), 1);
601 assert_eq!(attachments.len(), 1);
602
603 let child_ref = children[0].as_ref();
605 assert_eq!(child_ref.context_type_id(), TypeId::of::<i32>());
606 assert_eq!(child_ref.context_downcast::<i32>().unwrap(), &1);
607 assert_eq!(child_ref.children().len(), 0);
608 assert_eq!(child_ref.attachments().len(), 1);
609
610 let parent_attachment_ref = attachments[0].as_ref();
612 let child_attachment_ref = child_ref.attachments()[0].as_ref();
613
614 assert_eq!(
615 parent_attachment_ref.attachment_type_id(),
616 TypeId::of::<i32>()
617 );
618 assert_eq!(
619 child_attachment_ref.attachment_type_id(),
620 TypeId::of::<i32>()
621 );
622
623 assert_eq!(
625 *parent_attachment_ref.attachment_downcast::<i32>().unwrap(),
626 200
627 );
628 assert_eq!(
629 *child_attachment_ref.attachment_downcast::<i32>().unwrap(),
630 100
631 );
632
633 assert!(core::ptr::eq(parent_ref.vtable(), child_ref.vtable()));
635 }
636
637 #[test]
638 fn test_raw_report_mut_basic() {
639 let mut report = RawReport::new::<i32, HandlerI32>(789, vec![], vec![]);
640
641 let mut report_mut = unsafe { report.as_mut() };
643
644 let report_ref = report_mut.as_ref();
646 assert_eq!(report_ref.context_type_id(), TypeId::of::<i32>());
647 assert_eq!(report_ref.context_downcast::<i32>().unwrap(), &789);
648
649 let reborrowed = report_mut.reborrow();
651 let ref_from_reborrow = reborrowed.as_ref();
652 assert_eq!(ref_from_reborrow.context_type_id(), TypeId::of::<i32>());
653 assert_eq!(ref_from_reborrow.context_downcast::<i32>().unwrap(), &789);
654
655 let ptr = report_mut.into_mut_ptr();
657 assert!(!ptr.is_null());
658 }
659
660 #[test]
661 fn test_raw_report_mut_reborrow_lifetime() {
662 let mut report =
663 RawReport::new::<String, HandlerString>(String::from("test"), vec![], vec![]);
664
665 let mut report_mut = unsafe { report.as_mut() };
667
668 {
670 let short_reborrow = report_mut.reborrow();
671 let ref_from_short = short_reborrow.as_ref();
672 assert_eq!(ref_from_short.context_downcast::<String>().unwrap(), "test");
673 }
674
675 let final_ref = report_mut.as_ref();
677 assert_eq!(final_ref.context_downcast::<String>().unwrap(), "test");
678 }
679
680 #[test]
681 fn test_raw_report_mut_with_children() {
682 let child = RawReport::new::<i32, HandlerI32>(1, vec![], vec![]);
683 let mut parent = RawReport::new::<i32, HandlerI32>(0, vec![child], vec![]);
684
685 let mut parent_mut = unsafe { parent.as_mut() };
687
688 let parent_ref = parent_mut.as_ref();
689 assert_eq!(parent_ref.context_downcast::<i32>().unwrap(), &0);
690
691 let children = parent_ref.children();
693 assert_eq!(children.len(), 1);
694
695 let child_ref = children[0].as_ref();
696 assert_eq!(child_ref.context_downcast::<i32>().unwrap(), &1);
697
698 let reborrowed = parent_mut.reborrow();
700 let reborrow_ref = reborrowed.as_ref();
701 let reborrow_children = reborrow_ref.children();
702 assert_eq!(reborrow_children.len(), 1);
703 assert_eq!(
704 reborrow_children[0]
705 .as_ref()
706 .context_downcast::<i32>()
707 .unwrap(),
708 &1
709 );
710 }
711
712 #[test]
713 fn test_raw_report_mut_ptr_consistency() {
714 let mut report = RawReport::new::<i32, HandlerI32>(42, vec![], vec![]);
715
716 let immut_ref = report.as_ref();
718 let immut_ptr = immut_ref.as_ptr() as usize;
719 let report_mut = unsafe { report.as_mut() };
721
722 let mut_ptr = report_mut.into_mut_ptr();
724
725 assert_eq!(immut_ptr, mut_ptr as *const _ as usize);
727 }
728 #[test]
729 fn test_send_sync() {
730 static_assertions::assert_not_impl_any!(RawReport: Send, Sync);
731 static_assertions::assert_not_impl_any!(RawReportRef<'_>: Send, Sync);
732 static_assertions::assert_not_impl_any!(RawReportMut<'_>: Send, Sync);
733 }
734}