1use 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#[repr(transparent)]
31pub struct RawReport {
32 ptr: NonNull<ReportData<Erased>>,
34}
35
36impl RawReport {
37 #[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 let ptr: NonNull<ReportData<Erased>> = unsafe { NonNull::new_unchecked(ptr) };
45
46 Self { ptr }
47 }
48
49 #[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 #[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 #[inline]
72 pub fn as_ref(&self) -> RawReportRef<'_> {
73 RawReportRef {
74 ptr: self.ptr,
75 _marker: core::marker::PhantomData,
76 }
77 }
78
79 #[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 unsafe {
112 vtable.drop(self.ptr);
113 }
114 }
115}
116
117#[derive(Clone, Copy)]
126#[repr(transparent)]
127pub struct RawReportRef<'a> {
128 ptr: NonNull<ReportData<Erased>>,
130 _marker: core::marker::PhantomData<&'a ReportData<Erased>>,
133}
134
135impl<'a> RawReportRef<'a> {
136 #[inline]
143 pub(super) unsafe fn cast_inner<C: CastTo>(self) -> &'a ReportData<C::Target> {
144 debug_assert_eq!(self.vtable().type_id(), TypeId::of::<C>());
146
147 let this = self.ptr.cast::<ReportData<C::Target>>();
148 unsafe { this.as_ref() }
151 }
152
153 #[inline]
155 pub(super) fn as_ptr(self) -> *const ReportData<Erased> {
156 self.ptr.as_ptr()
157 }
158
159 #[inline]
161 pub fn context_type_id(self) -> TypeId {
162 self.vtable().type_id()
163 }
164
165 #[inline]
167 pub fn context_handler_type_id(self) -> TypeId {
168 self.vtable().handler_type_id()
169 }
170
171 #[inline]
174 pub fn context_downcast<C: 'static>(self) -> Option<&'a C> {
175 if self.context_type_id() == core::any::TypeId::of::<C>() {
176 unsafe { Some(self.context_downcast_unchecked::<C>()) }
180 } else {
181 None
182 }
183 }
184
185 #[inline]
188 pub fn context_source(self) -> Option<&'a (dyn core::error::Error + 'static)> {
189 let vtable = self.vtable();
190 unsafe { vtable.source(self) }
194 }
195
196 #[inline]
199 pub fn context_display(self, formatter: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
200 let vtable = self.vtable();
201 unsafe { vtable.display(self, formatter) }
205 }
206
207 #[inline]
210 pub fn context_debug(self, formatter: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
211 let vtable = self.vtable();
212 unsafe { vtable.debug(self, formatter) }
216 }
217
218 #[inline]
230 pub fn preferred_context_formatting_style(
231 self,
232 report_formatting_function: FormattingFunction,
233 ) -> ContextFormattingStyle {
234 let vtable = self.vtable();
235 unsafe { vtable.preferred_context_formatting_style(self, report_formatting_function) }
239 }
240
241 #[inline]
249 pub unsafe fn clone_arc(self) -> RawReport {
250 let vtable = self.vtable();
251 unsafe { vtable.clone_arc(self.ptr) }
259 }
260
261 #[inline]
263 pub fn strong_count(self) -> usize {
264 let vtable = self.vtable();
265 unsafe { vtable.strong_count(self.ptr) }
269 }
270}
271
272#[repr(transparent)]
281pub struct RawReportMut<'a> {
282 ptr: NonNull<ReportData<Erased>>,
284 _marker: core::marker::PhantomData<&'a mut ReportData<Erased>>,
287}
288
289impl<'a> RawReportMut<'a> {
290 #[inline]
297 pub(super) unsafe fn cast_inner<C: CastTo>(self) -> &'a mut ReportData<C::Target> {
298 debug_assert_eq!(self.as_ref().vtable().type_id(), TypeId::of::<C>());
300
301 let mut this = self.ptr.cast::<ReportData<C::Target>>();
302 unsafe { this.as_mut() }
305 }
306
307 #[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 #[inline]
319 pub fn as_ref(&self) -> RawReportRef<'_> {
320 RawReportRef {
321 ptr: self.ptr,
322 _marker: core::marker::PhantomData,
323 }
324 }
325
326 #[inline]
329 pub fn into_ref(self) -> RawReportRef<'a> {
330 RawReportRef {
331 ptr: self.ptr,
332 _marker: core::marker::PhantomData,
333 }
334 }
335
336 #[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 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 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 assert_eq!(report_ref.context_type_id(), TypeId::of::<i32>());
472
473 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 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 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 assert_eq!(int_ref.context_type_id(), TypeId::of::<i32>());
502 assert_eq!(string_ref.context_type_id(), TypeId::of::<String>());
503
504 assert!(!core::ptr::eq(int_ref.vtable(), string_ref.vtable()));
506
507 assert!(int_ref.context_downcast::<String>().is_none());
509 assert!(string_ref.context_downcast::<i32>().is_none());
510
511 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 let children = parent_ref.children();
526 assert_eq!(children.len(), 1);
527
528 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 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 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 let attachment1 = RawAttachment::new::<i32, AttachmentHandlerI32>(100);
556 let attachment2 = RawAttachment::new::<i32, AttachmentHandlerI32>(200);
557
558 let child = RawReport::new::<i32, HandlerI32>(1, vec![], vec![attachment1]);
560
561 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 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 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 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 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 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 let mut report_mut = unsafe { report.as_mut() };
613
614 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 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 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 let mut report_mut = unsafe { report.as_mut() };
637
638 {
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 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 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 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 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 let immut_ref = report.as_ref();
688 let immut_ptr = immut_ref.as_ptr() as usize;
689 let report_mut = unsafe { report.as_mut() };
691
692 let mut_ptr = report_mut.into_mut_ptr();
694
695 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}