mirror of
https://github.com/status-im/react-native.git
synced 2025-01-13 19:15:05 +00:00
Move cxx module support into oss
Reviewed By: mhorowitz Differential Revision: D3319751 fbshipit-source-id: 87f91a541cfbbe45bd8561d94f269ba976a9f702
This commit is contained in:
parent
04d86d819e
commit
a8acf8a5ce
@ -10,6 +10,10 @@ import os
|
||||
def react_native_target(path):
|
||||
return '//ReactAndroid/src/main/' + path
|
||||
|
||||
# Example: react_native_target('bridge:bridge')
|
||||
def react_native_xplat_target(path):
|
||||
return '//ReactCommon/' + path
|
||||
|
||||
# Example: react_native_tests_target('java/com/facebook/react/modules:modules')
|
||||
def react_native_tests_target(path):
|
||||
return '//ReactAndroid/src/test/' + path
|
||||
|
@ -17,9 +17,9 @@ cxx_library(
|
||||
'//native/third-party/android-ndk:android',
|
||||
'//xplat/folly:molly',
|
||||
'//xplat/fbsystrace:fbsystrace',
|
||||
'//xplat/react/module:module',
|
||||
react_native_target('jni/react/jni:jni'),
|
||||
react_native_xplat_target('bridge:bridge'),
|
||||
react_native_xplat_target('bridge:module'),
|
||||
],
|
||||
srcs = glob(['*.cpp']),
|
||||
exported_headers = EXPORTED_HEADERS,
|
||||
|
@ -9,7 +9,7 @@
|
||||
#include <jni/LocalString.h>
|
||||
#include <jni/Registration.h>
|
||||
|
||||
#include <Module/JsArgumentHelpers.h>
|
||||
#include <cxxreact/JsArgumentHelpers.h>
|
||||
|
||||
#include <android/log.h>
|
||||
|
||||
|
@ -2,7 +2,7 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <Module/CxxModule.h>
|
||||
#include <cxxreact/CxxModule.h>
|
||||
#include <fb/fbjni.h>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
@ -6,10 +6,9 @@
|
||||
|
||||
#include <fb/fbjni.h>
|
||||
|
||||
#include <Module/CxxModule.h>
|
||||
#include <Module/JsArgumentHelpers.h>
|
||||
|
||||
#include <cxxreact/CxxModule.h>
|
||||
#include <cxxreact/Instance.h>
|
||||
#include <cxxreact/JsArgumentHelpers.h>
|
||||
#include <cxxreact/NativeModule.h>
|
||||
#include <react/jni/ReadableNativeArray.h>
|
||||
|
||||
|
@ -1,3 +1,5 @@
|
||||
include_defs('//ReactAndroid/DEFS')
|
||||
|
||||
cxx_library(
|
||||
name = 'perftests',
|
||||
srcs = [ 'OnLoad.cpp' ],
|
||||
@ -9,7 +11,7 @@ cxx_library(
|
||||
'//native:base',
|
||||
'//native/fb:fb',
|
||||
'//xplat/folly:molly',
|
||||
'//xplat/react/module:module',
|
||||
react_native_xplat_target('bridge:module'),
|
||||
],
|
||||
visibility = [
|
||||
'//instrumentation_tests/com/facebook/react/...',
|
||||
|
@ -2,8 +2,8 @@
|
||||
|
||||
#include <fb/log.h>
|
||||
#include <fb/fbjni.h>
|
||||
#include <Module/CxxModule.h>
|
||||
#include <Module/JsArgumentHelpers.h>
|
||||
#include <cxxreact/CxxModule.h>
|
||||
#include <cxxreact/JsArgumentHelpers.h>
|
||||
|
||||
#include <mutex>
|
||||
#include <condition_variable>
|
||||
|
@ -38,7 +38,6 @@ if THIS_IS_FBANDROID:
|
||||
)
|
||||
|
||||
elif THIS_IS_FBOBJC:
|
||||
|
||||
def react_library(**kwargs):
|
||||
ios_library(
|
||||
name = 'bridge',
|
||||
@ -55,20 +54,91 @@ elif THIS_IS_FBOBJC:
|
||||
)
|
||||
)
|
||||
|
||||
LOCAL_HEADERS = [
|
||||
'JSCTracing.h',
|
||||
'JSCLegacyProfiler.h',
|
||||
'JSCLegacyTracing.h',
|
||||
'JSCMemory.h',
|
||||
'JSCPerfStats.h',
|
||||
]
|
||||
cxx_library(
|
||||
name = 'module',
|
||||
header_namespace = 'cxxreact',
|
||||
force_static = True,
|
||||
exported_headers = [
|
||||
'CxxModule.h',
|
||||
'JsArgumentHelpers.h',
|
||||
'JsArgumentHelpers-inl.h',
|
||||
],
|
||||
deps = [
|
||||
'//xplat/folly:molly',
|
||||
],
|
||||
visibility = [
|
||||
'PUBLIC',
|
||||
],
|
||||
)
|
||||
|
||||
cxx_library(
|
||||
name = 'samplemodule',
|
||||
soname = 'libxplat_react_module_samplemodule.so',
|
||||
srcs = ['SampleCxxModule.cpp'],
|
||||
exported_headers = ['SampleCxxModule.h'],
|
||||
header_namespace = '',
|
||||
compiler_flags = [
|
||||
'-fno-omit-frame-pointer',
|
||||
'-Wall',
|
||||
'-Werror',
|
||||
'-std=c++11',
|
||||
'-fexceptions',
|
||||
],
|
||||
deps = [
|
||||
':module',
|
||||
'//xplat/folly:molly',
|
||||
],
|
||||
visibility = [
|
||||
'PUBLIC',
|
||||
],
|
||||
)
|
||||
|
||||
react_library(
|
||||
soname = 'libreactnativefb.so',
|
||||
header_namespace = 'cxxreact',
|
||||
force_static = True,
|
||||
srcs = glob(['*.cpp']),
|
||||
headers = LOCAL_HEADERS,
|
||||
srcs = [
|
||||
'Instance.cpp',
|
||||
'JSCExecutor.cpp',
|
||||
'JSCHelpers.cpp',
|
||||
'JSCLegacyProfiler.cpp',
|
||||
'JSCLegacyTracing.cpp',
|
||||
'JSCMemory.cpp',
|
||||
'JSCPerfStats.cpp',
|
||||
'JSCTracing.cpp',
|
||||
'JSCWebWorker.cpp',
|
||||
'MethodCall.cpp',
|
||||
'ModuleRegistry.cpp',
|
||||
'NativeToJsBridge.cpp',
|
||||
'Platform.cpp',
|
||||
'Value.cpp',
|
||||
],
|
||||
headers = [
|
||||
'JSCLegacyProfiler.h',
|
||||
'JSCLegacyTracing.h',
|
||||
'JSCMemory.h',
|
||||
'JSCPerfStats.h',
|
||||
'JSCTracing.h',
|
||||
],
|
||||
exported_headers = [
|
||||
'Executor.h',
|
||||
'ExecutorToken.h',
|
||||
'ExecutorTokenFactory.h',
|
||||
'Instance.h',
|
||||
'JSCExecutor.h',
|
||||
'JSCHelpers.h',
|
||||
'JSCWebWorker.h',
|
||||
'JSModulesUnbundle.h',
|
||||
'MessageQueueThread.h',
|
||||
'MethodCall.h',
|
||||
'ModuleRegistry.h',
|
||||
'NativeModule.h',
|
||||
'NativeToJsBridge.h',
|
||||
'noncopyable.h',
|
||||
'Platform.h',
|
||||
'SystraceSection.h',
|
||||
'Value.h',
|
||||
],
|
||||
preprocessor_flags = [
|
||||
'-DLOG_TAG="ReactNative"',
|
||||
'-DWITH_FBSYSTRACE=1',
|
||||
@ -79,7 +149,6 @@ react_library(
|
||||
'-fvisibility=hidden',
|
||||
'-frtti',
|
||||
],
|
||||
exported_headers = glob(['*.h'], excludes=LOCAL_HEADERS),
|
||||
deps = [
|
||||
'//xplat/fbsystrace:fbsystrace',
|
||||
],
|
||||
|
132
ReactCommon/bridge/CxxModule.h
Normal file
132
ReactCommon/bridge/CxxModule.h
Normal file
@ -0,0 +1,132 @@
|
||||
// Copyright 2004-present Facebook. All Rights Reserved.
|
||||
|
||||
#ifndef FBXPLATMODULE
|
||||
#define FBXPLATMODULE
|
||||
|
||||
#include <folly/dynamic.h>
|
||||
|
||||
#include <functional>
|
||||
|
||||
#include <map>
|
||||
#include <tuple>
|
||||
#include <vector>
|
||||
|
||||
using namespace std::placeholders;
|
||||
|
||||
namespace facebook { namespace xplat { namespace module {
|
||||
|
||||
/**
|
||||
* Base class for Catalyst native modules whose implementations are
|
||||
* written in C++. Native methods are represented by instances of the
|
||||
* Method struct. Generally, a derived class will manage an instance
|
||||
* which represents the data for the module, and non-Catalyst-specific
|
||||
* methods can be wrapped in lambdas which convert between
|
||||
* folly::dynamic and native C++ objects. The Callback arguments will
|
||||
* pass through to js functions passed to the analogous javascript
|
||||
* methods. At most two callbacks will be converted. Results should
|
||||
* be passed to the first callback, and errors to the second callback.
|
||||
* Exceptions thrown by a method will be converted to platform
|
||||
* exceptions, and handled however they are handled on that platform.
|
||||
* (TODO mhorowitz #7128529: this exception behavior is not yet
|
||||
* implemented.)
|
||||
*
|
||||
* There are two sets of constructors here. The first set initializes
|
||||
* a Method using a name and anything convertible to a std::function.
|
||||
* This is most useful for registering a lambda as a RN method. There
|
||||
* are overloads to support functions which take no arguments,
|
||||
* arguments only, and zero, one, or two callbacks.
|
||||
*
|
||||
* The second set of methods is similar, but instead of taking a
|
||||
* function, takes the method name, an object, and a pointer to a
|
||||
* method on that object.
|
||||
*/
|
||||
|
||||
class CxxModule {
|
||||
public:
|
||||
typedef std::function<void(std::vector<folly::dynamic>)> Callback;
|
||||
|
||||
struct Method {
|
||||
std::string name;
|
||||
size_t callbacks;
|
||||
std::function<void(folly::dynamic, Callback, Callback)> func;
|
||||
|
||||
// std::function/lambda ctors
|
||||
|
||||
Method(std::string aname,
|
||||
std::function<void()>&& afunc)
|
||||
: name(std::move(aname))
|
||||
, callbacks(0)
|
||||
, func(std::bind(std::move(afunc))) {}
|
||||
|
||||
Method(std::string aname,
|
||||
std::function<void(folly::dynamic)>&& afunc)
|
||||
: name(std::move(aname))
|
||||
, callbacks(0)
|
||||
, func(std::bind(std::move(afunc), _1)) {}
|
||||
|
||||
Method(std::string aname,
|
||||
std::function<void(folly::dynamic, Callback)>&& afunc)
|
||||
: name(std::move(aname))
|
||||
, callbacks(1)
|
||||
, func(std::bind(std::move(afunc), _1, _2)) {}
|
||||
|
||||
Method(std::string aname,
|
||||
std::function<void(folly::dynamic, Callback, Callback)>&& afunc)
|
||||
: name(std::move(aname))
|
||||
, callbacks(2)
|
||||
, func(std::move(afunc)) {}
|
||||
|
||||
// method pointer ctors
|
||||
|
||||
template <typename T>
|
||||
Method(std::string aname, T* t, void (T::*method)())
|
||||
: name(std::move(aname))
|
||||
, callbacks(0)
|
||||
, func(std::bind(method, t)) {}
|
||||
|
||||
template <typename T>
|
||||
Method(std::string aname, T* t, void (T::*method)(folly::dynamic))
|
||||
: name(std::move(aname))
|
||||
, callbacks(0)
|
||||
, func(std::bind(method, t, _1)) {}
|
||||
|
||||
template <typename T>
|
||||
Method(std::string aname, T* t, void (T::*method)(folly::dynamic, Callback))
|
||||
: name(std::move(aname))
|
||||
, callbacks(1)
|
||||
, func(std::bind(method, t, _1, _2)) {}
|
||||
|
||||
template <typename T>
|
||||
Method(std::string aname, T* t, void (T::*method)(folly::dynamic, Callback, Callback))
|
||||
: name(std::move(aname))
|
||||
, callbacks(2)
|
||||
, func(std::bind(method, t, _1, _2, _3)) {}
|
||||
};
|
||||
|
||||
/**
|
||||
* This may block, if necessary to complete cleanup before the
|
||||
* object is destroyed.
|
||||
*/
|
||||
virtual ~CxxModule() {}
|
||||
|
||||
/**
|
||||
* @return the name of this module. This will be the name used to {@code require()} this module
|
||||
* from javascript.
|
||||
*/
|
||||
virtual std::string getName() = 0;
|
||||
|
||||
/**
|
||||
* Each entry in the map will be exported as a property to JS. The
|
||||
* key is the property name, and the value can be anything.
|
||||
*/
|
||||
virtual auto getConstants() -> std::map<std::string, folly::dynamic> = 0;
|
||||
|
||||
/**
|
||||
* @return a list of methods this module exports to JS.
|
||||
*/
|
||||
virtual auto getMethods() -> std::vector<Method> = 0;
|
||||
};
|
||||
|
||||
}}}
|
||||
|
||||
#endif
|
90
ReactCommon/bridge/JsArgumentHelpers-inl.h
Normal file
90
ReactCommon/bridge/JsArgumentHelpers-inl.h
Normal file
@ -0,0 +1,90 @@
|
||||
// Copyright 2004-present Facebook. All Rights Reserved.
|
||||
|
||||
#pragma once
|
||||
|
||||
namespace facebook {
|
||||
namespace xplat {
|
||||
|
||||
namespace detail {
|
||||
|
||||
template <typename R, typename M, typename... T>
|
||||
R jsArg1(const folly::dynamic& arg, M asFoo, const T&... desc) {
|
||||
try {
|
||||
return (arg.*asFoo)();
|
||||
} catch (const folly::TypeError& ex) {
|
||||
throw JsArgumentException(
|
||||
folly::to<std::string>(
|
||||
"Error converting javascript arg ", desc..., " to C++: ", ex.what()));
|
||||
} catch (const std::range_error& ex) {
|
||||
throw JsArgumentException(
|
||||
folly::to<std::string>(
|
||||
"Could not convert argument ", desc..., " to required type: ", ex.what()));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
template <typename R, typename... T>
|
||||
R jsArg(const folly::dynamic& arg, R (folly::dynamic::*asFoo)() const, const T&... desc) {
|
||||
return detail::jsArg1<R>(arg, asFoo, desc...);
|
||||
}
|
||||
|
||||
template <typename R, typename... T>
|
||||
R jsArg(const folly::dynamic& arg, R (folly::dynamic::*asFoo)() const&, const T&... desc) {
|
||||
return detail::jsArg1<R>(arg, asFoo, desc...);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
typename detail::is_dynamic<T>::type& jsArgAsDynamic(T&& args, size_t n) {
|
||||
try {
|
||||
return args[n];
|
||||
} catch (const std::out_of_range& ex) {
|
||||
// Use 1-base counting for argument description.
|
||||
throw JsArgumentException(
|
||||
folly::to<std::string>(
|
||||
"JavaScript provided ", args.size(),
|
||||
" arguments for C++ method which references at least ", n + 1,
|
||||
" arguments: ", ex.what()));
|
||||
}
|
||||
}
|
||||
|
||||
template <typename R>
|
||||
R jsArgN(const folly::dynamic& args, size_t n, R (folly::dynamic::*asFoo)() const) {
|
||||
return jsArg(jsArgAsDynamic(args, n), asFoo, n);
|
||||
}
|
||||
template <typename R>
|
||||
R jsArgN(const folly::dynamic& args, size_t n, R (folly::dynamic::*asFoo)() const&) {
|
||||
return jsArg(jsArgAsDynamic(args, n), asFoo, n);
|
||||
}
|
||||
|
||||
namespace detail {
|
||||
|
||||
// This is a helper for jsArgAsArray and jsArgAsObject.
|
||||
|
||||
template <typename T>
|
||||
typename detail::is_dynamic<T>::type& jsArgAsType(T&& args, size_t n, const char* required,
|
||||
bool (folly::dynamic::*isFoo)() const) {
|
||||
T& ret = jsArgAsDynamic(args, n);
|
||||
if ((ret.*isFoo)()) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
// Use 1-base counting for argument description.
|
||||
throw JsArgumentException(
|
||||
folly::to<std::string>(
|
||||
"Argument ", n + 1, " of type ", ret.typeName(), " is not required type ", required));
|
||||
}
|
||||
|
||||
} // end namespace detail
|
||||
|
||||
template <typename T>
|
||||
typename detail::is_dynamic<T>::type& jsArgAsArray(T&& args, size_t n) {
|
||||
return detail::jsArgAsType(args, n, "Array", &folly::dynamic::isArray);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
typename detail::is_dynamic<T>::type& jsArgAsObject(T&& args, size_t n) {
|
||||
return detail::jsArgAsType(args, n, "Object", &folly::dynamic::isObject);
|
||||
}
|
||||
|
||||
}}
|
105
ReactCommon/bridge/JsArgumentHelpers.h
Normal file
105
ReactCommon/bridge/JsArgumentHelpers.h
Normal file
@ -0,0 +1,105 @@
|
||||
// Copyright 2004-present Facebook. All Rights Reserved.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <folly/Conv.h>
|
||||
#include <folly/dynamic.h>
|
||||
|
||||
#include <exception>
|
||||
|
||||
// When building a cross-platform module for React Native, arguments passed
|
||||
// from JS are represented as a folly::dynamic. This class provides helpers to
|
||||
// extract arguments from the folly::dynamic to concrete types usable by
|
||||
// cross-platform code, and converting exceptions to a JsArgumentException so
|
||||
// they can be caught and reported to RN consistently. The goal is to make the
|
||||
// jsArgAs... methods at the end simple to use should be most common, but any
|
||||
// non-detail method can be used when needed.
|
||||
|
||||
namespace facebook {
|
||||
namespace xplat {
|
||||
|
||||
class JsArgumentException : public std::logic_error {
|
||||
public:
|
||||
JsArgumentException(const std::string& msg) : std::logic_error(msg) {}
|
||||
};
|
||||
|
||||
// This extracts a single argument by calling the given method pointer on it.
|
||||
// If an exception is thrown, the additional arguments are passed to
|
||||
// folly::to<> to be included in the exception string. This will be most
|
||||
// commonly used when extracting values from non-scalar argument. The second
|
||||
// overload accepts ref-qualified member functions.
|
||||
|
||||
template <typename R, typename... T>
|
||||
R jsArg(const folly::dynamic& arg, R (folly::dynamic::*asFoo)() const, const T&... desc);
|
||||
template <typename R, typename... T>
|
||||
R jsArg(const folly::dynamic& arg, R (folly::dynamic::*asFoo)() const&, const T&... desc);
|
||||
|
||||
// This is like jsArg, but a operates on a dynamic representing an array of
|
||||
// arguments. The argument n is used both to index the array and build the
|
||||
// exception message, if any. It can be used directly, but will more often be
|
||||
// used by the type-specific methods following.
|
||||
|
||||
template <typename R>
|
||||
R jsArgN(const folly::dynamic& args, size_t n, R (folly::dynamic::*asFoo)() const);
|
||||
template <typename R>
|
||||
R jsArgN(const folly::dynamic& args, size_t n, R (folly::dynamic::*asFoo)() const&);
|
||||
|
||||
namespace detail {
|
||||
|
||||
// This is a type helper to implement functions which should work on both const
|
||||
// and non-const folly::dynamic arguments, and return a type with the same
|
||||
// constness. Basically, it causes the templates which use it to be defined
|
||||
// only for types compatible with folly::dynamic.
|
||||
template <typename T>
|
||||
struct is_dynamic {
|
||||
typedef typename std::enable_if<std::is_assignable<folly::dynamic, T>::value, T>::type type;
|
||||
};
|
||||
|
||||
} // end namespace detail
|
||||
|
||||
// Easy to use conversion helpers are here:
|
||||
|
||||
// Extract the n'th arg from the given dynamic, as a dynamic. Throws a
|
||||
// JsArgumentException if there is no n'th arg in the input.
|
||||
template <typename T>
|
||||
typename detail::is_dynamic<T>::type& jsArgAsDynamic(T&& args, size_t n);
|
||||
|
||||
// Extract the n'th arg from the given dynamic, as a dynamic Array. Throws a
|
||||
// JsArgumentException if there is no n'th arg in the input, or it is not an
|
||||
// Array.
|
||||
template <typename T>
|
||||
typename detail::is_dynamic<T>::type& jsArgAsArray(T&& args, size_t n);
|
||||
|
||||
// Extract the n'th arg from the given dynamic, as a dynamic Object. Throws a
|
||||
// JsArgumentException if there is no n'th arg in the input, or it is not an
|
||||
// Object.
|
||||
template <typename T>
|
||||
typename detail::is_dynamic<T>::type& jsArgAsObject(T&& args, size_t n);
|
||||
|
||||
// Extract the n'th arg from the given dynamic, as a bool. Throws a
|
||||
// JsArgumentException if this fails for some reason.
|
||||
inline bool jsArgAsBool(const folly::dynamic& args, size_t n) {
|
||||
return jsArgN(args, n, &folly::dynamic::asBool);
|
||||
}
|
||||
|
||||
// Extract the n'th arg from the given dynamic, as an integer. Throws a
|
||||
// JsArgumentException if this fails for some reason.
|
||||
inline int64_t jsArgAsInt(const folly::dynamic& args, size_t n) {
|
||||
return jsArgN(args, n, &folly::dynamic::asInt);
|
||||
}
|
||||
|
||||
// Extract the n'th arg from the given dynamic, as a double. Throws a
|
||||
// JsArgumentException if this fails for some reason.
|
||||
inline double jsArgAsDouble(const folly::dynamic& args, size_t n) {
|
||||
return jsArgN(args, n, &folly::dynamic::asDouble);
|
||||
}
|
||||
|
||||
// Extract the n'th arg from the given dynamic, as a string. Throws a
|
||||
// JsArgumentException if this fails for some reason.
|
||||
inline std::string jsArgAsString(const folly::dynamic& args, size_t n) {
|
||||
return jsArgN(args, n, &folly::dynamic::asString);
|
||||
}
|
||||
|
||||
}}
|
||||
|
||||
#include "JsArgumentHelpers-inl.h"
|
130
ReactCommon/bridge/SampleCxxModule.cpp
Normal file
130
ReactCommon/bridge/SampleCxxModule.cpp
Normal file
@ -0,0 +1,130 @@
|
||||
// Copyright 2004-present Facebook. All Rights Reserved.
|
||||
|
||||
#include "SampleCxxModule.h"
|
||||
#include <cxxreact/JsArgumentHelpers.h>
|
||||
|
||||
#include <folly/Memory.h>
|
||||
#include <glog/logging.h>
|
||||
|
||||
#include <thread>
|
||||
|
||||
using namespace folly;
|
||||
|
||||
namespace facebook { namespace xplat { namespace samples {
|
||||
|
||||
std::string Sample::hello() {
|
||||
LOG(WARNING) << "glog: hello, world";
|
||||
return "hello";
|
||||
}
|
||||
|
||||
double Sample::add(double a, double b) {
|
||||
return a + b;
|
||||
}
|
||||
|
||||
std::string Sample::concat(const std::string& a, const std::string& b) {
|
||||
return a + b;
|
||||
}
|
||||
|
||||
std::string Sample::repeat(int count, const std::string& str) {
|
||||
std::string ret;
|
||||
for (int i = 0; i < count; i++) {
|
||||
ret += str;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void Sample::save(std::map<std::string, std::string> dict)
|
||||
{
|
||||
state_ = std::move(dict);
|
||||
}
|
||||
|
||||
std::map<std::string, std::string> Sample::load() {
|
||||
return state_;
|
||||
}
|
||||
|
||||
void Sample::except() {
|
||||
// TODO mhorowitz #7128529: There's no way to automatically test this
|
||||
// right now.
|
||||
// throw std::runtime_error("oops");
|
||||
}
|
||||
|
||||
void Sample::call_later(int msec, std::function<void()> f) {
|
||||
std::thread t([=] {
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(msec));
|
||||
f();
|
||||
});
|
||||
t.detach();
|
||||
}
|
||||
|
||||
SampleCxxModule::SampleCxxModule(std::unique_ptr<Sample> sample)
|
||||
: sample_(std::move(sample)) {}
|
||||
|
||||
std::string SampleCxxModule::getName() {
|
||||
return "Sample";
|
||||
}
|
||||
|
||||
auto SampleCxxModule::getConstants() -> std::map<std::string, folly::dynamic> {
|
||||
return {
|
||||
{ "one", 1 },
|
||||
{ "two", 2 },
|
||||
{ "animal", "fox" },
|
||||
};
|
||||
}
|
||||
|
||||
auto SampleCxxModule::getMethods() -> std::vector<Method> {
|
||||
return {
|
||||
Method("hello", [this] {
|
||||
sample_->hello();
|
||||
}),
|
||||
Method("add", [this](dynamic args, Callback cb) {
|
||||
LOG(WARNING) << "Sample: add => "
|
||||
<< sample_->add(jsArgAsDouble(args, 0), jsArgAsDouble(args, 1));
|
||||
cb({sample_->add(jsArgAsDouble(args, 0), jsArgAsDouble(args, 1))});
|
||||
}),
|
||||
Method("concat", [this](dynamic args, Callback cb) {
|
||||
cb({sample_->concat(jsArgAsString(args, 0),
|
||||
jsArgAsString(args, 1))});
|
||||
}),
|
||||
Method("repeat", [this](dynamic args, Callback cb) {
|
||||
cb({sample_->repeat(jsArgAsInt(args, 0),
|
||||
jsArgAsString(args, 1))});
|
||||
}),
|
||||
Method("save", this, &SampleCxxModule::save),
|
||||
Method("load", this, &SampleCxxModule::load),
|
||||
Method("call_later", [this](dynamic args, Callback cb) {
|
||||
sample_->call_later(jsArgAsInt(args, 0), [cb] {
|
||||
cb({});
|
||||
});
|
||||
}),
|
||||
Method("except", [this] {
|
||||
sample_->except();
|
||||
}),
|
||||
};
|
||||
}
|
||||
|
||||
void SampleCxxModule::save(folly::dynamic args) {
|
||||
std::map<std::string, std::string> m;
|
||||
for (const auto& p : jsArgN(args, 0, &dynamic::items)) {
|
||||
m.emplace(jsArg(p.first, &dynamic::asString, "map key"),
|
||||
jsArg(p.second, &dynamic::asString, "map value"));
|
||||
}
|
||||
sample_->save(std::move(m));
|
||||
}
|
||||
|
||||
void SampleCxxModule::load(folly::dynamic args, Callback cb) {
|
||||
dynamic d = dynamic::object;
|
||||
for (const auto& p : sample_->load()) {
|
||||
d.insert(p.first, p.second);
|
||||
}
|
||||
cb({d});
|
||||
}
|
||||
|
||||
}}}
|
||||
|
||||
// By convention, the function name should be the same as the class
|
||||
// name.
|
||||
extern "C" facebook::xplat::module::CxxModule *SampleCxxModule() {
|
||||
return new facebook::xplat::samples::SampleCxxModule(
|
||||
folly::make_unique<facebook::xplat::samples::Sample>());
|
||||
}
|
51
ReactCommon/bridge/SampleCxxModule.h
Normal file
51
ReactCommon/bridge/SampleCxxModule.h
Normal file
@ -0,0 +1,51 @@
|
||||
// Copyright 2004-present Facebook. All Rights Reserved.
|
||||
|
||||
#ifndef FBSAMPLEXPLATMODULE
|
||||
#define FBSAMPLEXPLATMODULE
|
||||
|
||||
#include <cxxreact/CxxModule.h>
|
||||
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
namespace facebook { namespace xplat { namespace samples {
|
||||
|
||||
// In a less contrived example, Sample would be part of a traditional
|
||||
// C++ library.
|
||||
|
||||
class Sample {
|
||||
public:
|
||||
std::string hello();
|
||||
double add(double a, double b);
|
||||
std::string concat(const std::string& a, const std::string& b);
|
||||
std::string repeat(int count, const std::string& str);
|
||||
void save(std::map<std::string, std::string> dict);
|
||||
std::map<std::string, std::string> load();
|
||||
void call_later(int msec, std::function<void()> f);
|
||||
void except();
|
||||
|
||||
private:
|
||||
std::map<std::string, std::string> state_;
|
||||
};
|
||||
|
||||
class SampleCxxModule : public module::CxxModule {
|
||||
public:
|
||||
SampleCxxModule(std::unique_ptr<Sample> sample);
|
||||
|
||||
std::string getName();
|
||||
|
||||
virtual auto getConstants() -> std::map<std::string, folly::dynamic>;
|
||||
|
||||
virtual auto getMethods() -> std::vector<Method>;
|
||||
|
||||
private:
|
||||
void save(folly::dynamic args);
|
||||
void load(folly::dynamic args, Callback cb);
|
||||
|
||||
std::unique_ptr<Sample> sample_;
|
||||
};
|
||||
|
||||
}}}
|
||||
|
||||
#endif
|
||||
|
Loading…
x
Reference in New Issue
Block a user