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<'a>(&'a self) -> RawReportRef<'a> {
67 RawReportRef {
68 ptr: self.ptr,
69 _marker: core::marker::PhantomData,
70 }
71 }
72
73 pub unsafe fn as_mut<'a>(&'a mut self) -> RawReportMut<'a> {
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(
205 self,
206 report_formatting_function: FormattingFunction,
207 report_formatting_alternate: bool,
208 ) -> ContextFormattingStyle {
209 let vtable = self.vtable();
210 unsafe {
214 vtable.preferred_context_formatting_style(
215 self,
216 report_formatting_function,
217 report_formatting_alternate,
218 )
219 }
220 }
221
222 pub unsafe fn clone_arc(self) -> RawReport {
228 let vtable = self.vtable();
229 unsafe { vtable.clone_arc(self.ptr) }
237 }
238
239 pub fn strong_count(self) -> usize {
241 let vtable = self.vtable();
242 unsafe { vtable.strong_count(self.ptr) }
246 }
247}
248
249#[repr(transparent)]
258pub struct RawReportMut<'a> {
259 ptr: NonNull<ReportData<Erased>>,
260 _marker: core::marker::PhantomData<&'a mut ReportData<Erased>>,
261}
262
263impl<'a> RawReportMut<'a> {
264 pub fn reborrow<'b>(&'b mut self) -> RawReportMut<'b> {
266 RawReportMut {
267 ptr: self.ptr,
268 _marker: core::marker::PhantomData,
269 }
270 }
271
272 pub fn as_ref(&self) -> RawReportRef<'_> {
274 RawReportRef {
275 ptr: self.ptr,
276 _marker: core::marker::PhantomData,
277 }
278 }
279
280 pub fn into_ref(self) -> RawReportRef<'a> {
282 RawReportRef {
283 ptr: self.ptr,
284 _marker: core::marker::PhantomData,
285 }
286 }
287
288 pub(super) fn into_mut_ptr(self) -> *mut ReportData<Erased> {
292 self.ptr.as_ptr()
293 }
294}
295
296#[cfg(test)]
297mod tests {
298 use alloc::{string::String, vec};
299 use core::{error::Error, fmt};
300
301 use super::*;
302 use crate::handlers::ContextHandler;
303
304 struct HandlerI32;
305 impl ContextHandler<i32> for HandlerI32 {
306 fn source(_value: &i32) -> Option<&(dyn Error + 'static)> {
307 None
308 }
309 fn display(value: &i32, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
310 fmt::Display::fmt(value, formatter)
311 }
312 fn debug(value: &i32, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
313 fmt::Debug::fmt(value, formatter)
314 }
315 }
316
317 struct HandlerString;
318 impl ContextHandler<String> for HandlerString {
319 fn source(_value: &String) -> Option<&(dyn Error + 'static)> {
320 None
321 }
322 fn display(value: &String, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
323 fmt::Display::fmt(value, formatter)
324 }
325 fn debug(value: &String, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
326 fmt::Debug::fmt(value, formatter)
327 }
328 }
329
330 #[test]
331 fn test_raw_report_size() {
332 assert_eq!(
333 core::mem::size_of::<RawReport>(),
334 core::mem::size_of::<usize>()
335 );
336 assert_eq!(
337 core::mem::size_of::<Option<RawReport>>(),
338 core::mem::size_of::<usize>()
339 );
340 assert_eq!(
341 core::mem::size_of::<Result<(), RawReport>>(),
342 core::mem::size_of::<usize>()
343 );
344 assert_eq!(
345 core::mem::size_of::<Result<String, RawReport>>(),
346 core::mem::size_of::<String>()
347 );
348 assert_eq!(
349 core::mem::size_of::<Option<Option<RawReport>>>(),
350 core::mem::size_of::<Option<usize>>()
351 );
352
353 assert_eq!(
354 core::mem::size_of::<RawReportRef<'_>>(),
355 core::mem::size_of::<usize>()
356 );
357 assert_eq!(
358 core::mem::size_of::<Option<RawReportRef<'_>>>(),
359 core::mem::size_of::<usize>()
360 );
361 assert_eq!(
362 core::mem::size_of::<Result<(), RawReportRef<'_>>>(),
363 core::mem::size_of::<usize>()
364 );
365 assert_eq!(
366 core::mem::size_of::<Result<String, RawReportRef<'_>>>(),
367 core::mem::size_of::<String>()
368 );
369 assert_eq!(
370 core::mem::size_of::<Option<Option<RawReportRef<'_>>>>(),
371 core::mem::size_of::<Option<usize>>()
372 );
373
374 assert_eq!(
375 core::mem::size_of::<RawReportMut<'_>>(),
376 core::mem::size_of::<usize>()
377 );
378 assert_eq!(
379 core::mem::size_of::<Option<RawReportMut<'_>>>(),
380 core::mem::size_of::<usize>()
381 );
382 assert_eq!(
383 core::mem::size_of::<Result<(), RawReportMut<'_>>>(),
384 core::mem::size_of::<usize>()
385 );
386 assert_eq!(
387 core::mem::size_of::<Result<String, RawReportMut<'_>>>(),
388 core::mem::size_of::<String>()
389 );
390 assert_eq!(
391 core::mem::size_of::<Option<Option<RawReportMut<'_>>>>(),
392 core::mem::size_of::<Option<usize>>()
393 );
394 }
395
396 #[test]
397 fn test_raw_report_get_refs() {
398 let report = RawReport::new::<i32, HandlerI32>(789, vec![], vec![]);
399 let report_ref = report.as_ref();
400
401 let ptr1 = report_ref.as_ptr();
403 let ptr2 = report_ref.as_ptr();
404 assert_eq!(ptr1, ptr2);
405 }
406
407 #[test]
408 fn test_raw_report_clone_arc() {
409 let report = RawReport::new::<i32, HandlerI32>(123, vec![], vec![]);
411 let report_ref = report.as_ref();
412
413 assert_eq!(report_ref.strong_count(), 1);
414
415 assert_eq!(report_ref.context_type_id(), TypeId::of::<i32>());
417
418 let cloned = unsafe { report_ref.clone_arc() };
421 let cloned_ref = cloned.as_ref();
422
423 assert_eq!(report_ref.strong_count(), 2);
424 assert_eq!(cloned_ref.strong_count(), 2);
425
426 assert_eq!(report_ref.context_type_id(), cloned_ref.context_type_id());
428 assert!(core::ptr::eq(report_ref.vtable(), cloned_ref.vtable()));
429
430 core::mem::drop(cloned);
431
432 assert_eq!(report_ref.strong_count(), 1);
434 }
435
436 #[test]
437 fn test_raw_attachment_downcast() {
438 let int_report = RawReport::new::<i32, HandlerI32>(42, vec![], vec![]);
439 let string_report =
440 RawReport::new::<String, HandlerString>(String::from("test"), vec![], vec![]);
441
442 let int_ref = int_report.as_ref();
443 let string_ref = string_report.as_ref();
444
445 assert_eq!(int_ref.context_type_id(), TypeId::of::<i32>());
447 assert_eq!(string_ref.context_type_id(), TypeId::of::<String>());
448
449 assert!(!core::ptr::eq(int_ref.vtable(), string_ref.vtable()));
451
452 assert!(int_ref.context_downcast::<String>().is_none());
454 assert!(string_ref.context_downcast::<i32>().is_none());
455
456 assert_eq!(int_ref.context_downcast::<i32>().unwrap(), &42);
458 assert_eq!(string_ref.context_downcast::<String>().unwrap(), "test");
459 }
460
461 #[test]
462 fn test_raw_report_children() {
463 let child = RawReport::new::<i32, HandlerI32>(1, vec![], vec![]);
464 let parent = RawReport::new::<i32, HandlerI32>(0, vec![child], vec![]);
465
466 let parent_ref = parent.as_ref();
467 assert_eq!(parent_ref.context_downcast::<i32>().unwrap(), &0);
468
469 let children = parent_ref.children();
471 assert_eq!(children.len(), 1);
472
473 let child_ref = children[0].as_ref();
475 assert_eq!(child_ref.context_type_id(), TypeId::of::<i32>());
476 assert_eq!(child_ref.children().len(), 0);
477 assert_eq!(child_ref.context_downcast::<i32>().unwrap(), &1);
478
479 assert!(core::ptr::eq(parent_ref.vtable(), child_ref.vtable()));
481 }
482
483 #[test]
484 fn test_raw_report_with_attachments() {
485 use crate::{attachment::RawAttachment, handlers::AttachmentHandler};
486
487 struct AttachmentHandlerI32;
489 impl AttachmentHandler<i32> for AttachmentHandlerI32 {
490 fn display(value: &i32, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
491 fmt::Display::fmt(value, formatter)
492 }
493 fn debug(value: &i32, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
494 fmt::Debug::fmt(value, formatter)
495 }
496 }
497
498 let attachment1 = RawAttachment::new::<i32, AttachmentHandlerI32>(100);
500 let attachment2 = RawAttachment::new::<i32, AttachmentHandlerI32>(200);
501
502 let child = RawReport::new::<i32, HandlerI32>(1, vec![], vec![attachment1]);
504
505 let parent = RawReport::new::<i32, HandlerI32>(0, vec![child], vec![attachment2]);
507
508 let parent_ref = parent.as_ref();
509 assert_eq!(parent_ref.context_downcast::<i32>().unwrap(), &0);
510
511 let children = parent_ref.children();
513 let attachments = parent_ref.attachments();
514 assert_eq!(children.len(), 1);
515 assert_eq!(attachments.len(), 1);
516
517 let child_ref = children[0].as_ref();
519 assert_eq!(child_ref.context_type_id(), TypeId::of::<i32>());
520 assert_eq!(child_ref.context_downcast::<i32>().unwrap(), &1);
521 assert_eq!(child_ref.children().len(), 0);
522 assert_eq!(child_ref.attachments().len(), 1);
523
524 let parent_attachment_ref = attachments[0].as_ref();
526 let child_attachment_ref = child_ref.attachments()[0].as_ref();
527
528 assert_eq!(
529 parent_attachment_ref.attachment_type_id(),
530 TypeId::of::<i32>()
531 );
532 assert_eq!(
533 child_attachment_ref.attachment_type_id(),
534 TypeId::of::<i32>()
535 );
536
537 assert_eq!(
539 *parent_attachment_ref.attachment_downcast::<i32>().unwrap(),
540 200
541 );
542 assert_eq!(
543 *child_attachment_ref.attachment_downcast::<i32>().unwrap(),
544 100
545 );
546
547 assert!(core::ptr::eq(parent_ref.vtable(), child_ref.vtable()));
549 }
550
551 #[test]
552 fn test_raw_report_mut_basic() {
553 let mut report = RawReport::new::<i32, HandlerI32>(789, vec![], vec![]);
554
555 let mut report_mut = unsafe { report.as_mut() };
557
558 let report_ref = report_mut.as_ref();
560 assert_eq!(report_ref.context_type_id(), TypeId::of::<i32>());
561 assert_eq!(report_ref.context_downcast::<i32>().unwrap(), &789);
562
563 let reborrowed = report_mut.reborrow();
565 let ref_from_reborrow = reborrowed.as_ref();
566 assert_eq!(ref_from_reborrow.context_type_id(), TypeId::of::<i32>());
567 assert_eq!(ref_from_reborrow.context_downcast::<i32>().unwrap(), &789);
568
569 let ptr = report_mut.into_mut_ptr();
571 assert!(!ptr.is_null());
572 }
573
574 #[test]
575 fn test_raw_report_mut_reborrow_lifetime() {
576 let mut report =
577 RawReport::new::<String, HandlerString>(String::from("test"), vec![], vec![]);
578
579 let mut report_mut = unsafe { report.as_mut() };
581
582 {
584 let short_reborrow = report_mut.reborrow();
585 let ref_from_short = short_reborrow.as_ref();
586 assert_eq!(ref_from_short.context_downcast::<String>().unwrap(), "test");
587 }
588
589 let final_ref = report_mut.as_ref();
591 assert_eq!(final_ref.context_downcast::<String>().unwrap(), "test");
592 }
593
594 #[test]
595 fn test_raw_report_mut_with_children() {
596 let child = RawReport::new::<i32, HandlerI32>(1, vec![], vec![]);
597 let mut parent = RawReport::new::<i32, HandlerI32>(0, vec![child], vec![]);
598
599 let mut parent_mut = unsafe { parent.as_mut() };
601
602 let parent_ref = parent_mut.as_ref();
603 assert_eq!(parent_ref.context_downcast::<i32>().unwrap(), &0);
604
605 let children = parent_ref.children();
607 assert_eq!(children.len(), 1);
608
609 let child_ref = children[0].as_ref();
610 assert_eq!(child_ref.context_downcast::<i32>().unwrap(), &1);
611
612 let reborrowed = parent_mut.reborrow();
614 let reborrow_ref = reborrowed.as_ref();
615 let reborrow_children = reborrow_ref.children();
616 assert_eq!(reborrow_children.len(), 1);
617 assert_eq!(
618 reborrow_children[0]
619 .as_ref()
620 .context_downcast::<i32>()
621 .unwrap(),
622 &1
623 );
624 }
625
626 #[test]
627 fn test_raw_report_mut_ptr_consistency() {
628 let mut report = RawReport::new::<i32, HandlerI32>(42, vec![], vec![]);
629
630 let immut_ref = report.as_ref();
632 let immut_ptr = immut_ref.as_ptr() as usize;
633 let report_mut = unsafe { report.as_mut() };
635
636 let mut_ptr = report_mut.into_mut_ptr();
638
639 assert_eq!(immut_ptr, mut_ptr as *const _ as usize);
641 }
642}