mirror of
https://github.com/napi-rs/napi-rs.git
synced 2025-12-08 19:56:07 +00:00
feat(napi): new handle scope API (#2650)
This commit is contained in:
parent
18816c710c
commit
92b094e487
@ -25,6 +25,7 @@ mod object;
|
||||
#[cfg(all(feature = "tokio_rt", feature = "napi4"))]
|
||||
mod promise;
|
||||
mod promise_raw;
|
||||
mod scope;
|
||||
#[cfg(feature = "serde-json")]
|
||||
mod serde;
|
||||
mod set;
|
||||
@ -52,6 +53,7 @@ pub use object::*;
|
||||
#[cfg(all(feature = "tokio_rt", feature = "napi4"))]
|
||||
pub use promise::*;
|
||||
pub use promise_raw::*;
|
||||
pub use scope::*;
|
||||
#[cfg(feature = "web_stream")]
|
||||
pub use stream::*;
|
||||
pub use string::*;
|
||||
|
||||
201
crates/napi/src/bindgen_runtime/js_values/scope.rs
Normal file
201
crates/napi/src/bindgen_runtime/js_values/scope.rs
Normal file
@ -0,0 +1,201 @@
|
||||
use std::ptr;
|
||||
|
||||
use crate::{check_status, sys, Env, JsValue, Result};
|
||||
|
||||
pub struct HandleScope {
|
||||
pub(crate) scope: sys::napi_handle_scope,
|
||||
}
|
||||
|
||||
impl HandleScope {
|
||||
pub fn create(env: &Env) -> Result<Self> {
|
||||
let mut scope = ptr::null_mut();
|
||||
check_status!(
|
||||
unsafe { sys::napi_open_handle_scope(env.0, &mut scope) },
|
||||
"Failed to open handle scope"
|
||||
)?;
|
||||
Ok(Self { scope })
|
||||
}
|
||||
|
||||
pub fn run<A, T>(self, arg: A, f: impl FnOnce(A) -> Result<T>) -> Result<T>
|
||||
where
|
||||
A: JsValuesTuple,
|
||||
{
|
||||
let env = arg.env();
|
||||
let ret = f(arg);
|
||||
check_status!(
|
||||
unsafe { sys::napi_close_handle_scope(env, self.scope) },
|
||||
"Failed to close handle scope"
|
||||
)?;
|
||||
ret
|
||||
}
|
||||
}
|
||||
|
||||
pub trait JsValuesTuple {
|
||||
fn env(&self) -> sys::napi_env;
|
||||
}
|
||||
|
||||
impl<'env, T: JsValue<'env>> JsValuesTuple for T {
|
||||
fn env(&self) -> sys::napi_env {
|
||||
self.value().env
|
||||
}
|
||||
}
|
||||
|
||||
impl<'env, T1: JsValue<'env>, T2: JsValue<'env>> JsValuesTuple for (T1, T2) {
|
||||
fn env(&self) -> sys::napi_env {
|
||||
self.0.value().env
|
||||
}
|
||||
}
|
||||
|
||||
impl<'env, T1: JsValue<'env>, T2: JsValue<'env>, T3: JsValue<'env>> JsValuesTuple for (T1, T2, T3) {
|
||||
fn env(&self) -> sys::napi_env {
|
||||
self.0.value().env
|
||||
}
|
||||
}
|
||||
|
||||
impl<'env, T1: JsValue<'env>, T2: JsValue<'env>, T3: JsValue<'env>, T4: JsValue<'env>> JsValuesTuple
|
||||
for (T1, T2, T3, T4)
|
||||
{
|
||||
fn env(&self) -> sys::napi_env {
|
||||
self.0.value().env
|
||||
}
|
||||
}
|
||||
|
||||
impl<
|
||||
'env,
|
||||
T1: JsValue<'env>,
|
||||
T2: JsValue<'env>,
|
||||
T3: JsValue<'env>,
|
||||
T4: JsValue<'env>,
|
||||
T5: JsValue<'env>,
|
||||
> JsValuesTuple for (T1, T2, T3, T4, T5)
|
||||
{
|
||||
fn env(&self) -> sys::napi_env {
|
||||
self.0.value().env
|
||||
}
|
||||
}
|
||||
|
||||
impl<
|
||||
'env,
|
||||
T1: JsValue<'env>,
|
||||
T2: JsValue<'env>,
|
||||
T3: JsValue<'env>,
|
||||
T4: JsValue<'env>,
|
||||
T5: JsValue<'env>,
|
||||
T6: JsValue<'env>,
|
||||
> JsValuesTuple for (T1, T2, T3, T4, T5, T6)
|
||||
{
|
||||
fn env(&self) -> sys::napi_env {
|
||||
self.0.value().env
|
||||
}
|
||||
}
|
||||
|
||||
impl<
|
||||
'env,
|
||||
T1: JsValue<'env>,
|
||||
T2: JsValue<'env>,
|
||||
T3: JsValue<'env>,
|
||||
T4: JsValue<'env>,
|
||||
T5: JsValue<'env>,
|
||||
T6: JsValue<'env>,
|
||||
T7: JsValue<'env>,
|
||||
> JsValuesTuple for (T1, T2, T3, T4, T5, T6, T7)
|
||||
{
|
||||
fn env(&self) -> sys::napi_env {
|
||||
self.0.value().env
|
||||
}
|
||||
}
|
||||
|
||||
impl<
|
||||
'env,
|
||||
T1: JsValue<'env>,
|
||||
T2: JsValue<'env>,
|
||||
T3: JsValue<'env>,
|
||||
T4: JsValue<'env>,
|
||||
T5: JsValue<'env>,
|
||||
T6: JsValue<'env>,
|
||||
T7: JsValue<'env>,
|
||||
T8: JsValue<'env>,
|
||||
> JsValuesTuple for (T1, T2, T3, T4, T5, T6, T7, T8)
|
||||
{
|
||||
fn env(&self) -> sys::napi_env {
|
||||
self.0.value().env
|
||||
}
|
||||
}
|
||||
|
||||
impl<
|
||||
'env,
|
||||
T1: JsValue<'env>,
|
||||
T2: JsValue<'env>,
|
||||
T3: JsValue<'env>,
|
||||
T4: JsValue<'env>,
|
||||
T5: JsValue<'env>,
|
||||
T6: JsValue<'env>,
|
||||
T7: JsValue<'env>,
|
||||
T8: JsValue<'env>,
|
||||
T9: JsValue<'env>,
|
||||
> JsValuesTuple for (T1, T2, T3, T4, T5, T6, T7, T8, T9)
|
||||
{
|
||||
fn env(&self) -> sys::napi_env {
|
||||
self.0.value().env
|
||||
}
|
||||
}
|
||||
|
||||
impl<
|
||||
'env,
|
||||
T1: JsValue<'env>,
|
||||
T2: JsValue<'env>,
|
||||
T3: JsValue<'env>,
|
||||
T4: JsValue<'env>,
|
||||
T5: JsValue<'env>,
|
||||
T6: JsValue<'env>,
|
||||
T7: JsValue<'env>,
|
||||
T8: JsValue<'env>,
|
||||
T9: JsValue<'env>,
|
||||
T10: JsValue<'env>,
|
||||
> JsValuesTuple for (T1, T2, T3, T4, T5, T6, T7, T8, T9, T10)
|
||||
{
|
||||
fn env(&self) -> sys::napi_env {
|
||||
self.0.value().env
|
||||
}
|
||||
}
|
||||
|
||||
impl<
|
||||
'env,
|
||||
T1: JsValue<'env>,
|
||||
T2: JsValue<'env>,
|
||||
T3: JsValue<'env>,
|
||||
T4: JsValue<'env>,
|
||||
T5: JsValue<'env>,
|
||||
T6: JsValue<'env>,
|
||||
T7: JsValue<'env>,
|
||||
T8: JsValue<'env>,
|
||||
T9: JsValue<'env>,
|
||||
T10: JsValue<'env>,
|
||||
T11: JsValue<'env>,
|
||||
> JsValuesTuple for (T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11)
|
||||
{
|
||||
fn env(&self) -> sys::napi_env {
|
||||
self.0.value().env
|
||||
}
|
||||
}
|
||||
|
||||
impl<
|
||||
'env,
|
||||
T1: JsValue<'env>,
|
||||
T2: JsValue<'env>,
|
||||
T3: JsValue<'env>,
|
||||
T4: JsValue<'env>,
|
||||
T5: JsValue<'env>,
|
||||
T6: JsValue<'env>,
|
||||
T7: JsValue<'env>,
|
||||
T8: JsValue<'env>,
|
||||
T9: JsValue<'env>,
|
||||
T10: JsValue<'env>,
|
||||
T11: JsValue<'env>,
|
||||
T12: JsValue<'env>,
|
||||
> JsValuesTuple for (T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12)
|
||||
{
|
||||
fn env(&self) -> sys::napi_env {
|
||||
self.0.value().env
|
||||
}
|
||||
}
|
||||
@ -824,6 +824,8 @@ Generated by [AVA](https://avajs.dev).
|
||||
value: number␊
|
||||
}␊
|
||||
␊
|
||||
export declare function shorterScope(arr: unknown[]): Array<number>␊
|
||||
␊
|
||||
export declare function shutdownRuntime(): void␊
|
||||
␊
|
||||
export declare function spawnThreadInThread(tsfn: ((err: Error | null, arg: number) => number)): void␊
|
||||
|
||||
Binary file not shown.
@ -232,6 +232,7 @@ import {
|
||||
extendsJavascriptError,
|
||||
shutdownRuntime,
|
||||
callAsyncWithUnknownReturnValue,
|
||||
shorterScope,
|
||||
} from '../index.cjs'
|
||||
// import other stuff in `#[napi(module_exports)]`
|
||||
import nativeAddon from '../index.cjs'
|
||||
@ -1660,3 +1661,8 @@ test('extends javascript error', (t) => {
|
||||
test('module exports', (t) => {
|
||||
t.is(nativeAddon.NAPI_RS_SYMBOL, Symbol.for('NAPI_RS_SYMBOL'))
|
||||
})
|
||||
|
||||
test('shorter scope', (t) => {
|
||||
const result = shorterScope(['hello', { foo: 'bar' }, 'world', true])
|
||||
t.deepEqual(result, [5, 1, 5, 0])
|
||||
})
|
||||
|
||||
@ -292,6 +292,7 @@ export const roundtripStr = __napiModule.exports.roundtripStr
|
||||
export const runScript = __napiModule.exports.runScript
|
||||
export const setNullByteProperty = __napiModule.exports.setNullByteProperty
|
||||
export const setSymbolInObj = __napiModule.exports.setSymbolInObj
|
||||
export const shorterScope = __napiModule.exports.shorterScope
|
||||
export const shutdownRuntime = __napiModule.exports.shutdownRuntime
|
||||
export const spawnThreadInThread = __napiModule.exports.spawnThreadInThread
|
||||
export const Status = __napiModule.exports.Status
|
||||
|
||||
@ -316,6 +316,7 @@ module.exports.roundtripStr = __napiModule.exports.roundtripStr
|
||||
module.exports.runScript = __napiModule.exports.runScript
|
||||
module.exports.setNullByteProperty = __napiModule.exports.setNullByteProperty
|
||||
module.exports.setSymbolInObj = __napiModule.exports.setSymbolInObj
|
||||
module.exports.shorterScope = __napiModule.exports.shorterScope
|
||||
module.exports.shutdownRuntime = __napiModule.exports.shutdownRuntime
|
||||
module.exports.spawnThreadInThread = __napiModule.exports.spawnThreadInThread
|
||||
module.exports.Status = __napiModule.exports.Status
|
||||
|
||||
@ -606,6 +606,7 @@ module.exports.roundtripStr = nativeBinding.roundtripStr
|
||||
module.exports.runScript = nativeBinding.runScript
|
||||
module.exports.setNullByteProperty = nativeBinding.setNullByteProperty
|
||||
module.exports.setSymbolInObj = nativeBinding.setSymbolInObj
|
||||
module.exports.shorterScope = nativeBinding.shorterScope
|
||||
module.exports.shutdownRuntime = nativeBinding.shutdownRuntime
|
||||
module.exports.spawnThreadInThread = nativeBinding.spawnThreadInThread
|
||||
module.exports.Status = nativeBinding.Status
|
||||
|
||||
@ -786,6 +786,8 @@ export interface Shared {
|
||||
value: number
|
||||
}
|
||||
|
||||
export declare function shorterScope(arr: unknown[]): Array<number>
|
||||
|
||||
export declare function shutdownRuntime(): void
|
||||
|
||||
export declare function spawnThreadInThread(tsfn: ((err: Error | null, arg: number) => number)): void
|
||||
|
||||
@ -80,6 +80,7 @@ mod number;
|
||||
mod object;
|
||||
mod promise;
|
||||
mod reference;
|
||||
mod scope;
|
||||
mod serde;
|
||||
mod set;
|
||||
mod shared;
|
||||
|
||||
21
examples/napi/src/scope.rs
Normal file
21
examples/napi/src/scope.rs
Normal file
@ -0,0 +1,21 @@
|
||||
use napi::{bindgen_prelude::*, JsString};
|
||||
|
||||
#[napi]
|
||||
pub fn shorter_scope(env: &Env, arr: Array) -> Result<Vec<u32>> {
|
||||
let len = arr.len();
|
||||
let mut result = Vec::with_capacity(len as usize);
|
||||
for i in 0..len {
|
||||
let scope = HandleScope::create(env)?;
|
||||
let value: Unknown = arr.get_element(i)?;
|
||||
let len = scope.run(value, |v| match v.get_type()? {
|
||||
ValueType::String => {
|
||||
let string = unsafe { v.cast::<JsString>() }?;
|
||||
Ok(string.utf8_len()? as u32)
|
||||
}
|
||||
ValueType::Object => Ok(1),
|
||||
_ => Ok(0),
|
||||
})?;
|
||||
result.push(len);
|
||||
}
|
||||
Ok(result)
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user