From d4cd5d2733cbc9bef0f8b39f4461384ac6dc880c Mon Sep 17 00:00:00 2001 From: Bert Belder Date: Fri, 17 Jan 2020 08:22:11 +0100 Subject: [PATCH] Move error constructors and helper functions under v8::Exception (#215) * The purpose of this change is to match the C++ API more closely. * This patch also increases consistency between the 'extern "C"' function definitions on the Rust side with those on the C++ side. * The 'message' parameter (a v8::String) to the various error constructors no longer needs to be mutable. --- src/exception.rs | 154 ++++++++++++++++++++++++---------------------- tests/test_api.rs | 34 +++++----- 2 files changed, 97 insertions(+), 91 deletions(-) diff --git a/src/exception.rs b/src/exception.rs index 44834e4f..91b17ad6 100644 --- a/src/exception.rs +++ b/src/exception.rs @@ -50,18 +50,18 @@ extern "C" { fn v8__StackFrame__IsWasm(self_: &StackFrame) -> bool; fn v8__StackFrame__IsUserJavaScript(self_: &StackFrame) -> bool; - fn v8__Exception__RangeError(message: *mut String) -> *mut Value; - fn v8__Exception__ReferenceError(message: *mut String) -> *mut Value; - fn v8__Exception__SyntaxError(message: *mut String) -> *mut Value; - fn v8__Exception__TypeError(message: *mut String) -> *mut Value; - fn v8__Exception__Error(message: *mut String) -> *mut Value; + fn v8__Exception__Error(message: Local) -> *mut Value; + fn v8__Exception__RangeError(message: Local) -> *mut Value; + fn v8__Exception__ReferenceError(message: Local) -> *mut Value; + fn v8__Exception__SyntaxError(message: Local) -> *mut Value; + fn v8__Exception__TypeError(message: Local) -> *mut Value; fn v8__Exception__CreateMessage( isolate: &Isolate, exception: Local, ) -> *mut Message; - fn v8__Exception__GetStackTrace(exception: *mut Value) -> *mut StackTrace; + fn v8__Exception__GetStackTrace(exception: Local) -> *mut StackTrace; } /// Representation of a JavaScript stack trace. The information collected is a @@ -262,78 +262,84 @@ impl Message { } } -/// Creates an error message for the given exception. -/// Will try to reconstruct the original stack trace from the exception value, -/// or capture the current stack trace if not available. -pub fn create_message<'sc>( - scope: &mut impl ToLocal<'sc>, - exception: Local, -) -> Local<'sc, Message> { - let isolate = scope.isolate(); - let ptr = unsafe { v8__Exception__CreateMessage(isolate, exception) }; - unsafe { scope.to_local(ptr) }.unwrap() -} +/// Create new error objects by calling the corresponding error object +/// constructor with the message. +pub struct Exception; -/// Returns the original stack trace that was captured at the creation time -/// of a given exception, or an empty handle if not available. -pub fn get_stack_trace<'sc>( - scope: &mut impl ToLocal<'sc>, - mut exception: Local, -) -> Option> { - unsafe { scope.to_local(v8__Exception__GetStackTrace(&mut *exception)) } -} +impl Exception { + pub fn error<'sc>( + scope: &mut impl ToLocal<'sc>, + message: Local, + ) -> Local<'sc, Value> { + let isolate = scope.isolate(); + isolate.enter(); + let e = unsafe { v8__Exception__Error(message) }; + isolate.exit(); + unsafe { scope.to_local(e) }.unwrap() + } -pub fn range_error<'sc>( - scope: &mut impl ToLocal<'sc>, - mut message: Local, -) -> Local<'sc, Value> { - let isolate = scope.isolate(); - isolate.enter(); - let e = unsafe { v8__Exception__RangeError(&mut *message) }; - isolate.exit(); - unsafe { scope.to_local(e) }.unwrap() -} + pub fn range_error<'sc>( + scope: &mut impl ToLocal<'sc>, + message: Local, + ) -> Local<'sc, Value> { + let isolate = scope.isolate(); + isolate.enter(); + let e = unsafe { v8__Exception__RangeError(message) }; + isolate.exit(); + unsafe { scope.to_local(e) }.unwrap() + } -pub fn reference_error<'sc>( - scope: &mut impl ToLocal<'sc>, - mut message: Local, -) -> Local<'sc, Value> { - let isolate = scope.isolate(); - isolate.enter(); - let e = unsafe { v8__Exception__ReferenceError(&mut *message) }; - isolate.exit(); - unsafe { scope.to_local(e) }.unwrap() -} + pub fn reference_error<'sc>( + scope: &mut impl ToLocal<'sc>, + message: Local, + ) -> Local<'sc, Value> { + let isolate = scope.isolate(); + isolate.enter(); + let e = unsafe { v8__Exception__ReferenceError(message) }; + isolate.exit(); + unsafe { scope.to_local(e) }.unwrap() + } -pub fn syntax_error<'sc>( - scope: &mut impl ToLocal<'sc>, - mut message: Local, -) -> Local<'sc, Value> { - let isolate = scope.isolate(); - isolate.enter(); - let e = unsafe { v8__Exception__SyntaxError(&mut *message) }; - isolate.exit(); - unsafe { scope.to_local(e) }.unwrap() -} + pub fn syntax_error<'sc>( + scope: &mut impl ToLocal<'sc>, + message: Local, + ) -> Local<'sc, Value> { + let isolate = scope.isolate(); + isolate.enter(); + let e = unsafe { v8__Exception__SyntaxError(message) }; + isolate.exit(); + unsafe { scope.to_local(e) }.unwrap() + } -pub fn type_error<'sc>( - scope: &mut impl ToLocal<'sc>, - mut message: Local, -) -> Local<'sc, Value> { - let isolate = scope.isolate(); - isolate.enter(); - let e = unsafe { v8__Exception__TypeError(&mut *message) }; - isolate.exit(); - unsafe { scope.to_local(e) }.unwrap() -} + pub fn type_error<'sc>( + scope: &mut impl ToLocal<'sc>, + message: Local, + ) -> Local<'sc, Value> { + let isolate = scope.isolate(); + isolate.enter(); + let e = unsafe { v8__Exception__TypeError(message) }; + isolate.exit(); + unsafe { scope.to_local(e) }.unwrap() + } -pub fn error<'sc>( - scope: &mut impl ToLocal<'sc>, - mut message: Local, -) -> Local<'sc, Value> { - let isolate = scope.isolate(); - isolate.enter(); - let e = unsafe { v8__Exception__Error(&mut *message) }; - isolate.exit(); - unsafe { scope.to_local(e) }.unwrap() + /// Creates an error message for the given exception. + /// Will try to reconstruct the original stack trace from the exception value, + /// or capture the current stack trace if not available. + pub fn create_message<'sc>( + scope: &mut impl ToLocal<'sc>, + exception: Local, + ) -> Local<'sc, Message> { + let isolate = scope.isolate(); + let ptr = unsafe { v8__Exception__CreateMessage(isolate, exception) }; + unsafe { scope.to_local(ptr) }.unwrap() + } + + /// Returns the original stack trace that was captured at the creation time + /// of a given exception, or an empty handle if not available. + pub fn get_stack_trace<'sc>( + scope: &mut impl ToLocal<'sc>, + exception: Local, + ) -> Option> { + unsafe { scope.to_local(v8__Exception__GetStackTrace(exception)) } + } } diff --git a/tests/test_api.rs b/tests/test_api.rs index d64a6a16..6fdf98bd 100644 --- a/tests/test_api.rs +++ b/tests/test_api.rs @@ -799,21 +799,21 @@ fn exception() { let scope = hs.enter(); let mut context = v8::Context::new(scope); context.enter(); - let reference = "This is a test error"; - let local = v8::String::new(scope, reference).unwrap(); - v8::range_error(scope, local); - v8::reference_error(scope, local); - v8::syntax_error(scope, local); - v8::type_error(scope, local); - let exception = v8::error(scope, local); - let msg = v8::create_message(scope, exception); - let msg_string = msg.get(scope); - let rust_msg_string = msg_string.to_rust_string_lossy(scope); - assert_eq!( - "Uncaught Error: This is a test error".to_string(), - rust_msg_string - ); - assert!(v8::get_stack_trace(scope, exception).is_none()); + + let msg_in = v8::String::new(scope, "This is a test error").unwrap(); + let _exception = v8::Exception::error(scope, msg_in); + let _exception = v8::Exception::range_error(scope, msg_in); + let _exception = v8::Exception::reference_error(scope, msg_in); + let _exception = v8::Exception::syntax_error(scope, msg_in); + let exception = v8::Exception::type_error(scope, msg_in); + + let actual_msg_out = + v8::Exception::create_message(scope, exception).get(scope); + let expected_msg_out = + v8::String::new(scope, "Uncaught TypeError: This is a test error").unwrap(); + assert!(actual_msg_out.strict_equals(expected_msg_out.into())); + assert!(v8::Exception::get_stack_trace(scope, exception).is_none()); + context.exit(); } @@ -836,7 +836,7 @@ fn create_message_argument_lifetimes() { |scope: v8::FunctionCallbackScope, args: v8::FunctionCallbackArguments, mut rv: v8::ReturnValue| { - let message = v8::create_message(scope, args.get(0)); + let message = v8::Exception::create_message(scope, args.get(0)); let message_str = message.get(scope); rv.set(message_str.into()) }, @@ -844,7 +844,7 @@ fn create_message_argument_lifetimes() { .unwrap(); let receiver = context.global(scope); let message_str = v8::String::new(scope, "mishap").unwrap(); - let exception = v8::type_error(scope, message_str); + let exception = v8::Exception::type_error(scope, message_str); let actual = create_message .call(scope, context, receiver.into(), &[exception]) .unwrap();