#include "napi.h" #include "test_helper.h" using namespace Napi; class FuncRefObject : public Napi::ObjectWrap { public: FuncRefObject(const Napi::CallbackInfo& info) : Napi::ObjectWrap(info) { Napi::Env env = info.Env(); int argLen = info.Length(); if (argLen <= 0 || !info[0].IsNumber()) { Napi::TypeError::New(env, "First param should be a number") .ThrowAsJavaScriptException(); return; } Napi::Number value = info[0].As(); this->_value = value.Int32Value(); } Napi::Value GetValue(const Napi::CallbackInfo& info) { int value = this->_value; return Napi::Number::New(info.Env(), value); } private: int _value; }; namespace { Value ConstructRefFromExisitingRef(const CallbackInfo& info) { EscapableHandleScope scope(info.Env()); FunctionReference ref; FunctionReference movedRef; ref.Reset(info[0].As()); movedRef = std::move(ref); return scope.Escape(MaybeUnwrap(movedRef({}))); } Value CallWithVectorArgs(const CallbackInfo& info) { EscapableHandleScope scope(info.Env()); std::vector newVec; FunctionReference ref; ref.Reset(info[0].As()); for (int i = 1; i < (int)info.Length(); i++) { newVec.push_back(info[i]); } return scope.Escape(MaybeUnwrap(ref.Call(newVec))); } Value CallWithInitList(const CallbackInfo& info) { EscapableHandleScope scope(info.Env()); FunctionReference ref; ref.Reset(info[0].As()); return scope.Escape(MaybeUnwrap(ref.Call({info[1], info[2], info[3]}))); } Value CallWithRecvInitList(const CallbackInfo& info) { EscapableHandleScope scope(info.Env()); FunctionReference ref; ref.Reset(info[0].As()); return scope.Escape( MaybeUnwrap(ref.Call(info[1], {info[2], info[3], info[4]}))); } Value CallWithRecvVector(const CallbackInfo& info) { EscapableHandleScope scope(info.Env()); FunctionReference ref; std::vector newVec; ref.Reset(info[0].As()); for (int i = 2; i < (int)info.Length(); i++) { newVec.push_back(info[i]); } return scope.Escape(MaybeUnwrap(ref.Call(info[1], newVec))); } Value CallWithRecvArgc(const CallbackInfo& info) { EscapableHandleScope scope(info.Env()); FunctionReference ref; ref.Reset(info[0].As()); size_t argLength = info.Length() > 2 ? info.Length() - 2 : 0; std::unique_ptr args{argLength > 0 ? new napi_value[argLength] : nullptr}; for (size_t i = 0; i < argLength; ++i) { args[i] = info[i + 2]; } return scope.Escape(MaybeUnwrap(ref.Call(info[1], argLength, args.get()))); } Value MakeAsyncCallbackWithInitList(const Napi::CallbackInfo& info) { Napi::FunctionReference ref; ref.Reset(info[0].As()); Napi::AsyncContext context(info.Env(), "func_ref_resources", {}); return MaybeUnwrap( ref.MakeCallback(Napi::Object::New(info.Env()), {}, context)); } Value MakeAsyncCallbackWithVector(const Napi::CallbackInfo& info) { Napi::FunctionReference ref; ref.Reset(info[0].As()); std::vector newVec; Napi::AsyncContext context(info.Env(), "func_ref_resources", {}); for (int i = 1; i < (int)info.Length(); i++) { newVec.push_back(info[i]); } return MaybeUnwrap( ref.MakeCallback(Napi::Object::New(info.Env()), newVec, context)); } Value MakeAsyncCallbackWithArgv(const Napi::CallbackInfo& info) { Napi::FunctionReference ref; ref.Reset(info[0].As()); size_t argLength = info.Length() > 1 ? info.Length() - 1 : 0; std::unique_ptr args{argLength > 0 ? new napi_value[argLength] : nullptr}; for (size_t i = 0; i < argLength; ++i) { args[i] = info[i + 1]; } Napi::AsyncContext context(info.Env(), "func_ref_resources", {}); return MaybeUnwrap(ref.MakeCallback(Napi::Object::New(info.Env()), argLength, argLength > 0 ? args.get() : nullptr, context)); } Value CreateFunctionReferenceUsingNew(const Napi::CallbackInfo& info) { Napi::Function func = ObjectWrap::DefineClass( info.Env(), "MyObject", {ObjectWrap::InstanceMethod("getValue", &FuncRefObject::GetValue)}); Napi::FunctionReference* constructor = new Napi::FunctionReference(); *constructor = Napi::Persistent(func); return MaybeUnwrapOr(constructor->New({info[0].As()}), Object()); } Value CreateFunctionReferenceUsingNewVec(const Napi::CallbackInfo& info) { Napi::Function func = ObjectWrap::DefineClass( info.Env(), "MyObject", {ObjectWrap::InstanceMethod("getValue", &FuncRefObject::GetValue)}); Napi::FunctionReference* constructor = new Napi::FunctionReference(); *constructor = Napi::Persistent(func); std::vector newVec; newVec.push_back(info[0]); return MaybeUnwrapOr(constructor->New(newVec), Object()); } Value Call(const CallbackInfo& info) { EscapableHandleScope scope(info.Env()); FunctionReference ref; ref.Reset(info[0].As()); return scope.Escape(MaybeUnwrapOr(ref.Call({}), Value())); } Value Construct(const CallbackInfo& info) { EscapableHandleScope scope(info.Env()); FunctionReference ref; ref.Reset(info[0].As()); return scope.Escape(MaybeUnwrapOr(ref.New({}), Object())); } } // namespace Object InitFunctionReference(Env env) { Object exports = Object::New(env); exports["CreateFuncRefWithNew"] = Function::New(env, CreateFunctionReferenceUsingNew); exports["CreateFuncRefWithNewVec"] = Function::New(env, CreateFunctionReferenceUsingNewVec); exports["CallWithRecvArgc"] = Function::New(env, CallWithRecvArgc); exports["CallWithRecvVector"] = Function::New(env, CallWithRecvVector); exports["CallWithRecvInitList"] = Function::New(env, CallWithRecvInitList); exports["CallWithInitList"] = Function::New(env, CallWithInitList); exports["CallWithVec"] = Function::New(env, CallWithVectorArgs); exports["ConstructWithMove"] = Function::New(env, ConstructRefFromExisitingRef); exports["AsyncCallWithInitList"] = Function::New(env, MakeAsyncCallbackWithInitList); exports["AsyncCallWithVector"] = Function::New(env, MakeAsyncCallbackWithVector); exports["AsyncCallWithArgv"] = Function::New(env, MakeAsyncCallbackWithArgv); exports["call"] = Function::New(env, Call); exports["construct"] = Function::New(env, Construct); return exports; }