From 3e5897a78bdfb7634eca06b5dcde256516b5cdb8 Mon Sep 17 00:00:00 2001 From: "Matthew \"strager\" Glazar" Date: Mon, 6 Sep 2021 19:53:11 -0700 Subject: [PATCH] src,test: allow creating Function with move-only functor Function::New fails to compile when given a move-only functor. For example, when constructing a callback function for Promise#then, a lambda might capture an ObjectReference. Creating a Function for such a lambda results in a compilation error. Tweak Function::New to work with move-only functors. For existing users of Function::New, this commit should not change behavior. --- napi-inl.h | 3 ++- test/function.cc | 20 ++++++++++++++++++++ test/function.js | 7 +++++++ 3 files changed, 29 insertions(+), 1 deletion(-) diff --git a/napi-inl.h b/napi-inl.h index a1d67ac17..52defe0ae 100644 --- a/napi-inl.h +++ b/napi-inl.h @@ -14,6 +14,7 @@ #include #include #include +#include namespace Napi { @@ -2154,7 +2155,7 @@ inline Function Function::New(napi_env env, void* data) { using ReturnType = decltype(cb(CallbackInfo(nullptr, nullptr))); using CbData = details::CallbackData; - auto callbackData = new CbData({ cb, data }); + auto callbackData = new CbData{std::move(cb), data}; napi_value value; napi_status status = CreateFunction(env, diff --git a/test/function.cc b/test/function.cc index 0fab27290..3c5033d8a 100644 --- a/test/function.cc +++ b/test/function.cc @@ -1,3 +1,4 @@ +#include #include "napi.h" #include "test_helper.h" @@ -271,5 +272,24 @@ Object InitFunction(Env env) { exports["callWithFunctionOperator"] = Function::New(env); result["templated"] = exports; + + exports = Object::New(env); + exports["lambdaWithNoCapture"] = + Function::New(env, [](const CallbackInfo& info) { + auto env = info.Env(); + return Boolean::New(env, true); + }); + exports["lambdaWithCapture"] = + Function::New(env, [data = 42](const CallbackInfo& info) { + auto env = info.Env(); + return Boolean::New(env, data == 42); + }); + exports["lambdaWithMoveOnlyCapture"] = Function::New( + env, [data = std::make_unique(42)](const CallbackInfo& info) { + auto env = info.Env(); + return Boolean::New(env, *data == 42); + }); + result["lambda"] = exports; + return result; } diff --git a/test/function.js b/test/function.js index 9c30e046d..7536f62e8 100644 --- a/test/function.js +++ b/test/function.js @@ -5,6 +5,7 @@ const assert = require('assert'); module.exports = require('./common').runTest(binding => { test(binding.function.plain); test(binding.function.templated); + testLambda(binding.function.lambda); }); function test(binding) { @@ -112,3 +113,9 @@ function test(binding) { binding.makeCallbackWithInvalidReceiver(() => {}); }); } + +function testLambda(binding) { + assert.ok(binding.lambdaWithNoCapture()); + assert.ok(binding.lambdaWithCapture()); + assert.ok(binding.lambdaWithMoveOnlyCapture()); +}