refactor!(napi): add lifetime for JsNumber (#2609)

This commit is contained in:
LongYinan 2025-05-07 20:11:33 +08:00 committed by GitHub
parent 8f852442cf
commit a456fcdbc7
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
10 changed files with 89 additions and 137 deletions

View File

@ -44,8 +44,8 @@ fn bench_tokio_future(ctx: CallContext) -> Result<JsObject> {
let buffer_ref = ctx.get::<Buffer>(0)?;
ctx
.env
.execute_tokio_future(async move { Ok(buffer_ref.len()) }, |env, v: usize| {
env.create_uint32(v as u32 + 1)
.execute_tokio_future(async move { Ok(buffer_ref.len()) }, |_, v: usize| {
Ok(v as u32 + 1)
})
}

View File

@ -57,7 +57,7 @@ impl<'env> CallContext<'env> {
}
}
pub fn try_get<ArgType: NapiValue + TypeName + FromNapiValue>(
pub fn try_get<ArgType: FromNapiValue + TypeName + FromNapiValue>(
&self,
index: usize,
) -> Result<Either<ArgType, JsUndefined>> {
@ -67,7 +67,7 @@ impl<'env> CallContext<'env> {
"Arguments index out of range".to_owned(),
))
} else if index < self.length {
unsafe { ArgType::from_raw(self.env.0, self.args[index]) }.map(Either::A)
unsafe { ArgType::from_napi_value(self.env.0, self.args[index]) }.map(Either::A)
} else {
self.env.get_undefined().map(Either::B)
}

View File

@ -81,7 +81,7 @@ impl Env {
check_status!(unsafe {
sys::napi_create_int32(self.0, int, (&mut raw_value) as *mut sys::napi_value)
})?;
Ok(unsafe { JsNumber::from_raw_unchecked(self.0, raw_value) })
unsafe { JsNumber::from_napi_value(self.0, raw_value) }
}
pub fn create_int64(&self, int: i64) -> Result<JsNumber> {
@ -89,13 +89,13 @@ impl Env {
check_status!(unsafe {
sys::napi_create_int64(self.0, int, (&mut raw_value) as *mut sys::napi_value)
})?;
Ok(unsafe { JsNumber::from_raw_unchecked(self.0, raw_value) })
unsafe { JsNumber::from_napi_value(self.0, raw_value) }
}
pub fn create_uint32(&self, number: u32) -> Result<JsNumber> {
let mut raw_value = ptr::null_mut();
check_status!(unsafe { sys::napi_create_uint32(self.0, number, &mut raw_value) })?;
Ok(unsafe { JsNumber::from_raw_unchecked(self.0, raw_value) })
unsafe { JsNumber::from_napi_value(self.0, raw_value) }
}
pub fn create_double(&self, double: f64) -> Result<JsNumber> {
@ -103,7 +103,7 @@ impl Env {
check_status!(unsafe {
sys::napi_create_double(self.0, double, (&mut raw_value) as *mut sys::napi_value)
})?;
Ok(unsafe { JsNumber::from_raw_unchecked(self.0, raw_value) })
unsafe { JsNumber::from_napi_value(self.0, raw_value) }
}
/// [n_api_napi_create_bigint_int64](https://nodejs.org/api/n-api.html#n_api_napi_create_bigint_int64)

View File

@ -4,6 +4,7 @@ use std::ptr;
use super::*;
use crate::{bindgen_runtime::TypeName, check_status, sys, Result};
#[deprecated(since = "3.0.0", note = "Use `napi::bindgen_prelude::BigInt` instead")]
#[derive(Clone, Copy)]
pub struct JsBigInt {
pub(crate) raw: Value,
@ -37,90 +38,6 @@ impl JsBigInt {
word_count,
}
}
pub fn into_unknown(self) -> JsUnknown {
unsafe { JsUnknown::from_raw_unchecked(self.raw.env, self.raw.value) }
}
pub fn coerce_to_number(self) -> Result<JsNumber> {
let mut new_raw_value = ptr::null_mut();
check_status!(unsafe {
sys::napi_coerce_to_number(self.raw.env, self.raw.value, &mut new_raw_value)
})?;
Ok(JsNumber(Value {
env: self.raw.env,
value: new_raw_value,
value_type: ValueType::Number,
}))
}
pub fn coerce_to_string(self) -> Result<JsString> {
let mut new_raw_value = ptr::null_mut();
check_status!(unsafe {
sys::napi_coerce_to_string(self.raw.env, self.raw.value, &mut new_raw_value)
})?;
Ok(JsString(Value {
env: self.raw.env,
value: new_raw_value,
value_type: ValueType::String,
}))
}
pub fn coerce_to_object(self) -> Result<JsObject> {
let mut new_raw_value = ptr::null_mut();
check_status!(unsafe {
sys::napi_coerce_to_object(self.raw.env, self.raw.value, &mut new_raw_value)
})?;
Ok(JsObject(Value {
env: self.raw.env,
value: new_raw_value,
value_type: ValueType::Object,
}))
}
pub fn is_date(&self) -> Result<bool> {
let mut is_date = true;
check_status!(unsafe { sys::napi_is_date(self.raw.env, self.raw.value, &mut is_date) })?;
Ok(is_date)
}
pub fn is_error(&self) -> Result<bool> {
let mut result = false;
check_status!(unsafe { sys::napi_is_error(self.raw.env, self.raw.value, &mut result) })?;
Ok(result)
}
pub fn is_typedarray(&self) -> Result<bool> {
let mut result = false;
check_status!(unsafe { sys::napi_is_typedarray(self.raw.env, self.raw.value, &mut result) })?;
Ok(result)
}
pub fn is_dataview(&self) -> Result<bool> {
let mut result = false;
check_status!(unsafe { sys::napi_is_dataview(self.raw.env, self.raw.value, &mut result) })?;
Ok(result)
}
pub fn is_array(&self) -> Result<bool> {
let mut is_array = false;
check_status!(unsafe { sys::napi_is_array(self.raw.env, self.raw.value, &mut is_array) })?;
Ok(is_array)
}
pub fn is_buffer(&self) -> Result<bool> {
let mut is_buffer = false;
check_status!(unsafe { sys::napi_is_buffer(self.raw.env, self.raw.value, &mut is_buffer) })?;
Ok(is_buffer)
}
pub fn instanceof<Constructor: NapiRaw>(&self, constructor: Constructor) -> Result<bool> {
let mut result = false;
check_status!(unsafe {
sys::napi_instanceof(self.raw.env, self.raw.value, constructor.raw(), &mut result)
})?;
Ok(result)
}
}
impl NapiRaw for JsBigInt {

View File

@ -1,5 +1,3 @@
use std::convert::TryInto;
use serde::de::Visitor;
use serde::de::{DeserializeSeed, EnumAccess, MapAccess, SeqAccess, Unexpected, VariantAccess};
@ -7,7 +5,7 @@ use crate::bindgen_runtime::{BufferSlice, FromNapiValue};
#[cfg(feature = "napi6")]
use crate::JsBigInt;
use crate::{type_of, NapiValue, Value, ValueType};
use crate::{Error, JsBoolean, JsNumber, JsObject, JsString, JsUnknown, Result, Status};
use crate::{Error, JsBoolean, JsObject, JsString, JsUnknown, Result, Status};
use super::JsArrayBuffer;
@ -34,8 +32,7 @@ impl<'x> serde::de::Deserializer<'x> for &mut De<'_> {
visitor.visit_bool(js_boolean.get_value()?)
}
ValueType::Number => {
let js_number: f64 =
unsafe { JsNumber::from_raw_unchecked(self.0.env, self.0.value).try_into()? };
let js_number: f64 = unsafe { FromNapiValue::from_napi_value(self.0.env, self.0.value)? };
if (js_number.trunc() - js_number).abs() < f64::EPSILON {
visitor.visit_i64(js_number as i64)
} else {

View File

@ -125,7 +125,11 @@ pub trait JsValue: Sized {
/// Convert the value to an unknown
fn into_unknown(self) -> JsUnknown {
unsafe { JsUnknown::from_raw_unchecked(self.value().env, self.value().value) }
JsUnknown(Value {
env: self.value().env,
value: self.value().value,
value_type: ValueType::Unknown,
})
}
/// Coerce the value to a boolean
@ -138,20 +142,23 @@ pub trait JsValue: Sized {
unsafe { bool::from_napi_value(env, new_raw_value) }
}
fn coerce_to_number(self) -> Result<JsNumber> {
fn coerce_to_number(&self) -> Result<JsNumber> {
let mut new_raw_value = ptr::null_mut();
let env = self.value().env;
check_status!(unsafe {
sys::napi_coerce_to_number(env, self.value().value, &mut new_raw_value)
})?;
Ok(JsNumber(Value {
env,
value: new_raw_value,
value_type: ValueType::Number,
}))
Ok(JsNumber(
Value {
env,
value: new_raw_value,
value_type: ValueType::Number,
},
std::marker::PhantomData,
))
}
fn coerce_to_string(self) -> Result<JsString> {
fn coerce_to_string(&self) -> Result<JsString> {
let mut new_raw_value = ptr::null_mut();
let env = self.value().env;
check_status!(unsafe {
@ -687,16 +694,19 @@ macro_rules! impl_js_value_methods {
}))
}
pub fn coerce_to_number(self) -> Result<JsNumber> {
pub fn coerce_to_number<'env>(self) -> Result<JsNumber<'env>> {
let mut new_raw_value = ptr::null_mut();
check_status!(unsafe {
sys::napi_coerce_to_number(self.0.env, self.0.value, &mut new_raw_value)
})?;
Ok(JsNumber(Value {
env: self.0.env,
value: new_raw_value,
value_type: ValueType::Number,
}))
Ok(JsNumber(
Value {
env: self.0.env,
value: new_raw_value,
value_type: ValueType::Number,
},
std::marker::PhantomData,
))
}
pub fn coerce_to_string(self) -> Result<JsString> {
@ -1181,7 +1191,6 @@ impl_js_value_methods!(JsBuffer);
impl_js_value_methods!(JsArrayBuffer);
impl_js_value_methods!(JsTypedArray);
impl_js_value_methods!(JsDataView);
impl_js_value_methods!(JsNumber);
impl_js_value_methods!(JsString);
impl_js_value_methods!(JsObject);
#[cfg(feature = "napi5")]
@ -1205,7 +1214,6 @@ impl_napi_value_trait!(JsBuffer, Object);
impl_napi_value_trait!(JsArrayBuffer, Object);
impl_napi_value_trait!(JsTypedArray, Object);
impl_napi_value_trait!(JsDataView, Object);
impl_napi_value_trait!(JsNumber, Number);
impl_napi_value_trait!(JsString, String);
impl_napi_value_trait!(JsObject, Object);
#[cfg(feature = "napi5")]

View File

@ -1,16 +1,19 @@
use std::convert::TryFrom;
use super::Value;
use crate::bindgen_runtime::{TypeName, ValidateNapiValue};
use crate::{check_status, ValueType};
use crate::{sys, Error, Result};
use crate::{
bindgen_runtime::{FromNapiValue, TypeName, ValidateNapiValue},
check_status, sys, Error, JsValue, Result, Value, ValueType,
};
#[derive(Clone, Copy)]
pub struct JsNumber(pub(crate) Value);
pub struct JsNumber<'env>(
pub(crate) Value,
pub(crate) std::marker::PhantomData<&'env ()>,
);
impl TypeName for JsNumber {
impl TypeName for JsNumber<'_> {
fn type_name() -> &'static str {
"f64"
"number"
}
fn value_type() -> crate::ValueType {
@ -18,9 +21,28 @@ impl TypeName for JsNumber {
}
}
impl ValidateNapiValue for JsNumber {}
impl ValidateNapiValue for JsNumber<'_> {}
impl JsNumber {
impl JsValue for JsNumber<'_> {
fn value(&self) -> Value {
self.0
}
}
impl FromNapiValue for JsNumber<'_> {
unsafe fn from_napi_value(env: sys::napi_env, napi_val: sys::napi_value) -> Result<Self> {
Ok(JsNumber(
Value {
env,
value: napi_val,
value_type: ValueType::Number,
},
std::marker::PhantomData,
))
}
}
impl JsNumber<'_> {
pub fn get_uint32(&self) -> Result<u32> {
let mut result = 0;
check_status!(unsafe { sys::napi_get_value_uint32(self.0.env, self.0.value, &mut result) })?;
@ -46,7 +68,7 @@ impl JsNumber {
}
}
impl TryFrom<JsNumber> for u32 {
impl TryFrom<JsNumber<'_>> for u32 {
type Error = Error;
fn try_from(value: JsNumber) -> Result<u32> {
@ -56,7 +78,7 @@ impl TryFrom<JsNumber> for u32 {
}
}
impl TryFrom<JsNumber> for i32 {
impl TryFrom<JsNumber<'_>> for i32 {
type Error = Error;
fn try_from(value: JsNumber) -> Result<i32> {
@ -66,7 +88,7 @@ impl TryFrom<JsNumber> for i32 {
}
}
impl TryFrom<JsNumber> for i64 {
impl TryFrom<JsNumber<'_>> for i64 {
type Error = Error;
fn try_from(value: JsNumber) -> Result<i64> {
@ -76,7 +98,7 @@ impl TryFrom<JsNumber> for i64 {
}
}
impl TryFrom<JsNumber> for f64 {
impl TryFrom<JsNumber<'_>> for f64 {
type Error = Error;
fn try_from(value: JsNumber) -> Result<f64> {

View File

@ -1,10 +1,18 @@
use std::fmt::{self, Display};
use crate::sys;
use super::ValueType;
#[derive(Clone, Copy)]
#[derive(Debug, Clone, Copy)]
pub struct Value {
pub env: sys::napi_env,
pub value: sys::napi_value,
pub value_type: ValueType,
}
impl Display for Value {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "Value({:?})", self.value_type)
}
}

View File

@ -11,18 +11,18 @@ pub fn set_instance_data(env: Env) -> ContextlessResult<JsUndefined> {
}
#[contextless_function]
pub fn get_instance_data(env: Env) -> ContextlessResult<JsNumber> {
pub fn get_instance_data(env: Env) -> ContextlessResult<i64> {
if let Some(obj) = env.get_instance_data::<NativeObject>()? {
env.create_int64(obj.count).map(Some)
Ok(Some(obj.count))
} else {
Ok(None)
}
}
#[contextless_function]
pub fn get_wrong_type_instance_data(env: Env) -> ContextlessResult<JsNumber> {
pub fn get_wrong_type_instance_data(env: Env) -> ContextlessResult<i64> {
if let Some(count) = env.get_instance_data::<i32>()? {
env.create_int64(*count as i64).map(Some)
Ok(Some(*count as i64))
} else {
Ok(None)
}

View File

@ -16,14 +16,14 @@ impl ComputeFib {
impl Task for ComputeFib {
type Output = u32;
type JsValue = JsNumber;
type JsValue = u32;
fn compute(&mut self) -> Result<Self::Output> {
Ok(fibonacci_native(self.n))
}
fn resolve(&mut self, env: Env, output: Self::Output) -> Result<Self::JsValue> {
env.create_uint32(output)
fn resolve(&mut self, _: Env, output: Self::Output) -> Result<Self::JsValue> {
Ok(output)
}
}
@ -54,7 +54,7 @@ impl CountBufferLength {
impl Task for CountBufferLength {
type Output = usize;
type JsValue = JsNumber;
type JsValue = u32;
fn compute(&mut self) -> Result<Self::Output> {
if self.data.len() == 10 {
@ -63,8 +63,8 @@ impl Task for CountBufferLength {
Ok(self.data.len())
}
fn resolve(&mut self, env: Env, output: Self::Output) -> Result<Self::JsValue> {
env.create_uint32(output as _)
fn resolve(&mut self, _: Env, output: Self::Output) -> Result<Self::JsValue> {
Ok(output as u32)
}
fn reject(&mut self, _env: Env, err: Error) -> Result<Self::JsValue> {