Skip to content

Commit 8826d8b

Browse files
REDMOND\acoatesfacebook-github-bot
REDMOND\acoates
authored andcommitted
Allow CxxModules to implement methods with two callbacks (#21586)
Summary: When writing a native module in C++ using CxxModule, its not currently possible to write async methods which take two callbacks, that shouldn't be projected to JS as a promise. I hit this when trying to implement the AppState module in c++. AppState has a single method on it, getCurrentAppState, which takes two callbacks (a success and a failure callback). This change adds a couple of new CxxModule::Method ctors, which allow devs to specify that they want two callbacks, but not a promise. This is done using an extra tag in the ctor, similar to how you specify that you want to make a synchronous method. I used the existing AsyncTag to indicate that the 2 callback version should be async, and not a promise. Pull Request resolved: #21586 Reviewed By: shergin Differential Revision: D10520204 Pulled By: fkgozali fbshipit-source-id: bcb2dbd91cba3c1db987dc18960247218fdbc032
1 parent 11d4512 commit 8826d8b

File tree

2 files changed

+54
-6
lines changed

2 files changed

+54
-6
lines changed

ReactCommon/cxxreact/CxxModule.h

+35-6
Original file line numberDiff line numberDiff line change
@@ -67,13 +67,14 @@ class CxxModule {
6767
std::string name;
6868

6969
size_t callbacks;
70+
bool isPromise;
7071
std::function<void(folly::dynamic, Callback, Callback)> func;
7172

7273
std::function<folly::dynamic(folly::dynamic)> syncFunc;
7374

7475
const char *getType() {
7576
assert(func || syncFunc);
76-
return func ? (callbacks == 2 ? "promise" : "async") : "sync";
77+
return func ? (isPromise ? "promise" : "async") : "sync";
7778
}
7879

7980
// std::function/lambda ctors
@@ -82,24 +83,36 @@ class CxxModule {
8283
std::function<void()>&& afunc)
8384
: name(std::move(aname))
8485
, callbacks(0)
86+
, isPromise(false)
8587
, func(std::bind(std::move(afunc))) {}
8688

8789
Method(std::string aname,
8890
std::function<void(folly::dynamic)>&& afunc)
8991
: name(std::move(aname))
9092
, callbacks(0)
91-
, func(std::bind(std::move(afunc), _1)) {}
93+
, isPromise(false)
94+
, func(std::bind(std::move(afunc), std::placeholders::_1)) {}
9295

9396
Method(std::string aname,
9497
std::function<void(folly::dynamic, Callback)>&& afunc)
9598
: name(std::move(aname))
9699
, callbacks(1)
97-
, func(std::bind(std::move(afunc), _1, _2)) {}
100+
, isPromise(false)
101+
, func(std::bind(std::move(afunc), std::placeholders::_1, std::placeholders::_2)) {}
98102

99103
Method(std::string aname,
100104
std::function<void(folly::dynamic, Callback, Callback)>&& afunc)
101105
: name(std::move(aname))
102106
, callbacks(2)
107+
, isPromise(true)
108+
, func(std::move(afunc)) {}
109+
110+
Method(std::string aname,
111+
std::function<void(folly::dynamic, Callback, Callback)>&& afunc,
112+
AsyncTagType)
113+
: name(std::move(aname))
114+
, callbacks(2)
115+
, isPromise(false)
103116
, func(std::move(afunc)) {}
104117

105118
// method pointer ctors
@@ -108,25 +121,39 @@ class CxxModule {
108121
Method(std::string aname, T* t, void (T::*method)())
109122
: name(std::move(aname))
110123
, callbacks(0)
124+
, isPromise(false)
111125
, func(std::bind(method, t)) {}
112126

113127
template <typename T>
114128
Method(std::string aname, T* t, void (T::*method)(folly::dynamic))
115129
: name(std::move(aname))
116130
, callbacks(0)
117-
, func(std::bind(method, t, _1)) {}
131+
, isPromise(false)
132+
, func(std::bind(method, t, std::placeholders::_1)) {}
118133

119134
template <typename T>
120135
Method(std::string aname, T* t, void (T::*method)(folly::dynamic, Callback))
121136
: name(std::move(aname))
122137
, callbacks(1)
123-
, func(std::bind(method, t, _1, _2)) {}
138+
, isPromise(false)
139+
, func(std::bind(method, t, std::placeholders::_1, std::placeholders::_2)) {}
124140

125141
template <typename T>
126142
Method(std::string aname, T* t, void (T::*method)(folly::dynamic, Callback, Callback))
127143
: name(std::move(aname))
128144
, callbacks(2)
129-
, func(std::bind(method, t, _1, _2, _3)) {}
145+
, isPromise(true)
146+
, func(std::bind(method, t, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3)) {}
147+
148+
template <typename T>
149+
Method(std::string aname,
150+
T* t,
151+
void (T::*method)(folly::dynamic, Callback, Callback),
152+
AsyncTagType)
153+
: name(std::move(aname))
154+
, callbacks(2)
155+
, isPromise(false)
156+
, func(std::bind(method, t, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3)) {}
130157

131158
// sync std::function/lambda ctors
132159

@@ -139,6 +166,7 @@ class CxxModule {
139166
SyncTagType)
140167
: name(std::move(aname))
141168
, callbacks(0)
169+
, isPromise(false)
142170
, syncFunc([afunc=std::move(afunc)] (const folly::dynamic&)
143171
{ return afunc(); })
144172
{}
@@ -148,6 +176,7 @@ class CxxModule {
148176
SyncTagType)
149177
: name(std::move(aname))
150178
, callbacks(0)
179+
, isPromise(false)
151180
, syncFunc(std::move(afunc))
152181
{}
153182
};

ReactCommon/cxxreact/SampleCxxModule.cpp

+19
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,25 @@ auto SampleCxxModule::getMethods() -> std::vector<Method> {
114114
sample_->hello();
115115
return nullptr;
116116
}, SyncTag),
117+
Method("addIfPositiveAsPromise", [](dynamic args, Callback cb, Callback cbError) {
118+
auto a = jsArgAsDouble(args, 0);
119+
auto b = jsArgAsDouble(args, 1);
120+
if (a < 0 || b < 0) {
121+
cbError({"Negative number!"});
122+
} else {
123+
cb({a + b});
124+
}
125+
}),
126+
Method("addIfPositiveAsAsync", [](dynamic args, Callback cb, Callback cbError) {
127+
auto a = jsArgAsDouble(args, 0);
128+
auto b = jsArgAsDouble(args, 1);
129+
if (a < 0 || b < 0) {
130+
cbError({"Negative number!"});
131+
} else {
132+
cb({a + b});
133+
}
134+
}, AsyncTag),
135+
117136
};
118137
}
119138

0 commit comments

Comments
 (0)