Skip to content

Commit b7ee9a4

Browse files
authored
Add a few From, Deref, and AsRef impls for wasmtime_internal_error::Error (#12201)
This matches `anyhow::Error` and makes migrating existing code easier. Found while migrating existing code.
1 parent 0c59b5e commit b7ee9a4

File tree

4 files changed

+110
-73
lines changed

4 files changed

+110
-73
lines changed

crates/error/src/context.rs

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
use crate::{
2-
Error, ErrorExt, Result,
2+
Error, ErrorExt, OutOfMemory, Result,
3+
boxed::try_new_uninit_box,
34
error::{OomOrDynError, OomOrDynErrorMut, OomOrDynErrorRef},
45
};
6+
use alloc::boxed::Box;
57
use core::any::TypeId;
68
use core::fmt;
79
use core::ptr::NonNull;
@@ -252,6 +254,17 @@ unsafe impl<C> ErrorExt for ContextError<C>
252254
where
253255
C: fmt::Display + Send + Sync + 'static,
254256
{
257+
fn ext_as_dyn_core_error(&self) -> &(dyn core::error::Error + Send + Sync + 'static) {
258+
self
259+
}
260+
261+
fn ext_into_boxed_dyn_core_error(
262+
self,
263+
) -> Result<Box<dyn core::error::Error + Send + Sync + 'static>, OutOfMemory> {
264+
let boxed = try_new_uninit_box()?;
265+
Ok(Box::write(boxed, self) as _)
266+
}
267+
255268
fn ext_source(&self) -> Option<OomOrDynErrorRef<'_>> {
256269
let error = self.error.as_ref()?;
257270
Some(error.inner.unpack())

crates/error/src/error.rs

Lines changed: 84 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,16 @@ use std::backtrace::{Backtrace, BacktraceStatus};
2222
/// not lie about whether they are or are not an instance of the given type id's
2323
/// associated type (or a newtype wrapper around that type). Violations will
2424
/// lead to unsafety.
25-
pub(crate) unsafe trait ErrorExt: core::error::Error + Send + Sync + 'static {
25+
pub(crate) unsafe trait ErrorExt: Send + Sync + 'static {
26+
/// Get this error as a shared reference to a `dyn core::error::Error` trait
27+
/// object.
28+
fn ext_as_dyn_core_error(&self) -> &(dyn core::error::Error + Send + Sync + 'static);
29+
30+
/// Get this error as a boxed `dyn core::error::Error` trait object.
31+
fn ext_into_boxed_dyn_core_error(
32+
self,
33+
) -> Result<Box<dyn core::error::Error + Send + Sync + 'static>, OutOfMemory>;
34+
2635
/// Get a shared borrow of the next error in the chain.
2736
fn ext_source(&self) -> Option<OomOrDynErrorRef<'_>>;
2837

@@ -488,6 +497,20 @@ impl From<Error> for Box<dyn core::error::Error + Send + Sync + 'static> {
488497
}
489498
}
490499

500+
impl From<Error> for Box<dyn core::error::Error + Send + 'static> {
501+
#[inline]
502+
fn from(error: Error) -> Self {
503+
error.into_boxed_dyn_error()
504+
}
505+
}
506+
507+
impl From<Error> for Box<dyn core::error::Error + 'static> {
508+
#[inline]
509+
fn from(error: Error) -> Self {
510+
error.into_boxed_dyn_error()
511+
}
512+
}
513+
491514
/// Convert a [`Error`] into an [`anyhow::Error`].
492515
///
493516
/// # Example
@@ -517,6 +540,28 @@ impl From<Error> for anyhow::Error {
517540
}
518541
}
519542

543+
impl core::ops::Deref for Error {
544+
type Target = dyn core::error::Error + Send + Sync + 'static;
545+
546+
fn deref(&self) -> &Self::Target {
547+
self.as_ref()
548+
}
549+
}
550+
551+
impl AsRef<dyn core::error::Error> for Error {
552+
#[inline]
553+
fn as_ref(&self) -> &(dyn core::error::Error + 'static) {
554+
self.inner.unpack().as_dyn_core_error()
555+
}
556+
}
557+
558+
impl AsRef<dyn core::error::Error + Send + Sync> for Error {
559+
#[inline]
560+
fn as_ref(&self) -> &(dyn core::error::Error + Send + Sync + 'static) {
561+
self.inner.unpack().as_dyn_core_error()
562+
}
563+
}
564+
520565
impl Error {
521566
/// Construct a new `Error` from a type that implements
522567
/// `core::error::Error`.
@@ -1107,38 +1152,22 @@ impl Error {
11071152
#[repr(transparent)]
11081153
struct ForeignError<E>(E);
11091154

1110-
impl<E> fmt::Debug for ForeignError<E>
1111-
where
1112-
E: core::error::Error + Send + Sync + 'static,
1113-
{
1114-
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1115-
fmt::Debug::fmt(&self.0, f)
1116-
}
1117-
}
1118-
1119-
impl<E> fmt::Display for ForeignError<E>
1155+
// Safety: `ext_is` is correct, `ext_move` always writes to `dest`.
1156+
unsafe impl<E> ErrorExt for ForeignError<E>
11201157
where
11211158
E: core::error::Error + Send + Sync + 'static,
11221159
{
1123-
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1124-
fmt::Display::fmt(&self.0, f)
1160+
fn ext_as_dyn_core_error(&self) -> &(dyn core::error::Error + Send + Sync + 'static) {
1161+
&self.0
11251162
}
1126-
}
11271163

1128-
impl<E> core::error::Error for ForeignError<E>
1129-
where
1130-
E: core::error::Error + Send + Sync + 'static,
1131-
{
1132-
fn source(&self) -> Option<&(dyn core::error::Error + 'static)> {
1133-
self.0.source()
1164+
fn ext_into_boxed_dyn_core_error(
1165+
self,
1166+
) -> Result<Box<dyn core::error::Error + Send + Sync + 'static>, OutOfMemory> {
1167+
let boxed = try_new_uninit_box()?;
1168+
Ok(Box::write(boxed, self.0) as _)
11341169
}
1135-
}
11361170

1137-
// Safety: `ext_is` is correct, `ext_move` always writes to `dest`.
1138-
unsafe impl<E> ErrorExt for ForeignError<E>
1139-
where
1140-
E: core::error::Error + Send + Sync + 'static,
1141-
{
11421171
fn ext_source(&self) -> Option<OomOrDynErrorRef<'_>> {
11431172
None
11441173
}
@@ -1206,6 +1235,17 @@ unsafe impl<M> ErrorExt for MessageError<M>
12061235
where
12071236
M: fmt::Debug + fmt::Display + Send + Sync + 'static,
12081237
{
1238+
fn ext_as_dyn_core_error(&self) -> &(dyn core::error::Error + Send + Sync + 'static) {
1239+
self
1240+
}
1241+
1242+
fn ext_into_boxed_dyn_core_error(
1243+
self,
1244+
) -> Result<Box<dyn core::error::Error + Send + Sync + 'static>, OutOfMemory> {
1245+
let boxed = try_new_uninit_box()?;
1246+
Ok(Box::write(boxed, self) as _)
1247+
}
1248+
12091249
fn ext_source(&self) -> Option<OomOrDynErrorRef<'_>> {
12101250
None
12111251
}
@@ -1247,27 +1287,19 @@ where
12471287
#[repr(transparent)]
12481288
struct BoxedError(Box<dyn core::error::Error + Send + Sync + 'static>);
12491289

1250-
impl fmt::Debug for BoxedError {
1251-
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1252-
fmt::Debug::fmt(&self.0, f)
1290+
// Safety: `ext_is` is implemented correctly and `ext_move` always
1291+
// writes to its pointer.
1292+
unsafe impl ErrorExt for BoxedError {
1293+
fn ext_as_dyn_core_error(&self) -> &(dyn core::error::Error + Send + Sync + 'static) {
1294+
&*self.0
12531295
}
1254-
}
12551296

1256-
impl fmt::Display for BoxedError {
1257-
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1258-
fmt::Display::fmt(&self.0, f)
1297+
fn ext_into_boxed_dyn_core_error(
1298+
self,
1299+
) -> Result<Box<dyn core::error::Error + Send + Sync + 'static>, OutOfMemory> {
1300+
Ok(self.0)
12591301
}
1260-
}
12611302

1262-
impl core::error::Error for BoxedError {
1263-
fn source(&self) -> Option<&(dyn core::error::Error + 'static)> {
1264-
self.0.source()
1265-
}
1266-
}
1267-
1268-
// Safety: `ext_is` is implemented correctly and `ext_move` always
1269-
// writes to its pointer.
1270-
unsafe impl ErrorExt for BoxedError {
12711303
fn ext_source(&self) -> Option<OomOrDynErrorRef<'_>> {
12721304
None
12731305
}
@@ -1311,31 +1343,20 @@ unsafe impl ErrorExt for BoxedError {
13111343
#[cfg(feature = "anyhow")]
13121344
struct AnyhowError(anyhow::Error);
13131345

1346+
// Safety: `ext_is` is implemented correctly and `ext_move` always
1347+
// writes to its pointer.
13141348
#[cfg(feature = "anyhow")]
1315-
impl fmt::Debug for AnyhowError {
1316-
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1317-
fmt::Debug::fmt(&self.0, f)
1318-
}
1319-
}
1320-
1321-
#[cfg(feature = "anyhow")]
1322-
impl fmt::Display for AnyhowError {
1323-
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1324-
fmt::Display::fmt(&self.0, f)
1349+
unsafe impl ErrorExt for AnyhowError {
1350+
fn ext_as_dyn_core_error(&self) -> &(dyn core::error::Error + Send + Sync + 'static) {
1351+
self.0.as_ref()
13251352
}
1326-
}
13271353

1328-
#[cfg(feature = "anyhow")]
1329-
impl core::error::Error for AnyhowError {
1330-
fn source(&self) -> Option<&(dyn core::error::Error + 'static)> {
1331-
self.0.source()
1354+
fn ext_into_boxed_dyn_core_error(
1355+
self,
1356+
) -> Result<Box<dyn core::error::Error + Send + Sync + 'static>, OutOfMemory> {
1357+
Ok(self.0.into_boxed_dyn_error())
13321358
}
1333-
}
13341359

1335-
// Safety: `ext_is` is implemented correctly and `ext_move` always
1336-
// writes to its pointer.
1337-
#[cfg(feature = "anyhow")]
1338-
unsafe impl ErrorExt for AnyhowError {
13391360
fn ext_source(&self) -> Option<OomOrDynErrorRef<'_>> {
13401361
None
13411362
}

crates/error/src/vtable.rs

Lines changed: 4 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
use super::{ConcreteError, DynError, ErrorExt, OomOrDynErrorMut, OomOrDynErrorRef, OutOfMemory};
2-
use crate::boxed::try_new_uninit_box;
32
use crate::ptr::{MutPtr, OwnedPtr, SharedPtr};
43
use alloc::boxed::Box;
54
use core::{any::TypeId, fmt, ptr::NonNull};
@@ -73,7 +72,7 @@ where
7372
let error = error.cast::<ConcreteError<E>>();
7473
// Safety: implied by all vtable functions' safety contract.
7574
let error = unsafe { error.as_ref() };
76-
fmt::Display::fmt(&error.error, f)
75+
fmt::Display::fmt(error.error.ext_as_dyn_core_error(), f)
7776
}
7877

7978
unsafe fn debug<E>(error: SharedPtr<'_, DynError>, f: &mut fmt::Formatter<'_>) -> fmt::Result
@@ -83,7 +82,7 @@ where
8382
let error = error.cast::<ConcreteError<E>>();
8483
// Safety: implied by all vtable functions' safety contract.
8584
let error = unsafe { error.as_ref() };
86-
fmt::Debug::fmt(&error.error, f)
85+
fmt::Debug::fmt(error.error.ext_as_dyn_core_error(), f)
8786
}
8887

8988
unsafe fn source<E>(error: SharedPtr<'_, DynError>) -> Option<OomOrDynErrorRef<'_>>
@@ -125,7 +124,7 @@ where
125124
let error = error.cast::<ConcreteError<E>>();
126125
// Safety: implied by all vtable functions' safety contract.
127126
let error = unsafe { error.as_ref() };
128-
&error.error as _
127+
error.error.ext_as_dyn_core_error()
129128
}
130129

131130
unsafe fn into_boxed_dyn_core_error<E>(
@@ -137,11 +136,7 @@ where
137136
let error = error.cast::<ConcreteError<E>>();
138137
// Safety: implied by all vtable functions' safety contract.
139138
let error = unsafe { error.into_box() };
140-
141-
let boxed = try_new_uninit_box()?;
142-
let error = Box::write(boxed, error.error);
143-
144-
Ok(error as _)
139+
error.error.ext_into_boxed_dyn_core_error()
145140
}
146141

147142
unsafe fn drop_and_deallocate<E>(error: OwnedPtr<DynError>)

crates/error/tests/tests.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -200,6 +200,14 @@ fn is() {
200200
assert!(!e.is::<&str>());
201201
}
202202

203+
#[test]
204+
fn is_for_root_cause_with_initial_error_source() {
205+
let error = std::fmt::Error;
206+
let error = ChainError::new("whoops", Some(Box::new(error)));
207+
let error = Error::new(error);
208+
assert!(error.root_cause().is::<std::fmt::Error>());
209+
}
210+
203211
#[test]
204212
#[cfg(feature = "backtrace")]
205213
fn backtrace() {

0 commit comments

Comments
 (0)