1use 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#[repr(transparent)]
27pub struct RawReport {
28 ptr: NonNull<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 { ptr }
42 }
43
44 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 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 pub fn as_ref(&self) -> RawReportRef<'_> {
64 RawReportRef {
65 ptr: self.ptr,
66 _marker: core::marker::PhantomData,
67 }
68 }
69
70 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 unsafe {
98 vtable.drop(self.ptr);
99 }
100 }
101}
102
103#[derive(Clone, Copy)]
112#[repr(transparent)]
113pub struct RawReportRef<'a> {
114 ptr: NonNull<ReportData<Erased>>,
116 _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>>,
252 _marker: core::marker::PhantomData<&'a mut ReportData<Erased>>,
255}
256
257impl<'a> RawReportMut<'a> {
258 pub(super) unsafe fn cast_inner<C: CastTo>(self) -> &'a mut ReportData<C::Target> {
264 debug_assert_eq!(self.as_ref().vtable().type_id(), TypeId::of::<C>());
266
267 let mut this = self.ptr.cast::<ReportData<C::Target>>();
268 unsafe { this.as_mut() }
271 }
272
273 pub fn reborrow<'b>(&'b mut self) -> RawReportMut<'b> {
275 RawReportMut {
276 ptr: self.ptr,
277 _marker: core::marker::PhantomData,
278 }
279 }
280
281 pub fn as_ref(&self) -> RawReportRef<'_> {
283 RawReportRef {
284 ptr: self.ptr,
285 _marker: core::marker::PhantomData,
286 }
287 }
288
289 pub fn into_ref(self) -> RawReportRef<'a> {
291 RawReportRef {
292 ptr: self.ptr,
293 _marker: core::marker::PhantomData,
294 }
295 }
296
297 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 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 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 assert_eq!(report_ref.context_type_id(), TypeId::of::<i32>());
426
427 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 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 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 assert_eq!(int_ref.context_type_id(), TypeId::of::<i32>());
456 assert_eq!(string_ref.context_type_id(), TypeId::of::<String>());
457
458 assert!(!core::ptr::eq(int_ref.vtable(), string_ref.vtable()));
460
461 assert!(int_ref.context_downcast::<String>().is_none());
463 assert!(string_ref.context_downcast::<i32>().is_none());
464
465 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 let children = parent_ref.children();
480 assert_eq!(children.len(), 1);
481
482 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 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 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 let attachment1 = RawAttachment::new::<i32, AttachmentHandlerI32>(100);
509 let attachment2 = RawAttachment::new::<i32, AttachmentHandlerI32>(200);
510
511 let child = RawReport::new::<i32, HandlerI32>(1, vec![], vec![attachment1]);
513
514 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 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 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 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 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 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 let mut report_mut = unsafe { report.as_mut() };
566
567 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 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 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 let mut report_mut = unsafe { report.as_mut() };
590
591 {
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 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 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 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 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 let immut_ref = report.as_ref();
641 let immut_ptr = immut_ref.as_ptr() as usize;
642 let report_mut = unsafe { report.as_mut() };
644
645 let mut_ptr = report_mut.into_mut_ptr();
647
648 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}