summaryrefslogtreecommitdiff
path: root/core
diff options
context:
space:
mode:
Diffstat (limited to 'core')
-rw-r--r--core/core_isolate.rs22
-rw-r--r--core/errors.rs126
-rw-r--r--core/es_isolate.rs3
-rw-r--r--core/lib.rs1
4 files changed, 114 insertions, 38 deletions
diff --git a/core/core_isolate.rs b/core/core_isolate.rs
index 160e37f1d..f4acbd1ac 100644
--- a/core/core_isolate.rs
+++ b/core/core_isolate.rs
@@ -87,6 +87,17 @@ impl StartupData<'_> {
type JSErrorCreateFn = dyn Fn(JSError) -> ErrBox;
+pub trait RustErrToJsonFn: for<'e> Fn(&'e ErrBox) -> Box<[u8]> {}
+impl<F> RustErrToJsonFn for F where for<'e> F: Fn(&'e ErrBox) -> Box<[u8]> {}
+
+fn rust_err_to_json(e: &ErrBox) -> Box<[u8]> {
+ let value = json!({
+ "kind": "Error",
+ "message": e.to_string()
+ });
+ serde_json::to_vec(&value).unwrap().into_boxed_slice()
+}
+
/// Objects that need to live as long as the isolate
#[derive(Default)]
struct IsolateAllocations {
@@ -123,6 +134,7 @@ pub struct CoreIsolateState {
pub(crate) js_macrotask_cb: Option<v8::Global<v8::Function>>,
pub(crate) pending_promise_exceptions: HashMap<i32, v8::Global<v8::Value>>,
pub(crate) js_error_create_fn: Box<JSErrorCreateFn>,
+ pub rust_err_to_json_fn: &'static dyn RustErrToJsonFn,
pub(crate) shared: SharedQueue,
pending_ops: FuturesUnordered<PendingOpFuture>,
pending_unref_ops: FuturesUnordered<PendingOpFuture>,
@@ -307,6 +319,7 @@ impl CoreIsolate {
js_recv_cb: None,
js_macrotask_cb: None,
js_error_create_fn: Box::new(JSError::create),
+ rust_err_to_json_fn: &rust_err_to_json,
shared: SharedQueue::new(RECOMMENDED_SIZE),
pending_ops: FuturesUnordered::new(),
pending_unref_ops: FuturesUnordered::new(),
@@ -539,8 +552,8 @@ fn serialize_result(
Err(err) => json!({
"promiseId": promise_id ,
"err": {
+ "kind": "Error",
"message": err.to_string(),
- "kind": "Other", // TODO(ry) Figure out how to propagate errors.
}
}),
};
@@ -668,6 +681,13 @@ impl CoreIsolateState {
self.js_error_create_fn = Box::new(f);
}
+ pub fn set_rust_err_to_json_fn(
+ &mut self,
+ f: &'static (impl for<'e> Fn(&'e ErrBox) -> Box<[u8]> + 'static),
+ ) {
+ self.rust_err_to_json_fn = f;
+ }
+
pub fn dispatch_op<'s>(
&mut self,
scope: &mut v8::HandleScope<'s>,
diff --git a/core/errors.rs b/core/errors.rs
index 218d7c619..3dfe5824c 100644
--- a/core/errors.rs
+++ b/core/errors.rs
@@ -3,11 +3,12 @@
use rusty_v8 as v8;
use std::any::Any;
use std::any::TypeId;
+use std::borrow::Cow;
use std::convert::TryFrom;
use std::convert::TryInto;
use std::error::Error;
use std::fmt;
-use std::ops::Deref;
+use std::io;
// The Send and Sync traits are required because deno is multithreaded and we
// need to be able to handle errors across threads.
@@ -15,60 +16,97 @@ pub trait AnyError: Any + Error + Send + Sync + 'static {}
impl<T> AnyError for T where T: Any + Error + Send + Sync + Sized + 'static {}
#[derive(Debug)]
-pub struct ErrBox(Box<dyn AnyError>);
+pub enum ErrBox {
+ Simple {
+ class: &'static str,
+ message: Cow<'static, str>,
+ },
+ Boxed(Box<dyn AnyError>),
+}
-impl dyn AnyError {
- pub fn downcast_ref<T: AnyError>(&self) -> Option<&T> {
- if Any::type_id(self) == TypeId::of::<T>() {
- let target = self as *const Self as *const T;
- let target = unsafe { &*target };
- Some(target)
- } else {
- None
+impl ErrBox {
+ pub fn new(
+ class: &'static str,
+ message: impl Into<Cow<'static, str>>,
+ ) -> Self {
+ Self::Simple {
+ class,
+ message: message.into(),
}
}
-}
-impl ErrBox {
+ pub fn bad_resource(message: impl Into<Cow<'static, str>>) -> Self {
+ Self::new("BadResource", message)
+ }
+
+ pub fn bad_resource_id() -> Self {
+ Self::new("BadResource", "Bad resource ID")
+ }
+
+ pub fn error(message: impl Into<Cow<'static, str>>) -> Self {
+ Self::new("Error", message)
+ }
+
+ pub fn not_supported() -> Self {
+ Self::new("NotSupported", "The operation is supported")
+ }
+
+ pub fn resource_unavailable() -> Self {
+ Self::new(
+ "Busy",
+ "Resource is unavailable because it is in use by a promise",
+ )
+ }
+
+ pub fn type_error(message: impl Into<Cow<'static, str>>) -> Self {
+ Self::new("TypeError", message)
+ }
+
+ pub fn last_os_error() -> Self {
+ Self::from(io::Error::last_os_error())
+ }
+
pub fn downcast<T: AnyError>(self) -> Result<T, Self> {
- if Any::type_id(&*self.0) == TypeId::of::<T>() {
- let target = Box::into_raw(self.0) as *mut T;
- let target = unsafe { Box::from_raw(target) };
- Ok(*target)
- } else {
- Err(self)
+ match self {
+ Self::Boxed(error) if Any::type_id(&*error) == TypeId::of::<T>() => {
+ let error = Box::into_raw(error) as *mut T;
+ let error = unsafe { Box::from_raw(error) };
+ Ok(*error)
+ }
+ other => Err(other),
}
}
-}
-impl AsRef<dyn AnyError> for ErrBox {
- fn as_ref(&self) -> &dyn AnyError {
- self.0.as_ref()
+ pub fn downcast_ref<T: AnyError>(&self) -> Option<&T> {
+ match self {
+ Self::Boxed(error) if Any::type_id(&**error) == TypeId::of::<T>() => {
+ let error = &**error as *const dyn AnyError as *const T;
+ let error = unsafe { &*error };
+ Some(error)
+ }
+ _ => None,
+ }
}
}
-impl Deref for ErrBox {
- type Target = Box<dyn AnyError>;
- fn deref(&self) -> &Self::Target {
- &self.0
+impl fmt::Display for ErrBox {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ match self {
+ Self::Simple { message, .. } => f.write_str(message),
+ Self::Boxed(error) => error.fmt(f),
+ }
}
}
impl<T: AnyError> From<T> for ErrBox {
fn from(error: T) -> Self {
- Self(Box::new(error))
+ Self::Boxed(Box::new(error))
}
}
impl From<Box<dyn AnyError>> for ErrBox {
fn from(boxed: Box<dyn AnyError>) -> Self {
- Self(boxed)
- }
-}
-
-impl fmt::Display for ErrBox {
- fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- self.0.fmt(f)
+ Self::Boxed(boxed)
}
}
@@ -116,7 +154,7 @@ fn get_property<'a>(
impl JSError {
pub(crate) fn create(js_error: Self) -> ErrBox {
- ErrBox::from(js_error)
+ js_error.into()
}
pub fn from_v8_exception(
@@ -362,6 +400,7 @@ pub(crate) fn attach_handle_to_error(
err: ErrBox,
handle: v8::Local<v8::Value>,
) -> ErrBox {
+ // TODO(bartomieju): this is a special case...
ErrWithV8Handle::new(scope, err, handle).into()
}
@@ -406,3 +445,20 @@ impl fmt::Debug for ErrWithV8Handle {
self.err.fmt(f)
}
}
+
+#[cfg(tests)]
+mod tests {
+ #[test]
+ fn test_bad_resource() {
+ let err = ErrBox::bad_resource("Resource has been closed".to_string());
+ assert_eq!(err.1, "BadResource");
+ assert_eq!(err.to_string(), "Resource has been closed");
+ }
+
+ #[test]
+ fn test_bad_resource_id() {
+ let err = ErrBox::bad_resource_id();
+ assert_eq!(err.1, "BadResource");
+ assert_eq!(err.to_string(), "Bad resource ID");
+ }
+}
diff --git a/core/es_isolate.rs b/core/es_isolate.rs
index 3ede1a5e4..a829a3a3b 100644
--- a/core/es_isolate.rs
+++ b/core/es_isolate.rs
@@ -784,8 +784,7 @@ pub mod tests {
_maybe_referrer: Option<ModuleSpecifier>,
_is_dyn_import: bool,
) -> Pin<Box<ModuleSourceFuture>> {
- async { Err(ErrBox::from(io::Error::from(io::ErrorKind::NotFound))) }
- .boxed()
+ async { Err(io::Error::from(io::ErrorKind::NotFound).into()) }.boxed()
}
}
diff --git a/core/lib.rs b/core/lib.rs
index 940e0c026..78a2fc244 100644
--- a/core/lib.rs
+++ b/core/lib.rs
@@ -28,6 +28,7 @@ pub use crate::core_isolate::js_check;
pub use crate::core_isolate::CoreIsolate;
pub use crate::core_isolate::CoreIsolateState;
pub use crate::core_isolate::HeapLimits;
+pub use crate::core_isolate::RustErrToJsonFn;
pub use crate::core_isolate::Script;
pub use crate::core_isolate::Snapshot;
pub use crate::core_isolate::StartupData;