1use crate::chain::Chain;
2use crate::ptr::{MutPtr, OwnedPtr, RefPtr};
3use crate::EyreHandler;
4use crate::{Report, StdError};
5use core::any::TypeId;
6use core::fmt::{self, Debug, Display};
7use core::mem::{self, ManuallyDrop};
8use core::ptr::{self, NonNull};
9
10use core::ops::{Deref, DerefMut};
11
12impl Report {
13 /// Create a new error object from any error type.
14 ///
15 /// The error type must be threadsafe and `'static`, so that the `Report`
16 /// will be as well.
17 ///
18 /// If the error type does not provide a backtrace, a backtrace will be
19 /// created here to ensure that a backtrace exists.
20 #[cfg_attr(track_caller, track_caller)]
21 pub fn new<E>(error: E) -> Self
22 where
23 E: StdError + Send + Sync + 'static,
24 {
25 Report::from_std(error)
26 }
27
28 /// Create a new error object from a printable error message.
29 ///
30 /// If the argument implements std::error::Error, prefer `Report::new`
31 /// instead which preserves the underlying error's cause chain and
32 /// backtrace. If the argument may or may not implement std::error::Error
33 /// now or in the future, use `eyre!(err)` which handles either way
34 /// correctly.
35 ///
36 /// `Report::msg("...")` is equivalent to `eyre!("...")` but occasionally
37 /// convenient in places where a function is preferable over a macro, such
38 /// as iterator or stream combinators:
39 ///
40 /// ```
41 /// # mod ffi {
42 /// # pub struct Input;
43 /// # pub struct Output;
44 /// # pub async fn do_some_work(_: Input) -> Result<Output, &'static str> {
45 /// # unimplemented!()
46 /// # }
47 /// # }
48 /// #
49 /// # use ffi::{Input, Output};
50 /// #
51 /// use eyre::{Report, Result};
52 /// use futures::stream::{Stream, StreamExt, TryStreamExt};
53 ///
54 /// async fn demo<S>(stream: S) -> Result<Vec<Output>>
55 /// where
56 /// S: Stream<Item = Input>,
57 /// {
58 /// stream
59 /// .then(ffi::do_some_work) // returns Result<Output, &str>
60 /// .map_err(Report::msg)
61 /// .try_collect()
62 /// .await
63 /// }
64 /// ```
65 #[cfg_attr(track_caller, track_caller)]
66 pub fn msg<M>(message: M) -> Self
67 where
68 M: Display + Debug + Send + Sync + 'static,
69 {
70 Report::from_adhoc(message)
71 }
72
73 #[cfg_attr(track_caller, track_caller)]
74 /// Creates a new error from an implementor of [`std::error::Error`]
75 pub(crate) fn from_std<E>(error: E) -> Self
76 where
77 E: StdError + Send + Sync + 'static,
78 {
79 let vtable = &ErrorVTable {
80 object_drop: object_drop::<E>,
81 object_ref: object_ref::<E>,
82 object_mut: object_mut::<E>,
83 object_boxed: object_boxed::<E>,
84 object_downcast: object_downcast::<E>,
85 object_downcast_mut: object_downcast_mut::<E>,
86 object_drop_rest: object_drop_front::<E>,
87 };
88
89 // Safety: passing vtable that operates on the right type E.
90 let handler = Some(crate::capture_handler(&error));
91
92 unsafe { Report::construct(error, vtable, handler) }
93 }
94
95 #[cfg_attr(track_caller, track_caller)]
96 pub(crate) fn from_adhoc<M>(message: M) -> Self
97 where
98 M: Display + Debug + Send + Sync + 'static,
99 {
100 use crate::wrapper::MessageError;
101 let error: MessageError<M> = MessageError(message);
102 let vtable = &ErrorVTable {
103 object_drop: object_drop::<MessageError<M>>,
104 object_ref: object_ref::<MessageError<M>>,
105 object_mut: object_mut::<MessageError<M>>,
106 object_boxed: object_boxed::<MessageError<M>>,
107 object_downcast: object_downcast::<M>,
108 object_downcast_mut: object_downcast_mut::<M>,
109 object_drop_rest: object_drop_front::<M>,
110 };
111
112 // Safety: MessageError is repr(transparent) so it is okay for the
113 // vtable to allow casting the MessageError<M> to M.
114 let handler = Some(crate::capture_handler(&error));
115
116 unsafe { Report::construct(error, vtable, handler) }
117 }
118
119 #[cfg_attr(track_caller, track_caller)]
120 pub(crate) fn from_display<M>(message: M) -> Self
121 where
122 M: Display + Send + Sync + 'static,
123 {
124 use crate::wrapper::{DisplayError, NoneError};
125 let error: DisplayError<M> = DisplayError(message);
126 let vtable = &ErrorVTable {
127 object_drop: object_drop::<DisplayError<M>>,
128 object_ref: object_ref::<DisplayError<M>>,
129 object_mut: object_mut::<DisplayError<M>>,
130 object_boxed: object_boxed::<DisplayError<M>>,
131 object_downcast: object_downcast::<M>,
132 object_downcast_mut: object_downcast_mut::<M>,
133 object_drop_rest: object_drop_front::<M>,
134 };
135
136 // Safety: DisplayError is repr(transparent) so it is okay for the
137 // vtable to allow casting the DisplayError<M> to M.
138 let handler = Some(crate::capture_handler(&NoneError));
139
140 unsafe { Report::construct(error, vtable, handler) }
141 }
142
143 #[cfg_attr(track_caller, track_caller)]
144 pub(crate) fn from_msg<D, E>(msg: D, error: E) -> Self
145 where
146 D: Display + Send + Sync + 'static,
147 E: StdError + Send + Sync + 'static,
148 {
149 let error: ContextError<D, E> = ContextError { msg, error };
150
151 let vtable = &ErrorVTable {
152 object_drop: object_drop::<ContextError<D, E>>,
153 object_ref: object_ref::<ContextError<D, E>>,
154 object_mut: object_mut::<ContextError<D, E>>,
155 object_boxed: object_boxed::<ContextError<D, E>>,
156 object_downcast: context_downcast::<D, E>,
157 object_downcast_mut: context_downcast_mut::<D, E>,
158 object_drop_rest: context_drop_rest::<D, E>,
159 };
160
161 // Safety: passing vtable that operates on the right type.
162 let handler = Some(crate::capture_handler(&error));
163
164 unsafe { Report::construct(error, vtable, handler) }
165 }
166
167 #[cfg_attr(track_caller, track_caller)]
168 pub(crate) fn from_boxed(error: Box<dyn StdError + Send + Sync>) -> Self {
169 use crate::wrapper::BoxedError;
170 let error = BoxedError(error);
171 let handler = Some(crate::capture_handler(&error));
172
173 let vtable = &ErrorVTable {
174 object_drop: object_drop::<BoxedError>,
175 object_ref: object_ref::<BoxedError>,
176 object_mut: object_mut::<BoxedError>,
177 object_boxed: object_boxed::<BoxedError>,
178 object_downcast: object_downcast::<Box<dyn StdError + Send + Sync>>,
179 object_downcast_mut: object_downcast_mut::<Box<dyn StdError + Send + Sync>>,
180 object_drop_rest: object_drop_front::<Box<dyn StdError + Send + Sync>>,
181 };
182
183 // Safety: BoxedError is repr(transparent) so it is okay for the vtable
184 // to allow casting to Box<dyn StdError + Send + Sync>.
185 unsafe { Report::construct(error, vtable, handler) }
186 }
187
188 // Takes backtrace as argument rather than capturing it here so that the
189 // user sees one fewer layer of wrapping noise in the backtrace.
190 //
191 // Unsafe because the given vtable must have sensible behavior on the error
192 // value of type E.
193 unsafe fn construct<E>(
194 error: E,
195 vtable: &'static ErrorVTable,
196 handler: Option<Box<dyn EyreHandler>>,
197 ) -> Self
198 where
199 E: StdError + Send + Sync + 'static,
200 {
201 let inner = ErrorImpl {
202 header: ErrorHeader { vtable, handler },
203 _object: error,
204 };
205
206 // Construct a new owned allocation through a raw pointer
207 //
208 // This does not keep the allocation around as a `Box` which would invalidate an
209 // references when moved
210 let ptr = OwnedPtr::<ErrorImpl<E>>::new(inner);
211
212 // Safety: the type
213 let ptr = ptr.cast::<ErrorImpl<()>>();
214 Report { inner: ptr }
215 }
216
217 /// Create a new error from an error message to wrap the existing error.
218 ///
219 /// For attaching a higher level error message to a `Result` as it is propagated, the
220 /// [`WrapErr`][crate::WrapErr] extension trait may be more convenient than this function.
221 ///
222 /// The primary reason to use `error.wrap_err(...)` instead of `result.wrap_err(...)` via the
223 /// `WrapErr` trait would be if the message needs to depend on some data held by the underlying
224 /// error:
225 ///
226 /// ```
227 /// # use std::fmt::{self, Debug, Display};
228 /// #
229 /// # type T = ();
230 /// #
231 /// # impl std::error::Error for ParseError {}
232 /// # impl Debug for ParseError {
233 /// # fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
234 /// # unimplemented!()
235 /// # }
236 /// # }
237 /// # impl Display for ParseError {
238 /// # fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
239 /// # unimplemented!()
240 /// # }
241 /// # }
242 /// #
243 /// use eyre::Result;
244 /// use std::fs::File;
245 /// use std::path::Path;
246 ///
247 /// struct ParseError {
248 /// line: usize,
249 /// column: usize,
250 /// }
251 ///
252 /// fn parse_impl(file: File) -> Result<T, ParseError> {
253 /// # const IGNORE: &str = stringify! {
254 /// ...
255 /// # };
256 /// # unimplemented!()
257 /// }
258 ///
259 /// pub fn parse(path: impl AsRef<Path>) -> Result<T> {
260 /// let file = File::open(&path)?;
261 /// parse_impl(file).map_err(|error| {
262 /// let message = format!(
263 /// "only the first {} lines of {} are valid",
264 /// error.line, path.as_ref().display(),
265 /// );
266 /// eyre::Report::new(error).wrap_err(message)
267 /// })
268 /// }
269 /// ```
270 pub fn wrap_err<D>(mut self, msg: D) -> Self
271 where
272 D: Display + Send + Sync + 'static,
273 {
274 // Safety: this access a `ErrorImpl<unknown>` as a valid reference to a `ErrorImpl<()>`
275 //
276 // As the generic is at the end of the struct and the struct is `repr(C)` this reference
277 // will be within bounds of the original pointer, and the field will have the same offset
278 let handler = header_mut(self.inner.as_mut()).handler.take();
279 let error: ContextError<D, Report> = ContextError { msg, error: self };
280
281 let vtable = &ErrorVTable {
282 object_drop: object_drop::<ContextError<D, Report>>,
283 object_ref: object_ref::<ContextError<D, Report>>,
284 object_mut: object_mut::<ContextError<D, Report>>,
285 object_boxed: object_boxed::<ContextError<D, Report>>,
286 object_downcast: context_chain_downcast::<D>,
287 object_downcast_mut: context_chain_downcast_mut::<D>,
288 object_drop_rest: context_chain_drop_rest::<D>,
289 };
290
291 // Safety: passing vtable that operates on the right type.
292 unsafe { Report::construct(error, vtable, handler) }
293 }
294
295 /// Access the vtable for the current error object.
296 fn vtable(&self) -> &'static ErrorVTable {
297 header(self.inner.as_ref()).vtable
298 }
299
300 /// An iterator of the chain of source errors contained by this Report.
301 ///
302 /// This iterator will visit every error in the cause chain of this error
303 /// object, beginning with the error that this error object was created
304 /// from.
305 ///
306 /// # Example
307 ///
308 /// ```
309 /// use eyre::Report;
310 /// use std::io;
311 ///
312 /// pub fn underlying_io_error_kind(error: &Report) -> Option<io::ErrorKind> {
313 /// for cause in error.chain() {
314 /// if let Some(io_error) = cause.downcast_ref::<io::Error>() {
315 /// return Some(io_error.kind());
316 /// }
317 /// }
318 /// None
319 /// }
320 /// ```
321 pub fn chain(&self) -> Chain<'_> {
322 ErrorImpl::chain(self.inner.as_ref())
323 }
324
325 /// The lowest level cause of this error &mdash; this error's cause's
326 /// cause's cause etc.
327 ///
328 /// The root cause is the last error in the iterator produced by
329 /// [`chain()`][Report::chain].
330 pub fn root_cause(&self) -> &(dyn StdError + 'static) {
331 let mut chain = self.chain();
332 let mut root_cause = chain.next().unwrap();
333 for cause in chain {
334 root_cause = cause;
335 }
336 root_cause
337 }
338
339 /// Returns true if `E` is the type held by this error object.
340 ///
341 /// For errors constructed from messages, this method returns true if `E` matches the type of
342 /// the message `D` **or** the type of the error on which the message has been attached. For
343 /// details about the interaction between message and downcasting, [see here].
344 ///
345 /// [see here]: trait.WrapErr.html#effect-on-downcasting
346 pub fn is<E>(&self) -> bool
347 where
348 E: Display + Debug + Send + Sync + 'static,
349 {
350 self.downcast_ref::<E>().is_some()
351 }
352
353 /// Attempt to downcast the error object to a concrete type.
354 pub fn downcast<E>(self) -> Result<E, Self>
355 where
356 E: Display + Debug + Send + Sync + 'static,
357 {
358 let target = TypeId::of::<E>();
359 unsafe {
360 // Use vtable to find NonNull<()> which points to a value of type E
361 // somewhere inside the data structure.
362 let addr = match (self.vtable().object_downcast)(self.inner.as_ref(), target) {
363 Some(addr) => addr,
364 None => return Err(self),
365 };
366
367 // Prepare to read E out of the data structure. We'll drop the rest
368 // of the data structure separately so that E is not dropped.
369 let outer = ManuallyDrop::new(self);
370
371 // Read E from where the vtable found it.
372 let error = ptr::read(addr.cast::<E>().as_ptr());
373
374 // Read Box<ErrorImpl<()>> from self. Can't move it out because
375 // Report has a Drop impl which we want to not run.
376 let inner = ptr::read(&outer.inner);
377
378 // Drop rest of the data structure outside of E.
379 (outer.vtable().object_drop_rest)(inner, target);
380
381 Ok(error)
382 }
383 }
384
385 /// Downcast this error object by reference.
386 ///
387 /// # Example
388 ///
389 /// ```
390 /// # use eyre::{Report, eyre};
391 /// # use std::fmt::{self, Display};
392 /// # use std::task::Poll;
393 /// #
394 /// # #[derive(Debug)]
395 /// # enum DataStoreError {
396 /// # Censored(()),
397 /// # }
398 /// #
399 /// # impl Display for DataStoreError {
400 /// # fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
401 /// # unimplemented!()
402 /// # }
403 /// # }
404 /// #
405 /// # impl std::error::Error for DataStoreError {}
406 /// #
407 /// # const REDACTED_CONTENT: () = ();
408 /// #
409 /// # #[cfg(not(feature = "auto-install"))]
410 /// # eyre::set_hook(Box::new(eyre::DefaultHandler::default_with)).unwrap();
411 /// #
412 /// # let error: Report = eyre!("...");
413 /// # let root_cause = &error;
414 /// #
415 /// # let ret =
416 /// // If the error was caused by redaction, then return a tombstone instead
417 /// // of the content.
418 /// match root_cause.downcast_ref::<DataStoreError>() {
419 /// Some(DataStoreError::Censored(_)) => Ok(Poll::Ready(REDACTED_CONTENT)),
420 /// None => Err(error),
421 /// }
422 /// # ;
423 /// ```
424 pub fn downcast_ref<E>(&self) -> Option<&E>
425 where
426 E: Display + Debug + Send + Sync + 'static,
427 {
428 let target = TypeId::of::<E>();
429 unsafe {
430 // Use vtable to find NonNull<()> which points to a value of type E
431 // somewhere inside the data structure.
432 let addr = (self.vtable().object_downcast)(self.inner.as_ref(), target)?;
433 Some(addr.cast::<E>().as_ref())
434 }
435 }
436
437 /// Downcast this error object by mutable reference.
438 pub fn downcast_mut<E>(&mut self) -> Option<&mut E>
439 where
440 E: Display + Debug + Send + Sync + 'static,
441 {
442 let target = TypeId::of::<E>();
443 unsafe {
444 // Use vtable to find NonNull<()> which points to a value of type E
445 // somewhere inside the data structure.
446 let addr = (self.vtable().object_downcast_mut)(self.inner.as_mut(), target)?;
447 Some(addr.cast::<E>().as_mut())
448 }
449 }
450
451 /// Get a reference to the Handler for this Report.
452 pub fn handler(&self) -> &dyn EyreHandler {
453 header(self.inner.as_ref())
454 .handler
455 .as_ref()
456 .unwrap()
457 .as_ref()
458 }
459
460 /// Get a mutable reference to the Handler for this Report.
461 pub fn handler_mut(&mut self) -> &mut dyn EyreHandler {
462 header_mut(self.inner.as_mut())
463 .handler
464 .as_mut()
465 .unwrap()
466 .as_mut()
467 }
468
469 /// Get a reference to the Handler for this Report.
470 #[doc(hidden)]
471 pub fn context(&self) -> &dyn EyreHandler {
472 header(self.inner.as_ref())
473 .handler
474 .as_ref()
475 .unwrap()
476 .as_ref()
477 }
478
479 /// Get a mutable reference to the Handler for this Report.
480 #[doc(hidden)]
481 pub fn context_mut(&mut self) -> &mut dyn EyreHandler {
482 header_mut(self.inner.as_mut())
483 .handler
484 .as_mut()
485 .unwrap()
486 .as_mut()
487 }
488}
489
490impl<E> From<E> for Report
491where
492 E: StdError + Send + Sync + 'static,
493{
494 #[cfg_attr(track_caller, track_caller)]
495 fn from(error: E) -> Self {
496 Report::from_std(error)
497 }
498}
499
500impl Deref for Report {
501 type Target = dyn StdError + Send + Sync + 'static;
502
503 fn deref(&self) -> &Self::Target {
504 ErrorImpl::error(self.inner.as_ref())
505 }
506}
507
508impl DerefMut for Report {
509 fn deref_mut(&mut self) -> &mut Self::Target {
510 ErrorImpl::error_mut(self.inner.as_mut())
511 }
512}
513
514impl Display for Report {
515 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
516 ErrorImpl::display(self.inner.as_ref(), f:formatter)
517 }
518}
519
520impl Debug for Report {
521 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
522 ErrorImpl::debug(self.inner.as_ref(), f:formatter)
523 }
524}
525
526impl Drop for Report {
527 fn drop(&mut self) {
528 unsafe {
529 // Read Box<ErrorImpl<()>> from self.
530 (self.vtable().object_drop)(self.inner);
531 }
532 }
533}
534
535struct ErrorVTable {
536 object_drop: unsafe fn(OwnedPtr<ErrorImpl<()>>),
537 object_ref: unsafe fn(RefPtr<'_, ErrorImpl<()>>) -> &(dyn StdError + Send + Sync + 'static),
538 object_mut: unsafe fn(MutPtr<'_, ErrorImpl<()>>) -> &mut (dyn StdError + Send + Sync + 'static),
539 #[allow(clippy::type_complexity)]
540 object_boxed: unsafe fn(OwnedPtr<ErrorImpl<()>>) -> Box<dyn StdError + Send + Sync + 'static>,
541 object_downcast: unsafe fn(RefPtr<'_, ErrorImpl<()>>, TypeId) -> Option<NonNull<()>>,
542 object_downcast_mut: unsafe fn(MutPtr<'_, ErrorImpl<()>>, TypeId) -> Option<NonNull<()>>,
543 object_drop_rest: unsafe fn(OwnedPtr<ErrorImpl<()>>, TypeId),
544}
545
546/// # Safety
547///
548/// Requires layout of *e to match ErrorImpl<E>.
549unsafe fn object_drop<E>(e: OwnedPtr<ErrorImpl<()>>) {
550 // Cast to a context type and drop the Box allocation.
551 let unerased: Box> = unsafe { e.cast::<ErrorImpl<E>>().into_box() };
552 drop(unerased);
553}
554
555/// # Safety
556///
557/// Requires layout of *e to match ErrorImpl<E>.
558unsafe fn object_drop_front<E>(e: OwnedPtr<ErrorImpl<()>>, target: TypeId) {
559 // Drop the fields of ErrorImpl other than E as well as the Box allocation,
560 // without dropping E itself. This is used by downcast after doing a
561 // ptr::read to take ownership of the E.
562 let _ = target;
563 // Note: This must not use `mem::transmute` because it tries to reborrow the `Unique`
564 // contained in `Box`, which must not be done. In practice this probably won't make any
565 // difference by now, but technically it's unsound.
566 // see: https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.m
567 let unerased: Box> = unsafe { e.cast::<ErrorImpl<E>>().into_box() };
568
569 mem::forget(unerased._object)
570}
571
572/// # Safety
573///
574/// Requires layout of *e to match ErrorImpl<E>.
575unsafe fn object_ref<E>(e: RefPtr<'_, ErrorImpl<()>>) -> &(dyn StdError + Send + Sync + 'static)
576where
577 E: StdError + Send + Sync + 'static,
578{
579 // Attach E's native StdError vtable onto a pointer to self._object.
580 &unsafe { e.cast::<ErrorImpl<E>>().as_ref() }._object
581}
582
583/// # Safety
584///
585/// Requires layout of *e to match ErrorImpl<E>.
586unsafe fn object_mut<E>(e: MutPtr<'_, ErrorImpl<()>>) -> &mut (dyn StdError + Send + Sync + 'static)
587where
588 E: StdError + Send + Sync + 'static,
589{
590 // Attach E's native StdError vtable onto a pointer to self._object.
591 &mut unsafe { e.cast::<ErrorImpl<E>>().into_mut() }._object
592}
593
594/// # Safety
595///
596/// Requires layout of *e to match ErrorImpl<E>.
597unsafe fn object_boxed<E>(e: OwnedPtr<ErrorImpl<()>>) -> Box<dyn StdError + Send + Sync + 'static>
598where
599 E: StdError + Send + Sync + 'static,
600{
601 // Attach ErrorImpl<E>'s native StdError vtable. The StdError impl is below.
602 unsafe { e.cast::<ErrorImpl<E>>().into_box() }
603}
604
605/// # Safety
606///
607/// Requires layout of *e to match ErrorImpl<E>.
608unsafe fn object_downcast<E>(e: RefPtr<'_, ErrorImpl<()>>, target: TypeId) -> Option<NonNull<()>>
609where
610 E: 'static,
611{
612 if TypeId::of::<E>() == target {
613 // Caller is looking for an E pointer and e is ErrorImpl<E>, take a
614 // pointer to its E field.
615 let unerased: &ErrorImpl = unsafe { e.cast::<ErrorImpl<E>>().as_ref() };
616 Some(NonNull::from(&(unerased._object)).cast::<()>())
617 } else {
618 None
619 }
620}
621
622/// # Safety
623///
624/// Requires layout of *e to match ErrorImpl<E>.
625unsafe fn object_downcast_mut<E>(
626 e: MutPtr<'_, ErrorImpl<()>>,
627 target: TypeId,
628) -> Option<NonNull<()>>
629where
630 E: 'static,
631{
632 if TypeId::of::<E>() == target {
633 // Caller is looking for an E pointer and e is ErrorImpl<E>, take a
634 // pointer to its E field.
635 let unerased: &mut ErrorImpl = unsafe { e.cast::<ErrorImpl<E>>().into_mut() };
636 Some(NonNull::from(&mut (unerased._object)).cast::<()>())
637 } else {
638 None
639 }
640}
641
642/// # Safety
643///
644/// Requires layout of *e to match ErrorImpl<ContextError<D, E>>.
645unsafe fn context_downcast<D, E>(
646 e: RefPtr<'_, ErrorImpl<()>>,
647 target: TypeId,
648) -> Option<NonNull<()>>
649where
650 D: 'static,
651 E: 'static,
652{
653 if TypeId::of::<D>() == target {
654 let unerased: &ErrorImpl> = unsafe { e.cast::<ErrorImpl<ContextError<D, E>>>().as_ref() };
655 let addr: NonNull<()> = NonNull::from(&unerased._object.msg).cast::<()>();
656 Some(addr)
657 } else if TypeId::of::<E>() == target {
658 let unerased: &ErrorImpl> = unsafe { e.cast::<ErrorImpl<ContextError<D, E>>>().as_ref() };
659 let addr: NonNull<()> = NonNull::from(&unerased._object.error).cast::<()>();
660 Some(addr)
661 } else {
662 None
663 }
664}
665
666/// # Safety
667///
668/// Requires layout of *e to match ErrorImpl<ContextError<D, E>>.
669unsafe fn context_downcast_mut<D, E>(
670 e: MutPtr<'_, ErrorImpl<()>>,
671 target: TypeId,
672) -> Option<NonNull<()>>
673where
674 D: 'static,
675 E: 'static,
676{
677 if TypeId::of::<D>() == target {
678 let unerased: &mut ErrorImpl> = unsafe { e.cast::<ErrorImpl<ContextError<D, E>>>().into_mut() };
679 let addr: NonNull<()> = NonNull::from(&unerased._object.msg).cast::<()>();
680 Some(addr)
681 } else if TypeId::of::<E>() == target {
682 let unerased: &mut ErrorImpl> = unsafe { e.cast::<ErrorImpl<ContextError<D, E>>>().into_mut() };
683 let addr: NonNull<()> = NonNull::from(&mut unerased._object.error).cast::<()>();
684 Some(addr)
685 } else {
686 None
687 }
688}
689/// # Safety
690///
691/// Requires layout of *e to match ErrorImpl<ContextError<D, E>>.
692unsafe fn context_drop_rest<D, E>(e: OwnedPtr<ErrorImpl<()>>, target: TypeId)
693where
694 D: 'static,
695 E: 'static,
696{
697 // Called after downcasting by value to either the D or the E and doing a
698 // ptr::read to take ownership of that value.
699 if TypeId::of::<D>() == target {
700 unsafe {
701 eOwnedPtr>>.cast::<ErrorImpl<ContextError<ManuallyDrop<D>, E>>>()
702 .into_box()
703 };
704 } else {
705 debug_assert_eq!(TypeId::of::<E>(), target);
706 unsafe {
707 eOwnedPtr>>.cast::<ErrorImpl<ContextError<D, ManuallyDrop<E>>>>()
708 .into_box()
709 };
710 }
711}
712
713/// # Safety
714///
715/// Requires layout of *e to match ErrorImpl<ContextError<D, Report>>.
716unsafe fn context_chain_downcast<D>(
717 e: RefPtr<'_, ErrorImpl<()>>,
718 target: TypeId,
719) -> Option<NonNull<()>>
720where
721 D: 'static,
722{
723 let unerased: &ErrorImpl> = unsafe { e.cast::<ErrorImpl<ContextError<D, Report>>>().as_ref() };
724 if TypeId::of::<D>() == target {
725 let addr: NonNull<()> = NonNull::from(&unerased._object.msg).cast::<()>();
726 Some(addr)
727 } else {
728 // Recurse down the context chain per the inner error's vtable.
729 let source: &Report = &unerased._object.error;
730 unsafe { (source.vtable().object_downcast)(source.inner.as_ref(), target) }
731 }
732}
733
734/// # Safety
735///
736/// Requires layout of *e to match ErrorImpl<ContextError<D, Report>>.
737unsafe fn context_chain_downcast_mut<D>(
738 e: MutPtr<'_, ErrorImpl<()>>,
739 target: TypeId,
740) -> Option<NonNull<()>>
741where
742 D: 'static,
743{
744 let unerased: &mut ErrorImpl> = unsafe { e.cast::<ErrorImpl<ContextError<D, Report>>>().into_mut() };
745 if TypeId::of::<D>() == target {
746 let addr: NonNull<()> = NonNull::from(&unerased._object.msg).cast::<()>();
747 Some(addr)
748 } else {
749 // Recurse down the context chain per the inner error's vtable.
750 let source: &mut Report = &mut unerased._object.error;
751 unsafe { (source.vtable().object_downcast_mut)(source.inner.as_mut(), target) }
752 }
753}
754
755/// # Safety
756///
757/// Requires layout of *e to match ErrorImpl<ContextError<D, Report>>.
758unsafe fn context_chain_drop_rest<D>(e: OwnedPtr<ErrorImpl<()>>, target: TypeId)
759where
760 D: 'static,
761{
762 // Called after downcasting by value to either the D or one of the causes
763 // and doing a ptr::read to take ownership of that value.
764 if TypeId::of::<D>() == target {
765 let unerased: Box>> = unsafe {
766 eOwnedPtr>>.cast::<ErrorImpl<ContextError<ManuallyDrop<D>, Report>>>()
767 .into_box()
768 };
769 // Drop the entire rest of the data structure rooted in the next Report.
770 drop(unerased);
771 } else {
772 unsafe {
773 let unerased: Box>> = eOwnedPtr>>
774 .cast::<ErrorImpl<ContextError<D, ManuallyDrop<Report>>>>()
775 .into_box();
776 // Read out a ManuallyDrop<Box<ErrorImpl<()>>> from the next error.
777 let inner: OwnedPtr = ptr::read(&unerased.as_ref()._object.error.inner);
778 drop(unerased);
779 // Recursively drop the next error using the same target typeid.
780 (header(inner.as_ref()).vtable.object_drop_rest)(inner, target);
781 }
782 }
783}
784
785#[repr(C)]
786pub(crate) struct ErrorHeader {
787 vtable: &'static ErrorVTable,
788 pub(crate) handler: Option<Box<dyn EyreHandler>>,
789}
790
791// repr C to ensure that E remains in the final position.
792#[repr(C)]
793pub(crate) struct ErrorImpl<E = ()> {
794 header: ErrorHeader,
795 // NOTE: Don't use directly. Use only through vtable. Erased type may have
796 // different alignment.
797 _object: E,
798}
799
800// repr C to ensure that ContextError<D, E> has the same layout as
801// ContextError<ManuallyDrop<D>, E> and ContextError<D, ManuallyDrop<E>>.
802#[repr(C)]
803pub(crate) struct ContextError<D, E> {
804 pub(crate) msg: D,
805 pub(crate) error: E,
806}
807
808impl<E> ErrorImpl<E> {
809 /// Returns a type erased Error
810 fn erase(&self) -> RefPtr<'_, ErrorImpl<()>> {
811 // Erase the concrete type of E but preserve the vtable in self.vtable
812 // for manipulating the resulting thin pointer. This is analogous to an
813 // unsize coersion.
814 RefPtr::new(self).cast()
815 }
816}
817
818// Reads the header out of `p`. This is the same as `p.as_ref().header`, but
819// avoids converting `p` into a reference of a shrunk provenance with a type different than the
820// allocation.
821fn header(p: RefPtr<'_, ErrorImpl<()>>) -> &'_ ErrorHeader {
822 // Safety: `ErrorHeader` is the first field of repr(C) `ErrorImpl`
823 unsafe { p.cast().as_ref() }
824}
825
826fn header_mut(p: MutPtr<'_, ErrorImpl<()>>) -> &mut ErrorHeader {
827 // Safety: `ErrorHeader` is the first field of repr(C) `ErrorImpl`
828 unsafe { p.cast().into_mut() }
829}
830
831impl ErrorImpl<()> {
832 pub(crate) fn error(this: RefPtr<'_, Self>) -> &(dyn StdError + Send + Sync + 'static) {
833 // Use vtable to attach E's native StdError vtable for the right
834 // original type E.
835 unsafe { (header(this).vtable.object_ref)(this) }
836 }
837
838 pub(crate) fn error_mut(this: MutPtr<'_, Self>) -> &mut (dyn StdError + Send + Sync + 'static) {
839 // Use vtable to attach E's native StdError vtable for the right
840 // original type E.
841 unsafe { (header_mut(this).vtable.object_mut)(this) }
842 }
843
844 pub(crate) fn chain(this: RefPtr<'_, Self>) -> Chain<'_> {
845 Chain::new(Self::error(this))
846 }
847
848 pub(crate) fn header(this: RefPtr<'_, ErrorImpl>) -> &ErrorHeader {
849 header(this)
850 }
851}
852
853impl<E> StdError for ErrorImpl<E>
854where
855 E: StdError,
856{
857 fn source(&self) -> Option<&(dyn StdError + 'static)> {
858 ErrorImpl::<()>::error(self.erase()).source()
859 }
860}
861
862impl<E> Debug for ErrorImpl<E>
863where
864 E: Debug,
865{
866 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
867 ErrorImpl::debug(self.erase(), f:formatter)
868 }
869}
870
871impl<E> Display for ErrorImpl<E>
872where
873 E: Display,
874{
875 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
876 Display::fmt(self:ErrorImpl::error(self.erase()), f:formatter)
877 }
878}
879
880impl From<Report> for Box<dyn StdError + Send + Sync + 'static> {
881 fn from(error: Report) -> Self {
882 let outer: ManuallyDrop = ManuallyDrop::new(error);
883 unsafe {
884 // Read Box<ErrorImpl<()>> from error. Can't move it out because
885 // Report has a Drop impl which we want to not run.
886 // Use vtable to attach ErrorImpl<E>'s native StdError vtable for
887 // the right original type E.
888 (header(outer.inner.as_ref()).vtable.object_boxed)(outer.inner)
889 }
890 }
891}
892
893impl From<Report> for Box<dyn StdError + 'static> {
894 fn from(error: Report) -> Self {
895 Box::<dyn StdError + Send + Sync>::from(error)
896 }
897}
898
899impl AsRef<dyn StdError + Send + Sync> for Report {
900 fn as_ref(&self) -> &(dyn StdError + Send + Sync + 'static) {
901 &**self
902 }
903}
904
905impl AsRef<dyn StdError> for Report {
906 fn as_ref(&self) -> &(dyn StdError + 'static) {
907 &**self
908 }
909}
910
911#[cfg(feature = "pyo3")]
912mod pyo3_compat;
913

Provided by KDAB

Privacy Policy
Learn Rust with the experts
Find out more