diff options
author | John Firebaugh <john.firebaugh@gmail.com> | 2017-10-17 11:35:36 -0700 |
---|---|---|
committer | John Firebaugh <john.firebaugh@gmail.com> | 2017-10-17 14:16:16 -0700 |
commit | 84685bfe567712c4a40892079b6c9b40473ea050 (patch) | |
tree | 897333ebb7f74798a383f6704741170645d3d394 | |
parent | a0874815f8c9fd6fccd9ffd7e28f8aa8abaded19 (diff) | |
download | qtlocation-mapboxgl-84685bfe567712c4a40892079b6c9b40473ea050.tar.gz |
Require explicit specialization for ValueTraits
* Allows using more natural types for the trait method inputs (`const JSValue*` instead of `const JSValue* const&`)
* Makes it a compile error rather than a link error if you pass the wrong type to the templated Value constructor
* Allows the compiler to inline the trait methods into the vtable
-rw-r--r-- | cmake/core-files.cmake | 1 | ||||
-rw-r--r-- | cmake/node.cmake | 1 | ||||
-rw-r--r-- | include/mbgl/style/conversion.hpp | 16 | ||||
-rw-r--r-- | platform/android/config.cmake | 1 | ||||
-rw-r--r-- | platform/android/src/style/android_conversion.cpp | 106 | ||||
-rw-r--r-- | platform/android/src/style/android_conversion.hpp | 98 | ||||
-rw-r--r-- | platform/darwin/src/MGLConversion.h | 137 | ||||
-rw-r--r-- | platform/darwin/src/MGLConversion.mm | 149 | ||||
-rw-r--r-- | platform/ios/ios.xcodeproj/project.pbxproj | 6 | ||||
-rw-r--r-- | platform/macos/macos.xcodeproj/project.pbxproj | 13 | ||||
-rw-r--r-- | platform/node/src/node_conversion.cpp | 137 | ||||
-rw-r--r-- | platform/node/src/node_conversion.hpp | 122 | ||||
-rw-r--r-- | platform/qt/qt.cmake | 1 | ||||
-rw-r--r-- | platform/qt/src/qt_conversion.cpp | 133 | ||||
-rw-r--r-- | platform/qt/src/qt_conversion.hpp | 130 | ||||
-rw-r--r-- | src/mbgl/style/rapidjson_conversion.cpp | 112 | ||||
-rw-r--r-- | src/mbgl/style/rapidjson_conversion.hpp | 106 |
17 files changed, 591 insertions, 678 deletions
diff --git a/cmake/core-files.cmake b/cmake/core-files.cmake index cbb0d0e625..7621283e7e 100644 --- a/cmake/core-files.cmake +++ b/cmake/core-files.cmake @@ -350,7 +350,6 @@ set(MBGL_CORE_FILES src/mbgl/style/parser.cpp src/mbgl/style/parser.hpp src/mbgl/style/properties.hpp - src/mbgl/style/rapidjson_conversion.cpp src/mbgl/style/rapidjson_conversion.hpp src/mbgl/style/source.cpp src/mbgl/style/source_impl.cpp diff --git a/cmake/node.cmake b/cmake/node.cmake index 575f45020a..388a98b68f 100644 --- a/cmake/node.cmake +++ b/cmake/node.cmake @@ -14,7 +14,6 @@ target_sources(mbgl-node PRIVATE platform/node/src/node_logging.hpp PRIVATE platform/node/src/node_logging.cpp PRIVATE platform/node/src/node_conversion.hpp - PRIVATE platform/node/src/node_conversion.cpp PRIVATE platform/node/src/node_map.hpp PRIVATE platform/node/src/node_map.cpp PRIVATE platform/node/src/node_request.hpp diff --git a/include/mbgl/style/conversion.hpp b/include/mbgl/style/conversion.hpp index 41034c8a33..3fe7bbe508 100644 --- a/include/mbgl/style/conversion.hpp +++ b/include/mbgl/style/conversion.hpp @@ -33,21 +33,7 @@ namespace conversion { struct Error { std::string message; }; template <typename T> -struct ValueTraits { - static bool isUndefined(const T& value); - static bool isArray(const T& value); - static std::size_t arrayLength(const T& value); - static T arrayMember(const T& value, std::size_t i); - static bool isObject(const T& value); - static optional<T> objectMember(const T& value, const char * name); - static optional<Error> eachMember(const T& value, const std::function<optional<Error> (const std::string&, const T&)>& fn); - static optional<bool> toBool(const T& value); - static optional<float> toNumber(const T& value); - static optional<double> toDouble(const T& value); - static optional<std::string> toString(const T& value); - static optional<mbgl::Value> toValue(const T& value); - static optional<GeoJSON> toGeoJSON(const T& value, Error& error); -}; +class ValueTraits; class Value { public: diff --git a/platform/android/config.cmake b/platform/android/config.cmake index da752e4cb8..db75b850f1 100644 --- a/platform/android/config.cmake +++ b/platform/android/config.cmake @@ -146,7 +146,6 @@ add_library(mbgl-android STATIC # Style conversion Java -> C++ platform/android/src/style/android_conversion.hpp - platform/android/src/style/android_conversion.cpp platform/android/src/style/value.cpp platform/android/src/style/value.hpp platform/android/src/style/conversion/url_or_tileset.hpp diff --git a/platform/android/src/style/android_conversion.cpp b/platform/android/src/style/android_conversion.cpp deleted file mode 100644 index 43940c2acd..0000000000 --- a/platform/android/src/style/android_conversion.cpp +++ /dev/null @@ -1,106 +0,0 @@ -#include "android_conversion.hpp" -#include <mbgl/style/conversion/geojson.hpp> - - -namespace mbgl { -namespace style { -namespace conversion { - -using AndroidValue = mbgl::android::Value; - -template<> bool ValueTraits<AndroidValue>::isUndefined(const AndroidValue& value) { - return value.isNull(); -} - -template<> bool ValueTraits<AndroidValue>::isArray(const AndroidValue& value) { - return value.isArray(); -} - -template<> bool ValueTraits<AndroidValue>::isObject(const AndroidValue& value) { - return value.isObject(); -} - -template<> std::size_t ValueTraits<AndroidValue>::arrayLength(const AndroidValue& value) { - return value.getLength();; -} - -template<> AndroidValue ValueTraits<AndroidValue>::arrayMember(const AndroidValue& value, std::size_t i) { - return value.get(i); -} - -template<> optional<AndroidValue> ValueTraits<AndroidValue>::objectMember(const AndroidValue& value, const char* key) { - AndroidValue member = value.get(key); - - if (!member.isNull()) { - return member; - } else { - return {}; - } -} - -template<> optional<Error> ValueTraits<AndroidValue>::eachMember(const AndroidValue&, const std::function<optional<Error> (const std::string&, const AndroidValue&)>&) { - // TODO - mbgl::Log::Warning(mbgl::Event::Android, "eachMember not implemented"); - return {}; -} - -template<> optional<bool> ValueTraits<AndroidValue>::toBool(const AndroidValue& value) { - if (value.isBool()) { - return value.toBool(); - } else { - return {}; - } -} - -template<> optional<float> ValueTraits<AndroidValue>::toNumber(const AndroidValue& value) { - if (value.isNumber()) { - auto num = value.toFloat(); - return num; - } else { - return {}; - } -} - -template<> optional<double> ValueTraits<AndroidValue>::toDouble(const AndroidValue& value) { - if (value.isNumber()) { - return value.toDouble(); - } else { - return {}; - } -} - -template<> optional<std::string> ValueTraits<AndroidValue>::toString(const AndroidValue& value) { - if (value.isString()) { - return value.toString(); - } else { - return {}; - } -} - -template<> optional<mbgl::Value> ValueTraits<AndroidValue>::toValue(const AndroidValue& value) { - if (value.isNull()) { - return {}; - } else if (value.isBool()) { - return { value.toBool() }; - } else if (value.isString()) { - return { value.toString() }; - } else if (value.isNumber()) { - auto doubleVal = value.toDouble(); - return { doubleVal - (int) doubleVal > 0.0 ? doubleVal : value.toLong() }; - } else { - return {}; - } -} - -template<> optional<GeoJSON> ValueTraits<AndroidValue>::toGeoJSON(const AndroidValue &value, Error &error) { - if(value.isNull() || !value.isString()) { - error = { "no json data found" }; - return {}; - } - - return parseGeoJSON(value.toString(), error); -} - -} // namespace conversion -} // namespace style -} // namespace mbgl diff --git a/platform/android/src/style/android_conversion.hpp b/platform/android/src/style/android_conversion.hpp index 3969553816..bc067fbc53 100644 --- a/platform/android/src/style/android_conversion.hpp +++ b/platform/android/src/style/android_conversion.hpp @@ -4,8 +4,9 @@ #include <mbgl/util/feature.hpp> #include <mbgl/util/logging.hpp> -#include <mbgl/style/conversion.hpp> #include <mbgl/util/optional.hpp> +#include <mbgl/style/conversion.hpp> +#include <mbgl/style/conversion/geojson.hpp> #include <jni/jni.hpp> @@ -13,6 +14,101 @@ namespace mbgl { namespace style { namespace conversion { +template <> +class ValueTraits<mbgl::android::Value> { +public: + static bool isUndefined(const mbgl::android::Value& value) { + return value.isNull(); + } + + static bool isArray(const mbgl::android::Value& value) { + return value.isArray(); + } + + static bool isObject(const mbgl::android::Value& value) { + return value.isObject(); + } + + static std::size_t arrayLength(const mbgl::android::Value& value) { + return value.getLength();; + } + + static mbgl::android::Value arrayMember(const mbgl::android::Value& value, std::size_t i) { + return value.get(i); + } + + static optional<mbgl::android::Value> objectMember(const mbgl::android::Value& value, const char* key) { + mbgl::android::Value member = value.get(key); + if (!member.isNull()) { + return member; + } else { + return {}; + } + } + + static optional<Error> eachMember(const mbgl::android::Value&, const std::function<optional<Error> (const std::string&, const mbgl::android::Value&)>&) { + // TODO + mbgl::Log::Warning(mbgl::Event::Android, "eachMember not implemented"); + return {}; + } + + static optional<bool> toBool(const mbgl::android::Value& value) { + if (value.isBool()) { + return value.toBool(); + } else { + return {}; + } + } + + static optional<float> toNumber(const mbgl::android::Value& value) { + if (value.isNumber()) { + auto num = value.toFloat(); + return num; + } else { + return {}; + } + } + + static optional<double> toDouble(const mbgl::android::Value& value) { + if (value.isNumber()) { + return value.toDouble(); + } else { + return {}; + } + } + + static optional<std::string> toString(const mbgl::android::Value& value) { + if (value.isString()) { + return value.toString(); + } else { + return {}; + } + } + + static optional<mbgl::Value> toValue(const mbgl::android::Value& value) { + if (value.isNull()) { + return {}; + } else if (value.isBool()) { + return { value.toBool() }; + } else if (value.isString()) { + return { value.toString() }; + } else if (value.isNumber()) { + auto doubleVal = value.toDouble(); + return { doubleVal - (int) doubleVal > 0.0 ? doubleVal : value.toLong() }; + } else { + return {}; + } + } + + static optional<GeoJSON> toGeoJSON(const mbgl::android::Value &value, Error &error) { + if (value.isNull() || !value.isString()) { + error = { "no json data found" }; + return {}; + } + return parseGeoJSON(value.toString(), error); + } +}; + template <class T, class...Args> optional<T> convert(const mbgl::android::Value& value, Error& error, Args&&...args) { return convert<T>(Value(value), error, std::forward<Args>(args)...); diff --git a/platform/darwin/src/MGLConversion.h b/platform/darwin/src/MGLConversion.h index a354c28cd9..f5db1acfe5 100644 --- a/platform/darwin/src/MGLConversion.h +++ b/platform/darwin/src/MGLConversion.h @@ -6,7 +6,142 @@ namespace mbgl { namespace style { namespace conversion { -Value makeValue(const id value); +class Holder { +public: + Holder(const id v) : value(v) {} + const id value; +}; + +template <> +class ValueTraits<Holder> { +public: + static bool isUndefined(const Holder& holder) { + const id value = holder.value; + return !value || value == [NSNull null]; + } + + static bool isArray(const Holder& holder) { + const id value = holder.value; + return [value isKindOfClass:[NSArray class]]; + } + + static bool isObject(const Holder& holder) { + const id value = holder.value; + return [value isKindOfClass:[NSDictionary 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; + } + + 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]}; + } + + 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 {}; + } + } + + static optional<Error> eachMember(const Holder& holder, const std::function<optional<Error> (const std::string&, const Holder&)>& fn) { + // Not implemented (unneeded for MGLStyleFunction conversion). + NSCAssert(NO, @"eachMember not implemented"); + return {}; + } + + static optional<bool> toBool(const Holder& holder) { + const id value = holder.value; + if (_isBool(value)) { + return ((NSNumber *)value).boolValue; + } else { + return {}; + } + } + + static optional<float> toNumber(const Holder& holder) { + const id value = holder.value; + if (_isNumber(value)) { + return ((NSNumber *)value).floatValue; + } else { + return {}; + } + } + + static optional<double> toDouble(const Holder& holder) { + const id value = holder.value; + if (_isNumber(value)) { + return ((NSNumber *)value).doubleValue; + } 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 {}; + } + } + + 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 {}; + } + } + + static optional<GeoJSON> toGeoJSON(const Holder& holder, Error& error) { + error = { "toGeoJSON not implemented" }; + 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)); + } + + 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 Value makeValue(const id value) { + return {Holder(value)}; +} } // namespace conversion } // namespace style diff --git a/platform/darwin/src/MGLConversion.mm b/platform/darwin/src/MGLConversion.mm deleted file mode 100644 index 890a96c34d..0000000000 --- a/platform/darwin/src/MGLConversion.mm +++ /dev/null @@ -1,149 +0,0 @@ -#import <Foundation/Foundation.h> - -#include "MGLConversion.h" - -NS_ASSUME_NONNULL_BEGIN - -namespace mbgl { -namespace style { -namespace conversion { - -class Holder { -public: - Holder(const id v) : value(v) {} - const id value; -}; - -template<> bool ValueTraits<Holder>::isUndefined(const Holder& holder) { - const id value = holder.value; - return !value || value == [NSNull null]; -} - -template<> bool ValueTraits<Holder>::isArray(const Holder& holder) { - const id value = holder.value; - return [value isKindOfClass:[NSArray class]]; -} - -template<> bool ValueTraits<Holder>::isObject(const Holder& holder) { - const id value = holder.value; - return [value isKindOfClass:[NSDictionary class]]; -} - -template<> std::size_t ValueTraits<Holder>::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; -} - -template<> Holder ValueTraits<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]}; -} - -template<> optional<Holder> ValueTraits<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 {}; - } -} - -template<> optional<Error> ValueTraits<Holder>::eachMember(const Holder& holder, const std::function<optional<Error> (const std::string&, const Holder&)>& fn) { - // Not implemented (unneeded for MGLStyleFunction conversion). - NSCAssert(NO, @"eachMember not implemented"); - 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]]; -} - -template<> optional<bool> ValueTraits<Holder>::toBool(const Holder& holder) { - const id value = holder.value; - if (_isBool(value)) { - return ((NSNumber *)value).boolValue; - } else { - return {}; - } -} - -template<> optional<float> ValueTraits<Holder>::toNumber(const Holder& holder) { - const id value = holder.value; - if (_isNumber(value)) { - return ((NSNumber *)value).floatValue; - } else { - return {}; - } -} - -template<> optional<double> ValueTraits<Holder>::toDouble(const Holder& holder) { - const id value = holder.value; - if (_isNumber(value)) { - return ((NSNumber *)value).doubleValue; - } else { - return {}; - } -} - -template<> optional<std::string> ValueTraits<Holder>::toString(const Holder& holder) { - const id value = holder.value; - if (_isString(value)) { - return std::string(static_cast<const char *>([value UTF8String])); - } else { - return {}; - } -} - -template<> optional<mbgl::Value> ValueTraits<Holder>::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 {}; - } -} - -template<> optional<GeoJSON> ValueTraits<Holder>::toGeoJSON(const Holder& holder, Error& error) { - error = { "toGeoJSON not implemented" }; - return {}; -} - -Value makeValue(const id value) { - return {Holder(value)}; -} - - -} // namespace conversion -} // namespace style -} // namespace mbgl - -NS_ASSUME_NONNULL_END - diff --git a/platform/ios/ios.xcodeproj/project.pbxproj b/platform/ios/ios.xcodeproj/project.pbxproj index 63fc76b2df..a3ccc9337b 100644 --- a/platform/ios/ios.xcodeproj/project.pbxproj +++ b/platform/ios/ios.xcodeproj/project.pbxproj @@ -14,8 +14,6 @@ 071BBB071EE77631001FB02A /* MGLImageSourceTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 071BBB051EE7761A001FB02A /* MGLImageSourceTests.m */; }; 1753ED421E53CE6F00A9FD90 /* MGLConversion.h in Headers */ = {isa = PBXBuildFile; fileRef = 1753ED411E53CE6F00A9FD90 /* MGLConversion.h */; }; 1753ED431E53CE6F00A9FD90 /* MGLConversion.h in Headers */ = {isa = PBXBuildFile; fileRef = 1753ED411E53CE6F00A9FD90 /* MGLConversion.h */; }; - 17DBEF831F95066000E60A6B /* MGLConversion.mm in Sources */ = {isa = PBXBuildFile; fileRef = 17DBEF821F95066000E60A6B /* MGLConversion.mm */; }; - 17DBEF841F95066000E60A6B /* MGLConversion.mm in Sources */ = {isa = PBXBuildFile; fileRef = 17DBEF821F95066000E60A6B /* MGLConversion.mm */; }; 1F06668A1EC64F8E001C16D7 /* MGLLight.h in Headers */ = {isa = PBXBuildFile; fileRef = 1F0666881EC64F8E001C16D7 /* MGLLight.h */; settings = {ATTRIBUTES = (Public, ); }; }; 1F06668D1EC64F8E001C16D7 /* MGLLight.mm in Sources */ = {isa = PBXBuildFile; fileRef = 1F0666891EC64F8E001C16D7 /* MGLLight.mm */; }; 1F7454921ECBB42C00021D39 /* MGLLight.mm in Sources */ = {isa = PBXBuildFile; fileRef = 1F0666891EC64F8E001C16D7 /* MGLLight.mm */; }; @@ -574,7 +572,6 @@ 071BBAFD1EE75CD4001FB02A /* MGLImageSource.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = MGLImageSource.mm; sourceTree = "<group>"; }; 071BBB051EE7761A001FB02A /* MGLImageSourceTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = MGLImageSourceTests.m; path = ../../darwin/test/MGLImageSourceTests.m; sourceTree = "<group>"; }; 1753ED411E53CE6F00A9FD90 /* MGLConversion.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MGLConversion.h; sourceTree = "<group>"; }; - 17DBEF821F95066000E60A6B /* MGLConversion.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = MGLConversion.mm; sourceTree = "<group>"; }; 1F0666881EC64F8E001C16D7 /* MGLLight.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MGLLight.h; sourceTree = "<group>"; }; 1F0666891EC64F8E001C16D7 /* MGLLight.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = MGLLight.mm; sourceTree = "<group>"; }; 1F7454941ECD450D00021D39 /* MGLLight_Private.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MGLLight_Private.h; sourceTree = "<group>"; }; @@ -1097,7 +1094,6 @@ 35599DA21D4682B60048254D /* Styling */ = { isa = PBXGroup; children = ( - 17DBEF821F95066000E60A6B /* MGLConversion.mm */, 1753ED411E53CE6F00A9FD90 /* MGLConversion.h */, 35599DB81D46AD7F0048254D /* Categories */, 353933F01D3FB6BA003F57D7 /* Layers */, @@ -2328,7 +2324,6 @@ DA8848501CBAFB9800AB86E3 /* MGLAnnotationImage.m in Sources */, DA8848281CBAFA6200AB86E3 /* MGLShape.mm in Sources */, DA35A2B31CCA141D00E826B2 /* MGLCompassDirectionFormatter.m in Sources */, - 17DBEF831F95066000E60A6B /* MGLConversion.mm in Sources */, DD0902A91DB1929D00C5BDCE /* MGLNetworkConfiguration.m in Sources */, 35D13AB91D3D15E300AFB4E0 /* MGLStyleLayer.mm in Sources */, DA35A2CB1CCAAAD200E826B2 /* NSValue+MGLAdditions.m in Sources */, @@ -2416,7 +2411,6 @@ DAA4E41F1CBB730400178DFB /* MGLMultiPoint.mm in Sources */, DD0902AA1DB1929D00C5BDCE /* MGLNetworkConfiguration.m in Sources */, DA35A2B41CCA141D00E826B2 /* MGLCompassDirectionFormatter.m in Sources */, - 17DBEF841F95066000E60A6B /* MGLConversion.mm in Sources */, 35D13ABA1D3D15E300AFB4E0 /* MGLStyleLayer.mm in Sources */, 071BBAFF1EE7613E001FB02A /* MGLImageSource.mm in Sources */, DA35A2CC1CCAAAD200E826B2 /* NSValue+MGLAdditions.m in Sources */, diff --git a/platform/macos/macos.xcodeproj/project.pbxproj b/platform/macos/macos.xcodeproj/project.pbxproj index 6f99382b02..34f8860686 100644 --- a/platform/macos/macos.xcodeproj/project.pbxproj +++ b/platform/macos/macos.xcodeproj/project.pbxproj @@ -73,7 +73,6 @@ 40B77E451DB11BC9003DA2FE /* NSArray+MGLAdditions.h in Headers */ = {isa = PBXBuildFile; fileRef = 40B77E431DB11BB0003DA2FE /* NSArray+MGLAdditions.h */; }; 40B77E461DB11BCD003DA2FE /* NSArray+MGLAdditions.mm in Sources */ = {isa = PBXBuildFile; fileRef = 40B77E421DB11BB0003DA2FE /* NSArray+MGLAdditions.mm */; }; 40E1601D1DF217D6005EA6D9 /* MGLStyleLayerTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 40E1601B1DF216E6005EA6D9 /* MGLStyleLayerTests.m */; }; - 5241C2BE1F7AFFAF00DDB20E /* MGLConversion.mm in Sources */ = {isa = PBXBuildFile; fileRef = 5241C2BD1F7AFFAF00DDB20E /* MGLConversion.mm */; }; 52B5D17F1E5E26DF00BBCB48 /* libmbgl-loop-darwin.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5548BE7B1D0ACBBD005DDE81 /* libmbgl-loop-darwin.a */; }; 52B5D1801E5E26DF00BBCB48 /* libmbgl-loop-darwin.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5548BE7B1D0ACBBD005DDE81 /* libmbgl-loop-darwin.a */; }; 5548BE781D09E718005DDE81 /* libmbgl-core.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DAE6C3451CC31D1200DB3429 /* libmbgl-core.a */; }; @@ -350,7 +349,6 @@ 40B77E431DB11BB0003DA2FE /* NSArray+MGLAdditions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSArray+MGLAdditions.h"; sourceTree = "<group>"; }; 40E1601A1DF216E6005EA6D9 /* MGLStyleLayerTests.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MGLStyleLayerTests.h; sourceTree = "<group>"; }; 40E1601B1DF216E6005EA6D9 /* MGLStyleLayerTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MGLStyleLayerTests.m; sourceTree = "<group>"; }; - 5241C2BD1F7AFFAF00DDB20E /* MGLConversion.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = MGLConversion.mm; sourceTree = "<group>"; }; 52BECB091CC5A26F009CD791 /* SystemConfiguration.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SystemConfiguration.framework; path = System/Library/Frameworks/SystemConfiguration.framework; sourceTree = SDKROOT; }; 5548BE7B1D0ACBBD005DDE81 /* libmbgl-loop-darwin.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = "libmbgl-loop-darwin.a"; path = "cmake/Debug/libmbgl-loop-darwin.a"; sourceTree = "<group>"; }; 556660C51E1BEA0100E2C41B /* MGLFoundation.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MGLFoundation.h; sourceTree = "<group>"; }; @@ -700,7 +698,6 @@ isa = PBXGroup; children = ( 1753ED3F1E53CE5200A9FD90 /* MGLConversion.h */, - 5241C2BD1F7AFFAF00DDB20E /* MGLConversion.mm */, 352742791D4C235C00A1ECE6 /* Categories */, 35136D471D42295400C20EFD /* Layers */, 3527427E1D4C242B00A1ECE6 /* Sources */, @@ -730,14 +727,6 @@ name = "Test Helpers"; sourceTree = "<group>"; }; - 5241C2BA1F7AF16100DDB20E /* Recovered References */ = { - isa = PBXGroup; - children = ( - 30E578141DAA7D920050F07E /* NSImage+MGLAdditions.h */, - ); - name = "Recovered References"; - sourceTree = "<group>"; - }; DA839E891CC2E3400062CAFB = { isa = PBXGroup; children = ( @@ -747,7 +736,6 @@ DAE6C31E1CC308BC00DB3429 /* Frameworks */, DAE6C3C41CC31F7800DB3429 /* Configuration */, DA839E931CC2E3400062CAFB /* Products */, - 5241C2BA1F7AF16100DDB20E /* Recovered References */, ); sourceTree = "<group>"; }; @@ -1445,7 +1433,6 @@ 1FCDF1431F2A4F3600A46694 /* MGLVectorSource+MGLAdditions.m in Sources */, DD0902B21DB1AC6400C5BDCE /* MGLNetworkConfiguration.m in Sources */, 1F7454A51ECFB00300021D39 /* MGLLight.mm in Sources */, - 5241C2BE1F7AFFAF00DDB20E /* MGLConversion.mm in Sources */, DAE6C3B11CC31EF300DB3429 /* MGLAnnotationImage.m in Sources */, 3508EC651D749D39009B0EE4 /* NSExpression+MGLAdditions.mm in Sources */, DACC22151CF3D3E200D220D9 /* MGLFeature.mm in Sources */, diff --git a/platform/node/src/node_conversion.cpp b/platform/node/src/node_conversion.cpp deleted file mode 100644 index ed082615d0..0000000000 --- a/platform/node/src/node_conversion.cpp +++ /dev/null @@ -1,137 +0,0 @@ -#include "node_conversion.hpp" -#include <mbgl/style/conversion/geojson.hpp> - -namespace mbgl { -namespace style { -namespace conversion { - -template<> bool ValueTraits<v8::Local<v8::Value>>::isUndefined(const v8::Local<v8::Value>& value) { - Nan::HandleScope scope; - - return value->IsUndefined() || value->IsNull(); -} - -template<> bool ValueTraits<v8::Local<v8::Value>>::isArray(const v8::Local<v8::Value>& value) { - Nan::HandleScope scope; - - return value->IsArray(); -} - -template<> std::size_t ValueTraits<v8::Local<v8::Value>>::arrayLength(const v8::Local<v8::Value>& value) { - Nan::HandleScope scope; - // const_cast because v8::Local<T>::As is not marked const until node v8.0 - v8::Local<v8::Array> array = const_cast<v8::Local<v8::Value>&>(value).As<v8::Array>(); - return array->Length(); -} - -template<> v8::Local<v8::Value> ValueTraits<v8::Local<v8::Value>>::arrayMember(const v8::Local<v8::Value>& value, std::size_t i) { - Nan::EscapableHandleScope scope; - // const_cast because v8::Local<T>::As is not marked const until node v8.0 - v8::Local<v8::Array> array = const_cast<v8::Local<v8::Value>&>(value).As<v8::Array>(); - return scope.Escape(Nan::Get(array, i).ToLocalChecked()); -} - -template<> bool ValueTraits<v8::Local<v8::Value>>::isObject(const v8::Local<v8::Value>& value) { - Nan::HandleScope scope; - - return value->IsObject() && !value->IsArray(); -} - -template<> optional<v8::Local<v8::Value>> ValueTraits<v8::Local<v8::Value>>::objectMember(const v8::Local<v8::Value>& value, const char * name) { - Nan::EscapableHandleScope scope; - - if (!Nan::Has(Nan::To<v8::Object>(value).ToLocalChecked(), Nan::New(name).ToLocalChecked()).FromJust()) { - return {}; - } - Nan::MaybeLocal<v8::Value> result = Nan::Get(Nan::To<v8::Object>(value).ToLocalChecked(), Nan::New(name).ToLocalChecked()); - if (result.IsEmpty()) { - return {}; - } - return {scope.Escape(result.ToLocalChecked())}; -} - -template<> optional<Error> ValueTraits<v8::Local<v8::Value>>::eachMember(const v8::Local<v8::Value>& value, const std::function<optional<Error> (const std::string&, const v8::Local<v8::Value>&)>& fn) { - Nan::HandleScope scope; - - v8::Local<v8::Array> names = Nan::GetOwnPropertyNames(Nan::To<v8::Object>(value).ToLocalChecked()).ToLocalChecked(); - for (uint32_t i = 0; i < names->Length(); ++i) { - v8::Local<v8::Value> k = Nan::Get(names, i).ToLocalChecked(); - v8::Local<v8::Value> v = Nan::Get(Nan::To<v8::Object>(value).ToLocalChecked(), k).ToLocalChecked(); - optional<Error> result = fn(*Nan::Utf8String(k), v); - if (result) { - return result; - } - } - return {}; -} - -template<> optional<bool> ValueTraits<v8::Local<v8::Value>>::toBool(const v8::Local<v8::Value>& value) { - Nan::HandleScope scope; - - if (!value->IsBoolean()) { - return {}; - } - return value->BooleanValue(); -} - -template<> optional<float> ValueTraits<v8::Local<v8::Value>>::toNumber(const v8::Local<v8::Value>& value) { - Nan::HandleScope scope; - - if (!value->IsNumber()) { - return {}; - } - return value->NumberValue(); -} - -template<> optional<double> ValueTraits<v8::Local<v8::Value>>::toDouble(const v8::Local<v8::Value>& value) { - Nan::HandleScope scope; - - if (!value->IsNumber()) { - return {}; - } - return value->NumberValue(); -} - -template<> optional<std::string> ValueTraits<v8::Local<v8::Value>>::toString(const v8::Local<v8::Value>& value) { - Nan::HandleScope scope; - - if (!value->IsString()) { - return {}; - } - return std::string(*Nan::Utf8String(value)); -} - -template<> optional<mbgl::Value> ValueTraits<v8::Local<v8::Value>>::toValue(const v8::Local<v8::Value>& value) { - - if (value->IsFalse()) { - return { false }; - } else if (value->IsTrue()) { - return { true }; - } else if (value->IsString()) { - return { std::string(*Nan::Utf8String(value)) }; - } else if (value->IsUint32()) { - return { std::uint64_t(value->Uint32Value()) }; - } else if (value->IsInt32()) { - return { std::int64_t(value->Int32Value()) }; - } else if (value->IsNumber()) { - return { value->NumberValue() }; - } else { - return {}; - } -} - -template<> optional<GeoJSON> ValueTraits<v8::Local<v8::Value>>::toGeoJSON(const v8::Local<v8::Value>& value, Error& error) { - try { - Nan::JSON JSON; - - std::string string = *Nan::Utf8String(JSON.Stringify(value->ToObject()).ToLocalChecked()); - return parseGeoJSON(string, error); - } catch (const std::exception& ex) { - error = { ex.what() }; - return {}; - } -} - -} // namespace conversion -} // namespace style -} // namespace mbgl diff --git a/platform/node/src/node_conversion.hpp b/platform/node/src/node_conversion.hpp index 7f0a7ed39e..7db5b23642 100644 --- a/platform/node/src/node_conversion.hpp +++ b/platform/node/src/node_conversion.hpp @@ -9,17 +9,137 @@ #include <mbgl/util/optional.hpp> #include <mbgl/util/feature.hpp> #include <mbgl/style/conversion.hpp> +#include <mbgl/style/conversion/geojson.hpp> namespace mbgl { namespace style { namespace conversion { +template <> +class ValueTraits<v8::Local<v8::Value>> { +public: + static bool isUndefined(const v8::Local<v8::Value>& value) { + Nan::HandleScope scope; + return value->IsUndefined() || value->IsNull(); + } + + static bool isArray(const v8::Local<v8::Value>& value) { + Nan::HandleScope scope; + return value->IsArray(); + } + + static std::size_t arrayLength(const v8::Local<v8::Value>& value) { + Nan::HandleScope scope; + // const_cast because v8::Local<T>::As is not marked const until node v8.0 + v8::Local<v8::Array> array = const_cast<v8::Local<v8::Value>&>(value).As<v8::Array>(); + return array->Length(); + } + + static v8::Local<v8::Value> arrayMember(const v8::Local<v8::Value>& value, std::size_t i) { + Nan::EscapableHandleScope scope; + // const_cast because v8::Local<T>::As is not marked const until node v8.0 + v8::Local<v8::Array> array = const_cast<v8::Local<v8::Value>&>(value).As<v8::Array>(); + return scope.Escape(Nan::Get(array, i).ToLocalChecked()); + } + + static bool isObject(const v8::Local<v8::Value>& value) { + Nan::HandleScope scope; + return value->IsObject() && !value->IsArray(); + } + + static optional<v8::Local<v8::Value>> objectMember(const v8::Local<v8::Value>& value, const char * name) { + Nan::EscapableHandleScope scope; + if (!Nan::Has(Nan::To<v8::Object>(value).ToLocalChecked(), Nan::New(name).ToLocalChecked()).FromJust()) { + return {}; + } + Nan::MaybeLocal<v8::Value> result = Nan::Get(Nan::To<v8::Object>(value).ToLocalChecked(), Nan::New(name).ToLocalChecked()); + if (result.IsEmpty()) { + return {}; + } + return {scope.Escape(result.ToLocalChecked())}; + } + + static optional<Error> eachMember(const v8::Local<v8::Value>& value, const std::function<optional<Error> (const std::string&, const v8::Local<v8::Value>&)>& fn) { + Nan::HandleScope scope; + v8::Local<v8::Array> names = Nan::GetOwnPropertyNames(Nan::To<v8::Object>(value).ToLocalChecked()).ToLocalChecked(); + for (uint32_t i = 0; i < names->Length(); ++i) { + v8::Local<v8::Value> k = Nan::Get(names, i).ToLocalChecked(); + v8::Local<v8::Value> v = Nan::Get(Nan::To<v8::Object>(value).ToLocalChecked(), k).ToLocalChecked(); + optional<Error> result = fn(*Nan::Utf8String(k), v); + if (result) { + return result; + } + } + return {}; + } + + static optional<bool> toBool(const v8::Local<v8::Value>& value) { + Nan::HandleScope scope; + if (!value->IsBoolean()) { + return {}; + } + return value->BooleanValue(); + } + + static optional<float> toNumber(const v8::Local<v8::Value>& value) { + Nan::HandleScope scope; + if (!value->IsNumber()) { + return {}; + } + return value->NumberValue(); + } + + static optional<double> toDouble(const v8::Local<v8::Value>& value) { + Nan::HandleScope scope; + if (!value->IsNumber()) { + return {}; + } + return value->NumberValue(); + } + + static optional<std::string> toString(const v8::Local<v8::Value>& value) { + Nan::HandleScope scope; + if (!value->IsString()) { + return {}; + } + return std::string(*Nan::Utf8String(value)); + } + + static optional<mbgl::Value> toValue(const v8::Local<v8::Value>& value) { + if (value->IsFalse()) { + return { false }; + } else if (value->IsTrue()) { + return { true }; + } else if (value->IsString()) { + return { std::string(*Nan::Utf8String(value)) }; + } else if (value->IsUint32()) { + return { std::uint64_t(value->Uint32Value()) }; + } else if (value->IsInt32()) { + return { std::int64_t(value->Int32Value()) }; + } else if (value->IsNumber()) { + return { value->NumberValue() }; + } else { + return {}; + } + } + + static optional<GeoJSON> toGeoJSON(const v8::Local<v8::Value>& value, Error& error) { + try { + Nan::JSON JSON; + std::string string = *Nan::Utf8String(JSON.Stringify(value->ToObject()).ToLocalChecked()); + return parseGeoJSON(string, error); + } catch (const std::exception& ex) { + error = { ex.what() }; + return {}; + } + } +}; + template <class T, class...Args> optional<T> convert(const v8::Local<v8::Value>& value, Error& error, Args&&...args) { return convert<T>(Value(value), error, std::forward<Args>(args)...); } - } // namespace conversion } // namespace style } // namespace mbgl diff --git a/platform/qt/qt.cmake b/platform/qt/qt.cmake index 918e6b93cd..a7862c3936 100644 --- a/platform/qt/qt.cmake +++ b/platform/qt/qt.cmake @@ -60,7 +60,6 @@ set(MBGL_QT_FILESOURCE_FILES add_library(qmapboxgl SHARED platform/qt/include/qmapbox.hpp platform/qt/include/qmapboxgl.hpp - platform/qt/src/qt_conversion.cpp platform/qt/src/qt_conversion.hpp platform/qt/src/qt_geojson.cpp platform/qt/src/qt_geojson.hpp diff --git a/platform/qt/src/qt_conversion.cpp b/platform/qt/src/qt_conversion.cpp deleted file mode 100644 index 35a6ef4fc9..0000000000 --- a/platform/qt/src/qt_conversion.cpp +++ /dev/null @@ -1,133 +0,0 @@ -#include <mbgl/util/feature.hpp> -#include <mbgl/style/conversion/geojson.hpp> -#include <QColor> -#include <QMapbox> -#include "qt_geojson.hpp" - -namespace mbgl { -namespace style { -namespace conversion { - -template<> bool ValueTraits<QVariant>::isUndefined(const QVariant& value) { - return value.isNull() || !value.isValid(); -} - -template<> bool ValueTraits<QVariant>::isArray(const QVariant& value) { - return value.canConvert(QVariant::List); -} - -template<> std::size_t ValueTraits<QVariant>::arrayLength(const QVariant& value) { - return value.toList().size(); -} - -template<> QVariant ValueTraits<QVariant>::arrayMember(const QVariant& value, std::size_t i) { - return value.toList()[i]; -} - -template<> bool ValueTraits<QVariant>::isObject(const QVariant& value) { - return value.canConvert(QVariant::Map) - || value.type() == QVariant::ByteArray -#if QT_VERSION >= 0x050000 - || QString(value.typeName()) == QStringLiteral("QMapbox::Feature"); -#else - || QString(value.typeName()) == QString("QMapbox::Feature"); -#endif -} - -template<> optional<QVariant> ValueTraits<QVariant>::objectMember(const QVariant& value, const char* key) { - auto map = value.toMap(); - auto iter = map.constFind(key); - - if (iter != map.constEnd()) { - return iter.value(); - } else { - return {}; - } -} - -using EachMemberFn = std::function<optional<Error>(const std::string&, const QVariant&)>; - -template<> optional<Error> ValueTraits<QVariant>::eachMember(const QVariant& value, const EachMemberFn& fn) { - auto map = value.toMap(); - auto iter = map.constBegin(); - - while (iter != map.constEnd()) { - optional<Error> result = fn(iter.key().toStdString(), iter.value()); - if (result) { - return result; - } - - ++iter; - } - - return {}; -} - -template<> optional<bool> ValueTraits<QVariant>::toBool(const QVariant& value) { - if (value.type() == QVariant::Bool) { - return value.toBool(); - } else { - return {}; - } -} - -template<> optional<float> ValueTraits<QVariant>::toNumber(const QVariant& value) { - if (value.type() == QVariant::Int || value.type() == QVariant::Double) { - return value.toFloat(); - } else { - return {}; - } -} -template<> optional<double> ValueTraits<QVariant>::toDouble(const QVariant& value) { - if (value.type() == QVariant::Int || value.type() == QVariant::Double) { - return value.toDouble(); - } else { - return {}; - } -} - -template<> optional<std::string> ValueTraits<QVariant>::toString(const QVariant& value) { - if (value.type() == QVariant::String) { - return value.toString().toStdString(); - } else if (value.type() == QVariant::Color) { - return value.value<QColor>().name().toStdString(); - } else { - return {}; - } -} - -template<> optional<mbgl::Value> ValueTraits<QVariant>::toValue(const QVariant& value) { - if (value.type() == QVariant::Bool) { - return { value.toBool() }; - } else if (value.type() == QVariant::String) { - return { value.toString().toStdString() }; - } else if (value.type() == QVariant::Color) { - return { value.value<QColor>().name().toStdString() }; - } else if (value.type() == QVariant::Int) { - return { int64_t(value.toInt()) }; - } else if (value.canConvert(QVariant::Double)) { - return { value.toDouble() }; - } else { - return {}; - } -} - -template <> optional<GeoJSON> ValueTraits<QVariant>::toGeoJSON(const QVariant& value, Error& error) { -#if QT_VERSION >= 0x050000 - if (value.typeName() == QStringLiteral("QMapbox::Feature")) { -#else - if (value.typeName() == QString("QMapbox::Feature")) { -#endif - return GeoJSON { asMapboxGLFeature(value.value<QMapbox::Feature>()) }; - } else if (value.type() != QVariant::ByteArray) { - error = { "JSON data must be in QByteArray" }; - return {}; - } - - QByteArray data = value.toByteArray(); - return parseGeoJSON(std::string(data.constData(), data.size()), error); -} - -} // namespace conversion -} // namespace style -} // namespace mbgl diff --git a/platform/qt/src/qt_conversion.hpp b/platform/qt/src/qt_conversion.hpp index bd830f8432..3f58147ca2 100644 --- a/platform/qt/src/qt_conversion.hpp +++ b/platform/qt/src/qt_conversion.hpp @@ -1,13 +1,143 @@ #pragma once #include <mbgl/style/conversion.hpp> +#include <mbgl/style/conversion/geojson.hpp> #include <mbgl/util/optional.hpp> + #include <QVariant> +#include <QColor> +#include <QMapbox> +#include "qt_geojson.hpp" namespace mbgl { namespace style { namespace conversion { +template <> +class ValueTraits<QVariant> { +public: + static bool isUndefined(const QVariant& value) { + return value.isNull() || !value.isValid(); + } + + static bool isArray(const QVariant& value) { + return value.canConvert(QVariant::List); + } + + static std::size_t arrayLength(const QVariant& value) { + return value.toList().size(); + } + + static QVariant arrayMember(const QVariant& value, std::size_t i) { + return value.toList()[i]; + } + + static bool isObject(const QVariant& value) { + return value.canConvert(QVariant::Map) + || value.type() == QVariant::ByteArray + #if QT_VERSION >= 0x050000 + || QString(value.typeName()) == QStringLiteral("QMapbox::Feature"); + #else + || QString(value.typeName()) == QString("QMapbox::Feature"); + #endif + } + + static optional<QVariant> objectMember(const QVariant& value, const char* key) { + auto map = value.toMap(); + auto iter = map.constFind(key); + + if (iter != map.constEnd()) { + return iter.value(); + } else { + return {}; + } + } + + using EachMemberFn = std::function<optional<Error>(const std::string&, const QVariant&)>; + + static optional<Error> eachMember(const QVariant& value, const EachMemberFn& fn) { + auto map = value.toMap(); + auto iter = map.constBegin(); + + while (iter != map.constEnd()) { + optional<Error> result = fn(iter.key().toStdString(), iter.value()); + if (result) { + return result; + } + + ++iter; + } + + return {}; + } + + static optional<bool> toBool(const QVariant& value) { + if (value.type() == QVariant::Bool) { + return value.toBool(); + } else { + return {}; + } + } + + static optional<float> toNumber(const QVariant& value) { + if (value.type() == QVariant::Int || value.type() == QVariant::Double) { + return value.toFloat(); + } else { + return {}; + } + } + + static optional<double> toDouble(const QVariant& value) { + if (value.type() == QVariant::Int || value.type() == QVariant::Double) { + return value.toDouble(); + } else { + return {}; + } + } + + static optional<std::string> toString(const QVariant& value) { + if (value.type() == QVariant::String) { + return value.toString().toStdString(); + } else if (value.type() == QVariant::Color) { + return value.value<QColor>().name().toStdString(); + } else { + return {}; + } + } + + static optional<mbgl::Value> toValue(const QVariant& value) { + if (value.type() == QVariant::Bool) { + return { value.toBool() }; + } else if (value.type() == QVariant::String) { + return { value.toString().toStdString() }; + } else if (value.type() == QVariant::Color) { + return { value.value<QColor>().name().toStdString() }; + } else if (value.type() == QVariant::Int) { + return { int64_t(value.toInt()) }; + } else if (value.canConvert(QVariant::Double)) { + return { value.toDouble() }; + } else { + return {}; + } + } + + static optional<GeoJSON> toGeoJSON(const QVariant& value, Error& error) { + #if QT_VERSION >= 0x050000 + if (value.typeName() == QStringLiteral("QMapbox::Feature")) { + #else + if (value.typeName() == QString("QMapbox::Feature")) { + #endif + return GeoJSON { asMapboxGLFeature(value.value<QMapbox::Feature>()) }; + } else if (value.type() != QVariant::ByteArray) { + error = { "JSON data must be in QByteArray" }; + return {}; + } + + QByteArray data = value.toByteArray(); + return parseGeoJSON(std::string(data.constData(), data.size()), error); + } +}; + template <class T, class...Args> optional<T> convert(const QVariant& value, Error& error, Args&&...args) { return convert<T>(Value(value), error, std::forward<Args>(args)...); diff --git a/src/mbgl/style/rapidjson_conversion.cpp b/src/mbgl/style/rapidjson_conversion.cpp deleted file mode 100644 index a6162f1b77..0000000000 --- a/src/mbgl/style/rapidjson_conversion.cpp +++ /dev/null @@ -1,112 +0,0 @@ -#include <mbgl/style/rapidjson_conversion.hpp> -#include <mapbox/geojson.hpp> -#include <mapbox/geojson/rapidjson.hpp> - - -namespace mbgl { -namespace style { -namespace conversion { - -template<> bool ValueTraits<const JSValue*>::isUndefined(const JSValue* const& value) { - return value->IsNull(); -} - -template<> bool ValueTraits<const JSValue*>::isArray(const JSValue* const& value) { - return value->IsArray(); -} - -template<> std::size_t ValueTraits<const JSValue*>::arrayLength(const JSValue* const& value) { - return value->Size(); -} - -template<> const JSValue* ValueTraits<const JSValue*>::arrayMember(const JSValue* const& value, std::size_t i) { - return &(*value)[rapidjson::SizeType(i)]; -} - -template<> bool ValueTraits<const JSValue*>::isObject(const JSValue* const& value) { - return value->IsObject(); -} - -template<> optional<const JSValue*> ValueTraits<const JSValue*>::objectMember(const JSValue* const& value, const char * name) { - if (!value->HasMember(name)) { - return optional<const JSValue*>(); - } - const JSValue* const& member = &(*value)[name]; - return {member}; -} - -template<> optional<Error> ValueTraits<const JSValue*>::eachMember(const JSValue* const& value, const std::function<optional<Error> (const std::string&, const JSValue* const&)>& fn) { - assert(value->IsObject()); - for (const auto& property : value->GetObject()) { - optional<Error> result = - fn({ property.name.GetString(), property.name.GetStringLength() }, &property.value); - if (result) { - return result; - } - } - return {}; -} - -template<> optional<bool> ValueTraits<const JSValue*>::toBool(const JSValue* const& value) { - if (!value->IsBool()) { - return {}; - } - return value->GetBool(); -} - -template<> optional<float> ValueTraits<const JSValue*>::toNumber(const JSValue* const& value) { - if (!value->IsNumber()) { - return {}; - } - return value->GetDouble(); -} - -template<> optional<double> ValueTraits<const JSValue*>::toDouble(const JSValue* const& value) { - if (!value->IsNumber()) { - return {}; - } - return value->GetDouble(); -} - -template<> optional<std::string> ValueTraits<const JSValue*>::toString(const JSValue* const& value) { - if (!value->IsString()) { - return {}; - } - return {{ value->GetString(), value->GetStringLength() }}; -} - -template<> optional<mbgl::Value> ValueTraits<const JSValue*>::toValue(const JSValue* const& value) { - switch (value->GetType()) { - case rapidjson::kNullType: - case rapidjson::kFalseType: - return { false }; - - case rapidjson::kTrueType: - return { true }; - - case rapidjson::kStringType: - return { std::string { value->GetString(), value->GetStringLength() } }; - - case rapidjson::kNumberType: - if (value->IsUint64()) return { value->GetUint64() }; - if (value->IsInt64()) return { value->GetInt64() }; - return { value->GetDouble() }; - - default: - return {}; - } -} - -template<> optional<GeoJSON> ValueTraits<const JSValue*>::toGeoJSON(const JSValue* const& value, Error& error) { - try { - return mapbox::geojson::convert(*value); - } catch (const std::exception& ex) { - error = { ex.what() }; - return {}; - } -} - - -} // namespace conversion -} // namespace style -} // namespace mbgl diff --git a/src/mbgl/style/rapidjson_conversion.hpp b/src/mbgl/style/rapidjson_conversion.hpp index 082fd1c064..ae3ead24b0 100644 --- a/src/mbgl/style/rapidjson_conversion.hpp +++ b/src/mbgl/style/rapidjson_conversion.hpp @@ -3,10 +3,116 @@ #include <mbgl/util/rapidjson.hpp> #include <mbgl/style/conversion.hpp> +#include <mapbox/geojson.hpp> +#include <mapbox/geojson/rapidjson.hpp> + namespace mbgl { namespace style { namespace conversion { +template <> +class ValueTraits<const JSValue*> { +public: + static bool isUndefined(const JSValue* value) { + return value->IsNull(); + } + + static bool isArray(const JSValue* value) { + return value->IsArray(); + } + + static std::size_t arrayLength(const JSValue* value) { + return value->Size(); + } + + static const JSValue* arrayMember(const JSValue* value, std::size_t i) { + return &(*value)[rapidjson::SizeType(i)]; + } + + static bool isObject(const JSValue* value) { + return value->IsObject(); + } + + static optional<const JSValue*> objectMember(const JSValue* value, const char * name) { + if (!value->HasMember(name)) { + return optional<const JSValue*>(); + } + const JSValue* const& member = &(*value)[name]; + return {member}; + } + + static optional<Error> eachMember(const JSValue* value, const std::function<optional<Error> (const std::string&, const JSValue* const&)>& fn) { + assert(value->IsObject()); + for (const auto& property : value->GetObject()) { + optional<Error> result = + fn({ property.name.GetString(), property.name.GetStringLength() }, &property.value); + if (result) { + return result; + } + } + return {}; + } + + static optional<bool> toBool(const JSValue* value) { + if (!value->IsBool()) { + return {}; + } + return value->GetBool(); + } + + static optional<float> toNumber(const JSValue* value) { + if (!value->IsNumber()) { + return {}; + } + return value->GetDouble(); + } + + static optional<double> toDouble(const JSValue* value) { + if (!value->IsNumber()) { + return {}; + } + return value->GetDouble(); + } + + static optional<std::string> toString(const JSValue* value) { + if (!value->IsString()) { + return {}; + } + return {{ value->GetString(), value->GetStringLength() }}; + } + + static optional<mbgl::Value> toValue(const JSValue* value) { + switch (value->GetType()) { + case rapidjson::kNullType: + case rapidjson::kFalseType: + return { false }; + + case rapidjson::kTrueType: + return { true }; + + case rapidjson::kStringType: + return { std::string { value->GetString(), value->GetStringLength() } }; + + case rapidjson::kNumberType: + if (value->IsUint64()) return { value->GetUint64() }; + if (value->IsInt64()) return { value->GetInt64() }; + return { value->GetDouble() }; + + default: + return {}; + } + } + + static optional<GeoJSON> toGeoJSON(const JSValue* value, Error& error) { + try { + return mapbox::geojson::convert(*value); + } catch (const std::exception& ex) { + error = { ex.what() }; + return {}; + } + } +}; + template <class T, class...Args> optional<T> convert(const JSValue& value, Error& error, Args&&...args) { return convert<T>(Value(&value), error, std::forward<Args>(args)...); |