From e56695daa89b7c53a88a691f35ee9a498caffbdf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bartek=20Iwa=C5=84czuk?= Date: Wed, 24 May 2023 15:41:43 +0200 Subject: [PATCH] fix(napi): add napi_async_init and napi_async_destroy (#19234) We don't have support for "AsyncContext" in "node:async_hooks" module, so these two APIs are just noops. Towards https://github.com/denoland/deno/issues/18610. --- cli/napi/async.rs | 19 +++++--- test_napi/make_callback_test.js | 53 ++++++++++++++++++++ test_napi/src/lib.rs | 2 + test_napi/src/make_callback.rs | 85 +++++++++++++++++++++++++++++++++ 4 files changed, 152 insertions(+), 7 deletions(-) create mode 100644 test_napi/make_callback_test.js create mode 100644 test_napi/src/make_callback.rs diff --git a/cli/napi/async.rs b/cli/napi/async.rs index 80d128063c..48de367280 100644 --- a/cli/napi/async.rs +++ b/cli/napi/async.rs @@ -2,6 +2,8 @@ use deno_runtime::deno_napi::*; +use crate::check_env; + #[repr(C)] pub struct AsyncWork { pub data: *mut c_void, @@ -69,19 +71,22 @@ fn napi_queue_async_work( napi_ok } -// TODO: Custom async operations. - +// NOTE: we don't support "async_hooks::AsyncContext" so these APIs are noops. #[napi_sym::napi_sym] fn napi_async_init( - _env: *mut Env, + env: *mut Env, _async_resource: napi_value, _async_resource_name: napi_value, - _result: *mut *mut (), + result: *mut *mut (), ) -> napi_status { - todo!() + check_env!(env); + *result = ptr::null_mut(); + napi_ok } #[napi_sym::napi_sym] -fn napi_async_destroy(_env: *mut Env, _async_context: *mut ()) -> napi_status { - todo!() +fn napi_async_destroy(env: *mut Env, async_context: *mut ()) -> napi_status { + check_env!(env); + assert!(async_context.is_null()); + napi_ok } diff --git a/test_napi/make_callback_test.js b/test_napi/make_callback_test.js new file mode 100644 index 0000000000..63ab18810d --- /dev/null +++ b/test_napi/make_callback_test.js @@ -0,0 +1,53 @@ +// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license. + +import { assertEquals, loadTestLibrary } from "./common.js"; + +const mc = loadTestLibrary(); + +Deno.test("napi makeCallback1", function () { + const resource = {}; + + let callCount = 0; + function cb() { + callCount++; + assertEquals(arguments.length, 0); + assertEquals(this, globalThis); + return 42; + } + assertEquals(mc.makeCallback(resource, globalThis, cb), 42); + assertEquals(callCount, 1); +}); + +Deno.test("napi makeCallback2", function () { + const resource = {}; + + let callCount = 0; + function cb(x) { + callCount++; + assertEquals(arguments.length, 1); + assertEquals(this, globalThis); + assertEquals(x, 1337); + return 42; + } + assertEquals(mc.makeCallback(resource, globalThis, cb, 1337), 42); + assertEquals(callCount, 1); +}); + +Deno.test("napi makeCallback3", function () { + const resource = {}; + + let callCount = 0; + + function multiArgFunc(arg1, arg2, arg3) { + callCount++; + assertEquals(arg1, 1); + assertEquals(arg2, 2); + assertEquals(arg3, 3); + return 42; + } + assertEquals( + mc.makeCallback(resource, globalThis, multiArgFunc, 1, 2, 3), + 42, + ); + assertEquals(callCount, 1); +}); diff --git a/test_napi/src/lib.rs b/test_napi/src/lib.rs index 8fa7d9ef69..9342656fda 100644 --- a/test_napi/src/lib.rs +++ b/test_napi/src/lib.rs @@ -16,6 +16,7 @@ pub mod date; pub mod env; pub mod error; pub mod finalizer; +pub mod make_callback; pub mod mem; pub mod numbers; pub mod object_wrap; @@ -162,6 +163,7 @@ unsafe extern "C" fn napi_register_module_v1( mem::init(env, exports); bigint::init(env, exports); symbol::init(env, exports); + make_callback::init(env, exports); init_cleanup_hook(env, exports); diff --git a/test_napi/src/make_callback.rs b/test_napi/src/make_callback.rs new file mode 100644 index 0000000000..c8d2b3342a --- /dev/null +++ b/test_napi/src/make_callback.rs @@ -0,0 +1,85 @@ +// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license. + +use crate::assert_napi_ok; +use crate::cstr; +use napi_sys::ValueType::napi_function; +use napi_sys::*; +use std::ptr; + +extern "C" fn make_callback( + env: napi_env, + info: napi_callback_info, +) -> napi_value { + const MAX_ARGUMENTS: usize = 10; + const RESERVED_ARGUMENTS: usize = 3; + + let mut args = [std::ptr::null_mut(); MAX_ARGUMENTS]; + let mut argc = MAX_ARGUMENTS; + assert_napi_ok!(napi_get_cb_info( + env, + info, + &mut argc, + args.as_mut_ptr(), + ptr::null_mut(), + ptr::null_mut(), + )); + + assert!(argc > 0); + let resource = args[0]; + let recv = args[1]; + let func = args[2]; + + let mut argv: Vec = Vec::new(); + argv.resize(MAX_ARGUMENTS - RESERVED_ARGUMENTS, ptr::null_mut()); + for i in RESERVED_ARGUMENTS..argc { + argv[i - RESERVED_ARGUMENTS] = args[i]; + } + + let mut func_type: napi_valuetype = -1; + assert_napi_ok!(napi_typeof(env, func, &mut func_type)); + + let mut resource_name = ptr::null_mut(); + assert_napi_ok!(napi_create_string_utf8( + env, + cstr!("test"), + usize::MAX, + &mut resource_name + )); + + let mut context: napi_async_context = ptr::null_mut(); + assert_napi_ok!(napi_async_init(env, resource, resource_name, &mut context)); + + let mut result = ptr::null_mut(); + assert_eq!(func_type, napi_function); + assert_napi_ok!(napi_make_callback( + env, + context, + recv, + func, + argc - RESERVED_ARGUMENTS, + argv.as_mut_ptr(), + &mut result + )); + + assert_napi_ok!(napi_async_destroy(env, context)); + result +} + +pub fn init(env: napi_env, exports: napi_value) { + let mut fn_: napi_value = ptr::null_mut(); + + assert_napi_ok!(napi_create_function( + env, + ptr::null_mut(), + usize::MAX, + Some(make_callback), + ptr::null_mut(), + &mut fn_, + )); + assert_napi_ok!(napi_set_named_property( + env, + exports, + cstr!("makeCallback"), + fn_ + )); +}