mirror of
https://github.com/napi-rs/napi-rs.git
synced 2025-12-08 19:56:07 +00:00
feat(napi): add from_napi_value for Ref<T: FromNapiValue> (#2603)
This commit is contained in:
parent
d942a6bab9
commit
bcf5e14aa8
2
.github/workflows/test-release.yaml
vendored
2
.github/workflows/test-release.yaml
vendored
@ -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
|
||||
|
||||
@ -278,20 +278,19 @@ fn generator_next_fn<T: AsyncGenerator>(
|
||||
};
|
||||
|
||||
let env = Env::from_raw(env);
|
||||
let promise: crate::bindgen_runtime::PromiseRaw<'_, Option<T::Yield>> = 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)
|
||||
}
|
||||
|
||||
|
||||
@ -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<Output = Result<T>>,
|
||||
R: 'static + FnOnce(Env, T) -> Result<V>,
|
||||
@ -1115,7 +1115,7 @@ impl Env {
|
||||
&self,
|
||||
fut: F,
|
||||
callback: R,
|
||||
) -> Result<PromiseRaw<T>> {
|
||||
) -> Result<PromiseRaw<V>> {
|
||||
use crate::tokio_runtime;
|
||||
|
||||
let promise = tokio_runtime::execute_tokio_future(self.0, fut, move |env, val| unsafe {
|
||||
|
||||
@ -19,7 +19,11 @@ unsafe impl<T> Sync for Ref<T> {}
|
||||
impl<T: NapiRaw> Ref<T> {
|
||||
pub fn new(env: &Env, value: &T) -> Result<Ref<T>> {
|
||||
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::<T>()
|
||||
)?;
|
||||
Ok(Ref {
|
||||
raw_ref,
|
||||
taken: false,
|
||||
@ -66,6 +70,13 @@ impl<T: 'static + FromNapiMutRef> Ref<T> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: FromNapiValue + NapiRaw> FromNapiValue for Ref<T> {
|
||||
unsafe fn from_napi_value(env: sys::napi_env, value: sys::napi_value) -> Result<Self> {
|
||||
let val = T::from_napi_value(env, value)?;
|
||||
Ref::new(&Env::from_raw(env), &val)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: 'static> ToNapiValue for Ref<T> {
|
||||
unsafe fn to_napi_value(env: sys::napi_env, val: Self) -> Result<sys::napi_value> {
|
||||
let mut result = ptr::null_mut();
|
||||
|
||||
@ -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 {
|
||||
|
||||
@ -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<unknown>)): Promise<number>␊
|
||||
␊
|
||||
export declare function callbackReturnPromise<T>(functionInput: () => T | Promise<T>, callback: (err: Error | null, result: T) => void): T | Promise<T>␊
|
||||
␊
|
||||
export declare function callbackReturnPromiseAndSpawn(jsFunc: (arg0: string) => Promise<string>): Promise<string>␊
|
||||
|
||||
Binary file not shown.
@ -230,6 +230,7 @@ import {
|
||||
getClassFromArray,
|
||||
extendsJavascriptError,
|
||||
shutdownRuntime,
|
||||
callAsyncWithUnknownReturnValue,
|
||||
} from '../index.cjs'
|
||||
|
||||
import { test } from './test.framework.js'
|
||||
@ -1390,6 +1391,22 @@ Napi4Test('threadsafe function return Promise and await in Rust', async (t) => {
|
||||
await new Promise((resolve) => setTimeout(resolve, 400))
|
||||
})
|
||||
|
||||
Napi4Test('call async with unknown return value', async (t) => {
|
||||
await new Promise<number>((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({
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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<unknown>)): Promise<number>
|
||||
|
||||
export declare function callbackReturnPromise<T>(functionInput: () => T | Promise<T>, callback: (err: Error | null, result: T) => void): T | Promise<T>
|
||||
|
||||
export declare function callbackReturnPromiseAndSpawn(jsFunc: (arg0: string) => Promise<string>): Promise<string>
|
||||
|
||||
@ -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<u32, Ref<Unknown>>,
|
||||
) -> Result<PromiseRaw<u32>> {
|
||||
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<u32, Promise<u32>>) -> napi::Result<u32> {
|
||||
tsfn.call_async(Ok(42)).await?.await
|
||||
|
||||
@ -42,7 +42,7 @@ pub struct Room {
|
||||
}
|
||||
|
||||
#[napi]
|
||||
pub fn test_async(env: &Env) -> napi::Result<napi::bindgen_prelude::PromiseRaw<String>> {
|
||||
pub fn test_async(env: &Env) -> napi::Result<napi::bindgen_prelude::PromiseRaw<()>> {
|
||||
let data = serde_json::json!({
|
||||
"findFirstBooking": {
|
||||
"id": "ckovh15xa104945sj64rdk8oas",
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user