CxxModule.h 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258
  1. /*
  2. * Copyright (c) Facebook, Inc. and its affiliates.
  3. *
  4. * This source code is licensed under the MIT license found in the
  5. * LICENSE file in the root directory of this source tree.
  6. */
  7. #pragma once
  8. #include <functional>
  9. #include <map>
  10. #include <tuple>
  11. #include <vector>
  12. #include <folly/dynamic.h>
  13. using namespace std::placeholders;
  14. namespace facebook {
  15. namespace react {
  16. class Instance;
  17. }
  18. } // namespace facebook
  19. namespace facebook {
  20. namespace xplat {
  21. namespace module {
  22. /**
  23. * Base class for Catalyst native modules whose implementations are
  24. * written in C++. Native methods are represented by instances of the
  25. * Method struct. Generally, a derived class will manage an instance
  26. * which represents the data for the module, and non-Catalyst-specific
  27. * methods can be wrapped in lambdas which convert between
  28. * folly::dynamic and native C++ objects. The Callback arguments will
  29. * pass through to js functions passed to the analogous javascript
  30. * methods. At most two callbacks will be converted. Results should
  31. * be passed to the first callback, and errors to the second callback.
  32. * Exceptions thrown by a method will be converted to platform
  33. * exceptions, and handled however they are handled on that platform.
  34. * (TODO mhorowitz #7128529: this exception behavior is not yet
  35. * implemented.)
  36. *
  37. * There are two sets of constructors here. The first set initializes
  38. * a Method using a name and anything convertible to a std::function.
  39. * This is most useful for registering a lambda as a RN method. There
  40. * are overloads to support functions which take no arguments,
  41. * arguments only, and zero, one, or two callbacks.
  42. *
  43. * The second set of methods is similar, but instead of taking a
  44. * function, takes the method name, an object, and a pointer to a
  45. * method on that object.
  46. */
  47. class CxxModule {
  48. class AsyncTagType {};
  49. class SyncTagType {};
  50. public:
  51. typedef std::function<std::unique_ptr<CxxModule>()> Provider;
  52. typedef std::function<void(std::vector<folly::dynamic>)> Callback;
  53. constexpr static AsyncTagType AsyncTag = AsyncTagType();
  54. constexpr static SyncTagType SyncTag = SyncTagType();
  55. struct Method {
  56. std::string name;
  57. size_t callbacks;
  58. bool isPromise;
  59. std::function<void(folly::dynamic, Callback, Callback)> func;
  60. std::function<folly::dynamic(folly::dynamic)> syncFunc;
  61. const char *getType() {
  62. assert(func || syncFunc);
  63. return func ? (isPromise ? "promise" : "async") : "sync";
  64. }
  65. // std::function/lambda ctors
  66. Method(std::string aname, std::function<void()> &&afunc)
  67. : name(std::move(aname)),
  68. callbacks(0),
  69. isPromise(false),
  70. func(std::bind(std::move(afunc))) {}
  71. Method(std::string aname, std::function<void(folly::dynamic)> &&afunc)
  72. : name(std::move(aname)),
  73. callbacks(0),
  74. isPromise(false),
  75. func(std::bind(std::move(afunc), std::placeholders::_1)) {}
  76. Method(
  77. std::string aname,
  78. std::function<void(folly::dynamic, Callback)> &&afunc)
  79. : name(std::move(aname)),
  80. callbacks(1),
  81. isPromise(false),
  82. func(std::bind(
  83. std::move(afunc),
  84. std::placeholders::_1,
  85. std::placeholders::_2)) {}
  86. Method(
  87. std::string aname,
  88. std::function<void(folly::dynamic, Callback, Callback)> &&afunc)
  89. : name(std::move(aname)),
  90. callbacks(2),
  91. isPromise(true),
  92. func(std::move(afunc)) {}
  93. Method(
  94. std::string aname,
  95. std::function<void(folly::dynamic, Callback, Callback)> &&afunc,
  96. AsyncTagType)
  97. : name(std::move(aname)),
  98. callbacks(2),
  99. isPromise(false),
  100. func(std::move(afunc)) {}
  101. // method pointer ctors
  102. template <typename T>
  103. Method(std::string aname, T *t, void (T::*method)())
  104. : name(std::move(aname)),
  105. callbacks(0),
  106. isPromise(false),
  107. func(std::bind(method, t)) {}
  108. template <typename T>
  109. Method(std::string aname, T *t, void (T::*method)(folly::dynamic))
  110. : name(std::move(aname)),
  111. callbacks(0),
  112. isPromise(false),
  113. func(std::bind(method, t, std::placeholders::_1)) {}
  114. template <typename T>
  115. Method(std::string aname, T *t, void (T::*method)(folly::dynamic, Callback))
  116. : name(std::move(aname)),
  117. callbacks(1),
  118. isPromise(false),
  119. func(std::bind(
  120. method,
  121. t,
  122. std::placeholders::_1,
  123. std::placeholders::_2)) {}
  124. template <typename T>
  125. Method(
  126. std::string aname,
  127. T *t,
  128. void (T::*method)(folly::dynamic, Callback, Callback))
  129. : name(std::move(aname)),
  130. callbacks(2),
  131. isPromise(true),
  132. func(std::bind(
  133. method,
  134. t,
  135. std::placeholders::_1,
  136. std::placeholders::_2,
  137. std::placeholders::_3)) {}
  138. template <typename T>
  139. Method(
  140. std::string aname,
  141. T *t,
  142. void (T::*method)(folly::dynamic, Callback, Callback),
  143. AsyncTagType)
  144. : name(std::move(aname)),
  145. callbacks(2),
  146. isPromise(false),
  147. func(std::bind(
  148. method,
  149. t,
  150. std::placeholders::_1,
  151. std::placeholders::_2,
  152. std::placeholders::_3)) {}
  153. // sync std::function/lambda ctors
  154. // Overloads for functions returning void give ambiguity errors.
  155. // I am not sure if this is a runtime/compiler bug, or a
  156. // limitation I do not understand.
  157. Method(
  158. std::string aname,
  159. std::function<folly::dynamic()> &&afunc,
  160. SyncTagType)
  161. : name(std::move(aname)),
  162. callbacks(0),
  163. isPromise(false),
  164. syncFunc([afunc = std::move(afunc)](const folly::dynamic &) {
  165. return afunc();
  166. }) {}
  167. Method(
  168. std::string aname,
  169. std::function<folly::dynamic(folly::dynamic)> &&afunc,
  170. SyncTagType)
  171. : name(std::move(aname)),
  172. callbacks(0),
  173. isPromise(false),
  174. syncFunc(std::move(afunc)) {}
  175. };
  176. /**
  177. * This may block, if necessary to complete cleanup before the
  178. * object is destroyed.
  179. */
  180. virtual ~CxxModule() {}
  181. /**
  182. * @return the name of this module. This will be the name used to {@code
  183. * require()} this module from javascript.
  184. */
  185. virtual std::string getName() = 0;
  186. /**
  187. * Each entry in the map will be exported as a property to JS. The
  188. * key is the property name, and the value can be anything.
  189. */
  190. virtual auto getConstants() -> std::map<std::string, folly::dynamic> {
  191. return {};
  192. };
  193. /**
  194. * @return a list of methods this module exports to JS.
  195. */
  196. virtual auto getMethods() -> std::vector<Method> = 0;
  197. /**
  198. * Called during the construction of CxxNativeModule.
  199. */
  200. void setInstance(std::weak_ptr<react::Instance> instance) {
  201. instance_ = instance;
  202. }
  203. /**
  204. * @return a weak_ptr to the current instance of the bridge.
  205. * When used with CxxNativeModule, this gives Cxx modules access to functions
  206. * such as `callJSFunction`, allowing them to communicate back to JS outside
  207. * of the regular callbacks.
  208. */
  209. std::weak_ptr<react::Instance> getInstance() {
  210. return instance_;
  211. }
  212. private:
  213. std::weak_ptr<react::Instance> instance_;
  214. };
  215. } // namespace module
  216. } // namespace xplat
  217. } // namespace facebook