1use core::any::TypeId;
2use core::fmt::{self, Debug, Display};
3use core::mem::ManuallyDrop;
4use core::ptr::{self, NonNull};
5use std::error::Error as StdError;
6
7use super::ptr::{Mut, Own, Ref};
8use super::Report;
9use super::ReportHandler;
10use crate::chain::Chain;
11use crate::eyreish::wrapper::WithSourceCode;
12use crate::{Diagnostic, SourceCode};
13use core::ops::{Deref, DerefMut};
14
15impl Report {
16 #[cfg_attr(track_caller, track_caller)]
24 #[cold]
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 #[cfg_attr(track_caller, track_caller)]
70 #[cold]
71 pub fn msg<M>(message: M) -> Self
72 where
73 M: Display + Debug + Send + Sync + 'static,
74 {
75 Report::from_adhoc(message)
76 }
77
78 #[cfg_attr(track_caller, track_caller)]
86 pub fn new_boxed(error: Box<dyn Diagnostic + Send + Sync + 'static>) -> Self {
87 Report::from_boxed(error)
88 }
89
90 #[cfg_attr(track_caller, track_caller)]
91 #[cold]
92 pub(crate) fn from_std<E>(error: E) -> Self
93 where
94 E: Diagnostic + Send + Sync + 'static,
95 {
96 let vtable = &ErrorVTable {
97 object_drop: object_drop::<E>,
98 object_ref: object_ref::<E>,
99 object_ref_stderr: object_ref_stderr::<E>,
100 object_boxed: object_boxed::<E>,
101 object_boxed_stderr: object_boxed_stderr::<E>,
102 object_downcast: object_downcast::<E>,
103 object_drop_rest: object_drop_front::<E>,
104 };
105
106 let handler = Some(super::capture_handler(&error));
108
109 unsafe { Report::construct(error, vtable, handler) }
110 }
111
112 #[cfg_attr(track_caller, track_caller)]
113 #[cold]
114 pub(crate) fn from_adhoc<M>(message: M) -> Self
115 where
116 M: Display + Debug + Send + Sync + 'static,
117 {
118 use super::wrapper::MessageError;
119 let error: MessageError<M> = MessageError(message);
120 let vtable = &ErrorVTable {
121 object_drop: object_drop::<MessageError<M>>,
122 object_ref: object_ref::<MessageError<M>>,
123 object_ref_stderr: object_ref_stderr::<MessageError<M>>,
124 object_boxed: object_boxed::<MessageError<M>>,
125 object_boxed_stderr: object_boxed_stderr::<MessageError<M>>,
126 object_downcast: object_downcast::<M>,
127 object_drop_rest: object_drop_front::<M>,
128 };
129
130 let handler = Some(super::capture_handler(&error));
133
134 unsafe { Report::construct(error, vtable, handler) }
135 }
136
137 #[cfg_attr(track_caller, track_caller)]
138 #[cold]
139 pub(crate) fn from_msg<D, E>(msg: D, error: E) -> Self
140 where
141 D: Display + Send + Sync + 'static,
142 E: Diagnostic + Send + Sync + 'static,
143 {
144 let error: ContextError<D, E> = ContextError { msg, error };
145
146 let vtable = &ErrorVTable {
147 object_drop: object_drop::<ContextError<D, E>>,
148 object_ref: object_ref::<ContextError<D, E>>,
149 object_ref_stderr: object_ref_stderr::<ContextError<D, E>>,
150 object_boxed: object_boxed::<ContextError<D, E>>,
151 object_boxed_stderr: object_boxed_stderr::<ContextError<D, E>>,
152 object_downcast: context_downcast::<D, E>,
153 object_drop_rest: context_drop_rest::<D, E>,
154 };
155
156 let handler = Some(super::capture_handler(&error));
158
159 unsafe { Report::construct(error, vtable, handler) }
160 }
161
162 #[cfg_attr(track_caller, track_caller)]
163 #[cold]
164 pub(crate) fn from_boxed(error: Box<dyn Diagnostic + Send + Sync>) -> Self {
165 use super::wrapper::BoxedError;
166 let error = BoxedError(error);
167 let handler = Some(super::capture_handler(&error));
168
169 let vtable = &ErrorVTable {
170 object_drop: object_drop::<BoxedError>,
171 object_ref: object_ref::<BoxedError>,
172 object_ref_stderr: object_ref_stderr::<BoxedError>,
173 object_boxed: object_boxed::<BoxedError>,
174 object_boxed_stderr: object_boxed_stderr::<BoxedError>,
175 object_downcast: object_downcast::<Box<dyn Diagnostic + Send + Sync>>,
176 object_drop_rest: object_drop_front::<Box<dyn Diagnostic + Send + Sync>>,
177 };
178
179 unsafe { Report::construct(error, vtable, handler) }
182 }
183
184 #[cold]
190 unsafe fn construct<E>(
191 error: E,
192 vtable: &'static ErrorVTable,
193 handler: Option<Box<dyn ReportHandler>>,
194 ) -> Self
195 where
196 E: Diagnostic + Send + Sync + 'static,
197 {
198 let inner = Box::new(ErrorImpl {
199 vtable,
200 handler,
201 _object: error,
202 });
203 let inner = Own::new(inner).cast::<ErasedErrorImpl>();
210 Report { inner }
211 }
212
213 pub fn wrap_err<D>(self, msg: D) -> Self
223 where
224 D: Display + Send + Sync + 'static,
225 {
226 let handler = unsafe { self.inner.by_mut().deref_mut().handler.take() };
227 let error: ContextError<D, Report> = ContextError { msg, error: self };
228
229 let vtable = &ErrorVTable {
230 object_drop: object_drop::<ContextError<D, Report>>,
231 object_ref: object_ref::<ContextError<D, Report>>,
232 object_ref_stderr: object_ref_stderr::<ContextError<D, Report>>,
233 object_boxed: object_boxed::<ContextError<D, Report>>,
234 object_boxed_stderr: object_boxed_stderr::<ContextError<D, Report>>,
235 object_downcast: context_chain_downcast::<D>,
236 object_drop_rest: context_chain_drop_rest::<D>,
237 };
238
239 unsafe { Report::construct(error, vtable, handler) }
241 }
242
243 pub fn context<D>(self, msg: D) -> Self
245 where
246 D: Display + Send + Sync + 'static,
247 {
248 self.wrap_err(msg)
249 }
250
251 #[cold]
273 pub fn chain(&self) -> Chain<'_> {
274 unsafe { ErrorImpl::chain(self.inner.by_ref()) }
275 }
276
277 pub fn root_cause(&self) -> &(dyn StdError + 'static) {
283 self.chain().last().unwrap()
284 }
285
286 pub fn is<E>(&self) -> bool
295 where
296 E: Display + Debug + Send + Sync + 'static,
297 {
298 self.downcast_ref::<E>().is_some()
299 }
300
301 pub fn downcast<E>(self) -> Result<E, Self>
303 where
304 E: Display + Debug + Send + Sync + 'static,
305 {
306 let target = TypeId::of::<E>();
307 let inner = self.inner.by_mut();
308 unsafe {
309 let addr = match (vtable(inner.ptr).object_downcast)(inner.by_ref(), target) {
312 Some(addr) => addr.by_mut().extend(),
313 None => return Err(self),
314 };
315
316 let outer = ManuallyDrop::new(self);
319
320 let error = addr.cast::<E>().read();
322
323 (vtable(outer.inner.ptr).object_drop_rest)(outer.inner, target);
325
326 Ok(error)
327 }
328 }
329
330 pub fn downcast_ref<E>(&self) -> Option<&E>
367 where
368 E: Display + Debug + Send + Sync + 'static,
369 {
370 let target = TypeId::of::<E>();
371 unsafe {
372 let addr = (vtable(self.inner.ptr).object_downcast)(self.inner.by_ref(), target)?;
375 Some(addr.cast::<E>().deref())
376 }
377 }
378
379 pub fn downcast_mut<E>(&mut self) -> Option<&mut E>
381 where
382 E: Display + Debug + Send + Sync + 'static,
383 {
384 let target = TypeId::of::<E>();
385 unsafe {
386 let addr =
389 (vtable(self.inner.ptr).object_downcast)(self.inner.by_ref(), target)?.by_mut();
390 Some(addr.cast::<E>().deref_mut())
391 }
392 }
393
394 pub fn handler(&self) -> &dyn ReportHandler {
396 unsafe {
397 self.inner
398 .by_ref()
399 .deref()
400 .handler
401 .as_ref()
402 .unwrap()
403 .as_ref()
404 }
405 }
406
407 pub fn handler_mut(&mut self) -> &mut dyn ReportHandler {
409 unsafe {
410 self.inner
411 .by_mut()
412 .deref_mut()
413 .handler
414 .as_mut()
415 .unwrap()
416 .as_mut()
417 }
418 }
419
420 pub fn with_source_code(self, source_code: impl SourceCode + 'static) -> Report {
422 WithSourceCode {
423 source_code,
424 error: self,
425 }
426 .into()
427 }
428
429 pub fn from_err<E>(err: E) -> Self
431 where
432 E: std::error::Error + Send + Sync + 'static,
433 {
434 super::DiagnosticError(Box::new(err)).into()
435 }
436}
437
438impl<E> From<E> for Report
439where
440 E: Diagnostic + Send + Sync + 'static,
441{
442 #[cfg_attr(track_caller, track_caller)]
443 #[cold]
444 fn from(error: E) -> Self {
445 Report::from_std(error)
446 }
447}
448
449impl Deref for Report {
450 type Target = dyn Diagnostic + Send + Sync + 'static;
451
452 fn deref(&self) -> &Self::Target {
453 unsafe { ErrorImpl::diagnostic(self.inner.by_ref()) }
454 }
455}
456
457impl DerefMut for Report {
458 fn deref_mut(&mut self) -> &mut Self::Target {
459 unsafe { ErrorImpl::diagnostic_mut(self.inner.by_mut()) }
460 }
461}
462
463impl Display for Report {
464 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
465 unsafe { ErrorImpl::display(self.inner.by_ref(), formatter) }
466 }
467}
468
469impl Debug for Report {
470 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
471 unsafe { ErrorImpl::debug(self.inner.by_ref(), formatter) }
472 }
473}
474
475impl Drop for Report {
476 fn drop(&mut self) {
477 unsafe {
478 (vtable(self.inner.ptr).object_drop)(self.inner);
480 }
481 }
482}
483
484struct ErrorVTable {
485 object_drop: unsafe fn(Own<ErasedErrorImpl>),
486 object_ref:
487 unsafe fn(Ref<'_, ErasedErrorImpl>) -> Ref<'_, dyn Diagnostic + Send + Sync + 'static>,
488 object_ref_stderr:
489 unsafe fn(Ref<'_, ErasedErrorImpl>) -> Ref<'_, dyn StdError + Send + Sync + 'static>,
490 #[allow(clippy::type_complexity)]
491 object_boxed: unsafe fn(Own<ErasedErrorImpl>) -> Box<dyn Diagnostic + Send + Sync + 'static>,
492 #[allow(clippy::type_complexity)]
493 object_boxed_stderr:
494 unsafe fn(Own<ErasedErrorImpl>) -> Box<dyn StdError + Send + Sync + 'static>,
495 object_downcast: unsafe fn(Ref<'_, ErasedErrorImpl>, TypeId) -> Option<Ref<'_, ()>>,
496 object_drop_rest: unsafe fn(Own<ErasedErrorImpl>, TypeId),
497}
498
499unsafe fn object_drop<E>(e: Own<ErasedErrorImpl>) {
501 let unerased = e.cast::<ErrorImpl<E>>().boxed();
504 drop(unerased);
505}
506
507unsafe fn object_drop_front<E>(e: Own<ErasedErrorImpl>, target: TypeId) {
509 let _ = target;
513 let unerased = e.cast::<ErrorImpl<ManuallyDrop<E>>>().boxed();
514 drop(unerased);
515}
516
517unsafe fn object_ref<E>(
519 e: Ref<'_, ErasedErrorImpl>,
520) -> Ref<'_, dyn Diagnostic + Send + Sync + 'static>
521where
522 E: Diagnostic + Send + Sync + 'static,
523{
524 let unerased = e.cast::<ErrorImpl<E>>();
526
527 Ref::from_raw(NonNull::new_unchecked(
528 ptr::addr_of!((*unerased.as_ptr())._object) as *mut E,
529 ))
530}
531
532unsafe fn object_ref_stderr<E>(
534 e: Ref<'_, ErasedErrorImpl>,
535) -> Ref<'_, dyn StdError + Send + Sync + 'static>
536where
537 E: StdError + Send + Sync + 'static,
538{
539 let unerased = e.cast::<ErrorImpl<E>>();
541
542 Ref::from_raw(NonNull::new_unchecked(
543 ptr::addr_of!((*unerased.as_ptr())._object) as *mut E,
544 ))
545}
546
547unsafe fn object_boxed<E>(e: Own<ErasedErrorImpl>) -> Box<dyn Diagnostic + Send + Sync + 'static>
549where
550 E: Diagnostic + Send + Sync + 'static,
551{
552 let unerased = e.cast::<ErrorImpl<E>>().boxed();
554 Box::new(unerased._object)
555}
556
557unsafe fn object_boxed_stderr<E>(
559 e: Own<ErasedErrorImpl>,
560) -> Box<dyn StdError + Send + Sync + 'static>
561where
562 E: StdError + Send + Sync + 'static,
563{
564 let unerased = e.cast::<ErrorImpl<E>>().boxed();
566 Box::new(unerased._object)
567}
568
569unsafe fn object_downcast<E>(e: Ref<'_, ErasedErrorImpl>, target: TypeId) -> Option<Ref<'_, ()>>
571where
572 E: 'static,
573{
574 if TypeId::of::<E>() == target {
575 let unerased = e.cast::<ErrorImpl<E>>();
578
579 Some(
580 Ref::from_raw(NonNull::new_unchecked(
581 ptr::addr_of!((*unerased.as_ptr())._object) as *mut E,
582 ))
583 .cast::<()>(),
584 )
585 } else {
586 None
587 }
588}
589
590unsafe fn context_downcast<D, E>(e: Ref<'_, ErasedErrorImpl>, target: TypeId) -> Option<Ref<'_, ()>>
592where
593 D: 'static,
594 E: 'static,
595{
596 if TypeId::of::<D>() == target {
597 let unerased = e.cast::<ErrorImpl<ContextError<D, E>>>().deref();
598 Some(Ref::new(&unerased._object.msg).cast::<()>())
599 } else if TypeId::of::<E>() == target {
600 let unerased = e.cast::<ErrorImpl<ContextError<D, E>>>().deref();
601 Some(Ref::new(&unerased._object.error).cast::<()>())
602 } else {
603 None
604 }
605}
606
607unsafe fn context_drop_rest<D, E>(e: Own<ErasedErrorImpl>, target: TypeId)
609where
610 D: 'static,
611 E: 'static,
612{
613 if TypeId::of::<D>() == target {
616 let unerased = e
617 .cast::<ErrorImpl<ContextError<ManuallyDrop<D>, E>>>()
618 .boxed();
619 drop(unerased);
620 } else {
621 let unerased = e
622 .cast::<ErrorImpl<ContextError<D, ManuallyDrop<E>>>>()
623 .boxed();
624 drop(unerased);
625 }
626}
627
628unsafe fn context_chain_downcast<D>(
630 e: Ref<'_, ErasedErrorImpl>,
631 target: TypeId,
632) -> Option<Ref<'_, ()>>
633where
634 D: 'static,
635{
636 let unerased = e.cast::<ErrorImpl<ContextError<D, Report>>>().deref();
637 if TypeId::of::<D>() == target {
638 Some(Ref::new(&unerased._object.msg).cast::<()>())
639 } else {
640 let source = &unerased._object.error;
642 (vtable(source.inner.ptr).object_downcast)(source.inner.by_ref(), target)
643 }
644}
645
646unsafe fn context_chain_drop_rest<D>(e: Own<ErasedErrorImpl>, target: TypeId)
648where
649 D: 'static,
650{
651 if TypeId::of::<D>() == target {
654 let unerased = e
655 .cast::<ErrorImpl<ContextError<ManuallyDrop<D>, Report>>>()
656 .boxed();
657 drop(unerased);
659 } else {
660 let unerased = e
661 .cast::<ErrorImpl<ContextError<D, ManuallyDrop<Report>>>>()
662 .boxed();
663 let inner = unerased._object.error.inner;
665 drop(unerased);
666 let vtable = vtable(inner.ptr);
667 (vtable.object_drop_rest)(inner, target);
669 }
670}
671
672#[repr(C)]
674pub(crate) struct ErrorImpl<E> {
675 vtable: &'static ErrorVTable,
676 pub(crate) handler: Option<Box<dyn ReportHandler>>,
677 _object: E,
680}
681
682#[repr(C)]
685pub(crate) struct ContextError<D, E> {
686 pub(crate) msg: D,
687 pub(crate) error: E,
688}
689
690type ErasedErrorImpl = ErrorImpl<()>;
691
692unsafe fn vtable(p: NonNull<ErasedErrorImpl>) -> &'static ErrorVTable {
694 (p.as_ptr() as *const &'static ErrorVTable).read()
695}
696
697impl<E> ErrorImpl<E> {
698 fn erase(&self) -> Ref<'_, ErasedErrorImpl> {
699 Ref::new(self).cast::<ErasedErrorImpl>()
703 }
704}
705
706impl ErasedErrorImpl {
707 pub(crate) unsafe fn error<'a>(
708 this: Ref<'a, Self>,
709 ) -> &'a (dyn StdError + Send + Sync + 'static) {
710 (vtable(this.ptr).object_ref_stderr)(this).deref()
713 }
714
715 pub(crate) unsafe fn diagnostic<'a>(
716 this: Ref<'a, Self>,
717 ) -> &'a (dyn Diagnostic + Send + Sync + 'static) {
718 (vtable(this.ptr).object_ref)(this).deref()
721 }
722
723 pub(crate) unsafe fn diagnostic_mut<'a>(
724 this: Mut<'a, Self>,
725 ) -> &'a mut (dyn Diagnostic + Send + Sync + 'static) {
726 (vtable(this.ptr).object_ref)(this.by_ref())
729 .by_mut()
730 .deref_mut()
731 }
732
733 #[cold]
734 pub(crate) unsafe fn chain(this: Ref<'_, Self>) -> Chain<'_> {
735 Chain::new(Self::error(this))
736 }
737}
738
739impl<E> Debug for ErrorImpl<E>
740where
741 E: Debug,
742{
743 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
744 unsafe { ErrorImpl::debug(self.erase(), formatter) }
745 }
746}
747
748impl<E> Display for ErrorImpl<E>
749where
750 E: Display,
751{
752 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
753 unsafe { Display::fmt(ErrorImpl::diagnostic(self.erase()), formatter) }
754 }
755}
756
757impl From<Report> for Box<dyn Diagnostic + Send + Sync + 'static> {
758 #[cold]
759 fn from(error: Report) -> Self {
760 let outer = ManuallyDrop::new(error);
761 unsafe {
762 (vtable(outer.inner.ptr).object_boxed)(outer.inner)
765 }
766 }
767}
768
769impl From<Report> for Box<dyn StdError + Send + Sync + 'static> {
770 #[cold]
771 fn from(error: Report) -> Self {
772 let outer = ManuallyDrop::new(error);
773 unsafe {
774 (vtable(outer.inner.ptr).object_boxed_stderr)(outer.inner)
777 }
778 }
779}
780
781impl From<Report> for Box<dyn Diagnostic + 'static> {
782 #[cold]
783 fn from(error: Report) -> Self {
784 Box::<dyn Diagnostic + Send + Sync>::from(error)
785 }
786}
787
788impl From<Report> for Box<dyn StdError + 'static> {
789 #[cold]
790 fn from(error: Report) -> Self {
791 Box::<dyn StdError + Send + Sync>::from(error)
792 }
793}
794
795impl AsRef<dyn Diagnostic + Send + Sync> for Report {
796 fn as_ref(&self) -> &(dyn Diagnostic + Send + Sync + 'static) {
797 &**self
798 }
799}
800
801impl AsRef<dyn Diagnostic> for Report {
802 fn as_ref(&self) -> &(dyn Diagnostic + 'static) {
803 &**self
804 }
805}
806
807impl AsRef<dyn StdError + Send + Sync> for Report {
808 fn as_ref(&self) -> &(dyn StdError + Send + Sync + 'static) {
809 unsafe { ErrorImpl::error(self.inner.by_ref()) }
810 }
811}
812
813impl AsRef<dyn StdError> for Report {
814 fn as_ref(&self) -> &(dyn StdError + 'static) {
815 unsafe { ErrorImpl::error(self.inner.by_ref()) }
816 }
817}
818
819impl std::borrow::Borrow<dyn Diagnostic> for Report {
820 fn borrow(&self) -> &(dyn Diagnostic + 'static) {
821 self.as_ref()
822 }
823}