From bcf5e14aa89b03896787513dfce5ed94e5f8ef9f Mon Sep 17 00:00:00 2001 From: LongYinan Date: Mon, 5 May 2025 23:38:46 +0800 Subject: [PATCH] feat(napi): add from_napi_value for Ref (#2603) --- .github/workflows/test-release.yaml | 2 +- .../src/bindgen_runtime/async_iterator.rs | 27 +++++++++--------- crates/napi/src/env.rs | 4 +-- crates/napi/src/js_values/value_ref.rs | 13 ++++++++- crates/napi/src/threadsafe_function.rs | 7 ++++- .../__tests__/__snapshots__/values.spec.ts.md | 2 ++ .../__snapshots__/values.spec.ts.snap | Bin 6453 -> 6478 bytes examples/napi/__tests__/values.spec.ts | 17 +++++++++++ examples/napi/example.wasi-browser.js | 1 + examples/napi/example.wasi.cjs | 1 + examples/napi/index.cjs | 1 + examples/napi/index.d.cts | 2 ++ examples/napi/src/threadsafe_function.rs | 22 ++++++++++++++ memory-testing/src/lib.rs | 2 +- 14 files changed, 81 insertions(+), 20 deletions(-) diff --git a/.github/workflows/test-release.yaml b/.github/workflows/test-release.yaml index 1ce6ea2a..06f4b4a8 100644 --- a/.github/workflows/test-release.yaml +++ b/.github/workflows/test-release.yaml @@ -631,7 +631,7 @@ jobs: with: operating_system: freebsd version: '14.2' - memory: 8G + memory: 12G cpu_count: 3 environment_variables: 'DEBUG RUSTUP_IO_THREADS' shell: bash diff --git a/crates/napi/src/bindgen_runtime/async_iterator.rs b/crates/napi/src/bindgen_runtime/async_iterator.rs index 350efd19..94c291e3 100644 --- a/crates/napi/src/bindgen_runtime/async_iterator.rs +++ b/crates/napi/src/bindgen_runtime/async_iterator.rs @@ -278,20 +278,19 @@ fn generator_next_fn( }; let env = Env::from_raw(env); - let promise: crate::bindgen_runtime::PromiseRaw<'_, Option> = env - .spawn_future_with_callback(item, |env, value| { - if let Some(v) = value { - let mut obj = Object::new(env.0)?; - obj.set("value", v)?; - obj.set("done", false)?; - Ok(obj) - } else { - let mut obj = Object::new(env.0)?; - obj.set("value", ())?; - obj.set("done", true)?; - Ok(obj) - } - })?; + let promise = env.spawn_future_with_callback(item, |env, value| { + if let Some(v) = value { + let mut obj = Object::new(env.0)?; + obj.set("value", v)?; + obj.set("done", false)?; + Ok(obj) + } else { + let mut obj = Object::new(env.0)?; + obj.set("value", ())?; + obj.set("done", true)?; + Ok(obj) + } + })?; Ok(promise.inner) } diff --git a/crates/napi/src/env.rs b/crates/napi/src/env.rs index c3a61506..f8f91e32 100644 --- a/crates/napi/src/env.rs +++ b/crates/napi/src/env.rs @@ -1107,7 +1107,7 @@ impl Env { /// Spawn a future with a callback /// So you can access the `Env` and resolved value after the future completed pub fn spawn_future_with_callback< - T: 'static + Send + ToNapiValue, + T: 'static + Send, V: ToNapiValue, F: 'static + Send + Future>, R: 'static + FnOnce(Env, T) -> Result, @@ -1115,7 +1115,7 @@ impl Env { &self, fut: F, callback: R, - ) -> Result> { + ) -> Result> { use crate::tokio_runtime; let promise = tokio_runtime::execute_tokio_future(self.0, fut, move |env, val| unsafe { diff --git a/crates/napi/src/js_values/value_ref.rs b/crates/napi/src/js_values/value_ref.rs index 1d5612fa..b83e9eec 100644 --- a/crates/napi/src/js_values/value_ref.rs +++ b/crates/napi/src/js_values/value_ref.rs @@ -19,7 +19,11 @@ unsafe impl Sync for Ref {} impl Ref { pub fn new(env: &Env, value: &T) -> Result> { let mut raw_ref = ptr::null_mut(); - check_status!(unsafe { sys::napi_create_reference(env.0, value.raw(), 1, &mut raw_ref) })?; + check_status!( + unsafe { sys::napi_create_reference(env.0, value.raw(), 1, &mut raw_ref) }, + "Create napi_ref from {} failed", + std::any::type_name::() + )?; Ok(Ref { raw_ref, taken: false, @@ -66,6 +70,13 @@ impl Ref { } } +impl FromNapiValue for Ref { + unsafe fn from_napi_value(env: sys::napi_env, value: sys::napi_value) -> Result { + let val = T::from_napi_value(env, value)?; + Ref::new(&Env::from_raw(env), &val) + } +} + impl ToNapiValue for Ref { unsafe fn to_napi_value(env: sys::napi_env, val: Self) -> Result { let mut result = ptr::null_mut(); diff --git a/crates/napi/src/threadsafe_function.rs b/crates/napi/src/threadsafe_function.rs index 5ffc099a..19c3c106 100644 --- a/crates/napi/src/threadsafe_function.rs +++ b/crates/napi/src/threadsafe_function.rs @@ -1,5 +1,6 @@ #![allow(clippy::single_component_path_imports)] +use std::convert::identity; use std::marker::PhantomData; use std::os::raw::c_void; use std::ptr::{self, null_mut}; @@ -492,7 +493,7 @@ impl< "Receive value from threadsafe function sender failed", ) }) - .and_then(|ret| ret) + .and_then(identity) } } @@ -771,6 +772,10 @@ fn handle_call_js_cb_status(status: sys::napi_status, raw_env: sys::napi_env) { } } +/// This is a placeholder type that is used to indicate that the return value of a threadsafe function is unknown. +/// Use this type when you don't care about the return value of a threadsafe function. +/// +/// And you can't get the value of it as well because it's just a placeholder. pub struct UnknownReturnValue; impl TypeName for UnknownReturnValue { diff --git a/examples/napi/__tests__/__snapshots__/values.spec.ts.md b/examples/napi/__tests__/__snapshots__/values.spec.ts.md index 740a4ec1..ec4acbc3 100644 --- a/examples/napi/__tests__/__snapshots__/values.spec.ts.md +++ b/examples/napi/__tests__/__snapshots__/values.spec.ts.md @@ -390,6 +390,8 @@ Generated by [AVA](https://avajs.dev). ␊ export declare function call2(callback: (arg0: number, arg1: number) => number, arg1: number, arg2: number): number␊ ␊ + export declare function callAsyncWithUnknownReturnValue(tsfn: ((err: Error | null, arg: number) => Ref)): Promise␊ + ␊ export declare function callbackReturnPromise(functionInput: () => T | Promise, callback: (err: Error | null, result: T) => void): T | Promise␊ ␊ export declare function callbackReturnPromiseAndSpawn(jsFunc: (arg0: string) => Promise): Promise␊ diff --git a/examples/napi/__tests__/__snapshots__/values.spec.ts.snap b/examples/napi/__tests__/__snapshots__/values.spec.ts.snap index 208646c7b40e702149c7d7aac066cbcdc46660b7..a2213b4b288c9b008ed34e8caa232518feb3f425 100644 GIT binary patch literal 6478 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 literal 6453 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 { await new Promise((resolve) => setTimeout(resolve, 400)) }) +Napi4Test('call async with unknown return value', async (t) => { + await new Promise((resolve, reject) => { + return callAsyncWithUnknownReturnValue((err, value) => { + if (err) { + reject(err) + } else { + resolve(value) + t.is(value, 42) + return {} + } + }).then((result) => { + t.is(result, 110) + }) + }) +}) + Napi4Test('object only from js', (t) => { return new Promise((resolve, reject) => { receiveObjectOnlyFromJs({ diff --git a/examples/napi/example.wasi-browser.js b/examples/napi/example.wasi-browser.js index 0a3a3097..07e36e28 100644 --- a/examples/napi/example.wasi-browser.js +++ b/examples/napi/example.wasi-browser.js @@ -139,6 +139,7 @@ export const buildThreadsafeFunctionFromFunctionCalleeHandle = __napiModule.expo export const call0 = __napiModule.exports.call0 export const call1 = __napiModule.exports.call1 export const call2 = __napiModule.exports.call2 +export const callAsyncWithUnknownReturnValue = __napiModule.exports.callAsyncWithUnknownReturnValue export const callbackReturnPromise = __napiModule.exports.callbackReturnPromise export const callbackReturnPromiseAndSpawn = __napiModule.exports.callbackReturnPromiseAndSpawn export const callCatchOnPromise = __napiModule.exports.callCatchOnPromise diff --git a/examples/napi/example.wasi.cjs b/examples/napi/example.wasi.cjs index 054dd70c..955c24c9 100644 --- a/examples/napi/example.wasi.cjs +++ b/examples/napi/example.wasi.cjs @@ -163,6 +163,7 @@ module.exports.buildThreadsafeFunctionFromFunctionCalleeHandle = __napiModule.ex module.exports.call0 = __napiModule.exports.call0 module.exports.call1 = __napiModule.exports.call1 module.exports.call2 = __napiModule.exports.call2 +module.exports.callAsyncWithUnknownReturnValue = __napiModule.exports.callAsyncWithUnknownReturnValue module.exports.callbackReturnPromise = __napiModule.exports.callbackReturnPromise module.exports.callbackReturnPromiseAndSpawn = __napiModule.exports.callbackReturnPromiseAndSpawn module.exports.callCatchOnPromise = __napiModule.exports.callCatchOnPromise diff --git a/examples/napi/index.cjs b/examples/napi/index.cjs index 1add9d4a..c555aa57 100644 --- a/examples/napi/index.cjs +++ b/examples/napi/index.cjs @@ -453,6 +453,7 @@ module.exports.buildThreadsafeFunctionFromFunctionCalleeHandle = nativeBinding.b module.exports.call0 = nativeBinding.call0 module.exports.call1 = nativeBinding.call1 module.exports.call2 = nativeBinding.call2 +module.exports.callAsyncWithUnknownReturnValue = nativeBinding.callAsyncWithUnknownReturnValue module.exports.callbackReturnPromise = nativeBinding.callbackReturnPromise module.exports.callbackReturnPromiseAndSpawn = nativeBinding.callbackReturnPromiseAndSpawn module.exports.callCatchOnPromise = nativeBinding.callCatchOnPromise diff --git a/examples/napi/index.d.cts b/examples/napi/index.d.cts index af02258a..46738df0 100644 --- a/examples/napi/index.d.cts +++ b/examples/napi/index.d.cts @@ -352,6 +352,8 @@ export declare function call1(callback: (arg: number) => number, arg: number): n export declare function call2(callback: (arg0: number, arg1: number) => number, arg1: number, arg2: number): number +export declare function callAsyncWithUnknownReturnValue(tsfn: ((err: Error | null, arg: number) => Ref)): Promise + export declare function callbackReturnPromise(functionInput: () => T | Promise, callback: (err: Error | null, result: T) => void): T | Promise export declare function callbackReturnPromiseAndSpawn(jsFunc: (arg0: string) => Promise): Promise diff --git a/examples/napi/src/threadsafe_function.rs b/examples/napi/src/threadsafe_function.rs index 723eee89..7a71331f 100644 --- a/examples/napi/src/threadsafe_function.rs +++ b/examples/napi/src/threadsafe_function.rs @@ -3,6 +3,7 @@ use std::{sync::Arc, thread, time::Duration}; use napi::{ bindgen_prelude::*, threadsafe_function::{ThreadsafeFunction, ThreadsafeFunctionCallMode, UnknownReturnValue}, + Ref, }; use crate::class::Animal; @@ -170,6 +171,27 @@ pub async fn tsfn_return_promise_timeout( } } +#[napi] +pub fn call_async_with_unknown_return_value( + env: &Env, + tsfn: ThreadsafeFunction>, +) -> Result> { + env.spawn_future_with_callback( + async move { + let return_value = tsfn.call_async(Ok(42)).await?; + Ok(return_value) + }, + |env, mut value| { + let return_value = value.get_value(&env)?; + value.unref(&env)?; + match return_value.get_type()? { + ValueType::Object => Ok(110), + _ => Ok(100), + } + }, + ) +} + #[napi] pub async fn tsfn_throw_from_js(tsfn: ThreadsafeFunction>) -> napi::Result { tsfn.call_async(Ok(42)).await?.await diff --git a/memory-testing/src/lib.rs b/memory-testing/src/lib.rs index b02fbe35..cb09ed3a 100644 --- a/memory-testing/src/lib.rs +++ b/memory-testing/src/lib.rs @@ -42,7 +42,7 @@ pub struct Room { } #[napi] -pub fn test_async(env: &Env) -> napi::Result> { +pub fn test_async(env: &Env) -> napi::Result> { let data = serde_json::json!({ "findFirstBooking": { "id": "ckovh15xa104945sj64rdk8oas",