123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139 |
- /*
- * 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.
- */
- #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 "RCTCxxUtils.h"
- #import <memory>
- 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 = std::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 which 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 %zu 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
|