iOS/FlipperKit/FBCxxFollyDynamicConvert/FBCxxFollyDynamicConvert.mm (107 lines of code) (raw):
/*
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#import "FBCxxFollyDynamicConvert.h"
#import <objc/runtime.h>
namespace facebook {
namespace cxxutils {
/*
* The implementation is taken from RCTFollyConvert(https://fburl.com/vzw8ql2q)
*/
id convertFollyDynamicToId(const folly::dynamic& dyn) {
// I could imagine an implementation which avoids copies by wrapping the
// dynamic in a derived class of NSDictionary. We can do that if profiling
// implies it will help.
switch (dyn.type()) {
case folly::dynamic::NULLT:
return (id)kCFNull;
case folly::dynamic::BOOL:
return dyn.getBool() ? @YES : @NO;
case folly::dynamic::INT64:
return @(dyn.getInt());
case folly::dynamic::DOUBLE:
return @(dyn.getDouble());
case folly::dynamic::STRING:
return [[NSString alloc] initWithBytes:dyn.c_str()
length:dyn.size()
encoding:NSUTF8StringEncoding];
case folly::dynamic::ARRAY: {
NSMutableArray* array =
[[NSMutableArray alloc] initWithCapacity:dyn.size()];
for (auto& elem : dyn) {
id obj = convertFollyDynamicToId(elem);
if (obj) {
[array addObject:obj];
}
}
return array;
}
case folly::dynamic::OBJECT: {
NSMutableDictionary* dict =
[[NSMutableDictionary alloc] initWithCapacity:dyn.size()];
for (auto& elem : dyn.items()) {
id obj = convertFollyDynamicToId(elem.second);
if (obj) {
dict[convertFollyDynamicToId(elem.first)] = obj;
}
}
return dict;
}
}
}
folly::dynamic convertIdToFollyDynamic(id json, bool nullifyNanAndInf) {
if (json == nil || json == (id)kCFNull) {
return nullptr;
} else if ([json isKindOfClass:[NSNumber class]]) {
const char* objCType = [json objCType];
switch (objCType[0]) {
// This is a c++ bool or C99 _Bool. On some platforms, BOOL is a bool.
case _C_BOOL:
return (bool)[json boolValue];
case _C_CHR:
// On some platforms, objc BOOL is a signed char, but it
// might also be a small number. Use the same hack JSC uses
// to distinguish them:
// https://phabricator.intern.facebook.com/diffusion/FBS/browse/master/fbobjc/xplat/third-party/jsc/safari-600-1-4-17/JavaScriptCore/API/JSValue.mm;b8ee03916489f8b12143cd5c0bca546da5014fc9$901
if ([json isKindOfClass:[@YES class]]) {
return (bool)[json boolValue];
} else {
const auto value = [json longLongValue];
if (nullifyNanAndInf && (isnan(value) || isinf(value))) {
return nullptr;
}
return value;
}
case _C_UCHR:
case _C_SHT:
case _C_USHT:
case _C_INT:
case _C_UINT:
case _C_LNG:
case _C_ULNG:
case _C_LNG_LNG:
case _C_ULNG_LNG: {
const auto value = [json longLongValue];
if (nullifyNanAndInf && (isnan(value) || isinf(value))) {
return nullptr;
}
return value;
}
case _C_FLT:
case _C_DBL: {
const auto value = [json doubleValue];
if (nullifyNanAndInf && (isnan(value) || isinf(value))) {
return nullptr;
}
return value;
}
// default:
// fall through
}
} else if ([json isKindOfClass:[NSString class]]) {
NSData* data = [json dataUsingEncoding:NSUTF8StringEncoding];
return std::string(reinterpret_cast<const char*>(data.bytes), data.length);
} else if ([json isKindOfClass:[NSArray class]]) {
folly::dynamic array = folly::dynamic::array;
for (id element in json) {
array.push_back(convertIdToFollyDynamic(element, nullifyNanAndInf));
}
return array;
} else if ([json isKindOfClass:[NSDictionary class]]) {
__block folly::dynamic object = folly::dynamic::object();
[json enumerateKeysAndObjectsUsingBlock:^(
NSString* key, NSString* value, __unused BOOL* stop) {
object.insert(
convertIdToFollyDynamic(key, nullifyNanAndInf),
convertIdToFollyDynamic(value, nullifyNanAndInf));
}];
return object;
}
return nil;
}
}
}