diff --git a/src/binding.cc b/src/binding.cc index f1274fb1..5e56d419 100644 --- a/src/binding.cc +++ b/src/binding.cc @@ -306,6 +306,18 @@ bool v8__Value__SameValue(const v8::Value& self, v8::Value* that) { return self.SameValue(ptr_to_local(that)); } +v8::String* v8__Value__ToString(const v8::Value& self, v8::Context* context) { + return maybe_local_to_ptr(self.ToString(ptr_to_local(context))); +} + +v8::Number* v8__Value__ToNumber(const v8::Value& self, v8::Context* context) { + return maybe_local_to_ptr(self.ToNumber(ptr_to_local(context))); +} + +v8::Object* v8__Value__ToObject(const v8::Value& self, v8::Context* context) { + return maybe_local_to_ptr(self.ToObject(ptr_to_local(context))); +} + v8::Primitive* v8__Null(v8::Isolate* isolate) { return local_to_ptr(v8::Null(isolate)); } diff --git a/src/lib.rs b/src/lib.rs index ef1ddbf3..49fe726b 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -23,7 +23,7 @@ //! code.to_rust_string_lossy(scope); //! let mut script = v8::Script::compile(scope, context, code, None).unwrap(); //! let result = script.run(scope, context).unwrap(); -//! let result = unsafe { v8::Local::::cast(result) }; +//! let result = result.to_string(scope).unwrap(); //! let str = result.to_rust_string_lossy(scope); //! println!("{}", str); //! diff --git a/src/value.rs b/src/value.rs index 54e08bfc..c77d01aa 100644 --- a/src/value.rs +++ b/src/value.rs @@ -1,4 +1,9 @@ +use crate::Context; use crate::Local; +use crate::Number; +use crate::Object; +use crate::String; +use crate::ToLocal; use crate::Value; extern "C" { @@ -12,6 +17,9 @@ extern "C" { fn v8__Value__IsObject(this: &Value) -> bool; fn v8__Value__StrictEquals(this: &Value, that: &Value) -> bool; fn v8__Value__SameValue(this: &Value, that: &Value) -> bool; + fn v8__Value__ToString(this: &Value, context: *mut Context) -> *mut String; + fn v8__Value__ToNumber(this: &Value, context: *mut Context) -> *mut Number; + fn v8__Value__ToObject(this: &Value, context: *mut Context) -> *mut Object; } impl Value { @@ -65,4 +73,31 @@ impl Value { pub fn same_value<'sc>(&self, that: Local<'sc, Value>) -> bool { unsafe { v8__Value__SameValue(self, &that) } } + + pub fn to_string<'sc>( + &self, + scope: &mut impl ToLocal<'sc>, + ) -> Option> { + let isolate = scope.isolate(); + let mut context = isolate.get_current_context(); + unsafe { Local::from_raw(v8__Value__ToString(self, &mut *context)) } + } + + pub fn to_number<'sc>( + &self, + scope: &mut impl ToLocal<'sc>, + ) -> Option> { + let isolate = scope.isolate(); + let mut context = isolate.get_current_context(); + unsafe { Local::from_raw(v8__Value__ToNumber(self, &mut *context)) } + } + + pub fn to_object<'sc>( + &self, + scope: &mut impl ToLocal<'sc>, + ) -> Option> { + let isolate = scope.isolate(); + let mut context = isolate.get_current_context(); + unsafe { Local::from_raw(v8__Value__ToObject(self, &mut *context)) } + } } diff --git a/tests/test_api.rs b/tests/test_api.rs index 035913b2..25f399d4 100644 --- a/tests/test_api.rs +++ b/tests/test_api.rs @@ -548,7 +548,7 @@ fn set_host_initialize_import_meta_object_callback() { assert!(result.is_some()); let meta = module.evaluate(s, context).unwrap(); assert!(meta.is_object()); - let meta = unsafe { Local::::cast(meta) }; + let meta = meta.to_object(s).unwrap(); let key = v8::String::new(s, "foo").unwrap(); let expected = v8::String::new(s, "bar").unwrap(); let actual = meta.get(s, context, key.into()).unwrap(); @@ -577,9 +577,7 @@ fn script_compile_and_run() { let mut script = v8::Script::compile(s, context, source, None).unwrap(); source.to_rust_string_lossy(s); let result = script.run(s, context).unwrap(); - // TODO: safer casts. - let result: v8::Local = - unsafe { std::mem::transmute_copy(&result) }; + let result = result.to_string(s).unwrap(); assert_eq!(result.to_rust_string_lossy(s), "Hello 13th planet"); context.exit(); } @@ -824,7 +822,7 @@ fn create_data_property() { .get(scope, context, key.into()) .unwrap(); assert!(obj.is_object()); - let obj = unsafe { Local::::cast(obj) }; + let obj = obj.to_object(scope).unwrap(); let key = v8_str(scope, "foo"); let value = v8_str(scope, "bar"); assert_eq!( @@ -869,14 +867,14 @@ fn promise_resolved() { resolver.resolve(context, value.into()); assert_eq!(promise.state(), v8::PromiseState::Fulfilled); let result = promise.result(scope); - let result_str = unsafe { Local::::cast(result) }; + let result_str = result.to_string(scope).unwrap(); assert_eq!(result_str.to_rust_string_lossy(scope), "test".to_string()); // Resolve again with different value, since promise is already in `Fulfilled` state // it should be ignored. let value = v8::String::new(scope, "test2").unwrap(); resolver.resolve(context, value.into()); let result = promise.result(scope); - let result_str = unsafe { Local::::cast(result) }; + let result_str = result.to_string(scope).unwrap(); assert_eq!(result_str.to_rust_string_lossy(scope), "test".to_string()); context.exit(); } @@ -906,14 +904,14 @@ fn promise_rejected() { assert!(rejected.unwrap()); assert_eq!(promise.state(), v8::PromiseState::Rejected); let result = promise.result(scope); - let result_str = unsafe { Local::::cast(result) }; + let result_str = result.to_string(scope).unwrap(); assert_eq!(result_str.to_rust_string_lossy(scope), "test".to_string()); // Reject again with different value, since promise is already in `Rejected` state // it should be ignored. let value = v8::String::new(scope, "test2").unwrap(); resolver.reject(context, value.into()); let result = promise.result(scope); - let result_str = unsafe { Local::::cast(result) }; + let result_str = result.to_string(scope).unwrap(); assert_eq!(result_str.to_rust_string_lossy(scope), "test".to_string()); context.exit(); } @@ -1008,7 +1006,7 @@ fn function() { vec![arg1.into(), arg2.into()], ); let value = maybe_value.unwrap(); - let value_str = unsafe { Local::::cast(value) }; + let value_str = value.to_string(scope).unwrap(); let rust_str = value_str.to_rust_string_lossy(scope); assert_eq!(rust_str, "Hello callback!".to_string()); context.exit(); @@ -1028,7 +1026,7 @@ extern "C" fn promise_reject_callback(msg: v8::PromiseRejectMessage) { { let mut hs = v8::HandleScope::new(&mut locker); let scope = hs.enter(); - let value_str = unsafe { Local::::cast(value) }; + let value_str = value.to_string(scope).unwrap(); let rust_str = value_str.to_rust_string_lossy(scope); assert_eq!(rust_str, "promise rejected".to_string()); }