feat(napi-derive): allow partial implement From/To Napivalue for Object (#1448)
This commit is contained in:
parent
e79eb34118
commit
c8352a1fb0
9 changed files with 99 additions and 27 deletions
|
@ -80,6 +80,8 @@ pub struct NapiStruct {
|
|||
pub fields: Vec<NapiStructField>,
|
||||
pub is_tuple: bool,
|
||||
pub kind: NapiStructKind,
|
||||
pub object_from_js: bool,
|
||||
pub object_to_js: bool,
|
||||
pub js_mod: Option<String>,
|
||||
pub comments: Vec<String>,
|
||||
pub implement_iterator: bool,
|
||||
|
|
|
@ -558,6 +558,46 @@ impl NapiStruct {
|
|||
}
|
||||
};
|
||||
|
||||
let to_napi_value = if self.object_to_js {
|
||||
quote! {
|
||||
impl napi::bindgen_prelude::ToNapiValue for #name {
|
||||
unsafe fn to_napi_value(env: napi::bindgen_prelude::sys::napi_env, val: #name) -> napi::bindgen_prelude::Result<napi::bindgen_prelude::sys::napi_value> {
|
||||
let env_wrapper = napi::bindgen_prelude::Env::from(env);
|
||||
let mut obj = env_wrapper.create_object()?;
|
||||
|
||||
let #destructed_fields = val;
|
||||
#(#obj_field_setters)*
|
||||
|
||||
napi::bindgen_prelude::Object::to_napi_value(env, obj)
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
quote! {}
|
||||
};
|
||||
|
||||
let from_napi_value = if self.object_from_js {
|
||||
quote! {
|
||||
impl napi::bindgen_prelude::FromNapiValue for #name {
|
||||
unsafe fn from_napi_value(
|
||||
env: napi::bindgen_prelude::sys::napi_env,
|
||||
napi_val: napi::bindgen_prelude::sys::napi_value
|
||||
) -> napi::bindgen_prelude::Result<Self> {
|
||||
let env_wrapper = napi::bindgen_prelude::Env::from(env);
|
||||
let mut obj = napi::bindgen_prelude::Object::from_napi_value(env, napi_val)?;
|
||||
|
||||
#(#obj_field_getters)*
|
||||
|
||||
let val = #destructed_fields;
|
||||
|
||||
Ok(val)
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
quote! {}
|
||||
};
|
||||
|
||||
quote! {
|
||||
impl napi::bindgen_prelude::TypeName for #name {
|
||||
fn type_name() -> &'static str {
|
||||
|
@ -569,33 +609,9 @@ impl NapiStruct {
|
|||
}
|
||||
}
|
||||
|
||||
impl napi::bindgen_prelude::ToNapiValue for #name {
|
||||
unsafe fn to_napi_value(env: napi::bindgen_prelude::sys::napi_env, val: #name) -> napi::bindgen_prelude::Result<napi::bindgen_prelude::sys::napi_value> {
|
||||
let env_wrapper = napi::bindgen_prelude::Env::from(env);
|
||||
let mut obj = env_wrapper.create_object()?;
|
||||
#to_napi_value
|
||||
|
||||
let #destructed_fields = val;
|
||||
#(#obj_field_setters)*
|
||||
|
||||
napi::bindgen_prelude::Object::to_napi_value(env, obj)
|
||||
}
|
||||
}
|
||||
|
||||
impl napi::bindgen_prelude::FromNapiValue for #name {
|
||||
unsafe fn from_napi_value(
|
||||
env: napi::bindgen_prelude::sys::napi_env,
|
||||
napi_val: napi::bindgen_prelude::sys::napi_value
|
||||
) -> napi::bindgen_prelude::Result<Self> {
|
||||
let env_wrapper = napi::bindgen_prelude::Env::from(env);
|
||||
let mut obj = napi::bindgen_prelude::Object::from_napi_value(env, napi_val)?;
|
||||
|
||||
#(#obj_field_getters)*
|
||||
|
||||
let val = #destructed_fields;
|
||||
|
||||
Ok(val)
|
||||
}
|
||||
}
|
||||
#from_napi_value
|
||||
|
||||
impl napi::bindgen_prelude::ValidateNapiValue for #name {}
|
||||
}
|
||||
|
|
|
@ -56,6 +56,8 @@ macro_rules! attrgen {
|
|||
(strict, Strict(Span)),
|
||||
(return_if_invalid, ReturnIfInvalid(Span)),
|
||||
(object, Object(Span)),
|
||||
(object_from_js, ObjectFromJs(Span, Option<bool>)),
|
||||
(object_to_js, ObjectToJs(Span, Option<bool>)),
|
||||
(custom_finalize, CustomFinalize(Span)),
|
||||
(namespace, Namespace(Span, String, Span)),
|
||||
(iterator, Iterator(Span)),
|
||||
|
|
|
@ -995,6 +995,8 @@ impl ConvertToAST for syn::ItemStruct {
|
|||
fields,
|
||||
is_tuple,
|
||||
kind: struct_kind,
|
||||
object_from_js: opts.object_from_js(),
|
||||
object_to_js: opts.object_to_js(),
|
||||
js_mod: namespace,
|
||||
comments: extract_doc_comments(&self.attrs),
|
||||
implement_iterator,
|
||||
|
|
|
@ -172,6 +172,11 @@ Generated by [AVA](https://avajs.dev).
|
|||
}␊
|
||||
export function createObjWithProperty(): { value: ArrayBuffer, get getter(): number }␊
|
||||
export function getterFromObj(): number␊
|
||||
export interface ObjectOnlyFromJs {␊
|
||||
count: number␊
|
||||
callback: (err: Error | null, value: number) => any␊
|
||||
}␊
|
||||
export function receiveObjectOnlyFromJs(obj: { count: number, callback: (err: Error | null, count: number) => void }): void␊
|
||||
export function asyncPlus100(p: Promise<number>): Promise<number>␊
|
||||
/** This is an interface for package.json */␊
|
||||
export interface PackageJson {␊
|
||||
|
|
Binary file not shown.
|
@ -89,6 +89,7 @@ import {
|
|||
returnJsFunction,
|
||||
testSerdeRoundtrip,
|
||||
createObjWithProperty,
|
||||
receiveObjectOnlyFromJs,
|
||||
dateToNumber,
|
||||
chronoDateToMillis,
|
||||
derefUint8Array,
|
||||
|
@ -816,6 +817,22 @@ Napi4Test('accept ThreadsafeFunction Fatal', async (t) => {
|
|||
})
|
||||
})
|
||||
|
||||
Napi4Test('object only from js', (t) => {
|
||||
return new Promise((resolve, reject) => {
|
||||
receiveObjectOnlyFromJs({
|
||||
count: 100,
|
||||
callback: (err: Error | null, count: number) => {
|
||||
if (err) {
|
||||
reject(err)
|
||||
} else {
|
||||
t.is(count, 100)
|
||||
resolve()
|
||||
}
|
||||
},
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
const Napi5Test = Number(process.versions.napi) >= 5 ? test : test.skip
|
||||
|
||||
Napi5Test('Date test', (t) => {
|
||||
|
|
5
examples/napi/index.d.ts
vendored
5
examples/napi/index.d.ts
vendored
|
@ -162,6 +162,11 @@ export interface TsTypeChanged {
|
|||
}
|
||||
export function createObjWithProperty(): { value: ArrayBuffer, get getter(): number }
|
||||
export function getterFromObj(): number
|
||||
export interface ObjectOnlyFromJs {
|
||||
count: number
|
||||
callback: (err: Error | null, value: number) => any
|
||||
}
|
||||
export function receiveObjectOnlyFromJs(obj: { count: number, callback: (err: Error | null, count: number) => void }): void
|
||||
export function asyncPlus100(p: Promise<number>): Promise<number>
|
||||
/** This is an interface for package.json */
|
||||
export interface PackageJson {
|
||||
|
|
|
@ -1,4 +1,7 @@
|
|||
use napi::{bindgen_prelude::*, JsGlobal, JsNull, JsObject, JsUndefined, Property};
|
||||
use napi::{
|
||||
bindgen_prelude::*, threadsafe_function::ThreadsafeFunction, JsGlobal, JsNull, JsObject,
|
||||
JsUndefined, Property,
|
||||
};
|
||||
|
||||
#[napi]
|
||||
fn list_obj_keys(obj: Object) -> Vec<String> {
|
||||
|
@ -101,3 +104,23 @@ pub fn create_obj_with_property(env: Env) -> Result<JsObject> {
|
|||
fn getter_from_obj() -> u32 {
|
||||
42
|
||||
}
|
||||
|
||||
#[napi(object, object_to_js = false)]
|
||||
struct ObjectOnlyFromJs {
|
||||
pub count: u32,
|
||||
pub callback: ThreadsafeFunction<u32>,
|
||||
}
|
||||
|
||||
#[napi]
|
||||
fn receive_object_only_from_js(
|
||||
#[napi(ts_arg_type = "{ count: number, callback: (err: Error | null, count: number) => void }")]
|
||||
obj: ObjectOnlyFromJs,
|
||||
) {
|
||||
let ObjectOnlyFromJs { callback, count } = obj;
|
||||
std::thread::spawn(move || {
|
||||
callback.call(
|
||||
Ok(count),
|
||||
napi::threadsafe_function::ThreadsafeFunctionCallMode::NonBlocking,
|
||||
);
|
||||
});
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue