1use core::{
2 any::TypeId,
3 fmt::{self, Debug, Display},
4 mem::ManuallyDrop,
5 ops::{Deref, DerefMut},
6 ptr::{self, NonNull},
7};
8use std::error::Error as StdError;
9
10use super::{
11 Report, ReportHandler,
12 ptr::{Mut, Own, Ref},
13};
14use crate::{Diagnostic, SourceCode, chain::Chain, eyreish::wrapper::WithSourceCode};
15
16impl Report {
17 #[track_caller]
25 pub fn new<E>(error: E) -> Self
26 where
27 E: Diagnostic + Send + Sync + 'static,
28 {
29 Report::from_std(error)
30 }
31
32 #[track_caller]
70 pub fn msg<M>(message: M) -> Self
71 where
72 M: Display + Debug + Send + Sync + 'static,
73 {
74 Report::from_adhoc(message)
75 }
76
77 #[track_caller]
85 pub fn new_boxed(error: Box<dyn Diagnostic + Send + Sync + 'static>) -> Self {
86 Report::from_boxed(error)
87 }
88
89 #[track_caller]
90 pub(crate) fn from_std<E>(error: E) -> Self
91 where
92 E: Diagnostic + Send + Sync + 'static,
93 {
94 let vtable = &ErrorVTable {
95 object_drop: object_drop::<E>,
96 object_ref: object_ref::<E>,
97 object_ref_stderr: object_ref_stderr::<E>,
98 object_boxed: object_boxed::<E>,
99 object_boxed_stderr: object_boxed_stderr::<E>,
100 object_downcast: object_downcast::<E>,
101 object_drop_rest: object_drop_front::<E>,
102 };
103
104 let handler = Some(super::capture_handler(&error));
106
107 unsafe { Report::construct(error, vtable, handler) }
108 }
109
110 #[track_caller]
111 pub(crate) fn from_adhoc<M>(message: M) -> Self
112 where
113 M: Display + Debug + Send + Sync + 'static,
114 {
115 use super::wrapper::MessageError;
116 let error: MessageError<M> = MessageError(message);
117 let vtable = &ErrorVTable {
118 object_drop: object_drop::<MessageError<M>>,
119 object_ref: object_ref::<MessageError<M>>,
120 object_ref_stderr: object_ref_stderr::<MessageError<M>>,
121 object_boxed: object_boxed::<MessageError<M>>,
122 object_boxed_stderr: object_boxed_stderr::<MessageError<M>>,
123 object_downcast: object_downcast::<M>,
124 object_drop_rest: object_drop_front::<M>,
125 };
126
127 let handler = Some(super::capture_handler(&error));
130
131 unsafe { Report::construct(error, vtable, handler) }
132 }
133
134 #[track_caller]
135 pub(crate) fn from_msg<D, E>(msg: D, error: E) -> Self
136 where
137 D: Display + Send + Sync + 'static,
138 E: Diagnostic + Send + Sync + 'static,
139 {
140 let error: ContextError<D, E> = ContextError { msg, error };
141
142 let vtable = &ErrorVTable {
143 object_drop: object_drop::<ContextError<D, E>>,
144 object_ref: object_ref::<ContextError<D, E>>,
145 object_ref_stderr: object_ref_stderr::<ContextError<D, E>>,
146 object_boxed: object_boxed::<ContextError<D, E>>,
147 object_boxed_stderr: object_boxed_stderr::<ContextError<D, E>>,
148 object_downcast: context_downcast::<D, E>,
149 object_drop_rest: context_drop_rest::<D, E>,
150 };
151
152 let handler = Some(super::capture_handler(&error));
154
155 unsafe { Report::construct(error, vtable, handler) }
156 }
157
158 #[track_caller]
159 pub(crate) fn from_boxed(error: Box<dyn Diagnostic + Send + Sync>) -> Self {
160 use super::wrapper::BoxedError;
161 let error = BoxedError(error);
162 let handler = Some(super::capture_handler(&error));
163
164 let vtable = &ErrorVTable {
165 object_drop: object_drop::<BoxedError>,
166 object_ref: object_ref::<BoxedError>,
167 object_ref_stderr: object_ref_stderr::<BoxedError>,
168 object_boxed: object_boxed::<BoxedError>,
169 object_boxed_stderr: object_boxed_stderr::<BoxedError>,
170 object_downcast: object_downcast::<Box<dyn Diagnostic + Send + Sync>>,
171 object_drop_rest: object_drop_front::<Box<dyn Diagnostic + Send + Sync>>,
172 };
173
174 unsafe { Report::construct(error, vtable, handler) }
177 }
178
179 unsafe fn construct<E>(
185 error: E,
186 vtable: &'static ErrorVTable,
187 handler: Option<Box<dyn ReportHandler>>,
188 ) -> Self
189 where
190 E: Diagnostic + Send + Sync + 'static,
191 {
192 let inner = Box::new(ErrorImpl { vtable, handler, _object: error });
193 let inner = Own::new(inner).cast::<ErasedErrorImpl>();
200 Report { inner }
201 }
202
203 pub fn wrap_err<D>(self, msg: D) -> Self
213 where
214 D: Display + Send + Sync + 'static,
215 {
216 let handler = unsafe { self.inner.by_mut().deref_mut().handler.take() };
217 let error: ContextError<D, Report> = ContextError { msg, error: self };
218
219 let vtable = &ErrorVTable {
220 object_drop: object_drop::<ContextError<D, Report>>,
221 object_ref: object_ref::<ContextError<D, Report>>,
222 object_ref_stderr: object_ref_stderr::<ContextError<D, Report>>,
223 object_boxed: object_boxed::<ContextError<D, Report>>,
224 object_boxed_stderr: object_boxed_stderr::<ContextError<D, Report>>,
225 object_downcast: context_chain_downcast::<D>,
226 object_drop_rest: context_chain_drop_rest::<D>,
227 };
228
229 unsafe { Report::construct(error, vtable, handler) }
231 }
232
233 pub fn context<D>(self, msg: D) -> Self
235 where
236 D: Display + Send + Sync + 'static,
237 {
238 self.wrap_err(msg)
239 }
240
241 pub fn chain(&self) -> Chain<'_> {
263 unsafe { ErrorImpl::chain(self.inner.by_ref()) }
264 }
265
266 pub fn root_cause(&self) -> &(dyn StdError + 'static) {
272 self.chain().next_back().unwrap()
273 }
274
275 pub fn is<E>(&self) -> bool
284 where
285 E: Display + Debug + Send + Sync + 'static,
286 {
287 self.downcast_ref::<E>().is_some()
288 }
289
290 pub fn downcast<E>(self) -> Result<E, Self>
292 where
293 E: Display + Debug + Send + Sync + 'static,
294 {
295 let target = TypeId::of::<E>();
296 let inner = self.inner.by_mut();
297 unsafe {
298 let addr = match (vtable(inner.ptr).object_downcast)(inner.by_ref(), target) {
301 Some(addr) => addr.by_mut().extend(),
302 None => return Err(self),
303 };
304
305 let outer = ManuallyDrop::new(self);
308
309 let error = addr.cast::<E>().read();
311
312 (vtable(outer.inner.ptr).object_drop_rest)(outer.inner, target);
314
315 Ok(error)
316 }
317 }
318
319 pub fn downcast_ref<E>(&self) -> Option<&E>
356 where
357 E: Display + Debug + Send + Sync + 'static,
358 {
359 let target = TypeId::of::<E>();
360 unsafe {
361 let addr = (vtable(self.inner.ptr).object_downcast)(self.inner.by_ref(), target)?;
364 Some(addr.cast::<E>().deref())
365 }
366 }
367
368 pub fn downcast_mut<E>(&mut self) -> Option<&mut E>
370 where
371 E: Display + Debug + Send + Sync + 'static,
372 {
373 let target = TypeId::of::<E>();
374 unsafe {
375 let addr =
378 (vtable(self.inner.ptr).object_downcast)(self.inner.by_ref(), target)?.by_mut();
379 Some(addr.cast::<E>().deref_mut())
380 }
381 }
382
383 pub fn handler(&self) -> &dyn ReportHandler {
385 unsafe { self.inner.by_ref().deref().handler.as_ref().unwrap().as_ref() }
386 }
387
388 pub fn handler_mut(&mut self) -> &mut dyn ReportHandler {
390 unsafe { self.inner.by_mut().deref_mut().handler.as_mut().unwrap().as_mut() }
391 }
392
393 pub fn with_source_code(self, source_code: impl SourceCode + 'static) -> Report {
395 WithSourceCode { source_code, error: self }.into()
396 }
397}
398
399impl<E> From<E> for Report
400where
401 E: Diagnostic + Send + Sync + 'static,
402{
403 #[track_caller]
404 fn from(error: E) -> Self {
405 Report::from_std(error)
406 }
407}
408
409impl Deref for Report {
410 type Target = dyn Diagnostic + Send + Sync + 'static;
411
412 fn deref(&self) -> &Self::Target {
413 unsafe { ErrorImpl::diagnostic(self.inner.by_ref()) }
414 }
415}
416
417impl DerefMut for Report {
418 fn deref_mut(&mut self) -> &mut Self::Target {
419 unsafe { ErrorImpl::diagnostic_mut(self.inner.by_mut()) }
420 }
421}
422
423impl Display for Report {
424 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
425 unsafe { ErrorImpl::display(self.inner.by_ref(), formatter) }
426 }
427}
428
429impl Debug for Report {
430 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
431 unsafe { ErrorImpl::debug(self.inner.by_ref(), formatter) }
432 }
433}
434
435impl Drop for Report {
436 fn drop(&mut self) {
437 unsafe {
438 (vtable(self.inner.ptr).object_drop)(self.inner);
440 }
441 }
442}
443
444struct ErrorVTable {
445 object_drop: unsafe fn(Own<ErasedErrorImpl>),
446 object_ref:
447 unsafe fn(Ref<'_, ErasedErrorImpl>) -> Ref<'_, dyn Diagnostic + Send + Sync + 'static>,
448 object_ref_stderr:
449 unsafe fn(Ref<'_, ErasedErrorImpl>) -> Ref<'_, dyn StdError + Send + Sync + 'static>,
450 #[allow(clippy::type_complexity)]
451 object_boxed: unsafe fn(Own<ErasedErrorImpl>) -> Box<dyn Diagnostic + Send + Sync + 'static>,
452 #[allow(clippy::type_complexity)]
453 object_boxed_stderr:
454 unsafe fn(Own<ErasedErrorImpl>) -> Box<dyn StdError + Send + Sync + 'static>,
455 object_downcast: unsafe fn(Ref<'_, ErasedErrorImpl>, TypeId) -> Option<Ref<'_, ()>>,
456 object_drop_rest: unsafe fn(Own<ErasedErrorImpl>, TypeId),
457}
458
459unsafe fn object_drop<E>(e: Own<ErasedErrorImpl>) {
461 unsafe {
462 let unerased = e.cast::<ErrorImpl<E>>().boxed();
465 drop(unerased);
466 }
467}
468
469unsafe fn object_drop_front<E>(e: Own<ErasedErrorImpl>, target: TypeId) {
471 unsafe {
472 let _ = target;
476 let unerased = e.cast::<ErrorImpl<ManuallyDrop<E>>>().boxed();
477 drop(unerased);
478 }
479}
480
481unsafe fn object_ref<E>(
483 e: Ref<'_, ErasedErrorImpl>,
484) -> Ref<'_, dyn Diagnostic + Send + Sync + 'static>
485where
486 E: Diagnostic + Send + Sync + 'static,
487{
488 unsafe {
489 let unerased = e.cast::<ErrorImpl<E>>();
491
492 Ref::from_raw(NonNull::new_unchecked(ptr::addr_of!((*unerased.as_ptr())._object) as *mut E))
493 }
494}
495
496unsafe fn object_ref_stderr<E>(
498 e: Ref<'_, ErasedErrorImpl>,
499) -> Ref<'_, dyn StdError + Send + Sync + 'static>
500where
501 E: StdError + Send + Sync + 'static,
502{
503 unsafe {
504 let unerased = e.cast::<ErrorImpl<E>>();
506
507 Ref::from_raw(NonNull::new_unchecked(ptr::addr_of!((*unerased.as_ptr())._object) as *mut E))
508 }
509}
510
511unsafe fn object_boxed<E>(e: Own<ErasedErrorImpl>) -> Box<dyn Diagnostic + Send + Sync + 'static>
513where
514 E: Diagnostic + Send + Sync + 'static,
515{
516 unsafe {
517 e.cast::<ErrorImpl<E>>().boxed()
519 }
520}
521
522unsafe fn object_boxed_stderr<E>(
524 e: Own<ErasedErrorImpl>,
525) -> Box<dyn StdError + Send + Sync + 'static>
526where
527 E: StdError + Send + Sync + 'static,
528{
529 unsafe {
530 e.cast::<ErrorImpl<E>>().boxed()
532 }
533}
534
535unsafe fn object_downcast<E>(e: Ref<'_, ErasedErrorImpl>, target: TypeId) -> Option<Ref<'_, ()>>
537where
538 E: 'static,
539{
540 unsafe {
541 if TypeId::of::<E>() == target {
542 let unerased = e.cast::<ErrorImpl<E>>();
545
546 Some(
547 Ref::from_raw(NonNull::new_unchecked(
548 ptr::addr_of!((*unerased.as_ptr())._object) as *mut E
549 ))
550 .cast::<()>(),
551 )
552 } else {
553 None
554 }
555 }
556}
557
558unsafe fn context_downcast<D, E>(e: Ref<'_, ErasedErrorImpl>, target: TypeId) -> Option<Ref<'_, ()>>
560where
561 D: 'static,
562 E: 'static,
563{
564 unsafe {
565 if TypeId::of::<D>() == target {
566 let unerased = e.cast::<ErrorImpl<ContextError<D, E>>>().deref();
567 Some(Ref::new(&unerased._object.msg).cast::<()>())
568 } else if TypeId::of::<E>() == target {
569 let unerased = e.cast::<ErrorImpl<ContextError<D, E>>>().deref();
570 Some(Ref::new(&unerased._object.error).cast::<()>())
571 } else {
572 None
573 }
574 }
575}
576
577unsafe fn context_drop_rest<D, E>(e: Own<ErasedErrorImpl>, target: TypeId)
579where
580 D: 'static,
581 E: 'static,
582{
583 unsafe {
584 if TypeId::of::<D>() == target {
587 let unerased = e.cast::<ErrorImpl<ContextError<ManuallyDrop<D>, E>>>().boxed();
588 drop(unerased);
589 } else {
590 let unerased = e.cast::<ErrorImpl<ContextError<D, ManuallyDrop<E>>>>().boxed();
591 drop(unerased);
592 }
593 }
594}
595
596unsafe fn context_chain_downcast<D>(
598 e: Ref<'_, ErasedErrorImpl>,
599 target: TypeId,
600) -> Option<Ref<'_, ()>>
601where
602 D: 'static,
603{
604 unsafe {
605 let unerased = e.cast::<ErrorImpl<ContextError<D, Report>>>().deref();
606 if TypeId::of::<D>() == target {
607 Some(Ref::new(&unerased._object.msg).cast::<()>())
608 } else {
609 let source = &unerased._object.error;
611 (vtable(source.inner.ptr).object_downcast)(source.inner.by_ref(), target)
612 }
613 }
614}
615
616unsafe fn context_chain_drop_rest<D>(e: Own<ErasedErrorImpl>, target: TypeId)
618where
619 D: 'static,
620{
621 unsafe {
622 if TypeId::of::<D>() == target {
625 let unerased = e.cast::<ErrorImpl<ContextError<ManuallyDrop<D>, Report>>>().boxed();
626 drop(unerased);
628 } else {
629 let unerased = e.cast::<ErrorImpl<ContextError<D, ManuallyDrop<Report>>>>().boxed();
630 let inner = unerased._object.error.inner;
632 drop(unerased);
633 let vtable = vtable(inner.ptr);
634 (vtable.object_drop_rest)(inner, target);
636 }
637 }
638}
639
640#[repr(C)]
642pub(crate) struct ErrorImpl<E> {
643 vtable: &'static ErrorVTable,
644 pub(crate) handler: Option<Box<dyn ReportHandler>>,
645 _object: E,
648}
649
650#[repr(C)]
653pub(crate) struct ContextError<D, E> {
654 pub(crate) msg: D,
655 pub(crate) error: E,
656}
657
658type ErasedErrorImpl = ErrorImpl<()>;
659
660unsafe fn vtable(p: NonNull<ErasedErrorImpl>) -> &'static ErrorVTable {
662 unsafe { (p.as_ptr() as *const &'static ErrorVTable).read() }
663}
664
665impl<E> ErrorImpl<E> {
666 fn erase(&self) -> Ref<'_, ErasedErrorImpl> {
667 Ref::new(self).cast::<ErasedErrorImpl>()
671 }
672}
673
674impl ErasedErrorImpl {
675 pub(crate) unsafe fn error<'a>(
676 this: Ref<'a, Self>,
677 ) -> &'a (dyn StdError + Send + Sync + 'static) {
678 unsafe {
679 (vtable(this.ptr).object_ref_stderr)(this).deref()
682 }
683 }
684
685 pub(crate) unsafe fn diagnostic<'a>(
686 this: Ref<'a, Self>,
687 ) -> &'a (dyn Diagnostic + Send + Sync + 'static) {
688 unsafe {
689 (vtable(this.ptr).object_ref)(this).deref()
692 }
693 }
694
695 pub(crate) unsafe fn diagnostic_mut<'a>(
696 this: Mut<'a, Self>,
697 ) -> &'a mut (dyn Diagnostic + Send + Sync + 'static) {
698 unsafe {
699 (vtable(this.ptr).object_ref)(this.by_ref()).by_mut().deref_mut()
702 }
703 }
704
705 pub(crate) unsafe fn chain(this: Ref<'_, Self>) -> Chain<'_> {
706 unsafe { Chain::new(Self::error(this)) }
707 }
708}
709
710impl<E> StdError for ErrorImpl<E>
711where
712 E: StdError,
713{
714 fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
715 unsafe { ErrorImpl::diagnostic(self.erase()).source() }
716 }
717}
718
719impl<E> Diagnostic for ErrorImpl<E> where E: Diagnostic {}
720
721impl<E> Debug for ErrorImpl<E>
722where
723 E: Debug,
724{
725 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
726 unsafe { ErrorImpl::debug(self.erase(), formatter) }
727 }
728}
729
730impl<E> Display for ErrorImpl<E>
731where
732 E: Display,
733{
734 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
735 unsafe { Display::fmt(ErrorImpl::diagnostic(self.erase()), formatter) }
736 }
737}
738
739impl From<Report> for Box<dyn Diagnostic + Send + Sync + 'static> {
740 fn from(error: Report) -> Self {
741 let outer = ManuallyDrop::new(error);
742 unsafe {
743 (vtable(outer.inner.ptr).object_boxed)(outer.inner)
746 }
747 }
748}
749
750impl From<Report> for Box<dyn StdError + Send + Sync + 'static> {
751 fn from(error: Report) -> Self {
752 let outer = ManuallyDrop::new(error);
753 unsafe {
754 (vtable(outer.inner.ptr).object_boxed_stderr)(outer.inner)
757 }
758 }
759}
760
761impl From<Report> for Box<dyn Diagnostic + 'static> {
762 fn from(error: Report) -> Self {
763 Box::<dyn Diagnostic + Send + Sync>::from(error)
764 }
765}
766
767impl From<Report> for Box<dyn StdError + 'static> {
768 fn from(error: Report) -> Self {
769 Box::<dyn StdError + Send + Sync>::from(error)
770 }
771}
772
773impl AsRef<dyn Diagnostic + Send + Sync> for Report {
774 fn as_ref(&self) -> &(dyn Diagnostic + Send + Sync + 'static) {
775 &**self
776 }
777}
778
779impl AsRef<dyn Diagnostic> for Report {
780 fn as_ref(&self) -> &(dyn Diagnostic + 'static) {
781 &**self
782 }
783}
784
785impl AsRef<dyn StdError + Send + Sync> for Report {
786 fn as_ref(&self) -> &(dyn StdError + Send + Sync + 'static) {
787 unsafe { ErrorImpl::error(self.inner.by_ref()) }
788 }
789}
790
791impl AsRef<dyn StdError> for Report {
792 fn as_ref(&self) -> &(dyn StdError + 'static) {
793 unsafe { ErrorImpl::error(self.inner.by_ref()) }
794 }
795}
796
797impl std::borrow::Borrow<dyn Diagnostic> for Report {
798 fn borrow(&self) -> &(dyn Diagnostic + 'static) {
799 self.as_ref()
800 }
801}