diff --git a/napi-inl.h b/napi-inl.h index 1cbf444c2..11a7882cf 100644 --- a/napi-inl.h +++ b/napi-inl.h @@ -2287,6 +2287,11 @@ inline MaybeOrValue Function::Call( return Call(Env().Undefined(), args); } +inline MaybeOrValue Function::Call( + const std::vector& args) const { + return Call(Env().Undefined(), args); +} + inline MaybeOrValue Function::Call(size_t argc, const napi_value* args) const { return Call(Env().Undefined(), argc, args); @@ -2302,6 +2307,27 @@ inline MaybeOrValue Function::Call( return Call(recv, args.size(), args.data()); } +inline MaybeOrValue Function::Call( + napi_value recv, const std::vector& args) const { + const size_t argc = args.size(); + const size_t stackArgsCount = 6; + napi_value stackArgs[stackArgsCount]; + std::vector heapArgs; + napi_value* argv; + if (argc <= stackArgsCount) { + argv = stackArgs; + } else { + heapArgs.resize(argc); + argv = heapArgs.data(); + } + + for (size_t index = 0; index < argc; index++) { + argv[index] = static_cast(args[index]); + } + + return Call(recv, argc, argv); +} + inline MaybeOrValue Function::Call(napi_value recv, size_t argc, const napi_value* args) const { diff --git a/napi.h b/napi.h index c0d0d6ef4..3ce33031b 100644 --- a/napi.h +++ b/napi.h @@ -1350,11 +1350,14 @@ namespace Napi { MaybeOrValue Call( const std::initializer_list& args) const; MaybeOrValue Call(const std::vector& args) const; + MaybeOrValue Call(const std::vector& args) const; MaybeOrValue Call(size_t argc, const napi_value* args) const; MaybeOrValue Call( napi_value recv, const std::initializer_list& args) const; MaybeOrValue Call(napi_value recv, const std::vector& args) const; + MaybeOrValue Call(napi_value recv, + const std::vector& args) const; MaybeOrValue Call(napi_value recv, size_t argc, const napi_value* args) const; diff --git a/test/function.cc b/test/function.cc index 3c5033d8a..0c1a2e703 100644 --- a/test/function.cc +++ b/test/function.cc @@ -69,6 +69,16 @@ Value CallWithVector(const CallbackInfo& info) { return MaybeUnwrap(func.Call(args)); } +Value CallWithVectorUsingCppWrapper(const CallbackInfo& info) { + Function func = info[0].As(); + std::vector args; + args.reserve(3); + args.push_back(info[1]); + args.push_back(info[2]); + args.push_back(info[3]); + return MaybeUnwrap(func.Call(args)); +} + Value CallWithCStyleArray(const CallbackInfo& info) { Function func = info[0].As(); std::vector args; @@ -108,6 +118,17 @@ Value CallWithReceiverAndVector(const CallbackInfo& info) { return MaybeUnwrap(func.Call(receiver, args)); } +Value CallWithReceiverAndVectorUsingCppWrapper(const CallbackInfo& info) { + Function func = info[0].As(); + Value receiver = info[1]; + std::vector args; + args.reserve(3); + args.push_back(info[2]); + args.push_back(info[3]); + args.push_back(info[4]); + return MaybeUnwrap(func.Call(receiver, args)); +} + Value CallWithInvalidReceiver(const CallbackInfo& info) { Function func = info[0].As(); return MaybeUnwrapOr(func.Call(Value(), std::initializer_list{}), @@ -213,11 +234,15 @@ Object InitFunction(Env env) { Function::New(env, ValueCallbackWithData, nullptr, &testData); exports["callWithArgs"] = Function::New(env, CallWithArgs); exports["callWithVector"] = Function::New(env, CallWithVector); + exports["callWithVectorUsingCppWrapper"] = + Function::New(env, CallWithVectorUsingCppWrapper); exports["callWithCStyleArray"] = Function::New(env, CallWithCStyleArray); exports["callWithReceiverAndCStyleArray"] = Function::New(env, CallWithReceiverAndCStyleArray); exports["callWithReceiverAndArgs"] = Function::New(env, CallWithReceiverAndArgs); exports["callWithReceiverAndVector"] = Function::New(env, CallWithReceiverAndVector); + exports["callWithReceiverAndVectorUsingCppWrapper"] = + Function::New(env, CallWithReceiverAndVectorUsingCppWrapper); exports["callWithInvalidReceiver"] = Function::New(env, CallWithInvalidReceiver); exports["callConstructorWithArgs"] = Function::New(env, CallConstructorWithArgs); exports["callConstructorWithVector"] = Function::New(env, CallConstructorWithVector); @@ -246,6 +271,8 @@ Object InitFunction(Env env) { Function::New(env, nullptr, &testData); exports["callWithArgs"] = Function::New(env); exports["callWithVector"] = Function::New(env); + exports["callWithVectorUsingCppWrapper"] = + Function::New(env); exports["callWithCStyleArray"] = Function::New(env); exports["callWithReceiverAndCStyleArray"] = Function::New(env); @@ -253,6 +280,8 @@ Object InitFunction(Env env) { Function::New(env); exports["callWithReceiverAndVector"] = Function::New(env); + exports["callWithReceiverAndVectorUsingCppWrapper"] = + Function::New(env); exports["callWithInvalidReceiver"] = Function::New(env); exports["callConstructorWithArgs"] = diff --git a/test/function.js b/test/function.js index 7536f62e8..bb5ed681b 100644 --- a/test/function.js +++ b/test/function.js @@ -8,71 +8,81 @@ module.exports = require('./common').runTest(binding => { testLambda(binding.function.lambda); }); -function test(binding) { +function test (binding) { assert.strictEqual(binding.emptyConstructor(true), true); assert.strictEqual(binding.emptyConstructor(false), false); let obj = {}; assert.deepStrictEqual(binding.voidCallback(obj), undefined); - assert.deepStrictEqual(obj, { "foo": "bar" }); + assert.deepStrictEqual(obj, { foo: 'bar' }); - assert.deepStrictEqual(binding.valueCallback(), { "foo": "bar" }); + assert.deepStrictEqual(binding.valueCallback(), { foo: 'bar' }); let args = null; let ret = null; let receiver = null; - function testFunction() { + function testFunction () { receiver = this; args = [].slice.call(arguments); return ret; } - function testConstructor() { + function testConstructor () { args = [].slice.call(arguments); } - function makeCallbackTestFunction(receiver, expectedOne, expectedTwo, expectedThree) { - return function callback(one, two, three) { + function makeCallbackTestFunction (receiver, expectedOne, expectedTwo, expectedThree) { + return function callback (one, two, three) { assert.strictEqual(this, receiver); assert.strictEqual(one, expectedOne); assert.strictEqual(two, expectedTwo); assert.strictEqual(three, expectedThree); - } + }; } ret = 4; assert.strictEqual(binding.callWithArgs(testFunction, 1, 2, 3), 4); assert.strictEqual(receiver, undefined); - assert.deepStrictEqual(args, [ 1, 2, 3 ]); + assert.deepStrictEqual(args, [1, 2, 3]); ret = 5; assert.strictEqual(binding.callWithVector(testFunction, 2, 3, 4), 5); assert.strictEqual(receiver, undefined); - assert.deepStrictEqual(args, [ 2, 3, 4 ]); + assert.deepStrictEqual(args, [2, 3, 4]); + + ret = 5; + assert.strictEqual(binding.callWithVectorUsingCppWrapper(testFunction, 2, 3, 4), 5); + assert.strictEqual(receiver, undefined); + assert.deepStrictEqual(args, [2, 3, 4]); ret = 6; assert.strictEqual(binding.callWithReceiverAndArgs(testFunction, obj, 3, 4, 5), 6); assert.deepStrictEqual(receiver, obj); - assert.deepStrictEqual(args, [ 3, 4, 5 ]); + assert.deepStrictEqual(args, [3, 4, 5]); ret = 7; assert.strictEqual(binding.callWithReceiverAndVector(testFunction, obj, 4, 5, 6), 7); assert.deepStrictEqual(receiver, obj); - assert.deepStrictEqual(args, [ 4, 5, 6 ]); + assert.deepStrictEqual(args, [4, 5, 6]); + + ret = 7; + assert.strictEqual(binding.callWithReceiverAndVectorUsingCppWrapper(testFunction, obj, 4, 5, 6), 7); + assert.deepStrictEqual(receiver, obj); + assert.deepStrictEqual(args, [4, 5, 6]); ret = 8; assert.strictEqual(binding.callWithCStyleArray(testFunction, 5, 6, 7), ret); assert.deepStrictEqual(receiver, undefined); - assert.deepStrictEqual(args, [ 5, 6, 7 ]); + assert.deepStrictEqual(args, [5, 6, 7]); ret = 9; assert.strictEqual(binding.callWithReceiverAndCStyleArray(testFunction, obj, 6, 7, 8), ret); assert.deepStrictEqual(receiver, obj); - assert.deepStrictEqual(args, [ 6, 7, 8 ]); + assert.deepStrictEqual(args, [6, 7, 8]); ret = 10; assert.strictEqual(binding.callWithFunctionOperator(testFunction, 7, 8, 9), ret); assert.strictEqual(receiver, undefined); - assert.deepStrictEqual(args, [ 7, 8, 9 ]); + assert.deepStrictEqual(args, [7, 8, 9]); assert.throws(() => { binding.callWithInvalidReceiver(); @@ -80,33 +90,35 @@ function test(binding) { obj = binding.callConstructorWithArgs(testConstructor, 5, 6, 7); assert(obj instanceof testConstructor); - assert.deepStrictEqual(args, [ 5, 6, 7 ]); + assert.deepStrictEqual(args, [5, 6, 7]); obj = binding.callConstructorWithVector(testConstructor, 6, 7, 8); assert(obj instanceof testConstructor); - assert.deepStrictEqual(args, [ 6, 7, 8 ]); + assert.deepStrictEqual(args, [6, 7, 8]); obj = binding.callConstructorWithCStyleArray(testConstructor, 7, 8, 9); assert(obj instanceof testConstructor); - assert.deepStrictEqual(args, [ 7, 8, 9 ]); + assert.deepStrictEqual(args, [7, 8, 9]); obj = {}; assert.deepStrictEqual(binding.voidCallbackWithData(obj), undefined); - assert.deepStrictEqual(obj, { "foo": "bar", "data": 1 }); + assert.deepStrictEqual(obj, { foo: 'bar', data: 1 }); - assert.deepStrictEqual(binding.valueCallbackWithData(), { "foo": "bar", "data": 1 }); + assert.deepStrictEqual(binding.valueCallbackWithData(), { foo: 'bar', data: 1 }); assert.strictEqual(binding.voidCallback.name, 'voidCallback'); assert.strictEqual(binding.valueCallback.name, 'valueCallback'); - let testConstructCall = undefined; + let testConstructCall; binding.isConstructCall((result) => { testConstructCall = result; }); assert.ok(!testConstructCall); + /* eslint-disable no-new, new-cap */ new binding.isConstructCall((result) => { testConstructCall = result; }); + /* eslint-enable no-new, new-cap */ assert.ok(testConstructCall); obj = {}; - binding.makeCallbackWithArgs(makeCallbackTestFunction(obj, "1", "2", "3"), obj, "1", "2", "3"); + binding.makeCallbackWithArgs(makeCallbackTestFunction(obj, '1', '2', '3'), obj, '1', '2', '3'); binding.makeCallbackWithVector(makeCallbackTestFunction(obj, 4, 5, 6), obj, 4, 5, 6); binding.makeCallbackWithCStyleArray(makeCallbackTestFunction(obj, 7, 8, 9), obj, 7, 8, 9); assert.throws(() => { @@ -114,7 +126,7 @@ function test(binding) { }); } -function testLambda(binding) { +function testLambda (binding) { assert.ok(binding.lambdaWithNoCapture()); assert.ok(binding.lambdaWithCapture()); assert.ok(binding.lambdaWithMoveOnlyCapture());