133 lines
4.0 KiB
Plaintext
133 lines
4.0 KiB
Plaintext
/**
|
|
* Copyright (c) 2015-present, Facebook, Inc.
|
|
* All rights reserved.
|
|
*
|
|
* This source code is licensed under the BSD-style license found in the
|
|
* LICENSE file in the root directory of this source tree. An additional grant
|
|
* of patent rights can be found in the PATENTS file in the same directory.
|
|
*/
|
|
|
|
#import "RCTCxxMethod.h"
|
|
|
|
#import <React/RCTBridge+Private.h>
|
|
#import <React/RCTBridge.h>
|
|
#import <React/RCTConvert.h>
|
|
#import <React/RCTFollyConvert.h>
|
|
#import <cxxreact/JsArgumentHelpers.h>
|
|
#import <folly/Memory.h>
|
|
|
|
#import "RCTCxxUtils.h"
|
|
|
|
using facebook::xplat::module::CxxModule;
|
|
using namespace facebook::react;
|
|
|
|
@implementation RCTCxxMethod
|
|
{
|
|
std::unique_ptr<CxxModule::Method> _method;
|
|
}
|
|
|
|
- (instancetype)initWithCxxMethod:(const CxxModule::Method &)method
|
|
{
|
|
if ((self = [super init])) {
|
|
_method = folly::make_unique<CxxModule::Method>(method);
|
|
}
|
|
return self;
|
|
}
|
|
|
|
- (const char *)JSMethodName
|
|
{
|
|
return _method->name.c_str();
|
|
}
|
|
|
|
- (RCTFunctionType)functionType
|
|
{
|
|
std::string type(_method->getType());
|
|
if (type == "sync") {
|
|
return RCTFunctionTypeSync;
|
|
} else if (type == "async") {
|
|
return RCTFunctionTypeNormal;
|
|
} else {
|
|
return RCTFunctionTypePromise;
|
|
}
|
|
}
|
|
|
|
- (id)invokeWithBridge:(RCTBridge *)bridge
|
|
module:(id)module
|
|
arguments:(NSArray *)arguments
|
|
{
|
|
// module is unused except for printing errors. The C++ object it represents
|
|
// is also baked into _method.
|
|
|
|
// the last N arguments are callbacks, according to the Method data. The
|
|
// preceding arguments are values whic have already been parsed from JS: they
|
|
// may be NSNumber (bool, int, double), NSString, NSArray, or NSObject.
|
|
|
|
CxxModule::Callback first;
|
|
CxxModule::Callback second;
|
|
|
|
if (arguments.count < _method->callbacks) {
|
|
RCTLogError(@"Method %@.%s expects at least %lu arguments, but got %tu",
|
|
RCTBridgeModuleNameForClass([module class]), _method->name.c_str(),
|
|
_method->callbacks, arguments.count);
|
|
return nil;
|
|
}
|
|
|
|
if (_method->callbacks >= 1) {
|
|
if (![arguments[arguments.count - 1] isKindOfClass:[NSNumber class]]) {
|
|
RCTLogError(@"Argument %tu (%@) of %@.%s should be a function",
|
|
arguments.count - 1, arguments[arguments.count - 1],
|
|
RCTBridgeModuleNameForClass([module class]), _method->name.c_str());
|
|
return nil;
|
|
}
|
|
|
|
NSNumber *id1;
|
|
if (_method->callbacks == 2) {
|
|
if (![arguments[arguments.count - 2] isKindOfClass:[NSNumber class]]) {
|
|
RCTLogError(@"Argument %tu (%@) of %@.%s should be a function",
|
|
arguments.count - 2, arguments[arguments.count - 2],
|
|
RCTBridgeModuleNameForClass([module class]), _method->name.c_str());
|
|
return nil;
|
|
}
|
|
|
|
id1 = arguments[arguments.count - 2];
|
|
NSNumber *id2 = arguments[arguments.count - 1];
|
|
|
|
second = ^(std::vector<folly::dynamic> args) {
|
|
[bridge enqueueCallback:id2 args:convertFollyDynamicToId(folly::dynamic(args.begin(), args.end()))];
|
|
};
|
|
} else {
|
|
id1 = arguments[arguments.count - 1];
|
|
}
|
|
|
|
first = ^(std::vector<folly::dynamic> args) {
|
|
[bridge enqueueCallback:id1 args:convertFollyDynamicToId(folly::dynamic(args.begin(), args.end()))];
|
|
};
|
|
}
|
|
|
|
folly::dynamic args = convertIdToFollyDynamic(arguments);
|
|
args.resize(args.size() - _method->callbacks);
|
|
|
|
try {
|
|
if (_method->func) {
|
|
_method->func(std::move(args), first, second);
|
|
return nil;
|
|
} else {
|
|
auto result = _method->syncFunc(std::move(args));
|
|
// TODO: we should convert this to JSValue directly
|
|
return convertFollyDynamicToId(result);
|
|
}
|
|
} catch (const facebook::xplat::JsArgumentException &ex) {
|
|
RCTLogError(@"Method %@.%s argument error: %s",
|
|
RCTBridgeModuleNameForClass([module class]), _method->name.c_str(),
|
|
ex.what());
|
|
return nil;
|
|
}
|
|
}
|
|
|
|
- (NSString *)description
|
|
{
|
|
return [NSString stringWithFormat:@"<%@: %p; name = %s>", [self class], self, self.JSMethodName];
|
|
}
|
|
|
|
@end
|