From 6385bd6f32d19c8f7ff0a5182d6d93b49fd769b4 Mon Sep 17 00:00:00 2001 From: Nathan Whitaker <17734409+nathanwhit@users.noreply.github.com> Date: Fri, 19 Jul 2024 18:34:32 -0700 Subject: [PATCH] chore: Add a couple convenience casting functions to `v8::Local` (#1533) * Rename cast -> cast_unchecked * Add cast helpers * Change a couple tests to use it * Add some small docs * Fmt * Add inline hint * Address comments --- examples/process.rs | 6 ++++-- examples/shell.rs | 3 ++- src/handle.rs | 46 +++++++++++++++++++++++++++++++++++++++++++-- tests/test_api.rs | 17 ++++++----------- 4 files changed, 56 insertions(+), 16 deletions(-) diff --git a/examples/process.rs b/examples/process.rs index d186fc2e..20e55126 100644 --- a/examples/process.rs +++ b/examples/process.rs @@ -324,8 +324,10 @@ where scope: &mut v8::HandleScope, request: v8::Local, ) -> *mut Box { - let external = request.get_internal_field(scope, 0).unwrap(); - let external = unsafe { v8::Local::::cast(external) }; + let external = request + .get_internal_field(scope, 0) + .unwrap() + .cast::(); external.value() as *mut Box } diff --git a/examples/shell.rs b/examples/shell.rs index d01800e5..9f4cfc0a 100644 --- a/examples/shell.rs +++ b/examples/shell.rs @@ -224,7 +224,8 @@ fn report_exceptions(mut try_catch: v8::TryCatch) { } else { return; }; - let stack_trace = unsafe { v8::Local::::cast(stack_trace) }; + let stack_trace = + unsafe { v8::Local::::cast_unchecked(stack_trace) }; let stack_trace = stack_trace .to_string(&mut try_catch) .map(|s| s.to_rust_string_lossy(&mut try_catch)); diff --git a/src/handle.rs b/src/handle.rs index 4bbe51c0..a7912ca1 100644 --- a/src/handle.rs +++ b/src/handle.rs @@ -105,9 +105,9 @@ impl<'s, T> Local<'s, T> { /// Create a local handle by downcasting from one of its super types. /// This function is unsafe because the cast is unchecked. #[inline(always)] - pub unsafe fn cast(other: Local<'s, A>) -> Self + pub unsafe fn cast_unchecked(other: Local<'s, A>) -> Self where - Local<'s, A>: From, + Local<'s, A>: TryFrom, { transmute(other) } @@ -153,6 +153,48 @@ impl<'s, T> Deref for Local<'s, T> { } } +impl<'s, T> Local<'s, T> { + /// Attempts to cast the contained type to another, + /// returning an error if the conversion fails. + /// + /// # Examples + /// + /// ``` + /// let value: Local<'_, Value> = get_v8_value(); + /// + /// if let Ok(func) = value.try_cast::( + self, + ) -> Result, >>::Error> + where + Self: TryInto>, + { + self.try_into() + } + + /// Attempts to cast the contained type to another, + /// panicking if the conversion fails. + /// + /// # Example + /// + /// ``` + /// let value: Local<'_, Value> = get_v8_value(); + /// + /// let func = value.cast::(); + /// ``` + #[inline(always)] + pub fn cast(self) -> Local<'s, A> + where + Self: TryInto, Error: std::fmt::Debug>, + { + self.try_into().unwrap() + } +} + /// An object reference that is independent of any handle scope. Where /// a Local handle only lives as long as the HandleScope in which it was /// allocated, a global handle remains valid until it is dropped. diff --git a/tests/test_api.rs b/tests/test_api.rs index 54ab6155..a37dedd7 100644 --- a/tests/test_api.rs +++ b/tests/test_api.rs @@ -97,8 +97,8 @@ fn handle_scope_numbers() { { let scope2 = &mut v8::HandleScope::new(scope1); let l3 = v8::Number::new(scope2, 78.9); - let l4 = v8::Local::::try_from(l1).unwrap(); - let l5 = v8::Local::::try_from(l2).unwrap(); + let l4 = l1.cast::(); + let l5 = l2.cast::(); assert_eq!(l1.value(), -123); assert_eq!(l2.value(), 456); assert_eq!(l3.value(), 78.9); @@ -2493,20 +2493,15 @@ fn object_template_set_named_property_handler() { name.into(), obj.into(), ); - let arr = v8::Local::::try_from( - eval(scope, "Object.keys(obj)").unwrap(), - ) - .unwrap(); + let arr = eval(scope, "Object.keys(obj)").unwrap().cast::(); assert_eq!(arr.length(), 1); let index = v8::Integer::new(scope, 0); let result = arr.get(scope, index.into()).unwrap(); let expected = v8::String::new(scope, "key").unwrap(); assert!(expected.strict_equals(result)); eval(scope, "obj.fallthrough = 'a'").unwrap(); - let arr = v8::Local::::try_from( - eval(scope, "Object.keys(obj)").unwrap(), - ) - .unwrap(); + let arr = eval(scope, "Object.keys(obj)").unwrap().cast::(); + assert_eq!(arr.length(), 2); // definer @@ -10935,7 +10930,7 @@ fn test_fast_calls_callback_options_data() { return; } - let data = v8::Local::::cast(options.data.data); + let data = v8::Local::::cast_unchecked(options.data.data); let data = &mut *(data.value() as *mut bool); *data = true; }