1use alloc::boxed::Box;
2#[cfg(feature = "std")]
3use core::ops::{Deref, DerefMut};
4use core::{
5 any::TypeId,
6 fmt::{self, Debug, Display},
7 mem::ManuallyDrop,
8 ptr,
9 ptr::NonNull,
10};
11#[cfg(error_generic_member_access)]
12use std::error::{self, Request};
13
14#[cfg(feature = "std")]
15use crate::ptr::Mut;
16use crate::{
17 Error, StdError,
18 backtrace::Backtrace,
19 chain::Chain,
20 ptr::{Own, Ref},
21};
22
23impl Error {
24 #[cfg(feature = "std")]
32 #[cfg_attr(docsrs, doc(cfg(feature = "std")))]
33 #[cold]
34 #[must_use]
35 pub fn new<E>(error: E) -> Self
36 where
37 E: StdError + Send + Sync + 'static,
38 {
39 let backtrace = backtrace_if_absent!(&error);
40 Error::from_std(error, backtrace)
41 }
42
43 #[cold]
81 #[must_use]
82 pub fn msg<M>(message: M) -> Self
83 where
84 M: Display + Debug + Send + Sync + 'static,
85 {
86 Error::from_adhoc(message, backtrace!())
87 }
88
89 #[cfg(feature = "std")]
90 #[cold]
91 pub(crate) fn from_std<E>(error: E, backtrace: Option<Backtrace>) -> Self
92 where
93 E: StdError + Send + Sync + 'static,
94 {
95 let vtable = &ErrorVTable {
96 object_drop: object_drop::<E>,
97 object_ref: object_ref::<E>,
98 object_boxed: object_boxed::<E>,
99 object_downcast: object_downcast::<E>,
100 object_drop_rest: object_drop_front::<E>,
101 #[cfg(all(not(error_generic_member_access), std_backtrace))]
102 object_backtrace: no_backtrace,
103 };
104
105 unsafe { Error::construct(error, vtable, backtrace) }
107 }
108
109 #[cold]
110 pub(crate) fn from_adhoc<M>(message: M, backtrace: Option<Backtrace>) -> Self
111 where
112 M: Display + Debug + Send + Sync + 'static,
113 {
114 use crate::wrapper::MessageError;
115 let error: MessageError<M> = MessageError(message);
116 let vtable = &ErrorVTable {
117 object_drop: object_drop::<MessageError<M>>,
118 object_ref: object_ref::<MessageError<M>>,
119 object_boxed: object_boxed::<MessageError<M>>,
120 object_downcast: object_downcast::<M>,
121 object_drop_rest: object_drop_front::<M>,
122 #[cfg(all(not(error_generic_member_access), std_backtrace))]
123 object_backtrace: no_backtrace,
124 };
125
126 unsafe { Error::construct(error, vtable, backtrace) }
129 }
130
131 #[cold]
132 pub(crate) fn from_display<M>(message: M, backtrace: Option<Backtrace>) -> Self
133 where
134 M: Display + Send + Sync + 'static,
135 {
136 use crate::wrapper::DisplayError;
137 let error: DisplayError<M> = DisplayError(message);
138 let vtable = &ErrorVTable {
139 object_drop: object_drop::<DisplayError<M>>,
140 object_ref: object_ref::<DisplayError<M>>,
141 object_boxed: object_boxed::<DisplayError<M>>,
142 object_downcast: object_downcast::<M>,
143 object_drop_rest: object_drop_front::<M>,
144 #[cfg(all(not(error_generic_member_access), std_backtrace))]
145 object_backtrace: no_backtrace,
146 };
147
148 unsafe { Error::construct(error, vtable, backtrace) }
151 }
152
153 #[cfg(feature = "std")]
154 #[cold]
155 pub(crate) fn from_context<C, E>(context: C, error: E, backtrace: Option<Backtrace>) -> Self
156 where
157 C: Display + Send + Sync + 'static,
158 E: StdError + Send + Sync + 'static,
159 {
160 let error: ContextError<C, E> = ContextError {
161 context,
162 error,
163 };
164
165 let vtable = &ErrorVTable {
166 object_drop: object_drop::<ContextError<C, E>>,
167 object_ref: object_ref::<ContextError<C, E>>,
168 object_boxed: object_boxed::<ContextError<C, E>>,
169 object_downcast: context_downcast::<C, E>,
170 object_drop_rest: context_drop_rest::<C, E>,
171 #[cfg(all(not(error_generic_member_access), std_backtrace))]
172 object_backtrace: no_backtrace,
173 };
174
175 unsafe { Error::construct(error, vtable, backtrace) }
177 }
178
179 #[cfg(feature = "std")]
180 #[cold]
181 pub(crate) fn from_boxed(error: Box<dyn StdError + Send + Sync>, backtrace: Option<Backtrace>) -> Self {
182 use crate::wrapper::BoxedError;
183 let error = BoxedError(error);
184 let vtable = &ErrorVTable {
185 object_drop: object_drop::<BoxedError>,
186 object_ref: object_ref::<BoxedError>,
187 object_boxed: object_boxed::<BoxedError>,
188 object_downcast: object_downcast::<Box<dyn StdError + Send + Sync>>,
189 object_drop_rest: object_drop_front::<Box<dyn StdError + Send + Sync>>,
190 #[cfg(all(not(error_generic_member_access), std_backtrace))]
191 object_backtrace: no_backtrace,
192 };
193
194 unsafe { Error::construct(error, vtable, backtrace) }
197 }
198
199 #[cold]
205 unsafe fn construct<E>(error: E, vtable: &'static ErrorVTable, backtrace: Option<Backtrace>) -> Self
206 where
207 E: StdError + Send + Sync + 'static,
208 {
209 let inner: Box<ErrorImpl<E>> = Box::new(ErrorImpl {
210 vtable,
211 backtrace,
212 _object: error,
213 });
214 let inner = Own::new(inner).cast::<ErrorImpl>();
221 Error {
222 inner,
223 }
224 }
225
226 #[cold]
281 #[must_use]
282 pub fn context<C>(self, context: C) -> Self
283 where
284 C: Display + Send + Sync + 'static,
285 {
286 let error: ContextError<C, Error> = ContextError {
287 context,
288 error: self,
289 };
290
291 let vtable = &ErrorVTable {
292 object_drop: object_drop::<ContextError<C, Error>>,
293 object_ref: object_ref::<ContextError<C, Error>>,
294 object_boxed: object_boxed::<ContextError<C, Error>>,
295 object_downcast: context_chain_downcast::<C>,
296 object_drop_rest: context_chain_drop_rest::<C>,
297 #[cfg(all(not(error_generic_member_access), std_backtrace))]
298 object_backtrace: context_backtrace::<C>,
299 };
300
301 let backtrace = None;
303
304 unsafe { Error::construct(error, vtable, backtrace) }
306 }
307
308 #[cfg(std_backtrace)]
336 pub fn backtrace(&self) -> &impl_backtrace!() {
337 unsafe { ErrorImpl::backtrace(self.inner.by_ref()) }
338 }
339
340 #[cfg(feature = "std")]
362 #[cfg_attr(docsrs, doc(cfg(feature = "std")))]
363 #[cold]
364 pub fn chain(&self) -> Chain<'_> {
365 unsafe { ErrorImpl::chain(self.inner.by_ref()) }
366 }
367
368 #[cfg(feature = "std")]
374 #[cfg_attr(docsrs, doc(cfg(feature = "std")))]
375 pub fn root_cause(&self) -> &(dyn StdError + 'static) {
376 self.chain().last().unwrap()
377 }
378
379 pub fn is<E>(&self) -> bool
388 where
389 E: Display + Debug + Send + Sync + 'static,
390 {
391 self.downcast_ref::<E>().is_some()
392 }
393
394 pub fn downcast<E>(mut self) -> Result<E, Self>
396 where
397 E: Display + Debug + Send + Sync + 'static,
398 {
399 let target = TypeId::of::<E>();
400 let inner = self.inner.by_mut();
401 unsafe {
402 let addr = match (vtable(inner.ptr).object_downcast)(inner.by_ref(), target) {
405 Some(addr) => addr.by_mut().extend(),
406 None => return Err(self),
407 };
408
409 let outer = ManuallyDrop::new(self);
412
413 let error = addr.cast::<E>().read();
415
416 (vtable(outer.inner.ptr).object_drop_rest)(outer.inner, target);
418
419 Ok(error)
420 }
421 }
422
423 pub fn downcast_ref<E>(&self) -> Option<&E>
460 where
461 E: Display + Debug + Send + Sync + 'static,
462 {
463 let target = TypeId::of::<E>();
464 unsafe {
465 let addr = (vtable(self.inner.ptr).object_downcast)(self.inner.by_ref(), target)?;
468 Some(addr.cast::<E>().deref())
469 }
470 }
471
472 pub fn downcast_mut<E>(&mut self) -> Option<&mut E>
474 where
475 E: Display + Debug + Send + Sync + 'static,
476 {
477 let target = TypeId::of::<E>();
478 unsafe {
479 let addr = (vtable(self.inner.ptr).object_downcast)(self.inner.by_ref(), target)?.by_mut();
483
484 Some(addr.cast::<E>().deref_mut())
485 }
486 }
487
488 #[cfg(error_generic_member_access)]
489 pub(crate) fn provide<'a>(&'a self, request: &mut Request<'a>) {
490 unsafe { ErrorImpl::provide(self.inner.by_ref(), request) }
491 }
492
493 #[cfg(error_generic_member_access)]
499 #[doc(hidden)]
500 pub fn thiserror_provide<'a>(&'a self, request: &mut Request<'a>) {
501 Self::provide(self, request);
502 }
503}
504
505#[cfg(feature = "std")]
506#[cfg_attr(docsrs, doc(cfg(feature = "std")))]
507impl<E> From<E> for Error
508where
509 E: StdError + Send + Sync + 'static,
510{
511 #[cold]
512 fn from(error: E) -> Self {
513 let backtrace = backtrace_if_absent!(&error);
514 Error::from_std(error, backtrace)
515 }
516}
517
518#[cfg(feature = "std")]
519#[cfg_attr(docsrs, doc(cfg(feature = "std")))]
520impl Deref for Error {
521 type Target = dyn StdError + Send + Sync + 'static;
522
523 fn deref(&self) -> &Self::Target {
524 unsafe { ErrorImpl::error(self.inner.by_ref()) }
525 }
526}
527
528#[cfg(feature = "std")]
529#[cfg_attr(docsrs, doc(cfg(feature = "std")))]
530impl DerefMut for Error {
531 fn deref_mut(&mut self) -> &mut Self::Target {
532 unsafe { ErrorImpl::error_mut(self.inner.by_mut()) }
533 }
534}
535
536impl Display for Error {
537 fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
538 unsafe { ErrorImpl::display(self.inner.by_ref(), formatter) }
539 }
540}
541
542impl Debug for Error {
543 fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
544 unsafe { ErrorImpl::debug(self.inner.by_ref(), formatter) }
545 }
546}
547
548impl Drop for Error {
549 fn drop(&mut self) {
550 unsafe {
551 (vtable(self.inner.ptr).object_drop)(self.inner);
553 }
554 }
555}
556
557struct ErrorVTable {
558 object_drop: unsafe fn(Own<ErrorImpl>),
559 object_ref: unsafe fn(Ref<ErrorImpl>) -> Ref<dyn StdError + Send + Sync + 'static>,
560 object_boxed: unsafe fn(Own<ErrorImpl>) -> Box<dyn StdError + Send + Sync + 'static>,
561 object_downcast: unsafe fn(Ref<ErrorImpl>, TypeId) -> Option<Ref<()>>,
562 object_drop_rest: unsafe fn(Own<ErrorImpl>, TypeId),
563 #[cfg(all(not(error_generic_member_access), std_backtrace))]
564 object_backtrace: unsafe fn(Ref<ErrorImpl>) -> Option<&Backtrace>,
565}
566
567unsafe fn object_drop<E>(e: Own<ErrorImpl>) {
569 let unerased_own = e.cast::<ErrorImpl<E>>();
572 drop(unsafe { unerased_own.boxed() });
573}
574
575unsafe fn object_drop_front<E>(e: Own<ErrorImpl>, target: TypeId) {
577 let _ = target;
581 let unerased_own = e.cast::<ErrorImpl<ManuallyDrop<E>>>();
582 drop(unsafe { unerased_own.boxed() });
583}
584
585unsafe fn object_ref<E>(e: Ref<ErrorImpl>) -> Ref<dyn StdError + Send + Sync + 'static>
587where
588 E: StdError + Send + Sync + 'static,
589{
590 let unerased_ref = e.cast::<ErrorImpl<E>>();
593
594 return Ref::from_raw(unsafe { NonNull::new_unchecked(ptr::addr_of!((*unerased_ref.as_ptr())._object) as *mut E) });
595}
596
597unsafe fn object_boxed<E>(e: Own<ErrorImpl>) -> Box<dyn StdError + Send + Sync + 'static>
599where
600 E: StdError + Send + Sync + 'static,
601{
602 let unerased_own = e.cast::<ErrorImpl<E>>();
604 unsafe { unerased_own.boxed() }
605}
606
607unsafe fn object_downcast<E>(e: Ref<ErrorImpl>, target: TypeId) -> Option<Ref<()>>
609where
610 E: 'static,
611{
612 if TypeId::of::<E>() == target {
613 let unerased_ref = e.cast::<ErrorImpl<E>>();
617
618 return Some(
619 Ref::from_raw(unsafe { NonNull::new_unchecked(ptr::addr_of!((*unerased_ref.as_ptr())._object) as *mut E) })
620 .cast::<()>(),
621 );
622 } else {
623 None
624 }
625}
626
627#[cfg(all(not(error_generic_member_access), std_backtrace))]
628fn no_backtrace(e: Ref<'_, ErrorImpl>) -> Option<&Backtrace> {
629 let _ = e;
630 None
631}
632
633#[cfg(feature = "std")]
635unsafe fn context_downcast<C, E>(e: Ref<ErrorImpl>, target: TypeId) -> Option<Ref<()>>
636where
637 C: 'static,
638 E: 'static,
639{
640 if TypeId::of::<C>() == target {
641 let unerased_ref = e.cast::<ErrorImpl<ContextError<C, E>>>();
642 let unerased = unsafe { unerased_ref.deref() };
643 Some(Ref::new(&unerased._object.context).cast::<()>())
644 } else if TypeId::of::<E>() == target {
645 let unerased_ref = e.cast::<ErrorImpl<ContextError<C, E>>>();
646 let unerased = unsafe { unerased_ref.deref() };
647 Some(Ref::new(&unerased._object.error).cast::<()>())
648 } else {
649 None
650 }
651}
652
653#[cfg(feature = "std")]
655unsafe fn context_drop_rest<C, E>(e: Own<ErrorImpl>, target: TypeId)
656where
657 C: 'static,
658 E: 'static,
659{
660 if TypeId::of::<C>() == target {
663 let unerased_own = e.cast::<ErrorImpl<ContextError<ManuallyDrop<C>, E>>>();
664 drop(unsafe { unerased_own.boxed() });
665 } else {
666 let unerased_own = e.cast::<ErrorImpl<ContextError<C, ManuallyDrop<E>>>>();
667 drop(unsafe { unerased_own.boxed() });
668 }
669}
670
671unsafe fn context_chain_downcast<C>(e: Ref<ErrorImpl>, target: TypeId) -> Option<Ref<()>>
673where
674 C: 'static,
675{
676 let unerased_ref = e.cast::<ErrorImpl<ContextError<C, Error>>>();
677 let unerased = unsafe { unerased_ref.deref() };
678 if TypeId::of::<C>() == target {
679 Some(Ref::new(&unerased._object.context).cast::<()>())
680 } else {
681 let source = &unerased._object.error;
683 unsafe { (vtable(source.inner.ptr).object_downcast)(source.inner.by_ref(), target) }
684 }
685}
686
687unsafe fn context_chain_drop_rest<C>(e: Own<ErrorImpl>, target: TypeId)
689where
690 C: 'static,
691{
692 if TypeId::of::<C>() == target {
695 let unerased_own = e.cast::<ErrorImpl<ContextError<ManuallyDrop<C>, Error>>>();
696 drop(unsafe { unerased_own.boxed() });
698 } else {
699 let unerased_own = e.cast::<ErrorImpl<ContextError<C, ManuallyDrop<Error>>>>();
700 let unerased = unsafe { unerased_own.boxed() };
701 let inner = unerased._object.error.inner;
703 drop(unerased);
704 let vtable = unsafe { vtable(inner.ptr) };
705 unsafe { (vtable.object_drop_rest)(inner, target) };
707 }
708}
709
710#[cfg(all(not(error_generic_member_access), std_backtrace))]
712#[allow(clippy::unnecessary_wraps)]
713unsafe fn context_backtrace<C>(e: Ref<'_, ErrorImpl>) -> Option<&Backtrace>
714where
715 C: 'static,
716{
717 let unerased_ref = e.cast::<ErrorImpl<ContextError<C, Error>>>();
718 let unerased = unsafe { unerased_ref.deref() };
719 let backtrace = unsafe { ErrorImpl::backtrace(unerased._object.error.inner.by_ref()) };
720 Some(backtrace)
721}
722
723#[repr(C)]
727pub(crate) struct ErrorImpl<E = ()> {
728 vtable: &'static ErrorVTable,
729 backtrace: Option<Backtrace>,
730 _object: E,
733}
734
735unsafe fn vtable(p: NonNull<ErrorImpl>) -> &'static ErrorVTable {
738 unsafe { *(p.as_ptr() as *const &'static ErrorVTable) }
740}
741
742#[repr(C)]
745pub(crate) struct ContextError<C, E> {
746 pub context: C,
747 pub error: E,
748}
749
750impl<E> ErrorImpl<E> {
751 fn erase(&self) -> Ref<'_, ErrorImpl> {
752 Ref::new(self).cast::<ErrorImpl>()
756 }
757}
758
759impl ErrorImpl {
760 pub(crate) unsafe fn error(this: Ref<'_, Self>) -> &(dyn StdError + Send + Sync + 'static) {
761 unsafe { (vtable(this.ptr).object_ref)(this).deref() }
764 }
765
766 #[cfg(feature = "std")]
767 pub(crate) unsafe fn error_mut(this: Mut<'_, Self>) -> &mut (dyn StdError + Send + Sync + 'static) {
768 unsafe { (vtable(this.ptr).object_ref)(this.by_ref()).by_mut().deref_mut() }
771 }
772
773 #[cfg(std_backtrace)]
774 pub(crate) unsafe fn backtrace(this: Ref<'_, Self>) -> &Backtrace {
775 unsafe { this.deref() }
779 .backtrace
780 .as_ref()
781 .or_else(|| {
782 #[cfg(error_generic_member_access)]
783 return error::request_ref::<Backtrace>(unsafe { Self::error(this) });
784 #[cfg(not(error_generic_member_access))]
785 return unsafe { (vtable(this.ptr).object_backtrace)(this) };
786 })
787 .expect("backtrace capture failed")
788 }
789
790 #[cfg(error_generic_member_access)]
791 unsafe fn provide<'a>(this: Ref<'a, Self>, request: &mut Request<'a>) {
792 if let Some(backtrace) = unsafe { &this.deref().backtrace } {
793 request.provide_ref(backtrace);
794 }
795 unsafe { Self::error(this) }.provide(request);
796 }
797
798 #[cold]
799 pub(crate) unsafe fn chain(this: Ref<Self>) -> Chain {
800 Chain::new(unsafe { Self::error(this) })
801 }
802}
803
804impl<E> StdError for ErrorImpl<E>
805where
806 E: StdError,
807{
808 fn source(&self) -> Option<&(dyn StdError + 'static)> {
809 unsafe { ErrorImpl::error(self.erase()).source() }
810 }
811
812 #[cfg(error_generic_member_access)]
813 fn provide<'a>(&'a self, request: &mut Request<'a>) {
814 unsafe { ErrorImpl::provide(self.erase(), request) }
815 }
816}
817
818impl<E> Debug for ErrorImpl<E>
819where
820 E: Debug,
821{
822 fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
823 unsafe { ErrorImpl::debug(self.erase(), formatter) }
824 }
825}
826
827impl<E> Display for ErrorImpl<E>
828where
829 E: Display,
830{
831 fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
832 unsafe { Display::fmt(ErrorImpl::error(self.erase()), formatter) }
833 }
834}
835
836impl From<Error> for Box<dyn StdError + Send + Sync + 'static> {
837 #[cold]
838 fn from(error: Error) -> Self {
839 let outer = ManuallyDrop::new(error);
840 unsafe {
841 (vtable(outer.inner.ptr).object_boxed)(outer.inner)
844 }
845 }
846}
847
848impl From<Error> for Box<dyn StdError + Send + 'static> {
849 fn from(error: Error) -> Self {
850 Box::<dyn StdError + Send + Sync>::from(error)
851 }
852}
853
854impl From<Error> for Box<dyn StdError + 'static> {
855 fn from(error: Error) -> Self {
856 Box::<dyn StdError + Send + Sync>::from(error)
857 }
858}
859
860#[cfg(feature = "std")]
861impl AsRef<dyn StdError + Send + Sync> for Error {
862 fn as_ref(&self) -> &(dyn StdError + Send + Sync + 'static) {
863 &**self
864 }
865}
866
867#[cfg(feature = "std")]
868impl AsRef<dyn StdError> for Error {
869 fn as_ref(&self) -> &(dyn StdError + 'static) {
870 &**self
871 }
872}