Skip to content

Commit

Permalink
refactor(rspack_napi): simplify the logic of JsRegExp
Browse files Browse the repository at this point in the history
  • Loading branch information
shulaoda committed Oct 29, 2024
1 parent 85bb238 commit c3b047d
Show file tree
Hide file tree
Showing 2 changed files with 27 additions and 71 deletions.
51 changes: 26 additions & 25 deletions crates/rspack_napi/src/js_values/js_reg_exp.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,10 @@
use std::fmt::Debug;

use napi::{
bindgen_prelude::{FromNapiValue, TypeName, ValidateNapiValue},
sys, Error, JsObject, NapiRaw, NapiValue, Result, Status,
bindgen_prelude::{FromNapiValue, Function, TypeName, ValidateNapiValue},
sys, Env, Error, JsObject, JsUnknown, NapiRaw, NapiValue, Result, Status,
};

use crate::utils::NapiTypeRef;

pub struct JsRegExp(JsObject);

impl Debug for JsRegExp {
Expand All @@ -31,6 +29,18 @@ impl JsRegExp {
}
}

impl ValidateNapiValue for JsRegExp {}

impl TypeName for JsRegExp {
fn type_name() -> &'static str {
"RegExp"
}

fn value_type() -> napi::ValueType {
napi::ValueType::Object
}
}

impl NapiRaw for JsRegExp {
unsafe fn raw(&self) -> sys::napi_value {
unsafe { self.0.raw() }
Expand All @@ -39,31 +49,22 @@ impl NapiRaw for JsRegExp {

impl FromNapiValue for JsRegExp {
unsafe fn from_napi_value(env: sys::napi_env, napi_val: sys::napi_value) -> Result<Self> {
// Safety: `JsObject::call_without_args` only leverages the `JsObject::raw` method.
// It's not necessarily have to be exactly an `JsObject` instance.
let js_object = unsafe { JsObject::from_raw_unchecked(env, napi_val) };
let ty = unsafe { NapiTypeRef::new(env, &js_object) }?;
if !ty.is_regex()? {
return Err(Error::new(
Status::InvalidArg,

let env = Env::from(env);
let global = env.get_global()?;
let regexp_constructor = global.get_named_property::<Function<JsUnknown, ()>>("RegExp")?;

if js_object.instanceof(regexp_constructor)? {
Ok(Self(js_object))
} else {
Err(Error::new(
Status::ObjectExpected,
format!(
"Expect value to be '[object RegExp]', but received {}",
ty.get_type()?
js_object.coerce_to_string()?.into_utf8()?.as_str()?
),
));
))
}
Ok(Self(unsafe { JsObject::from_napi_value(env, napi_val) }?))
}
}

impl ValidateNapiValue for JsRegExp {}

impl TypeName for JsRegExp {
fn type_name() -> &'static str {
"RegExp"
}

fn value_type() -> napi::ValueType {
napi::ValueType::Object
}
}
47 changes: 1 addition & 46 deletions crates/rspack_napi/src/utils.rs
Original file line number Diff line number Diff line change
@@ -1,49 +1,4 @@
use std::marker::PhantomData;

use napi::{
bindgen_prelude::FromNapiValue, sys, Env, JsFunction, JsObject, JsString, JsStringUtf8,
JsUnknown, NapiRaw, NapiValue, Result,
};

/// `Object.prototype.toString.call`
/// Safety: [napi::JsStringUtf8]'s lifetime is bound to `&T`
unsafe fn object_prototype_to_string_call<T: NapiRaw>(
raw_env: sys::napi_env,
obj: &T,
) -> Result<JsStringUtf8> {
let env = Env::from(raw_env);
let s: JsString = env
.get_global()?
// `Object` is a function, but we want to use it as an JSObject.
.get_named_property_unchecked::<JsObject>("Object")?
.get_named_property::<JsObject>("prototype")?
.get_named_property::<JsFunction>("toString")?
.call_without_args(Some(
// Safety: `JsObject::call_without_args` only leverages the `JsObject::raw` method.
// It's not necessarily have to be exactly an `JsObject` instance.
unsafe { &JsObject::from_raw_unchecked(raw_env, obj.raw()) },
))?
.try_into()?;
s.into_utf8()
}

pub struct NapiTypeRef<'r>(JsStringUtf8, PhantomData<&'r *mut ()>);

impl<'r> NapiTypeRef<'r> {
// Safety: This call would be successful when `val` is a valid `impl NapiRaw` and `env` is a valid `napi_env`.
pub unsafe fn new<T: NapiRaw>(env: sys::napi_env, val: &'r T) -> Result<NapiTypeRef<'r>> {
let s = unsafe { object_prototype_to_string_call(env, val) }?;
Ok(Self(s, PhantomData))
}

pub fn get_type(&self) -> Result<&str> {
self.0.as_str()
}

pub fn is_regex(&self) -> Result<bool> {
Ok(self.get_type()? == "[object RegExp]")
}
}
use napi::{bindgen_prelude::FromNapiValue, JsUnknown};

pub fn downcast_into<T: FromNapiValue + 'static>(o: JsUnknown) -> napi::Result<T> {
<T as FromNapiValue>::from_unknown(o)
Expand Down

0 comments on commit c3b047d

Please sign in to comment.