diff --git a/crates/neon/src/context/mod.rs b/crates/neon/src/context/mod.rs index 33517db5a..7c5f5a6ea 100644 --- a/crates/neon/src/context/mod.rs +++ b/crates/neon/src/context/mod.rs @@ -157,6 +157,7 @@ use crate::{ types::{ boxed::{Finalize, JsBox}, error::JsError, + extract::FromArgs, private::ValueInternal, Deferred, JsArray, JsArrayBuffer, JsBoolean, JsBuffer, JsFunction, JsNull, JsNumber, JsObject, JsPromise, JsString, JsUndefined, JsValue, StringResult, Value, @@ -212,6 +213,36 @@ impl CallbackInfo<'_> { local } } + + pub(crate) fn argv_exact<'b, C: Context<'b>, const N: usize>( + &self, + cx: &mut C, + ) -> [Handle<'b, JsValue>; N] { + use std::ptr; + + let mut argv = [JsValue::new_internal(ptr::null_mut()); N]; + let mut argc = argv.len(); + + // # Safety + // * Node-API fills empty slots with `undefined + // * `Handle` and `JsValue` are transparent wrappers around a raw pointer + unsafe { + assert_eq!( + sys::get_cb_info( + cx.env().to_raw(), + self.info, + &mut argc, + argv.as_mut_ptr().cast(), + ptr::null_mut(), + ptr::null_mut(), + ), + sys::Status::Ok, + ); + } + + // Empty values will be filled with `undefined` + argv + } } /// Indicates whether a function was called with `new`. @@ -683,6 +714,55 @@ impl<'a> FunctionContext<'a> { pub fn this_value(&mut self) -> Handle<'a, JsValue> { JsValue::new_internal(self.info.this(self)) } + + /// Extract Rust data from the JavaScript arguments. + /// + /// This is frequently more efficient and ergonomic than getting arguments + /// individually. See the [`extract`](crate::types::extract) module documentation + /// for more examples. + /// + /// ``` + /// # use neon::{prelude::*, types::extract::*}; + /// fn add(mut cx: FunctionContext) -> JsResult { + /// let (number(a), number(b)) = cx.args()?; + /// + /// Ok(cx.number(a + b)) + /// } + /// ``` + pub fn args(&mut self) -> NeonResult + where + T: FromArgs<'a>, + { + T::from_args(self) + } + + /// Extract Rust data from the JavaScript arguments. + /// + /// Similar to [`FunctionContext::args`], but does not throw a JavaScript exception on errors. Useful + /// for function overloading. + /// + /// ``` + /// # use neon::{prelude::*, types::extract::*}; + /// fn combine(mut cx: FunctionContext) -> JsResult { + /// if let Some((number(a), number(b))) = cx.args_opt()? { + /// return Ok(cx.number(a + b).upcast()); + /// } + /// + /// let (string(a), string(b)) = cx.args()?; + /// + /// Ok(cx.string(a + &b).upcast()) + /// } + /// ``` + pub fn args_opt(&mut self) -> NeonResult> + where + T: FromArgs<'a>, + { + T::from_args_opt(self) + } + + pub(crate) fn argv(&mut self) -> [Handle<'a, JsValue>; N] { + self.info.argv_exact(self) + } } impl<'a> ContextInternal<'a> for FunctionContext<'a> { diff --git a/crates/neon/src/lib.rs b/crates/neon/src/lib.rs index 818c078bc..6d45ef1c2 100644 --- a/crates/neon/src/lib.rs +++ b/crates/neon/src/lib.rs @@ -78,6 +78,8 @@ //! [supported]: https://github.com/neon-bindings/neon#platform-support #![cfg_attr(docsrs, feature(doc_cfg))] +extern crate core; + pub mod context; pub mod event; pub mod handle; diff --git a/crates/neon/src/types_impl/bigint.rs b/crates/neon/src/types_impl/bigint.rs index dd8db5b3b..805f8931a 100644 --- a/crates/neon/src/types_impl/bigint.rs +++ b/crates/neon/src/types_impl/bigint.rs @@ -428,8 +428,8 @@ unsafe impl TransparentNoCopyWrapper for JsBigInt { } impl private::ValueInternal for JsBigInt { - fn name() -> String { - "BigInt".to_string() + fn name() -> &'static str { + "BigInt" } fn is_typeof(env: Env, other: &Other) -> bool { diff --git a/crates/neon/src/types_impl/boxed.rs b/crates/neon/src/types_impl/boxed.rs index 990ce83cf..e54330757 100644 --- a/crates/neon/src/types_impl/boxed.rs +++ b/crates/neon/src/types_impl/boxed.rs @@ -183,8 +183,8 @@ unsafe impl TransparentNoCopyWrapper for JsBox { } impl ValueInternal for JsBox { - fn name() -> String { - any::type_name::().to_string() + fn name() -> &'static str { + any::type_name::() } fn is_typeof(env: Env, other: &Other) -> bool { diff --git a/crates/neon/src/types_impl/buffer/types.rs b/crates/neon/src/types_impl/buffer/types.rs index 652dc7a7d..6b499d66c 100644 --- a/crates/neon/src/types_impl/buffer/types.rs +++ b/crates/neon/src/types_impl/buffer/types.rs @@ -124,8 +124,8 @@ unsafe impl TransparentNoCopyWrapper for JsBuffer { } impl ValueInternal for JsBuffer { - fn name() -> String { - "Buffer".to_string() + fn name() -> &'static str { + "Buffer" } fn is_typeof(env: Env, other: &Other) -> bool { @@ -341,8 +341,8 @@ unsafe impl TransparentNoCopyWrapper for JsArrayBuffer { } impl ValueInternal for JsArrayBuffer { - fn name() -> String { - "JsArrayBuffer".to_string() + fn name() -> &'static str { + "JsArrayBuffer" } fn is_typeof(env: Env, other: &Other) -> bool { @@ -791,8 +791,8 @@ macro_rules! impl_typed_array { impl Object for JsTypedArray<$etyp> {} impl ValueInternal for JsTypedArray<$etyp> { - fn name() -> String { - stringify!($typ).to_string() + fn name() -> &'static str { + stringify!($typ) } fn is_typeof(env: Env, other: &Other) -> bool { diff --git a/crates/neon/src/types_impl/date.rs b/crates/neon/src/types_impl/date.rs index 6f9706a74..54ffcd44a 100644 --- a/crates/neon/src/types_impl/date.rs +++ b/crates/neon/src/types_impl/date.rs @@ -160,8 +160,8 @@ impl JsDate { } impl ValueInternal for JsDate { - fn name() -> String { - "object".to_string() + fn name() -> &'static str { + "object" } fn is_typeof(env: Env, other: &Other) -> bool { diff --git a/crates/neon/src/types_impl/error.rs b/crates/neon/src/types_impl/error.rs index c34d6de7f..bfc98b317 100644 --- a/crates/neon/src/types_impl/error.rs +++ b/crates/neon/src/types_impl/error.rs @@ -48,8 +48,8 @@ unsafe impl TransparentNoCopyWrapper for JsError { } impl ValueInternal for JsError { - fn name() -> String { - "Error".to_string() + fn name() -> &'static str { + "Error" } fn is_typeof(env: Env, other: &Other) -> bool { diff --git a/crates/neon/src/types_impl/extract/mod.rs b/crates/neon/src/types_impl/extract/mod.rs new file mode 100644 index 000000000..8afc24e9c --- /dev/null +++ b/crates/neon/src/types_impl/extract/mod.rs @@ -0,0 +1,201 @@ +//! Traits and utilities for extract Rust data from JavaScript values +//! +//! The full list of included extractors can be found on [`TryFromJs`]. +//! +//! ## Extracting Handles +//! +//! JavaScript arguments may be extracted into a Rust tuple. +//! +//! ``` +//! # use neon::{prelude::*, types::extract::*}; +//! fn greet(mut cx: FunctionContext) -> JsResult { +//! let (Val::(greeting), Val::(name)) = cx.args()?; +//! let message = format!("{}, {}!", greeting.value(&mut cx), name.value(&mut cx)); +//! +//! Ok(cx.string(message)) +//! } +//! ``` +//! +//! ## Extracting Native Types +//! +//! It's also possible to extract directly into native Rust types instead of a [`Handle`]. +//! +//! ``` +//! # use neon::{prelude::*, types::extract::*}; +//! fn add(mut cx: FunctionContext) -> JsResult { +//! let (number(a), number(b)) = cx.args()?; +//! +//! Ok(cx.number(a + b)) +//! } +//! ``` +//! +//! ## Extracting [`Option`] +//! +//! It's also possible to mix [`Handle`], Rust types, and even [`Option`] for +//! handling `null` and `undefined`. +//! +//! ``` +//! # use neon::{prelude::*, types::extract::*}; +//! fn get_or_default(mut cx: FunctionContext) -> JsResult { +//! let (Opt::(n), Val::(default_value)) = cx.args()?; +//! +//! if let Some(n) = n { +//! return Ok(cx.number(n).upcast()); +//! } +//! +//! Ok(default_value) +//! } +//! ``` +//! +//! ## Additional Extractors +//! +//! In some cases, the expected JavaScript type is ambiguous. For example, when +//! trying to extract an [`f64`], the argument may be a `Date` instead of a `number`. +//! Newtype extractors are provided to help. +//! +//! ``` +//! # use neon::{prelude::*, types::extract::*}; +//! # #[cfg(feature = "napi-5")] +//! # use neon::types::JsDate; +//! +//! # #[cfg(feature = "napi-5")] +//! fn add_hours(mut cx: FunctionContext) -> JsResult { +//! const MS_PER_HOUR: f64 = 60.0 * 60.0 * 1000.0; +//! +//! let (Date(date), number(hours)) = cx.args()?; +//! let date = date + hours * MS_PER_HOUR; +//! +//! cx.date(date).or_throw(&mut cx) +//! } +//! ``` +//! +//! ## Overloaded Functions +//! +//! It's common in JavaScript to overload function signatures. This can be implemented with +//! [`FunctionContext::args_opt`] or [`Context::try_catch`]. +//! +//! ``` +//! # use neon::{prelude::*, types::extract::*}; +//! +//! fn add(mut cx: FunctionContext, a: f64, b: f64) -> Handle { +//! cx.number(a + b) +//! } +//! +//! fn concat(mut cx: FunctionContext, a: String, b: String) -> Handle { +//! cx.string(a + &b) +//! } +//! +//! fn combine(mut cx: FunctionContext) -> JsResult { +//! if let Some((a, b)) = cx.args_opt()? { +//! return Ok(add(cx, a, b).upcast()); +//! } +//! +//! let (a, b) = cx.args()?; +//! +//! Ok(concat(cx, a, b).upcast()) +//! } +//! ``` +//! +//! Note well, in this example, type annotations are not required on the tuple because +//! Rust is able to infer it from the type arguments on `add` and `concat`. + +use crate::{ + context::{Context, FunctionContext}, + handle::Handle, + result::NeonResult, + types::JsValue, +}; + +pub use self::types::*; + +mod types; + +/// Extract Rust data from a JavaScript value +pub trait TryFromJs<'cx>: private::Sealed + Sized { + type Error; + + fn try_from_js(cx: &mut C, v: Handle<'cx, JsValue>) -> NeonResult> + where + C: Context<'cx>; + + fn from_js(cx: &mut C, v: Handle<'cx, JsValue>) -> NeonResult + where + C: Context<'cx>; +} + +/// Trait specifying values that may be extracted from function arguments. +/// +/// **Note:** This trait is implemented for tuples of up to 32 values, but for +/// the sake of brevity, only tuples up to size 8 are shown in this documentation. +pub trait FromArgs<'cx>: private::FromArgsInternal<'cx> {} + +macro_rules! impl_arguments { + ($(#[$attrs:meta])? [$($head:ident),*], []) => {}; + + ($(#[$attrs:meta])? [$($head:ident),*], [$cur:ident $(, $tail:ident)*]) => { + $(#[$attrs])? + impl<'cx, $($head,)* $cur> FromArgs<'cx> for ($($head,)* $cur,) + where + $($head: TryFromJs<'cx>,)* + $cur: TryFromJs<'cx>, + {} + + impl<'cx, $($head,)* $cur> private::FromArgsInternal<'cx> for ($($head,)* $cur,) + where + $($head: TryFromJs<'cx>,)* + $cur: TryFromJs<'cx>, + { + fn from_args(cx: &mut FunctionContext<'cx>) -> NeonResult { + #[allow(non_snake_case)] + let [$($head,)* $cur] = cx.argv(); + + Ok(( + $($head::from_js(cx, $head)?,)* + $cur::from_js(cx, $cur)?, + )) + } + + fn from_args_opt(cx: &mut FunctionContext<'cx>) -> NeonResult> { + #[allow(non_snake_case)] + let [$($head,)* $cur] = cx.argv(); + + Ok(Some(( + $( + match $head::try_from_js(cx, $head)? { + Ok(v) => v, + Err(_) => return Ok(None), + }, + )* + match $cur::try_from_js(cx, $cur)? { + Ok(v) => v, + Err(_) => return Ok(None), + }, + ))) + } + } + + impl_arguments!($(#[$attrs])? [$($head,)* $cur], [$($tail),*]); + }; +} + +impl_arguments!([], [T1, T2, T3, T4, T5, T6, T7, T8]); +impl_arguments!( + #[doc(hidden)] + [T1, T2, T3, T4, T5, T6, T7, T8], + [ + T9, T10, T11, T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, + T27, T28, T29, T30, T31, T32 + ] +); + +mod private { + use crate::{context::FunctionContext, result::NeonResult}; + + pub trait Sealed {} + + pub trait FromArgsInternal<'cx>: Sized { + fn from_args(cx: &mut FunctionContext<'cx>) -> NeonResult; + + fn from_args_opt(cx: &mut FunctionContext<'cx>) -> NeonResult>; + } +} diff --git a/crates/neon/src/types_impl/extract/types.rs b/crates/neon/src/types_impl/extract/types.rs new file mode 100644 index 000000000..0b44aadf2 --- /dev/null +++ b/crates/neon/src/types_impl/extract/types.rs @@ -0,0 +1,347 @@ +use std::{error, fmt, marker::PhantomData, ptr}; + +use crate::{ + context::Context, + handle::Handle, + result::{NeonResult, ResultExt, Throw}, + sys, + types::{ + extract::{private, TryFromJs}, + private::ValueInternal, + JsBoolean, JsNumber, JsString, JsValue, Value, + }, +}; + +#[cfg(feature = "napi-5")] +use crate::types::JsDate; + +pub struct TypeExpected(PhantomData); + +impl TypeExpected { + fn new() -> Self { + Self(PhantomData) + } +} + +impl fmt::Display for TypeExpected { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "expected {}", T::name()) + } +} + +impl fmt::Debug for TypeExpected { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.debug_tuple("TypeExpected").field(&T::name()).finish() + } +} + +impl error::Error for TypeExpected {} + +impl ResultExt for Result> { + fn or_throw<'a, C: Context<'a>>(self, cx: &mut C) -> NeonResult { + match self { + Ok(v) => Ok(v), + Err(_) => cx.throw_type_error(format!("expected {}", U::name())), + } + } +} + +macro_rules! delegate { + ($target:ident, $source:ident) => { + impl<'cx> TryFromJs<'cx> for $target { + type Error = <$source as TryFromJs<'cx>>::Error; + + fn try_from_js( + cx: &mut C, + v: Handle<'cx, JsValue>, + ) -> NeonResult> + where + C: Context<'cx>, + { + $source::try_from_js(cx, v).map(|v| v.map($target)) + } + + from_js!(); + } + + impl private::Sealed for $target {} + }; +} + +macro_rules! from_js { + () => { + fn from_js(cx: &mut C, v: Handle<'cx, JsValue>) -> NeonResult + where + C: Context<'cx>, + { + Self::try_from_js(cx, v)?.or_throw(cx) + } + }; +} + +/// Wrapper for extracting a JavaScript [`Handle`] +pub struct Val<'cx, V: Value>(pub Handle<'cx, V>) +where + V: Value; + +impl<'cx, V> TryFromJs<'cx> for Val<'cx, V> +where + V: Value, +{ + type Error = TypeExpected; + + fn try_from_js(cx: &mut C, v: Handle<'cx, JsValue>) -> NeonResult> + where + C: Context<'cx>, + { + Ok(v.downcast(cx).map(Self).map_err(|_| TypeExpected::new())) + } + + from_js!(); +} + +impl<'cx, V: Value> private::Sealed for Val<'cx, V> {} + +impl<'cx, V> TryFromJs<'cx> for Handle<'cx, V> +where + V: Value, +{ + type Error = TypeExpected; + + fn try_from_js(cx: &mut C, v: Handle<'cx, JsValue>) -> NeonResult> + where + C: Context<'cx>, + { + Ok(v.downcast(cx).map_err(|_| TypeExpected::new())) + } + + from_js!(); +} + +impl<'cx, V: Value> private::Sealed for Handle<'cx, V> {} + +/// Wrapper for extracting an [`Option`] from a value +pub struct Opt(pub Option) +where + for<'cx> T: TryFromJs<'cx>; + +impl<'cx, T> TryFromJs<'cx> for Opt +where + for<'a> T: TryFromJs<'a>, +{ + type Error = as TryFromJs<'cx>>::Error; + + fn try_from_js(cx: &mut C, v: Handle<'cx, JsValue>) -> NeonResult> + where + C: Context<'cx>, + { + as TryFromJs<'cx>>::try_from_js(cx, v).map(|v| v.map(Self)) + } + + fn from_js(cx: &mut C, v: Handle<'cx, JsValue>) -> NeonResult + where + C: Context<'cx>, + { + as TryFromJs<'cx>>::from_js(cx, v).map(Self) + } +} + +impl private::Sealed for Opt where for<'cx> T: TryFromJs<'cx> {} + +impl<'cx, T> TryFromJs<'cx> for Option +where + T: TryFromJs<'cx>, +{ + type Error = T::Error; + + fn try_from_js(cx: &mut C, v: Handle<'cx, JsValue>) -> NeonResult> + where + C: Context<'cx>, + { + if is_null_or_undefined(cx, v)? { + return Ok(Ok(None)); + } + + T::try_from_js(cx, v).map(|v| v.map(Some)) + } + + fn from_js(cx: &mut C, v: Handle<'cx, JsValue>) -> NeonResult + where + C: Context<'cx>, + { + if is_null_or_undefined(cx, v)? { + return Ok(None); + } + + T::from_js(cx, v).map(Some) + } +} + +impl<'cx, T> private::Sealed for Option where T: TryFromJs<'cx> {} + +#[allow(non_camel_case_types)] +/// Extract an [`f64`] from a [`JsNumber`] +pub struct number(pub f64); + +delegate!(number, f64); + +impl<'cx> TryFromJs<'cx> for f64 { + type Error = TypeExpected; + + fn try_from_js(cx: &mut C, v: Handle<'cx, JsValue>) -> NeonResult> + where + C: Context<'cx>, + { + let mut n = 0f64; + + unsafe { + match sys::get_value_double(cx.env().to_raw(), v.to_local(), &mut n) { + sys::Status::NumberExpected => return Ok(Err(TypeExpected::new())), + sys::Status::PendingException => return Err(Throw::new()), + status => assert_eq!(status, sys::Status::Ok), + } + } + + Ok(Ok(n)) + } + + from_js!(); +} + +impl private::Sealed for f64 {} + +#[allow(non_camel_case_types)] +/// Extract a [`bool`] from a [`JsBoolean`] +pub struct boolean(pub bool); + +delegate!(boolean, bool); + +impl<'cx> TryFromJs<'cx> for bool { + type Error = TypeExpected; + + fn try_from_js(cx: &mut C, v: Handle<'cx, JsValue>) -> NeonResult> + where + C: Context<'cx>, + { + let mut b = false; + + unsafe { + match sys::get_value_bool(cx.env().to_raw(), v.to_local(), &mut b) { + sys::Status::BooleanExpected => return Ok(Err(TypeExpected::new())), + sys::Status::PendingException => return Err(Throw::new()), + status => assert_eq!(status, sys::Status::Ok), + } + } + + Ok(Ok(b)) + } + + from_js!(); +} + +impl private::Sealed for bool {} + +#[allow(non_camel_case_types)] +/// Extract a [`String`] from a [`JsString`] +pub struct string(pub String); + +delegate!(string, String); + +impl<'cx> TryFromJs<'cx> for String { + type Error = TypeExpected; + + fn try_from_js(cx: &mut C, v: Handle<'cx, JsValue>) -> NeonResult> + where + C: Context<'cx>, + { + let env = cx.env().to_raw(); + let v = v.to_local(); + let mut len = 0usize; + + unsafe { + match sys::get_value_string_utf8(env, v, ptr::null_mut(), 0, &mut len) { + sys::Status::StringExpected => return Ok(Err(TypeExpected::new())), + sys::Status::PendingException => return Err(Throw::new()), + status => assert_eq!(status, sys::Status::Ok), + } + } + + // Make room for null terminator to avoid losing a character + let mut buf = Vec::::with_capacity(len + 1); + let mut written = 0usize; + + unsafe { + assert_eq!( + sys::get_value_string_utf8( + env, + v, + buf.as_mut_ptr().cast(), + buf.capacity(), + &mut written, + ), + sys::Status::Ok, + ); + + debug_assert_eq!(len, written); + buf.set_len(len); + + Ok(Ok(String::from_utf8_unchecked(buf))) + } + } + + from_js!(); +} + +impl private::Sealed for String {} + +#[cfg_attr(docsrs, doc(cfg(feature = "napi-5")))] +#[cfg(feature = "napi-5")] +/// Extract an [`f64`] from a [`JsDate`] +pub struct Date(pub f64); + +#[cfg_attr(docsrs, doc(cfg(feature = "napi-5")))] +#[cfg(feature = "napi-5")] +impl<'cx> TryFromJs<'cx> for Date { + type Error = TypeExpected; + + fn try_from_js(cx: &mut C, v: Handle<'cx, JsValue>) -> NeonResult> + where + C: Context<'cx>, + { + let mut d = 0f64; + + unsafe { + match sys::get_date_value(cx.env().to_raw(), v.to_local(), &mut d) { + sys::Status::DateExpected => return Ok(Err(TypeExpected::new())), + sys::Status::PendingException => return Err(Throw::new()), + status => assert_eq!(status, sys::Status::Ok), + } + } + + Ok(Ok(Date(d))) + } + + from_js!(); +} + +impl private::Sealed for Date {} + +fn is_null_or_undefined<'cx, C, V>(cx: &mut C, v: Handle) -> NeonResult +where + C: Context<'cx>, + V: Value, +{ + let mut ty = sys::ValueType::Object; + + unsafe { + match sys::typeof_value(cx.env().to_raw(), v.to_local(), &mut ty) { + sys::Status::PendingException => return Err(Throw::new()), + status => assert_eq!(status, sys::Status::Ok), + } + } + + Ok(matches!( + ty, + sys::ValueType::Undefined | sys::ValueType::Null, + )) +} diff --git a/crates/neon/src/types_impl/mod.rs b/crates/neon/src/types_impl/mod.rs index 327df09d0..73df1d312 100644 --- a/crates/neon/src/types_impl/mod.rs +++ b/crates/neon/src/types_impl/mod.rs @@ -8,6 +8,7 @@ pub mod buffer; #[cfg(feature = "napi-5")] pub(crate) mod date; pub(crate) mod error; +pub mod extract; pub mod function; pub(crate) mod promise; @@ -167,8 +168,8 @@ unsafe impl TransparentNoCopyWrapper for JsValue { } impl ValueInternal for JsValue { - fn name() -> String { - "any".to_string() + fn name() -> &'static str { + "any" } fn is_typeof(_env: Env, _other: &Other) -> bool { @@ -245,8 +246,8 @@ unsafe impl TransparentNoCopyWrapper for JsUndefined { } impl ValueInternal for JsUndefined { - fn name() -> String { - "undefined".to_string() + fn name() -> &'static str { + "undefined" } fn is_typeof(env: Env, other: &Other) -> bool { @@ -313,8 +314,8 @@ unsafe impl TransparentNoCopyWrapper for JsNull { } impl ValueInternal for JsNull { - fn name() -> String { - "null".to_string() + fn name() -> &'static str { + "null" } fn is_typeof(env: Env, other: &Other) -> bool { @@ -390,8 +391,8 @@ unsafe impl TransparentNoCopyWrapper for JsBoolean { } impl ValueInternal for JsBoolean { - fn name() -> String { - "boolean".to_string() + fn name() -> &'static str { + "boolean" } fn is_typeof(env: Env, other: &Other) -> bool { @@ -465,8 +466,8 @@ unsafe impl TransparentNoCopyWrapper for JsString { } impl ValueInternal for JsString { - fn name() -> String { - "string".to_string() + fn name() -> &'static str { + "string" } fn is_typeof(env: Env, other: &Other) -> bool { @@ -743,8 +744,8 @@ unsafe impl TransparentNoCopyWrapper for JsNumber { } impl ValueInternal for JsNumber { - fn name() -> String { - "number".to_string() + fn name() -> &'static str { + "number" } fn is_typeof(env: Env, other: &Other) -> bool { @@ -802,8 +803,8 @@ unsafe impl TransparentNoCopyWrapper for JsObject { } impl ValueInternal for JsObject { - fn name() -> String { - "object".to_string() + fn name() -> &'static str { + "object" } fn is_typeof(env: Env, other: &Other) -> bool { @@ -944,8 +945,8 @@ unsafe impl TransparentNoCopyWrapper for JsArray { } impl ValueInternal for JsArray { - fn name() -> String { - "Array".to_string() + fn name() -> &'static str { + "Array" } fn is_typeof(env: Env, other: &Other) -> bool { @@ -1226,8 +1227,8 @@ unsafe impl TransparentNoCopyWrapper for JsFunction { } impl ValueInternal for JsFunction { - fn name() -> String { - "function".to_string() + fn name() -> &'static str { + "function" } fn is_typeof(env: Env, other: &Other) -> bool { diff --git a/crates/neon/src/types_impl/private.rs b/crates/neon/src/types_impl/private.rs index 04eee2213..774dd0bcb 100644 --- a/crates/neon/src/types_impl/private.rs +++ b/crates/neon/src/types_impl/private.rs @@ -6,7 +6,7 @@ use crate::{ }; pub trait ValueInternal: TransparentNoCopyWrapper + 'static { - fn name() -> String; + fn name() -> &'static str; fn is_typeof(env: Env, other: &Other) -> bool; diff --git a/crates/neon/src/types_impl/promise.rs b/crates/neon/src/types_impl/promise.rs index 625d247e3..913d788ab 100644 --- a/crates/neon/src/types_impl/promise.rs +++ b/crates/neon/src/types_impl/promise.rs @@ -249,8 +249,8 @@ unsafe impl TransparentNoCopyWrapper for JsPromise { } impl ValueInternal for JsPromise { - fn name() -> String { - "Promise".to_string() + fn name() -> &'static str { + "Promise" } fn is_typeof(env: Env, other: &Other) -> bool {