Port the fix for miri failure from anyhow

This commit is contained in:
Nathan Whitaker 2022-08-19 18:02:45 -07:00
parent ba4ba47e4d
commit 460de635e0
5 changed files with 354 additions and 153 deletions

View File

@ -1,4 +1,4 @@
use super::error::ContextError;
use super::error::{ContextError, ErrorImpl};
use super::{Report, WrapErr};
use core::fmt::{self, Debug, Display, Write};
@ -116,7 +116,7 @@ where
D: Display,
{
fn source(&self) -> Option<&(dyn StdError + 'static)> {
Some(self.error.inner.error())
unsafe { Some(ErrorImpl::error(self.error.inner.by_ref())) }
}
}
@ -159,23 +159,23 @@ where
D: Display,
{
fn code<'a>(&'a self) -> Option<Box<dyn Display + 'a>> {
self.error.inner.diagnostic().code()
unsafe { ErrorImpl::diagnostic(self.error.inner.by_ref()).code() }
}
fn severity(&self) -> Option<crate::Severity> {
self.error.inner.diagnostic().severity()
unsafe { ErrorImpl::diagnostic(self.error.inner.by_ref()).severity() }
}
fn help<'a>(&'a self) -> Option<Box<dyn Display + 'a>> {
self.error.inner.diagnostic().help()
unsafe { ErrorImpl::diagnostic(self.error.inner.by_ref()).help() }
}
fn url<'a>(&'a self) -> Option<Box<dyn Display + 'a>> {
self.error.inner.diagnostic().url()
unsafe { ErrorImpl::diagnostic(self.error.inner.by_ref()).url() }
}
fn labels<'a>(&'a self) -> Option<Box<dyn Iterator<Item = LabeledSpan> + 'a>> {
self.error.inner.diagnostic().labels()
unsafe { ErrorImpl::diagnostic(self.error.inner.by_ref()).labels() }
}
fn source_code(&self) -> Option<&dyn crate::SourceCode> {

View File

@ -1,9 +1,10 @@
use core::any::TypeId;
use core::fmt::{self, Debug, Display};
use core::mem::{self, ManuallyDrop};
use core::mem::ManuallyDrop;
use core::ptr::{self, NonNull};
use std::error::Error as StdError;
use super::ptr::{Mut, Own, Ref};
use super::Report;
use super::ReportHandler;
use crate::chain::Chain;
@ -80,7 +81,6 @@ impl Report {
let vtable = &ErrorVTable {
object_drop: object_drop::<E>,
object_ref: object_ref::<E>,
object_mut: object_mut::<E>,
object_ref_stderr: object_ref_stderr::<E>,
object_boxed: object_boxed::<E>,
object_boxed_stderr: object_boxed_stderr::<E>,
@ -104,7 +104,6 @@ impl Report {
let vtable = &ErrorVTable {
object_drop: object_drop::<MessageError<M>>,
object_ref: object_ref::<MessageError<M>>,
object_mut: object_mut::<MessageError<M>>,
object_ref_stderr: object_ref_stderr::<MessageError<M>>,
object_boxed: object_boxed::<MessageError<M>>,
object_boxed_stderr: object_boxed_stderr::<MessageError<M>>,
@ -130,7 +129,6 @@ impl Report {
let vtable = &ErrorVTable {
object_drop: object_drop::<ContextError<D, E>>,
object_ref: object_ref::<ContextError<D, E>>,
object_mut: object_mut::<ContextError<D, E>>,
object_ref_stderr: object_ref_stderr::<ContextError<D, E>>,
object_boxed: object_boxed::<ContextError<D, E>>,
object_boxed_stderr: object_boxed_stderr::<ContextError<D, E>>,
@ -153,7 +151,6 @@ impl Report {
let vtable = &ErrorVTable {
object_drop: object_drop::<BoxedError>,
object_ref: object_ref::<BoxedError>,
object_mut: object_mut::<BoxedError>,
object_ref_stderr: object_ref_stderr::<BoxedError>,
object_boxed: object_boxed::<BoxedError>,
object_boxed_stderr: object_boxed_stderr::<BoxedError>,
@ -190,8 +187,7 @@ impl Report {
// result is a thin pointer. The necessary behavior for manipulating the
// underlying ErrorImpl<E> is preserved in the vtable provided by the
// caller rather than a builtin fat pointer vtable.
let erased = mem::transmute::<Box<ErrorImpl<E>>, Box<ErrorImpl<()>>>(inner);
let inner = ManuallyDrop::new(erased);
let inner = Own::new(inner).cast::<ErasedErrorImpl>();
Report { inner }
}
@ -204,17 +200,16 @@ impl Report {
/// The primary reason to use `error.wrap_err(...)` instead of
/// `result.wrap_err(...)` via the `WrapErr` trait would be if the
/// message needs to depend on some data held by the underlying error:
pub fn wrap_err<D>(mut self, msg: D) -> Self
pub fn wrap_err<D>(self, msg: D) -> Self
where
D: Display + Send + Sync + 'static,
{
let handler = self.inner.handler.take();
let handler = unsafe { self.inner.by_mut().deref_mut().handler.take() };
let error: ContextError<D, Report> = ContextError { msg, error: self };
let vtable = &ErrorVTable {
object_drop: object_drop::<ContextError<D, Report>>,
object_ref: object_ref::<ContextError<D, Report>>,
object_mut: object_mut::<ContextError<D, Report>>,
object_ref_stderr: object_ref_stderr::<ContextError<D, Report>>,
object_boxed: object_boxed::<ContextError<D, Report>>,
object_boxed_stderr: object_boxed_stderr::<ContextError<D, Report>>,
@ -256,7 +251,7 @@ impl Report {
/// }
/// ```
pub fn chain(&self) -> Chain<'_> {
self.inner.chain()
unsafe { ErrorImpl::chain(self.inner.by_ref()) }
}
/// The lowest level cause of this error &mdash; this error's cause's
@ -265,12 +260,7 @@ impl Report {
/// The root cause is the last error in the iterator produced by
/// [`chain()`](Report::chain).
pub fn root_cause(&self) -> &(dyn StdError + 'static) {
let mut chain = self.chain();
let mut root_cause = chain.next().unwrap();
for cause in chain {
root_cause = cause;
}
root_cause
self.chain().last().unwrap()
}
/// Returns true if `E` is the type held by this error object.
@ -294,11 +284,12 @@ impl Report {
E: Display + Debug + Send + Sync + 'static,
{
let target = TypeId::of::<E>();
let inner = self.inner.by_mut();
unsafe {
// Use vtable to find NonNull<()> which points to a value of type E
// somewhere inside the data structure.
let addr = match (self.inner.vtable.object_downcast)(&self.inner, target) {
Some(addr) => addr,
let addr = match (vtable(inner.ptr).object_downcast)(inner.by_ref(), target) {
Some(addr) => addr.by_mut().extend(),
None => return Err(self),
};
@ -307,15 +298,10 @@ impl Report {
let outer = ManuallyDrop::new(self);
// Read E from where the vtable found it.
let error = ptr::read(addr.cast::<E>().as_ptr());
// Read Box<ErrorImpl<()>> from self. Can't move it out because
// Report has a Drop impl which we want to not run.
let inner = ptr::read(&outer.inner);
let erased = ManuallyDrop::into_inner(inner);
let error = addr.cast::<E>().read();
// Drop rest of the data structure outside of E.
(erased.vtable.object_drop_rest)(erased, target);
(vtable(outer.inner.ptr).object_drop_rest)(outer.inner, target);
Ok(error)
}
@ -365,8 +351,8 @@ impl Report {
unsafe {
// Use vtable to find NonNull<()> which points to a value of type E
// somewhere inside the data structure.
let addr = (self.inner.vtable.object_downcast)(&self.inner, target)?;
Some(&*addr.cast::<E>().as_ptr())
let addr = (vtable(self.inner.ptr).object_downcast)(self.inner.by_ref(), target)?;
Some(addr.cast::<E>().deref())
}
}
@ -379,19 +365,36 @@ impl Report {
unsafe {
// Use vtable to find NonNull<()> which points to a value of type E
// somewhere inside the data structure.
let addr = (self.inner.vtable.object_downcast)(&self.inner, target)?;
Some(&mut *addr.cast::<E>().as_ptr())
let addr =
(vtable(self.inner.ptr).object_downcast)(self.inner.by_ref(), target)?.by_mut();
Some(addr.cast::<E>().deref_mut())
}
}
/// Get a reference to the Handler for this Report.
pub fn handler(&self) -> &dyn ReportHandler {
self.inner.handler.as_ref().unwrap().as_ref()
unsafe {
self.inner
.by_ref()
.deref()
.handler
.as_ref()
.unwrap()
.as_ref()
}
}
/// Get a mutable reference to the Handler for this Report.
pub fn handler_mut(&mut self) -> &mut dyn ReportHandler {
self.inner.handler.as_mut().unwrap().as_mut()
unsafe {
self.inner
.by_mut()
.deref_mut()
.handler
.as_mut()
.unwrap()
.as_mut()
}
}
/// Provide source code for this error
@ -418,154 +421,162 @@ impl Deref for Report {
type Target = dyn Diagnostic + Send + Sync + 'static;
fn deref(&self) -> &Self::Target {
self.inner.diagnostic()
unsafe { ErrorImpl::diagnostic(self.inner.by_ref()) }
}
}
impl DerefMut for Report {
fn deref_mut(&mut self) -> &mut Self::Target {
self.inner.diagnostic_mut()
unsafe { ErrorImpl::diagnostic_mut(self.inner.by_mut()) }
}
}
impl Display for Report {
fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
self.inner.display(formatter)
unsafe { ErrorImpl::display(self.inner.by_ref(), formatter) }
}
}
impl Debug for Report {
fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
self.inner.debug(formatter)
unsafe { ErrorImpl::debug(self.inner.by_ref(), formatter) }
}
}
impl Drop for Report {
fn drop(&mut self) {
unsafe {
// Read Box<ErrorImpl<()>> from self.
let inner = ptr::read(&self.inner);
let erased = ManuallyDrop::into_inner(inner);
// Invoke the vtable's drop behavior.
(erased.vtable.object_drop)(erased);
(vtable(self.inner.ptr).object_drop)(self.inner);
}
}
}
type ErasedErrorImpl = ErrorImpl<()>;
struct ErrorVTable {
object_drop: unsafe fn(Box<ErrorImpl<()>>),
object_ref: unsafe fn(&ErrorImpl<()>) -> &(dyn Diagnostic + Send + Sync + 'static),
object_mut: unsafe fn(&mut ErrorImpl<()>) -> &mut (dyn Diagnostic + Send + Sync + 'static),
object_ref_stderr: unsafe fn(&ErrorImpl<()>) -> &(dyn StdError + Send + Sync + 'static),
object_drop: unsafe fn(Own<ErasedErrorImpl>),
object_ref:
unsafe fn(Ref<'_, ErasedErrorImpl>) -> Ref<'_, dyn Diagnostic + Send + Sync + 'static>,
object_ref_stderr:
unsafe fn(Ref<'_, ErasedErrorImpl>) -> Ref<'_, dyn StdError + Send + Sync + 'static>,
#[allow(clippy::type_complexity)]
object_boxed: unsafe fn(Box<ErrorImpl<()>>) -> Box<dyn Diagnostic + Send + Sync + 'static>,
object_boxed: unsafe fn(Own<ErasedErrorImpl>) -> Box<dyn Diagnostic + Send + Sync + 'static>,
#[allow(clippy::type_complexity)]
object_boxed_stderr: unsafe fn(Box<ErrorImpl<()>>) -> Box<dyn StdError + Send + Sync + 'static>,
object_downcast: unsafe fn(&ErrorImpl<()>, TypeId) -> Option<NonNull<()>>,
object_drop_rest: unsafe fn(Box<ErrorImpl<()>>, TypeId),
object_boxed_stderr:
unsafe fn(Own<ErasedErrorImpl>) -> Box<dyn StdError + Send + Sync + 'static>,
object_downcast: unsafe fn(Ref<'_, ErasedErrorImpl>, TypeId) -> Option<Ref<'_, ()>>,
object_drop_rest: unsafe fn(Own<ErasedErrorImpl>, TypeId),
}
// Safety: requires layout of *e to match ErrorImpl<E>.
unsafe fn object_drop<E>(e: Box<ErrorImpl<()>>) {
unsafe fn object_drop<E>(e: Own<ErasedErrorImpl>) {
// Cast back to ErrorImpl<E> so that the allocator receives the correct
// Layout to deallocate the Box's memory.
let unerased = mem::transmute::<Box<ErrorImpl<()>>, Box<ErrorImpl<E>>>(e);
let unerased = e.cast::<ErrorImpl<E>>().boxed();
drop(unerased);
}
// Safety: requires layout of *e to match ErrorImpl<E>.
unsafe fn object_drop_front<E>(e: Box<ErrorImpl<()>>, target: TypeId) {
unsafe fn object_drop_front<E>(e: Own<ErasedErrorImpl>, target: TypeId) {
// Drop the fields of ErrorImpl other than E as well as the Box allocation,
// without dropping E itself. This is used by downcast after doing a
// ptr::read to take ownership of the E.
let _ = target;
let unerased = mem::transmute::<Box<ErrorImpl<()>>, Box<ErrorImpl<ManuallyDrop<E>>>>(e);
let unerased = e.cast::<ErrorImpl<ManuallyDrop<E>>>().boxed();
drop(unerased);
}
// Safety: requires layout of *e to match ErrorImpl<E>.
unsafe fn object_ref<E>(e: &ErrorImpl<()>) -> &(dyn Diagnostic + Send + Sync + 'static)
unsafe fn object_ref<E>(
e: Ref<'_, ErasedErrorImpl>,
) -> Ref<'_, dyn Diagnostic + Send + Sync + 'static>
where
E: Diagnostic + Send + Sync + 'static,
{
// Attach E's native StdError vtable onto a pointer to self._object.
&(*(e as *const ErrorImpl<()> as *const ErrorImpl<E>))._object
let unerased = e.cast::<ErrorImpl<E>>();
Ref::from_raw(NonNull::new_unchecked(
ptr::addr_of!((*unerased.as_ptr())._object) as *mut E,
))
}
// Safety: requires layout of *e to match ErrorImpl<E>.
unsafe fn object_mut<E>(e: &mut ErrorImpl<()>) -> &mut (dyn Diagnostic + Send + Sync + 'static)
where
E: Diagnostic + Send + Sync + 'static,
{
// Attach E's native StdError vtable onto a pointer to self._object.
&mut (*(e as *mut ErrorImpl<()> as *mut ErrorImpl<E>))._object
}
// Safety: requires layout of *e to match ErrorImpl<E>.
unsafe fn object_ref_stderr<E>(e: &ErrorImpl<()>) -> &(dyn StdError + Send + Sync + 'static)
unsafe fn object_ref_stderr<E>(
e: Ref<'_, ErasedErrorImpl>,
) -> Ref<'_, dyn StdError + Send + Sync + 'static>
where
E: StdError + Send + Sync + 'static,
{
// Attach E's native StdError vtable onto a pointer to self._object.
&(*(e as *const ErrorImpl<()> as *const ErrorImpl<E>))._object
let unerased = e.cast::<ErrorImpl<E>>();
Ref::from_raw(NonNull::new_unchecked(
ptr::addr_of!((*unerased.as_ptr())._object) as *mut E,
))
}
// Safety: requires layout of *e to match ErrorImpl<E>.
unsafe fn object_boxed<E>(e: Box<ErrorImpl<()>>) -> Box<dyn Diagnostic + Send + Sync + 'static>
unsafe fn object_boxed<E>(e: Own<ErasedErrorImpl>) -> Box<dyn Diagnostic + Send + Sync + 'static>
where
E: Diagnostic + Send + Sync + 'static,
{
// Attach ErrorImpl<E>'s native StdError vtable. The StdError impl is below.
mem::transmute::<Box<ErrorImpl<()>>, Box<ErrorImpl<E>>>(e)
e.cast::<ErrorImpl<E>>().boxed()
}
// Safety: requires layout of *e to match ErrorImpl<E>.
unsafe fn object_boxed_stderr<E>(e: Box<ErrorImpl<()>>) -> Box<dyn StdError + Send + Sync + 'static>
unsafe fn object_boxed_stderr<E>(
e: Own<ErasedErrorImpl>,
) -> Box<dyn StdError + Send + Sync + 'static>
where
E: StdError + Send + Sync + 'static,
{
// Attach ErrorImpl<E>'s native StdError vtable. The StdError impl is below.
mem::transmute::<Box<ErrorImpl<()>>, Box<ErrorImpl<E>>>(e)
e.cast::<ErrorImpl<E>>().boxed()
}
// Safety: requires layout of *e to match ErrorImpl<E>.
unsafe fn object_downcast<E>(e: &ErrorImpl<()>, target: TypeId) -> Option<NonNull<()>>
unsafe fn object_downcast<E>(e: Ref<'_, ErasedErrorImpl>, target: TypeId) -> Option<Ref<'_, ()>>
where
E: 'static,
{
if TypeId::of::<E>() == target {
// Caller is looking for an E pointer and e is ErrorImpl<E>, take a
// pointer to its E field.
let unerased = e as *const ErrorImpl<()> as *const ErrorImpl<E>;
let addr = &(*unerased)._object as *const E as *mut ();
Some(NonNull::new_unchecked(addr))
let unerased = e.cast::<ErrorImpl<E>>();
Some(
Ref::from_raw(NonNull::new_unchecked(
ptr::addr_of!((*unerased.as_ptr())._object) as *mut E,
))
.cast::<()>(),
)
} else {
None
}
}
// Safety: requires layout of *e to match ErrorImpl<ContextError<D, E>>.
unsafe fn context_downcast<D, E>(e: &ErrorImpl<()>, target: TypeId) -> Option<NonNull<()>>
unsafe fn context_downcast<D, E>(e: Ref<'_, ErasedErrorImpl>, target: TypeId) -> Option<Ref<'_, ()>>
where
D: 'static,
E: 'static,
{
if TypeId::of::<D>() == target {
let unerased = e as *const ErrorImpl<()> as *const ErrorImpl<ContextError<D, E>>;
let addr = &(*unerased)._object.msg as *const D as *mut ();
Some(NonNull::new_unchecked(addr))
let unerased = e.cast::<ErrorImpl<ContextError<D, E>>>().deref();
Some(Ref::new(&unerased._object.msg).cast::<()>())
} else if TypeId::of::<E>() == target {
let unerased = e as *const ErrorImpl<()> as *const ErrorImpl<ContextError<D, E>>;
let addr = &(*unerased)._object.error as *const E as *mut ();
Some(NonNull::new_unchecked(addr))
let unerased = e.cast::<ErrorImpl<ContextError<D, E>>>().deref();
Some(Ref::new(&unerased._object.error).cast::<()>())
} else {
None
}
}
// Safety: requires layout of *e to match ErrorImpl<ContextError<D, E>>.
unsafe fn context_drop_rest<D, E>(e: Box<ErrorImpl<()>>, target: TypeId)
unsafe fn context_drop_rest<D, E>(e: Own<ErasedErrorImpl>, target: TypeId)
where
D: 'static,
E: 'static,
@ -573,61 +584,59 @@ where
// Called after downcasting by value to either the D or the E and doing a
// ptr::read to take ownership of that value.
if TypeId::of::<D>() == target {
let unerased = mem::transmute::<
Box<ErrorImpl<()>>,
Box<ErrorImpl<ContextError<ManuallyDrop<D>, E>>>,
>(e);
let unerased = e
.cast::<ErrorImpl<ContextError<ManuallyDrop<D>, E>>>()
.boxed();
drop(unerased);
} else {
let unerased = mem::transmute::<
Box<ErrorImpl<()>>,
Box<ErrorImpl<ContextError<D, ManuallyDrop<E>>>>,
>(e);
let unerased = e
.cast::<ErrorImpl<ContextError<D, ManuallyDrop<E>>>>()
.boxed();
drop(unerased);
}
}
// Safety: requires layout of *e to match ErrorImpl<ContextError<D, Report>>.
unsafe fn context_chain_downcast<D>(e: &ErrorImpl<()>, target: TypeId) -> Option<NonNull<()>>
unsafe fn context_chain_downcast<D>(
e: Ref<'_, ErasedErrorImpl>,
target: TypeId,
) -> Option<Ref<'_, ()>>
where
D: 'static,
{
let unerased = e as *const ErrorImpl<()> as *const ErrorImpl<ContextError<D, Report>>;
let unerased = e.cast::<ErrorImpl<ContextError<D, Report>>>().deref();
if TypeId::of::<D>() == target {
let addr = &(*unerased)._object.msg as *const D as *mut ();
Some(NonNull::new_unchecked(addr))
Some(Ref::new(&unerased._object.msg).cast::<()>())
} else {
// Recurse down the context chain per the inner error's vtable.
let source = &(*unerased)._object.error;
(source.inner.vtable.object_downcast)(&source.inner, target)
let source = &unerased._object.error;
(vtable(source.inner.ptr).object_downcast)(source.inner.by_ref(), target)
}
}
// Safety: requires layout of *e to match ErrorImpl<ContextError<D, Report>>.
unsafe fn context_chain_drop_rest<D>(e: Box<ErrorImpl<()>>, target: TypeId)
unsafe fn context_chain_drop_rest<D>(e: Own<ErasedErrorImpl>, target: TypeId)
where
D: 'static,
{
// Called after downcasting by value to either the D or one of the causes
// and doing a ptr::read to take ownership of that value.
if TypeId::of::<D>() == target {
let unerased = mem::transmute::<
Box<ErrorImpl<()>>,
Box<ErrorImpl<ContextError<ManuallyDrop<D>, Report>>>,
>(e);
let unerased = e
.cast::<ErrorImpl<ContextError<ManuallyDrop<D>, Report>>>()
.boxed();
// Drop the entire rest of the data structure rooted in the next Report.
drop(unerased);
} else {
let unerased = mem::transmute::<
Box<ErrorImpl<()>>,
Box<ErrorImpl<ContextError<D, ManuallyDrop<Report>>>>,
>(e);
// Read out a ManuallyDrop<Box<ErrorImpl<()>>> from the next error.
let inner = ptr::read(&unerased._object.error.inner);
let unerased = e
.cast::<ErrorImpl<ContextError<D, ManuallyDrop<Report>>>>()
.boxed();
// Read out a ManuallyDrop<Box<ErasedErrorImpl>> from the next error.
let inner = unerased._object.error.inner;
drop(unerased);
let erased = ManuallyDrop::into_inner(inner);
let vtable = vtable(inner.ptr);
// Recursively drop the next error using the same target typeid.
(erased.vtable.object_drop_rest)(erased, target);
(vtable.object_drop_rest)(inner, target);
}
}
@ -649,36 +658,49 @@ pub(crate) struct ContextError<D, E> {
pub(crate) error: E,
}
// Safety: `ErrorVTable` must be the first field of `ErrorImpl`
unsafe fn vtable<E>(p: NonNull<ErrorImpl<E>>) -> &'static ErrorVTable {
(p.as_ptr() as *const &'static ErrorVTable).read()
}
impl<E> ErrorImpl<E> {
fn erase(&self) -> &ErrorImpl<()> {
fn erase(&self) -> Ref<'_, ErasedErrorImpl> {
// Erase the concrete type of E but preserve the vtable in self.vtable
// for manipulating the resulting thin pointer. This is analogous to an
// unsize coercion.
unsafe { &*(self as *const ErrorImpl<E> as *const ErrorImpl<()>) }
Ref::new(self).cast::<ErasedErrorImpl>()
}
}
impl ErrorImpl<()> {
pub(crate) fn error(&self) -> &(dyn StdError + Send + Sync + 'static) {
impl ErasedErrorImpl {
pub(crate) unsafe fn error<'a>(
this: Ref<'a, Self>,
) -> &'a (dyn StdError + Send + Sync + 'static) {
// Use vtable to attach E's native StdError vtable for the right
// original type E.
unsafe { &*(self.vtable.object_ref_stderr)(self) }
(vtable(this.ptr).object_ref_stderr)(this).deref()
}
pub(crate) fn diagnostic(&self) -> &(dyn Diagnostic + Send + Sync + 'static) {
pub(crate) unsafe fn diagnostic<'a>(
this: Ref<'a, Self>,
) -> &'a (dyn Diagnostic + Send + Sync + 'static) {
// Use vtable to attach E's native StdError vtable for the right
// original type E.
unsafe { &*(self.vtable.object_ref)(self) }
(vtable(this.ptr).object_ref)(this).deref()
}
pub(crate) fn diagnostic_mut(&mut self) -> &mut (dyn Diagnostic + Send + Sync + 'static) {
pub(crate) unsafe fn diagnostic_mut<'a>(
this: Mut<'a, Self>,
) -> &'a mut (dyn Diagnostic + Send + Sync + 'static) {
// Use vtable to attach E's native StdError vtable for the right
// original type E.
unsafe { &mut *(self.vtable.object_mut)(self) }
(vtable(this.ptr).object_ref)(this.by_ref())
.by_mut()
.deref_mut()
}
pub(crate) fn chain(&self) -> Chain<'_> {
Chain::new(self.error())
pub(crate) unsafe fn chain<'a>(this: Ref<'a, Self>) -> Chain<'a> {
Chain::new(Self::error(this))
}
}
@ -687,7 +709,7 @@ where
E: StdError,
{
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
self.erase().diagnostic().source()
unsafe { ErrorImpl::diagnostic(self.erase()).source() }
}
}
@ -698,7 +720,7 @@ where
E: Debug,
{
fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
self.erase().debug(formatter)
unsafe { ErrorImpl::debug(self.erase(), formatter) }
}
}
@ -707,7 +729,7 @@ where
E: Display,
{
fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
Display::fmt(&self.erase().diagnostic(), formatter)
unsafe { Display::fmt(ErrorImpl::diagnostic(self.erase()), formatter) }
}
}
@ -715,14 +737,9 @@ impl From<Report> for Box<dyn Diagnostic + Send + Sync + 'static> {
fn from(error: Report) -> Self {
let outer = ManuallyDrop::new(error);
unsafe {
// Read Box<ErrorImpl<()>> from error. Can't move it out because
// Report has a Drop impl which we want to not run.
let inner = ptr::read(&outer.inner);
let erased = ManuallyDrop::into_inner(inner);
// Use vtable to attach ErrorImpl<E>'s native StdError vtable for
// the right original type E.
(erased.vtable.object_boxed)(erased)
(vtable(outer.inner.ptr).object_boxed)(outer.inner)
}
}
}
@ -731,14 +748,9 @@ impl From<Report> for Box<dyn StdError + Send + Sync + 'static> {
fn from(error: Report) -> Self {
let outer = ManuallyDrop::new(error);
unsafe {
// Read Box<ErrorImpl<()>> from error. Can't move it out because
// Report has a Drop impl which we want to not run.
let inner = ptr::read(&outer.inner);
let erased = ManuallyDrop::into_inner(inner);
// Use vtable to attach ErrorImpl<E>'s native StdError vtable for
// the right original type E.
(erased.vtable.object_boxed_stderr)(erased)
(vtable(outer.inner.ptr).object_boxed_stderr)(outer.inner)
}
}
}

View File

@ -1,18 +1,20 @@
use super::error::ErrorImpl;
use super::{error::ErrorImpl, ptr::Ref};
use core::fmt;
impl ErrorImpl<()> {
pub(crate) fn display(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
self.handler
pub(crate) unsafe fn display(this: Ref<'_, Self>, f: &mut fmt::Formatter<'_>) -> fmt::Result {
this.deref()
.handler
.as_ref()
.map(|handler| handler.display(self.error(), f))
.unwrap_or_else(|| core::fmt::Display::fmt(self.diagnostic(), f))
.map(|handler| handler.display(Self::error(this), f))
.unwrap_or_else(|| core::fmt::Display::fmt(Self::diagnostic(this), f))
}
pub(crate) fn debug(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
self.handler
pub(crate) unsafe fn debug(this: Ref<'_, Self>, f: &mut fmt::Formatter<'_>) -> fmt::Result {
this.deref()
.handler
.as_ref()
.map(|handler| handler.debug(self.diagnostic(), f))
.unwrap_or_else(|| core::fmt::Debug::fmt(self.diagnostic(), f))
.map(|handler| handler.debug(Self::diagnostic(this), f))
.unwrap_or_else(|| core::fmt::Debug::fmt(Self::diagnostic(this), f))
}
}

View File

@ -5,7 +5,6 @@
clippy::wrong_self_convention
)]
use core::fmt::Display;
use core::mem::ManuallyDrop;
use std::error::Error as StdError;
@ -34,12 +33,15 @@ use crate::MietteHandler;
use error::ErrorImpl;
use self::ptr::Own;
mod context;
mod error;
mod fmt;
mod into_diagnostic;
mod kind;
mod macros;
mod ptr;
mod wrapper;
/**
@ -50,9 +52,12 @@ Core Diagnostic wrapper type.
You can just replace `use`s of `eyre::Report` with `miette::Report`.
*/
pub struct Report {
inner: ManuallyDrop<Box<ErrorImpl<()>>>,
inner: Own<ErrorImpl<()>>,
}
unsafe impl Sync for Report {}
unsafe impl Send for Report {}
///
pub type ErrorHook =
Box<dyn Fn(&(dyn Diagnostic + 'static)) -> Box<dyn ReportHandler> + Sync + Send + 'static>;

182
src/eyreish/ptr.rs Normal file
View File

@ -0,0 +1,182 @@
use std::{marker::PhantomData, ptr::NonNull};
#[repr(transparent)]
pub(crate) struct Own<T>
where
T: ?Sized,
{
pub(crate) ptr: NonNull<T>,
}
unsafe impl<T> Send for Own<T> where T: ?Sized {}
unsafe impl<T> Sync for Own<T> where T: ?Sized {}
impl<T> Copy for Own<T> where T: ?Sized {}
impl<T> Clone for Own<T>
where
T: ?Sized,
{
fn clone(&self) -> Self {
*self
}
}
impl<T> Own<T>
where
T: ?Sized,
{
pub(crate) fn new(ptr: Box<T>) -> Self {
Own {
ptr: unsafe { NonNull::new_unchecked(Box::into_raw(ptr)) },
}
}
pub(crate) fn cast<U: CastTo>(self) -> Own<U::Target> {
Own {
ptr: self.ptr.cast(),
}
}
pub(crate) unsafe fn boxed(self) -> Box<T> {
Box::from_raw(self.ptr.as_ptr())
}
pub(crate) fn by_ref<'a>(&self) -> Ref<'a, T> {
Ref {
ptr: self.ptr,
lifetime: PhantomData,
}
}
pub(crate) fn by_mut<'a>(self) -> Mut<'a, T> {
Mut {
ptr: self.ptr,
lifetime: PhantomData,
}
}
}
#[repr(transparent)]
pub(crate) struct Ref<'a, T>
where
T: ?Sized,
{
pub(crate) ptr: NonNull<T>,
lifetime: PhantomData<&'a T>,
}
impl<'a, T> Copy for Ref<'a, T> where T: ?Sized {}
impl<'a, T> Clone for Ref<'a, T>
where
T: ?Sized,
{
fn clone(&self) -> Self {
*self
}
}
impl<'a, T> Ref<'a, T>
where
T: ?Sized,
{
pub(crate) fn new(ptr: &'a T) -> Self {
Ref {
ptr: NonNull::from(ptr),
lifetime: PhantomData,
}
}
pub(crate) fn from_raw(ptr: NonNull<T>) -> Self {
Ref {
ptr,
lifetime: PhantomData,
}
}
pub(crate) fn cast<U: CastTo>(self) -> Ref<'a, U::Target> {
Ref {
ptr: self.ptr.cast(),
lifetime: PhantomData,
}
}
pub(crate) fn by_mut(self) -> Mut<'a, T> {
Mut {
ptr: self.ptr,
lifetime: PhantomData,
}
}
pub(crate) fn as_ptr(self) -> *const T {
self.ptr.as_ptr() as *const T
}
pub(crate) unsafe fn deref(self) -> &'a T {
&*self.ptr.as_ptr()
}
}
pub(crate) struct Mut<'a, T>
where
T: ?Sized,
{
pub(crate) ptr: NonNull<T>,
lifetime: PhantomData<&'a mut T>,
}
impl<'a, T> Copy for Mut<'a, T> where T: ?Sized {}
impl<'a, T> Clone for Mut<'a, T>
where
T: ?Sized,
{
fn clone(&self) -> Self {
*self
}
}
impl<'a, T> Mut<'a, T>
where
T: ?Sized,
{
pub(crate) fn cast<U: CastTo>(self) -> Mut<'a, U::Target> {
Mut {
ptr: self.ptr.cast(),
lifetime: PhantomData,
}
}
pub(crate) fn by_ref(self) -> Ref<'a, T> {
Ref {
ptr: self.ptr,
lifetime: PhantomData,
}
}
pub(crate) fn extend<'b>(self) -> Mut<'b, T> {
Mut {
ptr: self.ptr,
lifetime: PhantomData,
}
}
pub(crate) unsafe fn deref_mut(self) -> &'a mut T {
&mut *self.ptr.as_ptr()
}
}
impl<'a, T> Mut<'a, T> {
pub(crate) unsafe fn read(self) -> T {
self.ptr.as_ptr().read()
}
}
pub(crate) trait CastTo {
type Target;
}
impl<T> CastTo for T {
type Target = T;
}