diff --git a/crates/neon-runtime/src/napi/error.rs b/crates/neon-runtime/src/napi/error.rs index 0405983de..bcfd8323a 100644 --- a/crates/neon-runtime/src/napi/error.rs +++ b/crates/neon-runtime/src/napi/error.rs @@ -1,11 +1,23 @@ -use raw::Local; +use raw::{Env, Local}; -pub unsafe extern "C" fn throw(_val: Local) { unimplemented!() } +use nodejs_sys as napi; -pub unsafe extern "C" fn new_error(_out: &mut Local, _msg: Local) { unimplemented!() } +pub unsafe extern "C" fn throw(env: Env, error: Local) { + let status = napi::napi_throw(env, error); + assert_eq!(status, napi::napi_status::napi_ok); +} -pub unsafe extern "C" fn new_type_error(_out: &mut Local, _msg: Local) { unimplemented!() } +pub unsafe extern "C" fn new_error(out: &mut Local, env: Env, code: Local, msg: Local) { + let status = napi::napi_create_error(env, code, msg, out); + assert_eq!(status, napi::napi_status::napi_ok); +} -pub unsafe extern "C" fn new_range_error(_out: &mut Local, _msg: Local) { unimplemented!() } +pub unsafe extern "C" fn new_type_error(out: &mut Local, env: Env, code: Local, msg: Local) { + let status = napi::napi_create_type_error(env, code, msg, out); + assert_eq!(status, napi::napi_status::napi_ok); +} -pub unsafe extern "C" fn throw_error_from_utf8(_msg: *const u8, _len: i32) { unimplemented!() } +pub unsafe extern "C" fn new_range_error(out: &mut Local, env: Env, code: Local, msg: Local) { + let status = napi::napi_create_range_error(env, code, msg, out); + assert_eq!(status, napi::napi_status::napi_ok); +} diff --git a/src/context/mod.rs b/src/context/mod.rs index 2febcdaf8..38224cdf9 100644 --- a/src/context/mod.rs +++ b/src/context/mod.rs @@ -298,7 +298,11 @@ pub trait Context<'a>: ContextInternal<'a> { /// Throws a JS value. fn throw<'b, T: Value, U>(&mut self, v: Handle<'b, T>) -> NeonResult { unsafe { - neon_runtime::error::throw(v.to_raw()); + #[cfg(feature = "napi-runtime")] + neon_runtime::error::throw(self.env().to_raw(),v.to_raw()); + + #[cfg(feature = "legacy-runtime")] + neon_runtime::error::throw(v.to_raw()) } Err(Throw) } diff --git a/src/object/class/internal.rs b/src/object/class/internal.rs index 6c564cd90..7d8e6bcd8 100644 --- a/src/object/class/internal.rs +++ b/src/object/class/internal.rs @@ -1,15 +1,15 @@ +use super::{Callback, Class, ClassInternal}; +use context::internal::ContextInternal; +use context::{CallContext, CallbackInfo, Context}; +use handle::{Handle, Managed}; +use neon_runtime; +use neon_runtime::raw; +use result::{JsResult, NeonResult, Throw}; use std::mem; use std::os::raw::c_void; use std::ptr::null_mut; -use neon_runtime; -use neon_runtime::raw; -use super::{Class, ClassInternal, Callback}; -use handle::{Handle, Managed}; -use context::{CallbackInfo, CallContext, Context}; -use context::internal::ContextInternal; -use result::{NeonResult, JsResult, Throw}; -use types::{JsValue, JsObject, JsFunction, JsUndefined, build}; use types::error::convert_panics; +use types::{build, JsFunction, JsObject, JsUndefined, JsValue}; #[repr(C)] pub struct MethodCallback(pub fn(CallContext) -> JsResult); @@ -28,18 +28,21 @@ impl Callback<()> for MethodCallback { if !is_a_t { if let Ok(metadata) = T::metadata(&mut cx) { - neon_runtime::class::throw_this_error(mem::transmute(cx.env()), metadata.pointer); + neon_runtime::class::throw_this_error( + mem::transmute(cx.env()), + metadata.pointer, + ); } return; }; let dynamic_callback: fn(CallContext) -> JsResult = mem::transmute(neon_runtime::fun::get_dynamic_callback(data.to_raw())); - if let Ok(value) = convert_panics(|| { dynamic_callback(cx) }) { + if let Ok(value) = convert_panics(cx, |cx| dynamic_callback(cx)) { info.set_return(value); } }) } - } + } fn as_ptr(self) -> *mut c_void { self.0 as *mut c_void @@ -54,7 +57,10 @@ impl ConstructorCallCallback { fn callback(mut cx: CallContext) -> JsResult { unsafe { if let Ok(metadata) = T::metadata(&mut cx) { - neon_runtime::class::throw_call_error(mem::transmute(cx.env()), metadata.pointer); + neon_runtime::class::throw_call_error( + mem::transmute(cx.env()), + metadata.pointer, + ); } } Err(Throw) @@ -71,7 +77,7 @@ impl Callback<()> for ConstructorCallCallback { let data = info.data(); let kernel: fn(CallContext) -> JsResult = mem::transmute(neon_runtime::class::get_call_kernel(data.to_raw())); - if let Ok(value) = convert_panics(|| { kernel(cx) }) { + if let Ok(value) = convert_panics(cx, |cx| kernel(cx)) { info.set_return(value); } }) @@ -93,7 +99,8 @@ impl Callback<*mut c_void> for AllocateCallback { let data = info.data(); let kernel: fn(CallContext) -> NeonResult = mem::transmute(neon_runtime::class::get_allocate_kernel(data.to_raw())); - if let Ok(value) = convert_panics(|| { kernel(cx) }) { + + if let Ok(value) = convert_panics(cx, |cx| kernel(cx)) { let p = Box::into_raw(Box::new(value)); mem::transmute(p) } else { @@ -109,7 +116,9 @@ impl Callback<*mut c_void> for AllocateCallback { } #[repr(C)] -pub struct ConstructCallback(pub fn(CallContext) -> NeonResult>>); +pub struct ConstructCallback( + pub fn(CallContext) -> NeonResult>>, +); impl Callback for ConstructCallback { extern "C" fn invoke(info: &CallbackInfo) -> bool { @@ -118,13 +127,13 @@ impl Callback for ConstructCallback { let data = info.data(); let kernel: fn(CallContext) -> NeonResult>> = mem::transmute(neon_runtime::class::get_construct_kernel(data.to_raw())); - match convert_panics(|| { kernel(cx) }) { + match convert_panics(cx, |cx| kernel(cx)) { Ok(None) => true, Ok(Some(obj)) => { info.set_return(obj); true } - _ => false + _ => false, } }) } @@ -138,13 +147,20 @@ impl Callback for ConstructCallback { #[repr(C)] #[derive(Clone, Copy)] pub struct ClassMetadata { - pub(crate) pointer: *mut c_void + pub(crate) pointer: *mut c_void, } impl ClassMetadata { - pub unsafe fn constructor<'a, T: Class, C: Context<'a>>(&self, cx: &mut C) -> JsResult<'a, JsFunction> { + pub unsafe fn constructor<'a, T: Class, C: Context<'a>>( + &self, + cx: &mut C, + ) -> JsResult<'a, JsFunction> { build(|out| { - neon_runtime::class::metadata_to_constructor(out, mem::transmute(cx.env()), self.pointer) + neon_runtime::class::metadata_to_constructor( + out, + mem::transmute(cx.env()), + self.pointer, + ) }) } diff --git a/src/types/error.rs b/src/types/error.rs index d3f421979..d08ae2ac4 100644 --- a/src/types/error.rs +++ b/src/types/error.rs @@ -1,6 +1,6 @@ //! Types and traits representing JavaScript error values. -use std::panic::{UnwindSafe, catch_unwind}; +use std::panic::{catch_unwind, UnwindSafe}; use neon_runtime; use neon_runtime::raw; @@ -8,9 +8,9 @@ use neon_runtime::raw; use context::Context; use context::internal::Env; use result::{NeonResult, Throw}; -use types::{Value, Object, Handle, Managed, build}; use types::internal::ValueInternal; use types::utf8::Utf8; +use types::{build, Handle, Managed, Object, Value}; /// A JS `Error` object. #[repr(C)] @@ -18,54 +18,134 @@ use types::utf8::Utf8; pub struct JsError(raw::Local); impl Managed for JsError { - fn to_raw(self) -> raw::Local { self.0 } + fn to_raw(self) -> raw::Local { + self.0 + } - fn from_raw(h: raw::Local) -> Self { JsError(h) } + fn from_raw(h: raw::Local) -> Self { + JsError(h) + } } impl ValueInternal for JsError { - fn name() -> String { "Error".to_string() } + fn name() -> String { + "Error".to_string() + } fn is_typeof(env: Env, other: Other) -> bool { unsafe { neon_runtime::tag::is_error(env.to_raw(), other.to_raw()) } } } -impl Value for JsError { } +impl Value for JsError {} -impl Object for JsError { } +impl Object for JsError {} impl JsError { /// Creates a direct instance of the [`Error`](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Error) class. - pub fn error<'a, C: Context<'a>, S: AsRef>(cx: &mut C, msg: S) -> NeonResult> { + pub fn error<'a, C: Context<'a>, S: AsRef>( + cx: &mut C, + msg: S, + ) -> NeonResult> { + #[cfg(feature = "legacy-runtime")] let msg = cx.string(msg.as_ref()); + + #[cfg(feature = "napi-runtime")] + let (ptr, len) = if let Some(small) = Utf8::from(msg.as_ref()).into_small() { + small.lower() + } else { + return Err(Throw); + }; build(|out| unsafe { + #[cfg(feature = "napi-runtime")] + { + let mut local: raw::Local = std::mem::zeroed(); + neon_runtime::string::new(&mut local, cx.env().to_raw(), ptr, len); + neon_runtime::error::new_error(out, cx.env().to_raw(), std::ptr::null_mut(), local); + } + #[cfg(feature = "legacy-runtime")] neon_runtime::error::new_error(out, msg.to_raw()); true }) } /// Creates an instance of the [`TypeError`](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/TypeError) class. - pub fn type_error<'a, C: Context<'a>, S: AsRef>(cx: &mut C, msg: S) -> NeonResult> { + pub fn type_error<'a, C: Context<'a>, S: AsRef>( + cx: &mut C, + msg: S, + ) -> NeonResult> { + #[cfg(feature = "legacy-runtime")] let msg = cx.string(msg.as_ref()); + + #[cfg(feature = "napi-runtime")] + let (ptr, len) = if let Some(small) = Utf8::from(msg.as_ref()).into_small() { + small.lower() + } else { + return Err(Throw); + }; build(|out| unsafe { + #[cfg(feature = "napi-runtime")] + { + let mut local: raw::Local = std::mem::zeroed(); + neon_runtime::string::new(&mut local, cx.env().to_raw(), ptr, len); + neon_runtime::error::new_type_error( + out, + cx.env().to_raw(), + std::ptr::null_mut(), + local, + ); + } + #[cfg(feature = "legacy-runtime")] neon_runtime::error::new_type_error(out, msg.to_raw()); true }) } /// Creates an instance of the [`RangeError`](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/RangeError) class. - pub fn range_error<'a, C: Context<'a>, S: AsRef>(cx: &mut C, msg: S) -> NeonResult> { + pub fn range_error<'a, C: Context<'a>, S: AsRef>( + cx: &mut C, + msg: S, + ) -> NeonResult> { + #[cfg(feature = "legacy-runtime")] let msg = cx.string(msg.as_ref()); + + #[cfg(feature = "napi-runtime")] + let (ptr, len) = if let Some(small) = Utf8::from(msg.as_ref()).into_small() { + small.lower() + } else { + return Err(Throw); + }; build(|out| unsafe { + #[cfg(feature = "napi-runtime")] + { + let mut local: raw::Local = std::mem::zeroed(); + neon_runtime::string::new(&mut local, cx.env().to_raw(), ptr, len); + neon_runtime::error::new_range_error( + out, + cx.env().to_raw(), + std::ptr::null_mut(), + local, + ); + } + #[cfg(feature = "legacy-runtime")] neon_runtime::error::new_range_error(out, msg.to_raw()); true }) } } -pub(crate) fn convert_panics NeonResult>(f: F) -> NeonResult { - match catch_unwind(|| { f() }) { +pub(crate) fn convert_panics< + 'a, + T, + C: Context<'a> + std::panic::UnwindSafe, + F: UnwindSafe + FnOnce(C) -> NeonResult, +>( + cx: C, + f: F, +) -> NeonResult { + #[cfg(feature = "napi-runtime")] + let env = cx.env().to_raw(); + match catch_unwind(move || f(cx)) { Ok(result) => result, Err(panic) => { let msg = if let Some(string) = panic.downcast_ref::() { @@ -75,9 +155,25 @@ pub(crate) fn convert_panics NeonResult>(f: F) } else { "internal error in Neon module".to_string() }; - let (data, len) = Utf8::from(&msg[..]).truncate().lower(); - unsafe { - neon_runtime::error::throw_error_from_utf8(data, len); + println!("{}", msg); + #[cfg(feature = "legacy-runtime")] + { + let (data, len) = Utf8::from(&msg[..]).truncate().lower(); + unsafe { + neon_runtime::error::throw_error_from_utf8(data, len); + Err(Throw) + } + } + #[cfg(feature = "napi-runtime")] + { + let (data, len) = Utf8::from(&msg[..]).truncate().lower(); + unsafe { + let mut local: raw::Local = std::mem::zeroed(); + let mut error: raw::Local = std::mem::zeroed(); + neon_runtime::string::new(&mut local, env, data, len); + neon_runtime::error::new_error(&mut error, env, std::ptr::null_mut(), local); + neon_runtime::error::throw(env, error); + }; Err(Throw) } } diff --git a/src/types/internal.rs b/src/types/internal.rs index 880b9d4bd..979536d61 100644 --- a/src/types/internal.rs +++ b/src/types/internal.rs @@ -1,14 +1,14 @@ -use std::mem; -use std::os::raw::c_void; +use super::Value; +use context::{CallbackInfo, FunctionContext}; use neon_runtime; use neon_runtime::raw; -use context::{CallbackInfo, FunctionContext}; use context::internal::Env; use types::error::convert_panics; -use types::{JsObject, Handle, Managed}; -use result::JsResult; use object::class::Callback; -use super::Value; +use result::JsResult; +use std::mem; +use std::os::raw::c_void; +use types::{Handle, JsObject, Managed}; pub trait ValueInternal: Managed + 'static { fn name() -> String; @@ -38,13 +38,13 @@ impl Callback<()> for FunctionCallback { let data = info.data(); let dynamic_callback: fn(FunctionContext) -> JsResult = mem::transmute(neon_runtime::fun::get_dynamic_callback(data.to_raw())); - if let Ok(value) = convert_panics(|| { dynamic_callback(cx) }) { + + if let Ok(value) = convert_panics(cx, |cx| dynamic_callback(cx)) { info.set_return(value); } }) } } - fn as_ptr(self) -> *mut c_void { unsafe { mem::transmute(self.0) } }