Merge pull request #1064 from napi-rs/feature/obj-property-value

feat(napi): `with_value` method on `Property`
This commit is contained in:
LongYinan 2022-02-06 16:37:45 +08:00 committed by GitHub
commit 2cd105cfc6
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
9 changed files with 86 additions and 5 deletions

View file

@ -211,6 +211,38 @@ pub fn get_js_function(raw_fn: ExportRegisterCallback) -> Result<JsFunction> {
})
}
/// Get `C Callback` from defined Rust `fn`
/// ```rust
/// #[napi]
/// fn some_fn() -> u32 {
/// 1
/// }
///
/// #[napi]
/// fn create_obj(env: Env) -> Result<JsObject> {
/// let mut obj = env.create_object()?;
/// obj.define_property(&[Property::new("getter")?.with_getter(get_c_callback(some_fn_js_function)?)])?;
/// Ok(obj)
/// }
/// ```
///
/// ```js
/// console.log(createObj().getter) // 1
/// ```
///
pub fn get_c_callback(raw_fn: ExportRegisterCallback) -> Result<crate::Callback> {
FN_REGISTER_MAP
.borrow_mut()
.get(&raw_fn)
.and_then(|(_env, cb, _name)| *cb)
.ok_or_else(|| {
crate::Error::new(
crate::Status::InvalidArg,
"JavaScript function does not exists".to_owned(),
)
})
}
#[no_mangle]
unsafe extern "C" fn napi_register_module_v1(
env: sys::napi_env,

View file

@ -31,7 +31,7 @@ use serde::Serialize;
#[cfg(all(feature = "tokio_rt", feature = "napi4"))]
use std::future::Future;
pub type Callback = extern "C" fn(sys::napi_env, sys::napi_callback_info) -> sys::napi_value;
pub type Callback = unsafe extern "C" fn(sys::napi_env, sys::napi_callback_info) -> sys::napi_value;
#[derive(Clone, Copy)]
/// `Env` is used to represent a context that the underlying N-API implementation can use to persist VM-specific state.

View file

@ -2,18 +2,33 @@ use std::convert::From;
use std::ffi::CString;
use std::ptr;
use crate::{sys, Callback, Result};
use crate::{sys, Callback, NapiRaw, Result};
#[derive(Clone, Default)]
#[derive(Clone)]
pub struct Property {
pub name: CString,
getter: sys::napi_callback,
setter: sys::napi_callback,
method: sys::napi_callback,
attrs: PropertyAttributes,
value: sys::napi_value,
pub(crate) is_ctor: bool,
}
impl Default for Property {
fn default() -> Self {
Property {
name: Default::default(),
getter: Default::default(),
setter: Default::default(),
method: Default::default(),
attrs: Default::default(),
value: ptr::null_mut(),
is_ctor: Default::default(),
}
}
}
#[repr(i32)]
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub enum PropertyAttributes {
@ -75,6 +90,11 @@ impl Property {
self
}
pub fn with_value<T: NapiRaw>(mut self, value: &T) -> Self {
self.value = unsafe { T::raw(value) };
self
}
pub(crate) fn raw(&self) -> sys::napi_property_descriptor {
sys::napi_property_descriptor {
utf8name: self.name.as_ptr(),
@ -82,7 +102,7 @@ impl Property {
method: self.method,
getter: self.getter,
setter: self.setter,
value: ptr::null_mut(),
value: self.value,
attributes: self.attrs.into(),
data: ptr::null_mut(),
}

View file

@ -112,6 +112,8 @@ Generated by [AVA](https://avajs.dev).
typeOverride: object␊
typeOverrideOptional?: object␊
}␊
export function createObjWithProperty(): { value: ArrayBuffer, get getter(): number }␊
export function getterFromObj(): number␊
export function asyncPlus100(p: Promise<number>): Promise<number>
/** This is an interface for package.json */␊
export interface PackageJson {␊

View file

@ -81,6 +81,7 @@ import {
getStrFromObject,
returnJsFunction,
testSerdeRoundtrip,
createObjWithProperty,
} from '../'
test('export const', (t) => {
@ -220,6 +221,12 @@ test('get str from object', (t) => {
t.notThrows(() => getStrFromObject())
})
test('create object from Property', (t) => {
const obj = createObjWithProperty()
t.true(obj.value instanceof ArrayBuffer)
t.is(obj.getter, 42)
})
test('global', (t) => {
t.is(getGlobal(), global)
})

View file

@ -102,6 +102,8 @@ export interface TsTypeChanged {
typeOverride: object
typeOverrideOptional?: object
}
export function createObjWithProperty(): { value: ArrayBuffer, get getter(): number }
export function getterFromObj(): number
export function asyncPlus100(p: Promise<number>): Promise<number>
/** This is an interface for package.json */
export interface PackageJson {

View file

@ -1,3 +1,5 @@
#![allow(dead_code)]
#[macro_use]
extern crate napi_derive;
#[macro_use]

View file

@ -1,4 +1,4 @@
use napi::{bindgen_prelude::*, JsGlobal, JsNull, JsUndefined};
use napi::{bindgen_prelude::*, JsGlobal, JsNull, JsObject, JsUndefined, Property};
#[napi]
fn list_obj_keys(obj: Object) -> Vec<String> {
@ -85,3 +85,19 @@ pub struct TsTypeChanged {
#[napi(ts_type = "object")]
pub type_override_optional: Option<String>,
}
#[napi(ts_return_type = "{ value: ArrayBuffer, get getter(): number }")]
pub fn create_obj_with_property(env: Env) -> Result<JsObject> {
let mut obj = env.create_object()?;
let arraybuffer = env.create_arraybuffer(10)?.into_raw();
obj.define_properties(&[
Property::new("value")?.with_value(&arraybuffer),
Property::new("getter")?.with_getter(get_c_callback(getter_from_obj_js_function)?),
])?;
Ok(obj)
}
#[napi]
fn getter_from_obj() -> u32 {
42
}