1use alloc::vec::Vec;
7use core::{any::TypeId, marker::PhantomData, ptr::NonNull};
8
9use crate::{
10 attachment::RawAttachment,
11 handlers::{ContextFormattingStyle, ContextHandler, FormattingFunction},
12 report::data::ReportData,
13 util::{CastTo, Erased},
14};
15
16#[repr(transparent)]
27pub struct RawReport {
28 ptr: NonNull<ReportData<Erased>>,
29 _marker: core::marker::PhantomData<ReportData<Erased>>,
30}
31
32impl RawReport {
33 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 let ptr: NonNull<ReportData<Erased>> = unsafe { NonNull::new_unchecked(ptr) };
40
41 Self {
42 ptr,
43 _marker: PhantomData,
44 }
45 }
46
47 pub(super) fn into_non_null(self) -> NonNull<ReportData<Erased>> {
50 let ptr = self.ptr;
51 core::mem::forget(self);
52 ptr
53 }
54
55 pub fn new<C, H>(context: C, children: Vec<RawReport>, attachments: Vec<RawAttachment>) -> Self
57 where
58 C: 'static,
59 H: ContextHandler<C>,
60 {
61 let data = triomphe::Arc::new(ReportData::new::<H>(context, children, attachments));
62 Self::from_arc(data)
63 }
64
65 pub fn as_ref(&self) -> RawReportRef<'_> {
67 RawReportRef {
68 ptr: self.ptr,
69 _marker: core::marker::PhantomData,
70 }
71 }
72
73 pub unsafe fn as_mut(&mut self) -> RawReportMut<'_> {
80 RawReportMut {
81 ptr: self.ptr,
82 _marker: core::marker::PhantomData,
83 }
84 }
85}
86
87impl core::ops::Drop for RawReport {
88 fn drop(&mut self) {
89 let vtable = self.as_ref().vtable();
90
91 unsafe {
101 vtable.drop(self.ptr);
102 }
103 }
104}
105
106#[derive(Clone, Copy)]
115#[repr(transparent)]
116pub struct RawReportRef<'a> {
117 ptr: NonNull<ReportData<Erased>>,
118 _marker: core::marker::PhantomData<&'a ReportData<Erased>>,
119}
120
121impl<'a> RawReportRef<'a> {
122 pub(super) unsafe fn cast_inner<C: CastTo>(self) -> &'a ReportData<C::Target> {
128 debug_assert_eq!(self.vtable().type_id(), TypeId::of::<C>());
130
131 let this = self.ptr.cast::<ReportData<C::Target>>();
132 unsafe { this.as_ref() }
135 }
136
137 pub(super) fn as_ptr(self) -> *const ReportData<Erased> {
139 self.ptr.as_ptr()
140 }
141
142 pub fn context_type_id(self) -> TypeId {
144 self.vtable().type_id()
145 }
146
147 pub fn context_handler_type_id(self) -> TypeId {
149 self.vtable().handler_type_id()
150 }
151
152 pub fn context_downcast<C: 'static>(self) -> Option<&'a C> {
154 if self.context_type_id() == core::any::TypeId::of::<C>() {
155 unsafe { Some(self.context_downcast_unchecked::<C>()) }
158 } else {
159 None
160 }
161 }
162
163 pub fn context_source(self) -> Option<&'a (dyn core::error::Error + 'static)> {
166 let vtable = self.vtable();
167 unsafe { vtable.source(self) }
171 }
172
173 pub fn context_display(self, formatter: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
176 let vtable = self.vtable();
177 unsafe { vtable.display(self, formatter) }
181 }
182
183 pub fn context_debug(self, formatter: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
186 let vtable = self.vtable();
187 unsafe { vtable.debug(self, formatter) }
191 }
192
193 pub fn preferred_context_formatting_style(
203 self,
204 report_formatting_function: FormattingFunction,
205 ) -> ContextFormattingStyle {
206 let vtable = self.vtable();
207 unsafe { vtable.preferred_context_formatting_style(self, report_formatting_function) }
211 }
212
213 pub unsafe fn clone_arc(self) -> RawReport {
219 let vtable = self.vtable();
220 unsafe { vtable.clone_arc(self.ptr) }
228 }
229
230 pub fn strong_count(self) -> usize {
232 let vtable = self.vtable();
233 unsafe { vtable.strong_count(self.ptr) }
237 }
238}
239
240#[repr(transparent)]
249pub struct RawReportMut<'a> {
250 ptr: NonNull<ReportData<Erased>>,
251 _marker: core::marker::PhantomData<&'a mut ReportData<Erased>>,
252}
253
254impl<'a> RawReportMut<'a> {
255 pub(super) unsafe fn cast_inner<C: CastTo>(self) -> &'a mut ReportData<C::Target> {
261 debug_assert_eq!(self.as_ref().vtable().type_id(), TypeId::of::<C>());
263
264 let mut this = self.ptr.cast::<ReportData<C::Target>>();
265 unsafe { this.as_mut() }
268 }
269
270 pub fn reborrow<'b>(&'b mut self) -> RawReportMut<'b> {
272 RawReportMut {
273 ptr: self.ptr,
274 _marker: core::marker::PhantomData,
275 }
276 }
277
278 pub fn as_ref(&self) -> RawReportRef<'_> {
280 RawReportRef {
281 ptr: self.ptr,
282 _marker: core::marker::PhantomData,
283 }
284 }
285
286 pub fn into_ref(self) -> RawReportRef<'a> {
288 RawReportRef {
289 ptr: self.ptr,
290 _marker: core::marker::PhantomData,
291 }
292 }
293
294 pub(super) fn into_mut_ptr(self) -> *mut ReportData<Erased> {
298 self.ptr.as_ptr()
299 }
300}
301
302#[cfg(test)]
303mod tests {
304 use alloc::{string::String, vec};
305 use core::{error::Error, fmt};
306
307 use super::*;
308 use crate::handlers::ContextHandler;
309
310 struct HandlerI32;
311 impl ContextHandler<i32> for HandlerI32 {
312 fn source(_value: &i32) -> Option<&(dyn Error + 'static)> {
313 None
314 }
315 fn display(value: &i32, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
316 fmt::Display::fmt(value, formatter)
317 }
318 fn debug(value: &i32, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
319 fmt::Debug::fmt(value, formatter)
320 }
321 }
322
323 struct HandlerString;
324 impl ContextHandler<String> for HandlerString {
325 fn source(_value: &String) -> Option<&(dyn Error + 'static)> {
326 None
327 }
328 fn display(value: &String, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
329 fmt::Display::fmt(value, formatter)
330 }
331 fn debug(value: &String, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
332 fmt::Debug::fmt(value, formatter)
333 }
334 }
335
336 #[test]
337 fn test_raw_report_size() {
338 assert_eq!(
339 core::mem::size_of::<RawReport>(),
340 core::mem::size_of::<usize>()
341 );
342 assert_eq!(
343 core::mem::size_of::<Option<RawReport>>(),
344 core::mem::size_of::<usize>()
345 );
346 assert_eq!(
347 core::mem::size_of::<Result<(), RawReport>>(),
348 core::mem::size_of::<usize>()
349 );
350 assert_eq!(
351 core::mem::size_of::<Result<String, RawReport>>(),
352 core::mem::size_of::<String>()
353 );
354 assert_eq!(
355 core::mem::size_of::<Option<Option<RawReport>>>(),
356 core::mem::size_of::<Option<usize>>()
357 );
358
359 assert_eq!(
360 core::mem::size_of::<RawReportRef<'_>>(),
361 core::mem::size_of::<usize>()
362 );
363 assert_eq!(
364 core::mem::size_of::<Option<RawReportRef<'_>>>(),
365 core::mem::size_of::<usize>()
366 );
367 assert_eq!(
368 core::mem::size_of::<Result<(), RawReportRef<'_>>>(),
369 core::mem::size_of::<usize>()
370 );
371 assert_eq!(
372 core::mem::size_of::<Result<String, RawReportRef<'_>>>(),
373 core::mem::size_of::<String>()
374 );
375 assert_eq!(
376 core::mem::size_of::<Option<Option<RawReportRef<'_>>>>(),
377 core::mem::size_of::<Option<usize>>()
378 );
379
380 assert_eq!(
381 core::mem::size_of::<RawReportMut<'_>>(),
382 core::mem::size_of::<usize>()
383 );
384 assert_eq!(
385 core::mem::size_of::<Option<RawReportMut<'_>>>(),
386 core::mem::size_of::<usize>()
387 );
388 assert_eq!(
389 core::mem::size_of::<Result<(), RawReportMut<'_>>>(),
390 core::mem::size_of::<usize>()
391 );
392 assert_eq!(
393 core::mem::size_of::<Result<String, RawReportMut<'_>>>(),
394 core::mem::size_of::<String>()
395 );
396 assert_eq!(
397 core::mem::size_of::<Option<Option<RawReportMut<'_>>>>(),
398 core::mem::size_of::<Option<usize>>()
399 );
400 }
401
402 #[test]
403 fn test_raw_report_get_refs() {
404 let report = RawReport::new::<i32, HandlerI32>(789, vec![], vec![]);
405 let report_ref = report.as_ref();
406
407 let ptr1 = report_ref.as_ptr();
409 let ptr2 = report_ref.as_ptr();
410 assert_eq!(ptr1, ptr2);
411 }
412
413 #[test]
414 fn test_raw_report_clone_arc() {
415 let report = RawReport::new::<i32, HandlerI32>(123, vec![], vec![]);
417 let report_ref = report.as_ref();
418
419 assert_eq!(report_ref.strong_count(), 1);
420
421 assert_eq!(report_ref.context_type_id(), TypeId::of::<i32>());
423
424 let cloned = unsafe { report_ref.clone_arc() };
427 let cloned_ref = cloned.as_ref();
428
429 assert_eq!(report_ref.strong_count(), 2);
430 assert_eq!(cloned_ref.strong_count(), 2);
431
432 assert_eq!(report_ref.context_type_id(), cloned_ref.context_type_id());
434 assert!(core::ptr::eq(report_ref.vtable(), cloned_ref.vtable()));
435
436 core::mem::drop(cloned);
437
438 assert_eq!(report_ref.strong_count(), 1);
440 }
441
442 #[test]
443 fn test_raw_attachment_downcast() {
444 let int_report = RawReport::new::<i32, HandlerI32>(42, vec![], vec![]);
445 let string_report =
446 RawReport::new::<String, HandlerString>(String::from("test"), vec![], vec![]);
447
448 let int_ref = int_report.as_ref();
449 let string_ref = string_report.as_ref();
450
451 assert_eq!(int_ref.context_type_id(), TypeId::of::<i32>());
453 assert_eq!(string_ref.context_type_id(), TypeId::of::<String>());
454
455 assert!(!core::ptr::eq(int_ref.vtable(), string_ref.vtable()));
457
458 assert!(int_ref.context_downcast::<String>().is_none());
460 assert!(string_ref.context_downcast::<i32>().is_none());
461
462 assert_eq!(int_ref.context_downcast::<i32>().unwrap(), &42);
464 assert_eq!(string_ref.context_downcast::<String>().unwrap(), "test");
465 }
466
467 #[test]
468 fn test_raw_report_children() {
469 let child = RawReport::new::<i32, HandlerI32>(1, vec![], vec![]);
470 let parent = RawReport::new::<i32, HandlerI32>(0, vec![child], vec![]);
471
472 let parent_ref = parent.as_ref();
473 assert_eq!(parent_ref.context_downcast::<i32>().unwrap(), &0);
474
475 let children = parent_ref.children();
477 assert_eq!(children.len(), 1);
478
479 let child_ref = children[0].as_ref();
481 assert_eq!(child_ref.context_type_id(), TypeId::of::<i32>());
482 assert_eq!(child_ref.children().len(), 0);
483 assert_eq!(child_ref.context_downcast::<i32>().unwrap(), &1);
484
485 assert!(core::ptr::eq(parent_ref.vtable(), child_ref.vtable()));
487 }
488
489 #[test]
490 fn test_raw_report_with_attachments() {
491 use crate::{attachment::RawAttachment, handlers::AttachmentHandler};
492
493 struct AttachmentHandlerI32;
495 impl AttachmentHandler<i32> for AttachmentHandlerI32 {
496 fn display(value: &i32, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
497 fmt::Display::fmt(value, formatter)
498 }
499 fn debug(value: &i32, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
500 fmt::Debug::fmt(value, formatter)
501 }
502 }
503
504 let attachment1 = RawAttachment::new::<i32, AttachmentHandlerI32>(100);
506 let attachment2 = RawAttachment::new::<i32, AttachmentHandlerI32>(200);
507
508 let child = RawReport::new::<i32, HandlerI32>(1, vec![], vec![attachment1]);
510
511 let parent = RawReport::new::<i32, HandlerI32>(0, vec![child], vec![attachment2]);
513
514 let parent_ref = parent.as_ref();
515 assert_eq!(parent_ref.context_downcast::<i32>().unwrap(), &0);
516
517 let children = parent_ref.children();
519 let attachments = parent_ref.attachments();
520 assert_eq!(children.len(), 1);
521 assert_eq!(attachments.len(), 1);
522
523 let child_ref = children[0].as_ref();
525 assert_eq!(child_ref.context_type_id(), TypeId::of::<i32>());
526 assert_eq!(child_ref.context_downcast::<i32>().unwrap(), &1);
527 assert_eq!(child_ref.children().len(), 0);
528 assert_eq!(child_ref.attachments().len(), 1);
529
530 let parent_attachment_ref = attachments[0].as_ref();
532 let child_attachment_ref = child_ref.attachments()[0].as_ref();
533
534 assert_eq!(
535 parent_attachment_ref.attachment_type_id(),
536 TypeId::of::<i32>()
537 );
538 assert_eq!(
539 child_attachment_ref.attachment_type_id(),
540 TypeId::of::<i32>()
541 );
542
543 assert_eq!(
545 *parent_attachment_ref.attachment_downcast::<i32>().unwrap(),
546 200
547 );
548 assert_eq!(
549 *child_attachment_ref.attachment_downcast::<i32>().unwrap(),
550 100
551 );
552
553 assert!(core::ptr::eq(parent_ref.vtable(), child_ref.vtable()));
555 }
556
557 #[test]
558 fn test_raw_report_mut_basic() {
559 let mut report = RawReport::new::<i32, HandlerI32>(789, vec![], vec![]);
560
561 let mut report_mut = unsafe { report.as_mut() };
563
564 let report_ref = report_mut.as_ref();
566 assert_eq!(report_ref.context_type_id(), TypeId::of::<i32>());
567 assert_eq!(report_ref.context_downcast::<i32>().unwrap(), &789);
568
569 let reborrowed = report_mut.reborrow();
571 let ref_from_reborrow = reborrowed.as_ref();
572 assert_eq!(ref_from_reborrow.context_type_id(), TypeId::of::<i32>());
573 assert_eq!(ref_from_reborrow.context_downcast::<i32>().unwrap(), &789);
574
575 let ptr = report_mut.into_mut_ptr();
577 assert!(!ptr.is_null());
578 }
579
580 #[test]
581 fn test_raw_report_mut_reborrow_lifetime() {
582 let mut report =
583 RawReport::new::<String, HandlerString>(String::from("test"), vec![], vec![]);
584
585 let mut report_mut = unsafe { report.as_mut() };
587
588 {
590 let short_reborrow = report_mut.reborrow();
591 let ref_from_short = short_reborrow.as_ref();
592 assert_eq!(ref_from_short.context_downcast::<String>().unwrap(), "test");
593 }
594
595 let final_ref = report_mut.as_ref();
597 assert_eq!(final_ref.context_downcast::<String>().unwrap(), "test");
598 }
599
600 #[test]
601 fn test_raw_report_mut_with_children() {
602 let child = RawReport::new::<i32, HandlerI32>(1, vec![], vec![]);
603 let mut parent = RawReport::new::<i32, HandlerI32>(0, vec![child], vec![]);
604
605 let mut parent_mut = unsafe { parent.as_mut() };
607
608 let parent_ref = parent_mut.as_ref();
609 assert_eq!(parent_ref.context_downcast::<i32>().unwrap(), &0);
610
611 let children = parent_ref.children();
613 assert_eq!(children.len(), 1);
614
615 let child_ref = children[0].as_ref();
616 assert_eq!(child_ref.context_downcast::<i32>().unwrap(), &1);
617
618 let reborrowed = parent_mut.reborrow();
620 let reborrow_ref = reborrowed.as_ref();
621 let reborrow_children = reborrow_ref.children();
622 assert_eq!(reborrow_children.len(), 1);
623 assert_eq!(
624 reborrow_children[0]
625 .as_ref()
626 .context_downcast::<i32>()
627 .unwrap(),
628 &1
629 );
630 }
631
632 #[test]
633 fn test_raw_report_mut_ptr_consistency() {
634 let mut report = RawReport::new::<i32, HandlerI32>(42, vec![], vec![]);
635
636 let immut_ref = report.as_ref();
638 let immut_ptr = immut_ref.as_ptr() as usize;
639 let report_mut = unsafe { report.as_mut() };
641
642 let mut_ptr = report_mut.into_mut_ptr();
644
645 assert_eq!(immut_ptr, mut_ptr as *const _ as usize);
647 }
648}