diff options
Diffstat (limited to 'platform/darwin/src/MGLConversion.h')
-rw-r--r-- | platform/darwin/src/MGLConversion.h | 223 |
1 files changed, 118 insertions, 105 deletions
diff --git a/platform/darwin/src/MGLConversion.h b/platform/darwin/src/MGLConversion.h index d6363b28eb..0d18d4e716 100644 --- a/platform/darwin/src/MGLConversion.h +++ b/platform/darwin/src/MGLConversion.h @@ -1,9 +1,4 @@ -#import <Foundation/Foundation.h> - -#include <mbgl/util/logging.hpp> #include <mbgl/style/conversion.hpp> -#include <mbgl/util/feature.hpp> -#include <mbgl/util/optional.hpp> NS_ASSUME_NONNULL_BEGIN @@ -11,128 +6,147 @@ namespace mbgl { namespace style { namespace conversion { -/** - A minimal wrapper class conforming to the requirements for `objectMember(v, name)` (see mbgl/style/conversion.hpp) - This is necessary because using `NSObject*` as the value type in `optional<NSObject*>` causes problems for the ARC, - due to things like `optional(const value_type& __v)` - */ -class OptionalNSObjectValue { +// A wrapper class for `id`, so as not to confuse ARC. +class Holder { public: - OptionalNSObjectValue(NSObject * _Nullable _value) : value(_value) {} - - explicit operator bool() const { - return value; + Holder(const id v) : value(v) {} + const id value; +}; + +template <> +class ConversionTraits<Holder> { +public: + static bool isUndefined(const Holder& holder) { + const id value = holder.value; + return !value || value == [NSNull null]; } - - NSObject * _Nullable operator*() { - NSCAssert(this, @"Expected non-null value."); - return value; + + static bool isArray(const Holder& holder) { + const id value = holder.value; + return [value isKindOfClass:[NSArray class]]; } -private: - NSObject * _Nullable value; -}; -inline bool isUndefined(const id value) { - return !value || value == [NSNull null]; -} + static bool isObject(const Holder& holder) { + const id value = holder.value; + return [value isKindOfClass:[NSDictionary class]]; + } -inline bool isArray(const id value) { - return [value isKindOfClass:[NSArray class]]; -} + static std::size_t arrayLength(const Holder& holder) { + const id value = holder.value; + NSCAssert([value isKindOfClass:[NSArray class]], @"Value must be an NSArray for getLength()."); + NSArray *array = value; + auto length = [array count]; + NSCAssert(length <= std::numeric_limits<size_t>::max(), @"Array length out of bounds."); + return length; + } -inline bool isObject(const id value) { - return [value isKindOfClass:[NSDictionary class]]; -} + static Holder arrayMember(const Holder& holder, std::size_t i) { + const id value = holder.value; + NSCAssert([value isKindOfClass:[NSArray class]], @"Value must be an NSArray for get(int)."); + NSCAssert(i < NSUIntegerMax, @"Index must be less than NSUIntegerMax"); + return {[value objectAtIndex: i]}; + } -inline std::size_t arrayLength(const id value) { - NSCAssert([value isKindOfClass:[NSArray class]], @"Value must be an NSArray for getLength()."); - NSArray *array = value; - auto length = [array count]; - NSCAssert(length <= std::numeric_limits<size_t>::max(), @"Array length out of bounds."); - return length; -} + static optional<Holder> objectMember(const Holder& holder, const char *key) { + const id value = holder.value; + NSCAssert([value isKindOfClass:[NSDictionary class]], @"Value must be an NSDictionary for get(string)."); + NSObject *member = [value objectForKey: @(key)]; + if (member && member != [NSNull null]) { + return {member}; + } else { + return {}; + } + } -inline NSObject *arrayMember(const id value, std::size_t i) { - NSCAssert([value isKindOfClass:[NSArray class]], @"Value must be an NSArray for get(int)."); - NSCAssert(i < NSUIntegerMax, @"Index must be less than NSUIntegerMax"); - return [value objectAtIndex: i]; -} +// Compiler is wrong about `Fn` parameter missing a nullability specifier. +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wnullability-completeness" + template <class Fn> + static optional<Error> eachMember(const Holder&, Fn&&) { +#pragma clang diagnostic pop + // Not implemented (unneeded for MGLStyleFunction conversion). + NSCAssert(NO, @"eachMember not implemented"); + return {}; + } -inline OptionalNSObjectValue objectMember(const id value, const char *key) { - NSCAssert([value isKindOfClass:[NSDictionary class]], @"Value must be an NSDictionary for get(string)."); - NSObject *member = [value objectForKey: @(key)]; - if (member && member != [NSNull null]) { - return { member }; - } else { - return { nullptr }; + static optional<bool> toBool(const Holder& holder) { + const id value = holder.value; + if (_isBool(value)) { + return ((NSNumber *)value).boolValue; + } else { + return {}; + } } -} -// Not implemented (unneeded for MGLStyleFunction conversion): -// optional<Error> eachMember(const NSObject*, Fn&&) + static optional<float> toNumber(const Holder& holder) { + const id value = holder.value; + if (_isNumber(value)) { + return ((NSNumber *)value).floatValue; + } else { + return {}; + } + } -inline bool _isBool(const id value) { - if (![value isKindOfClass:[NSNumber class]]) return false; - // char: 32-bit boolean - // BOOL: 64-bit boolean - NSNumber *number = value; - return ((strcmp([number objCType], @encode(char)) == 0) || - (strcmp([number objCType], @encode(BOOL)) == 0)); -} - -inline bool _isNumber(const id value) { - return [value isKindOfClass:[NSNumber class]] && !_isBool(value); -} - -inline bool _isString(const id value) { - return [value isKindOfClass:[NSString class]]; -} + static optional<double> toDouble(const Holder& holder) { + const id value = holder.value; + if (_isNumber(value)) { + return ((NSNumber *)value).doubleValue; + } else { + return {}; + } + } -inline optional<bool> toBool(const id value) { - if (_isBool(value)) { - return ((NSNumber *)value).boolValue; - } else { - return {}; + static optional<std::string> toString(const Holder& holder) { + const id value = holder.value; + if (_isString(value)) { + return std::string(static_cast<const char *>([value UTF8String])); + } else { + return {}; + } } -} -inline optional<float> toNumber(const id value) { - if (_isNumber(value)) { - return ((NSNumber *)value).floatValue; - } else { - return {}; + static optional<mbgl::Value> toValue(const Holder& holder) { + const id value = holder.value; + if (isUndefined(value)) { + return {}; + } else if (_isBool(value)) { + return { *toBool(holder) }; + } else if ( _isString(value)) { + return { *toString(holder) }; + } else if (_isNumber(value)) { + // Need to cast to a double here as the float is otherwise considered a bool... + return { static_cast<double>(*toNumber(holder)) }; + } else { + return {}; + } } -} -inline optional<double> toDouble(const id value) { - if (_isNumber(value)) { - return ((NSNumber *)value).doubleValue; - } else { + static optional<GeoJSON> toGeoJSON(const Holder& holder, Error& error) { + error = { "toGeoJSON not implemented" }; return {}; } -} -inline optional<std::string> toString(const id value) { - if (_isString(value)) { - return std::string(static_cast<const char *>([value UTF8String])); - } else { - return {}; +private: + static bool _isBool(const id value) { + if (![value isKindOfClass:[NSNumber class]]) return false; + // char: 32-bit boolean + // BOOL: 64-bit boolean + NSNumber *number = value; + return ((strcmp([number objCType], @encode(char)) == 0) || + (strcmp([number objCType], @encode(BOOL)) == 0)); } -} -inline optional<mbgl::Value> toValue(const id value) { - if (isUndefined(value)) { - return {}; - } else if (_isBool(value)) { - return { *toBool(value) }; - } else if ( _isString(value)) { - return { *toString(value) }; - } else if (_isNumber(value)) { - // Need to cast to a double here as the float is otherwise considered a bool... - return { static_cast<double>(*toNumber(value)) }; - } else { - return {}; + static bool _isNumber(const id value) { + return [value isKindOfClass:[NSNumber class]] && !_isBool(value); } + + static bool _isString(const id value) { + return [value isKindOfClass:[NSString class]]; + } +}; + +inline Convertible makeConvertible(const id value) { + return Convertible(Holder(value)); } } // namespace conversion @@ -140,4 +154,3 @@ inline optional<mbgl::Value> toValue(const id value) { } // namespace mbgl NS_ASSUME_NONNULL_END - |