Moved TurboModule C++ core to github

Summary:
This is only the core C++ part of TurboModule - moving to github to make integration with existing NativeModules system slightly easier. Other bindings for iOS/Android are not yet ready to move.

Notes:
* TurboModules is not ready to use at the moment.
* Build configuration is not yet provided (cocoapods/.xcodeproj/gradle), just like Fabric.
* No effort was done to make this lib C++17 strictly compliant yet (there will be in the future).

Reviewed By: RSNara

Differential Revision: D13551211

fbshipit-source-id: cd3b458e6746ee9218451962ca65b1ad641a32db
This commit is contained in:
Kevin Gozali 2018-12-26 17:12:53 -08:00 коммит произвёл Facebook Github Bot
Родитель b748e83fbf
Коммит acc2ed2488
13 изменённых файлов: 819 добавлений и 0 удалений

Просмотреть файл

@ -0,0 +1,46 @@
load("@fbsource//tools/build_defs/apple:flag_defs.bzl", "get_debug_preprocessor_flags")
load("//tools/build_defs/oss:rn_defs.bzl", "ANDROID", "APPLE", "get_apple_compiler_flags", "get_apple_inspector_flags", "react_native_xplat_target", "rn_xplat_cxx_library", "subdir_glob")
APPLE_COMPILER_FLAGS = get_apple_compiler_flags()
rn_xplat_cxx_library(
name = "core",
srcs = glob(["**/*.cpp"]),
header_namespace = "",
exported_headers = subdir_glob(
[
("", "**/*.h"),
],
prefix = "jsireact",
),
compiler_flags = [
"-fexceptions",
"-frtti",
"-std=c++14",
"-Wall",
],
fbobjc_compiler_flags = APPLE_COMPILER_FLAGS,
fbobjc_preprocessor_flags = get_debug_preprocessor_flags() + get_apple_inspector_flags(),
force_static = True,
platforms = (ANDROID, APPLE),
preprocessor_flags = [
"-DLOG_TAG=\"ReactNative\"",
"-DWITH_FBSYSTRACE=1",
],
visibility = [
"PUBLIC",
],
deps = [
"xplat//fbsystrace:fbsystrace",
"xplat//folly:headers_only",
"xplat//folly:memory",
"xplat//folly:molly",
"xplat//jsi:JSIDynamic",
"xplat//third-party/glog:glog",
react_native_xplat_target("cxxreact:bridge"),
react_native_xplat_target("cxxreact:module"),
],
exported_deps = [
"xplat//jsi:jsi",
],
)

Просмотреть файл

@ -0,0 +1,27 @@
/**
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#include "JSCallInvoker.h"
#include <cxxreact/MessageQueueThread.h>
namespace facebook {
namespace react {
JSCallInvoker::JSCallInvoker(std::shared_ptr<MessageQueueThread> jsThread)
: jsThread_(jsThread) {}
void JSCallInvoker::invokeAsync(std::function<void()>&& func) {
jsThread_->runOnQueue(std::move(func));
}
void JSCallInvoker::invokeSync(std::function<void()>&& func) {
jsThread_->runOnQueueSync(std::move(func));
}
} // namespace react
} // namespace facebook

Просмотреть файл

@ -0,0 +1,38 @@
/**
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#pragma once
#include <functional>
#include <memory>
namespace facebook {
namespace react {
class MessageQueueThread;
/**
* A generic native-to-JS call invoker. It guarantees that any calls from any
* thread are queued on the right JS thread.
*
* For now, this is a thin-wrapper around existing MessageQueueThread. Eventually,
* it should be consolidated with Fabric implementation so there's only one
* API to call JS from native, whether synchronously or asynchronously.
*/
class JSCallInvoker {
public:
JSCallInvoker(std::shared_ptr<MessageQueueThread> jsThread);
void invokeAsync(std::function<void()>&& func);
void invokeSync(std::function<void()>&& func);
private:
std::shared_ptr<MessageQueueThread> jsThread_;
};
} // namespace react
} // namespace facebook

Просмотреть файл

@ -0,0 +1,49 @@
/**
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#include "LongLivedObject.h"
namespace facebook {
namespace react {
// LongLivedObjectCollection
LongLivedObjectCollection& LongLivedObjectCollection::get() {
static LongLivedObjectCollection instance;
return instance;
}
LongLivedObjectCollection::LongLivedObjectCollection() {}
void LongLivedObjectCollection::add(std::shared_ptr<LongLivedObject> so) {
collection_.insert(so);
}
void LongLivedObjectCollection::remove(const LongLivedObject *o) {
auto p = collection_.begin();
for (; p != collection_.end(); p++) {
if (p->get() == o) {
break;
}
}
if (p != collection_.end()) {
collection_.erase(p);
}
}
void LongLivedObjectCollection::clear() {
collection_.clear();
}
// LongLivedObject
LongLivedObject::LongLivedObject() {}
void LongLivedObject::allowRelease() {
LongLivedObjectCollection::get().remove(this);
}
} // namespace react
} // namespace facebook

Просмотреть файл

@ -0,0 +1,52 @@
/**
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#pragma once
#include <memory>
#include <unordered_set>
namespace facebook {
namespace react {
/**
* A simple wrapper class that can be registered to a collection that keep it alive for extended period of time.
* This object can be removed from the collection when needed.
*
* The subclass of this class must be created using std::make_shared<T>().
* After creation, add it to the `LongLivedObjectCollection`.
* When done with the object, call `allowRelease()` to allow the OS to release it.
*/
class LongLivedObject {
public:
void allowRelease();
protected:
LongLivedObject();
};
/**
* A singleton collection for the `LongLivedObject`s.
*/
class LongLivedObjectCollection {
public:
static LongLivedObjectCollection& get();
LongLivedObjectCollection(LongLivedObjectCollection const&) = delete;
void operator=(LongLivedObjectCollection const&) = delete;
void add(std::shared_ptr<LongLivedObject> o);
void remove(const LongLivedObject *o);
void clear();
private:
LongLivedObjectCollection();
std::unordered_set<std::shared_ptr<LongLivedObject>> collection_;
};
} // namespace react
} // namespace facebook

Просмотреть файл

@ -0,0 +1,147 @@
/**
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#include "TurboCxxModule.h"
#include <vector>
#include <jsi/JSIDynamic.h>
#include <jsireact/TurboModuleUtils.h>
using namespace facebook;
using namespace facebook::xplat::module;
namespace facebook {
namespace react {
static CxxModule::Callback makeTurboCxxModuleCallback(
jsi::Runtime &runtime,
std::shared_ptr<CallbackWrapper> callbackWrapper) {
return [callbackWrapper](std::vector<folly::dynamic> args) {
callbackWrapper->jsInvoker->invokeAsync([callbackWrapper, args]() {
std::vector<jsi::Value> innerArgs;
for (auto &a : args) {
innerArgs.push_back(jsi::valueFromDynamic(callbackWrapper->runtime, a));
}
callbackWrapper->callback.call(callbackWrapper->runtime, (const jsi::Value *)innerArgs.data(), innerArgs.size());
});
};
}
TurboCxxModule::TurboCxxModule(std::unique_ptr<CxxModule> cxxModule, std::shared_ptr<JSCallInvoker> jsInvoker)
: TurboModule(cxxModule->getName(), jsInvoker),
cxxMethods_(cxxModule->getMethods()),
cxxModule_(std::move(cxxModule)) {}
jsi::Value TurboCxxModule::get(jsi::Runtime& runtime, const jsi::PropNameID& propName) {
std::string propNameUtf8 = propName.utf8(runtime);
if (propNameUtf8 == "getConstants") {
// This is special cased because `getConstants()` is already a part of CxxModule.
return jsi::Function::createFromHostFunction(
runtime,
propName,
0,
[this](jsi::Runtime &rt, const jsi::Value &thisVal, const jsi::Value *args, size_t count) {
jsi::Object result(rt);
auto constants = cxxModule_->getConstants();
for (auto &pair : constants) {
result.setProperty(rt, pair.first.c_str(), jsi::valueFromDynamic(rt, pair.second));
}
return result;
});
}
for (auto &method : cxxMethods_) {
if (method.name == propNameUtf8) {
return jsi::Function::createFromHostFunction(
runtime,
propName,
0,
[this, &propNameUtf8](jsi::Runtime &rt, const jsi::Value &thisVal, const jsi::Value *args, size_t count) {
return invokeMethod(rt, VoidKind, propNameUtf8, args, count);
});
}
}
throw std::runtime_error("Function '" + propNameUtf8 + "' cannot be found on cxxmodule: " + name_);
}
jsi::Value TurboCxxModule::invokeMethod(
jsi::Runtime &runtime,
TurboModuleMethodValueKind valueKind,
const std::string &methodName,
const jsi::Value *args,
size_t count) {
auto it = cxxMethods_.begin();
for (; it != cxxMethods_.end(); it++) {
auto method = *it;
if (method.name == methodName) {
break;
}
}
if (it == cxxMethods_.end()) {
throw std::runtime_error("Function '" + methodName + "' cannot be found on cxxmodule: " + name_);
}
auto method = *it;
if (method.syncFunc) {
auto innerArgs = folly::dynamic::array();
for (size_t i = 0; i < count; i++) {
innerArgs.push_back(jsi::dynamicFromValue(runtime, args[i]));
}
return jsi::valueFromDynamic(runtime, method.syncFunc(std::move(innerArgs)));
} else if (method.func && !method.isPromise) {
// Async method.
CxxModule::Callback first;
CxxModule::Callback second;
if (count < method.callbacks) {
throw std::invalid_argument(folly::to<std::string>("Expected ", method.callbacks,
" callbacks, but only ", count, " parameters provided"));
}
if (method.callbacks == 1) {
auto wrapper = std::make_shared<CallbackWrapper>(args[count - 1].getObject(runtime).getFunction(runtime), runtime, jsInvoker_);
first = makeTurboCxxModuleCallback(runtime, wrapper);
} else if (method.callbacks == 2) {
auto wrapper1 = std::make_shared<CallbackWrapper>(args[count - 2].getObject(runtime).getFunction(runtime), runtime, jsInvoker_);
auto wrapper2 = std::make_shared<CallbackWrapper>(args[count - 1].getObject(runtime).getFunction(runtime), runtime, jsInvoker_);
first = makeTurboCxxModuleCallback(runtime, wrapper1);
second = makeTurboCxxModuleCallback(runtime, wrapper2);
}
auto innerArgs = folly::dynamic::array();
for (size_t i = 0; i < count - method.callbacks; i++) {
innerArgs.push_back(jsi::dynamicFromValue(runtime, args[i]));
}
method.func(std::move(innerArgs), first, second);
} else if (method.isPromise) {
return createPromiseAsJSIValue(runtime, [method, args, count, this](jsi::Runtime &rt, std::shared_ptr<Promise> promise) {
auto resolveWrapper = std::make_shared<CallbackWrapper>(promise->resolve_.getFunction(rt), rt, jsInvoker_);
auto rejectWrapper = std::make_shared<CallbackWrapper>(promise->reject_.getFunction(rt), rt, jsInvoker_);
CxxModule::Callback resolve = makeTurboCxxModuleCallback(rt, resolveWrapper);
CxxModule::Callback reject = makeTurboCxxModuleCallback(rt, rejectWrapper);
auto innerArgs = folly::dynamic::array();
for (size_t i = 0; i < count; i++) {
innerArgs.push_back(jsi::dynamicFromValue(rt, args[i]));
}
method.func(std::move(innerArgs), resolve, reject);
});
}
return jsi::Value::undefined();
}
} // namespace react
} // namespace facebook

Просмотреть файл

@ -0,0 +1,44 @@
/**
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#pragma once
#include <memory>
#include <vector>
#include <cxxreact/CxxModule.h>
#include "TurboModule.h"
namespace facebook {
namespace react {
/**
* A helper class to convert the legacy CxxModule instance to a TurboModule instance.
* This should be used only for migration purpose (to TurboModule), since it's not very performant
* due to a lot of back-and-forth value conversions between folly::dynamic and jsi::Value.
*/
class JSI_EXPORT TurboCxxModule : public TurboModule {
public:
TurboCxxModule(std::unique_ptr<facebook::xplat::module::CxxModule> cxxModule, std::shared_ptr<JSCallInvoker> jsInvoker);
virtual facebook::jsi::Value get(facebook::jsi::Runtime& runtime, const facebook::jsi::PropNameID& propName) override;
virtual jsi::Value invokeMethod(
jsi::Runtime &runtime,
TurboModuleMethodValueKind valueKind,
const std::string &methodName,
const jsi::Value *args,
size_t count) override;
private:
std::vector<facebook::xplat::module::CxxModule::Method> cxxMethods_;
std::unique_ptr<facebook::xplat::module::CxxModule> cxxModule_;
};
} // namespace react
} // namespace facebook

Просмотреть файл

@ -0,0 +1,51 @@
/**
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#include "TurboModule.h"
using namespace facebook;
namespace facebook {
namespace react {
TurboModule::TurboModule(const std::string &name, std::shared_ptr<JSCallInvoker> jsInvoker)
: name_(name),
jsInvoker_(jsInvoker) {}
TurboModule::~TurboModule() {
invalidate();
}
void TurboModule::invalidate() {}
jsi::Value TurboModule::get(jsi::Runtime& runtime, const jsi::PropNameID& propName) {
std::string propNameUtf8 = propName.utf8(runtime);
auto p = methodMap_.find(propNameUtf8);
if (p == methodMap_.end()) {
throw std::runtime_error("Function '" + propNameUtf8 + "' cannot be found on module: " + name_);
}
MethodMetadata meta = p->second;
return jsi::Function::createFromHostFunction(
runtime,
propName,
meta.argCount,
[this, meta](facebook::jsi::Runtime &rt, const facebook::jsi::Value &thisVal, const facebook::jsi::Value *args, size_t count) {
return meta.invoker(rt, *this, args, count);
});
}
jsi::Value TurboModule::invokeMethod(
jsi::Runtime &runtime,
TurboModuleMethodValueKind valueKind,
const std::string &methodName,
const jsi::Value *args,
size_t count) {
return jsi::Value::undefined();
}
} // namespace react
} // namespace facebook

Просмотреть файл

@ -0,0 +1,84 @@
/**
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#pragma once
#include <string>
#include <unordered_map>
#include <jsi/jsi.h>
#include "JSCallInvoker.h"
namespace facebook {
namespace react {
/**
* For now, support the same set of return types as existing impl.
* This can be improved to support richer typed objects.
*/
enum TurboModuleMethodValueKind {
VoidKind,
BooleanKind,
NumberKind,
StringKind,
ObjectKind,
ArrayKind,
FunctionKind,
PromiseKind,
};
/**
* Base HostObject class for every module to be exposed to JS
*/
class JSI_EXPORT TurboModule : public facebook::jsi::HostObject {
public:
TurboModule(const std::string &name, std::shared_ptr<JSCallInvoker> jsInvoker);
virtual ~TurboModule();
/**
* Instruct this module to invalidate itself.
*/
virtual void invalidate();
virtual facebook::jsi::Value get(facebook::jsi::Runtime& runtime, const facebook::jsi::PropNameID& propName) override;
/**
* General method invocation mechanism.
* Each subclass decides how the invocation should be, and whether it should be platform-specific.
*/
virtual jsi::Value invokeMethod(
jsi::Runtime &runtime,
TurboModuleMethodValueKind valueKind,
const std::string &methodName,
const jsi::Value *args,
size_t count);
const std::string name_;
std::shared_ptr<JSCallInvoker> jsInvoker_;
protected:
struct MethodMetadata {
size_t argCount;
facebook::jsi::Value (*invoker)(
facebook::jsi::Runtime& rt,
TurboModule &turboModule,
const facebook::jsi::Value* args,
size_t count);
};
std::unordered_map<std::string, MethodMetadata> methodMap_;
};
/**
* An app/platform-specific provider function to get an instance of a module given a name.
*/
using TurboModuleProviderFunctionType = std::function<std::shared_ptr<TurboModule>(
const std::string &name)>;
} // namespace react
} // namespace facebook

Просмотреть файл

@ -0,0 +1,72 @@
/**
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#include "TurboModuleBinding.h"
#include <string>
#include <cxxreact/SystraceSection.h>
using namespace facebook;
namespace facebook {
namespace react {
/**
* Public API to install the TurboModule system.
*/
TurboModuleBinding::TurboModuleBinding(const TurboModuleProviderFunctionType &moduleProvider)
: moduleProvider_(moduleProvider) {}
void TurboModuleBinding::install(
jsi::Runtime &runtime,
std::shared_ptr<TurboModuleBinding> binding) {
runtime.global().setProperty(
runtime,
"__turboModuleProxy",
jsi::Function::createFromHostFunction(
runtime,
jsi::PropNameID::forAscii(runtime, "__turboModuleProxy"),
1,
[binding](jsi::Runtime& rt, const jsi::Value& thisVal, const jsi::Value* args, size_t count) {
return binding->jsProxy(rt, thisVal, args, count);
}));
}
void TurboModuleBinding::invalidate() const {
// Nothing for now.
}
std::shared_ptr<TurboModule> TurboModuleBinding::getModule(const std::string &name) {
std::shared_ptr<TurboModule> module = nullptr;
{
SystraceSection s("TurboModuleBinding::getModule", "module", name);
module = moduleProvider_(name);
}
return module;
}
jsi::Value TurboModuleBinding::jsProxy(
jsi::Runtime& runtime,
const jsi::Value& thisVal,
const jsi::Value* args,
size_t count) {
if (count != 1) {
throw std::invalid_argument("TurboModuleBinding::jsProxy arg count must be 1");
}
std::string moduleName = args[0].getString(runtime).utf8(runtime);
std::shared_ptr<TurboModule> module = getModule(moduleName);
if (module == nullptr) {
return jsi::Value::null();
}
return jsi::Object::createFromHostObject(runtime, std::move(module));
}
} // namespace react
} // namespace facebook

Просмотреть файл

@ -0,0 +1,61 @@
/**
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#pragma once
#include <string>
#include <jsi/jsi.h>
#include <jsireact/TurboModule.h>
namespace facebook {
namespace react {
class JSCallInvoker;
/**
* Represents the JavaScript binding for the TurboModule system.
*/
class TurboModuleBinding {
public:
/*
* Installs TurboModuleBinding into JavaScript runtime.
* Thread synchronization must be enforced externally.
*/
static void install(
jsi::Runtime &runtime,
std::shared_ptr<TurboModuleBinding> binding);
TurboModuleBinding(const TurboModuleProviderFunctionType &moduleProvider);
/*
* Invalidates the binding.
* Can be called in any thread.
*/
void invalidate() const;
/**
* Get an TurboModule instance for the given module name.
*/
std::shared_ptr<TurboModule> getModule(const std::string &name);
private:
/**
* A lookup function exposed to JS to get an instance of a TurboModule
* for the given name.
*/
jsi::Value jsProxy(
jsi::Runtime& runtime,
const jsi::Value& thisVal,
const jsi::Value* args,
size_t count);
TurboModuleProviderFunctionType moduleProvider_;
};
} // namespace react
} // namespace facebook

Просмотреть файл

@ -0,0 +1,98 @@
/**
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#include "TurboModuleUtils.h"
namespace facebook {
namespace react {
static jsi::Value deepCopyJSIValue(jsi::Runtime &rt, const jsi::Value &value) {
if (value.isNull()) {
return jsi::Value::null();
}
if (value.isBool()) {
return jsi::Value(value.getBool());
}
if (value.isNumber()) {
return jsi::Value(value.getNumber());
}
if (value.isString()) {
return value.getString(rt);
}
if (value.isObject()) {
jsi::Object o = value.getObject(rt);
if (o.isArray(rt)) {
return deepCopyJSIArray(rt, o.getArray(rt));
}
if (o.isFunction(rt)) {
return o.getFunction(rt);
}
return deepCopyJSIObject(rt, o);
}
return jsi::Value::undefined();
}
jsi::Object deepCopyJSIObject(jsi::Runtime &rt, const jsi::Object &obj) {
jsi::Object copy(rt);
jsi::Array propertyNames = obj.getPropertyNames(rt);
size_t size = propertyNames.size(rt);
for (size_t i = 0; i < size; i++) {
jsi::String name = propertyNames.getValueAtIndex(rt, i).getString(rt);
jsi::Value value = obj.getProperty(rt, name);
copy.setProperty(rt, name, deepCopyJSIValue(rt, value));
}
return copy;
}
jsi::Array deepCopyJSIArray(jsi::Runtime &rt, const jsi::Array &arr) {
size_t size = arr.size(rt);
jsi::Array copy(rt, size);
for (size_t i = 0; i < size; i++) {
copy.setValueAtIndex(rt, i, deepCopyJSIValue(rt, arr.getValueAtIndex(rt, i)));
}
return copy;
}
Promise::Promise(jsi::Runtime &rt, jsi::Function resolve, jsi::Function reject)
: runtime_(rt),
resolve_(std::move(resolve)),
reject_(std::move(reject)) {}
void Promise::resolve(const jsi::Value &result) {
resolve_.call(runtime_, result);
}
void Promise::reject(const std::string &message) {
jsi::Object error(runtime_);
error.setProperty(runtime_, "message", jsi::String::createFromUtf8(runtime_, message));
reject_.call(runtime_, error);
}
jsi::Value createPromiseAsJSIValue(jsi::Runtime &rt, const PromiseSetupFunctionType func) {
jsi::Function JSPromise = rt.global().getPropertyAsFunction(rt, "Promise");
jsi::Function fn = jsi::Function::createFromHostFunction(
rt,
jsi::PropNameID::forAscii(rt, "fn"),
2,
[func](jsi::Runtime &rt2, const jsi::Value &thisVal, const jsi::Value *args, size_t count) {
jsi::Function resolve = args[0].getObject(rt2).getFunction(rt2);
jsi::Function reject = args[1].getObject(rt2).getFunction(rt2);
auto wrapper = std::make_shared<Promise>(rt2, std::move(resolve), std::move(reject));
func(rt2, wrapper);
return jsi::Value::undefined();
});
return JSPromise.callAsConstructor(rt, fn);
}
} // namespace react
} // namespace facebook

Просмотреть файл

@ -0,0 +1,50 @@
/**
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#pragma once
#include <string>
#include <jsi/jsi.h>
#include "JSCallInvoker.h"
using namespace facebook;
namespace facebook {
namespace react {
jsi::Object deepCopyJSIObject(jsi::Runtime &rt, const jsi::Object &obj);
jsi::Array deepCopyJSIArray(jsi::Runtime &rt, const jsi::Array &arr);
struct Promise {
Promise(jsi::Runtime &rt, jsi::Function resolve, jsi::Function reject);
void resolve(const jsi::Value &result);
void reject(const std::string &error);
jsi::Runtime &runtime_;
jsi::Function resolve_;
jsi::Function reject_;
};
using PromiseSetupFunctionType = std::function<void(jsi::Runtime &rt, std::shared_ptr<Promise>)>;
jsi::Value createPromiseAsJSIValue(jsi::Runtime &rt, const PromiseSetupFunctionType func);
// Helper for passing jsi::Function arg to other methods.
struct CallbackWrapper {
CallbackWrapper(jsi::Function callback, jsi::Runtime &runtime, std::shared_ptr<react::JSCallInvoker> jsInvoker)
: callback(std::move(callback)),
runtime(runtime),
jsInvoker(jsInvoker) {}
jsi::Function callback;
jsi::Runtime &runtime;
std::shared_ptr<react::JSCallInvoker> jsInvoker;
};
} // namespace react
} // namespace facebook