diff options
author | John Firebaugh <john.firebaugh@gmail.com> | 2017-09-26 14:14:44 -0700 |
---|---|---|
committer | John Firebaugh <john.firebaugh@gmail.com> | 2017-10-23 09:56:43 -0700 |
commit | 4b2e1cddb4645fb6d2c5f9634dbeb7c21516cede (patch) | |
tree | f11bd97ea5abf17bc6956f254796f1e8cf4a96f9 /include/mbgl/style | |
parent | bb58ddaea8c2d9da9551601318944d9d143ee247 (diff) | |
download | qtlocation-mapboxgl-4b2e1cddb4645fb6d2c5f9634dbeb7c21516cede.tar.gz |
Replace compile-time polymorphism with runtime polymorphism in the conversion system
Diffstat (limited to 'include/mbgl/style')
18 files changed, 290 insertions, 1402 deletions
diff --git a/include/mbgl/style/conversion.hpp b/include/mbgl/style/conversion.hpp index 27504a89b1..0b7e0b2b2f 100644 --- a/include/mbgl/style/conversion.hpp +++ b/include/mbgl/style/conversion.hpp @@ -1,6 +1,8 @@ #pragma once #include <mbgl/util/optional.hpp> +#include <mbgl/util/feature.hpp> +#include <mbgl/util/geojson.hpp> #include <string> @@ -9,9 +11,8 @@ namespace style { namespace conversion { /* - The `conversion` namespace defines conversions from a templated type `V` representing a JSON - object conforming to the schema defined by the Mapbox Style Specification, to the various C++ - types that form the C++ model of that domain: + The `conversion` namespace defines conversions from JSON structures conforming to the schema defined by + the Mapbox Style Specification, to the various C++ types that form the C++ model of that domain: * `std::unique_ptr<Source>` * `std::unique_ptr<Layer>` @@ -20,15 +21,31 @@ namespace conversion { A single template function serves as the public interface: - template <class T, class V> - optional<T> convert(const V& value, Error& error); + template <class T> + optional<T> convert(const Convertible& input, Error& error); Where `T` is one of the above types. If the conversion fails, the result is empty, and the error parameter includes diagnostic text suitable for presentation to a library user. Otherwise, a filled optional is returned. - The implementation of `convert` requires that the following are legal expressions for a value `v` - of type `const V&`: + `Convertible` is a type that encapsulates a special form of polymorphism over various underlying types that + can serve as input to the conversion algorithm. For instance, on macOS, we need to support + conversion from both RapidJSON types, and a JSON structure represented with `NSArray`/`NSDictionary`/etc. + On Qt, we need to support conversion from RapidJSON types and QVariant. + + We don't want to use traditional forms of polymorphism to accomplish this: + + * Compile time polymorphism using a template parameter for the actual value type leads to + excessive code bloat and long compile times. + * Runtime polymorphism using virtual methods requires extra heap allocation and ubiquitous + use of std::unique_ptr, unsuitable for this performance-sensitive code. + + Therefore, we're using a custom implementation of runtime polymorphism where we manually create and + dispatch through a table of function pointers (vtable), while keeping the storage for any of the possible + underlying types inline on the stack, using `std::aligned_storage`. + + For a given underlying type T, an explicit specialization of `ConversionTraits<T>` must be provided. This + specialization must provide the following static methods: * `isUndefined(v)` -- returns a boolean indication whether `v` is undefined or a JSON null @@ -48,21 +65,234 @@ namespace conversion { * `toNumber(v)` -- returns `optional<float>`, absence indicating `v` is not a JSON number * `toDouble(v)` -- returns `optional<double>`, absence indicating `v` is not a JSON number * `toString(v)` -- returns `optional<std::string>`, absence indicating `v` is not a JSON string - * `toValue(v)` -- returns `optional<mbgl::Value>`, a variant type, for generic conversion, + * `toValue(v)` -- returns `optional<Value>`, a variant type, for generic conversion, absence indicating `v` is not a boolean, number, or string. Numbers should be converted to unsigned integer, signed integer, or floating point, in descending preference. - The mbgl core implements these requirements for RapidJSON types, and the node bindings implement - them for v8 types. + In addition, the type T must be move-constructable. And finally, `Convertible::Storage`, a typedef for + `std::aligned_storage_t`, must be large enough to satisfy the memory requirements for any of the + possible underlying types. (A static assert will fail if this is not the case.) + + `Convertible` itself is movable, but not copyable. A moved-from `Convertible` is in an invalid state; + you must not do anything with it except let it go out of scope. */ struct Error { std::string message; }; +template <typename T> +class ConversionTraits; + +class Convertible { +public: + template <typename T> + Convertible(T&& value) : vtable(vtableForType<std::decay_t<T>>()) { + static_assert(sizeof(Storage) >= sizeof(std::decay_t<T>), "Storage must be large enough to hold value type"); + new (static_cast<void*>(&storage)) std::decay_t<T>(std::forward<T>(value)); + } + + Convertible(Convertible&& v) + : vtable(v.vtable) + { + if (vtable) { + vtable->move(std::move(v.storage), this->storage); + } + } + + ~Convertible() { + if (vtable) { + vtable->destroy(storage); + } + } + + Convertible& operator=(Convertible&& v) { + if (vtable) { + vtable->destroy(storage); + } + vtable = v.vtable; + if (vtable) { + vtable->move(std::move(v.storage), this->storage); + } + v.vtable = nullptr; + return *this; + } + + Convertible() = delete; + Convertible(const Convertible&) = delete; + Convertible& operator=(const Convertible&) = delete; + + friend inline bool isUndefined(const Convertible& v) { + assert(v.vtable); + return v.vtable->isUndefined(v.storage); + } + + friend inline bool isArray(const Convertible& v) { + assert(v.vtable); + return v.vtable->isArray(v.storage); + } + + friend inline std::size_t arrayLength(const Convertible& v) { + assert(v.vtable); + return v.vtable->arrayLength(v.storage); + } + + friend inline Convertible arrayMember(const Convertible& v, std::size_t i) { + assert(v.vtable); + return v.vtable->arrayMember(v.storage, i); + } + + friend inline bool isObject(const Convertible& v) { + assert(v.vtable); + return v.vtable->isObject(v.storage); + } + + friend inline optional<Convertible> objectMember(const Convertible& v, const char * name) { + assert(v.vtable); + return v.vtable->objectMember(v.storage, name); + } + + friend inline optional<Error> eachMember(const Convertible& v, const std::function<optional<Error> (const std::string&, const Convertible&)>& fn) { + assert(v.vtable); + return v.vtable->eachMember(v.storage, fn); + } + + friend inline optional<bool> toBool(const Convertible& v) { + assert(v.vtable); + return v.vtable->toBool(v.storage); + } + + friend inline optional<float> toNumber(const Convertible& v) { + assert(v.vtable); + return v.vtable->toNumber(v.storage); + } + + friend inline optional<double> toDouble(const Convertible& v) { + assert(v.vtable); + return v.vtable->toDouble(v.storage); + } + + friend inline optional<std::string> toString(const Convertible& v) { + assert(v.vtable); + return v.vtable->toString(v.storage); + } + + friend inline optional<Value> toValue(const Convertible& v) { + assert(v.vtable); + return v.vtable->toValue(v.storage); + } + + friend inline optional<GeoJSON> toGeoJSON(const Convertible& v, Error& error) { + assert(v.vtable); + return v.vtable->toGeoJSON(v.storage, error); + } + +private: +#if __ANDROID__ + // Android: JSValue* or mbgl::android::Value + using Storage = std::aligned_storage_t<32, 8>; +#elif __QT__ + // Qt: JSValue* or QVariant + using Storage = std::aligned_storage_t<32, 8>; +#else + // Node: JSValue* or v8::Local<v8::Value> + // iOS/macOS: JSValue* or id + using Storage = std::aligned_storage_t<8, 8>; +#endif + + struct VTable { + void (*move) (Storage&& src, Storage& dest); + void (*destroy) (Storage&); + + bool (*isUndefined) (const Storage&); + + bool (*isArray) (const Storage&); + std::size_t (*arrayLength) (const Storage&); + Convertible (*arrayMember) (const Storage&, std::size_t); + + bool (*isObject) (const Storage&); + optional<Convertible> (*objectMember) (const Storage&, const char *); + optional<Error> (*eachMember) (const Storage&, const std::function<optional<Error> (const std::string&, const Convertible&)>&); + + optional<bool> (*toBool) (const Storage&); + optional<float> (*toNumber) (const Storage&); + optional<double> (*toDouble) (const Storage&); + optional<std::string> (*toString) (const Storage&); + optional<Value> (*toValue) (const Storage&); + + // https://github.com/mapbox/mapbox-gl-native/issues/5623 + optional<GeoJSON> (*toGeoJSON) (const Storage&, Error&); + }; + + template <typename T> + static VTable* vtableForType() { + using Traits = ConversionTraits<T>; + static VTable vtable = { + [] (Storage&& src, Storage& dest) { + auto srcValue = reinterpret_cast<T&&>(src); + new (static_cast<void*>(&dest)) T(std::move(srcValue)); + srcValue.~T(); + }, + [] (Storage& s) { + reinterpret_cast<T&>(s).~T(); + }, + [] (const Storage& s) { + return Traits::isUndefined(reinterpret_cast<const T&>(s)); + }, + [] (const Storage& s) { + return Traits::isArray(reinterpret_cast<const T&>(s)); + }, + [] (const Storage& s) { + return Traits::arrayLength(reinterpret_cast<const T&>(s)); + }, + [] (const Storage& s, std::size_t i) { + return Convertible(Traits::arrayMember(reinterpret_cast<const T&>(s), i)); + }, + [] (const Storage& s) { + return Traits::isObject(reinterpret_cast<const T&>(s)); + }, + [] (const Storage& s, const char * key) { + optional<T> member = Traits::objectMember(reinterpret_cast<const T&>(s), key); + if (member) { + return optional<Convertible>(Convertible(std::move(*member))); + } else { + return optional<Convertible>(); + } + }, + [] (const Storage& s, const std::function<optional<Error> (const std::string&, const Convertible&)>& fn) { + return Traits::eachMember(reinterpret_cast<const T&>(s), [&](const std::string& k, T&& v) { + return fn(k, Convertible(std::move(v))); + }); + }, + [] (const Storage& s) { + return Traits::toBool(reinterpret_cast<const T&>(s)); + }, + [] (const Storage& s) { + return Traits::toNumber(reinterpret_cast<const T&>(s)); + }, + [] (const Storage& s) { + return Traits::toDouble(reinterpret_cast<const T&>(s)); + }, + [] (const Storage& s) { + return Traits::toString(reinterpret_cast<const T&>(s)); + }, + [] (const Storage& s) { + return Traits::toValue(reinterpret_cast<const T&>(s)); + }, + [] (const Storage& s, Error& err) { + return Traits::toGeoJSON(reinterpret_cast<const T&>(s), err); + } + }; + return &vtable; + } + + VTable* vtable; + Storage storage; +}; + template <class T, class Enable = void> struct Converter; -template <class T, class V, class...Args> -optional<T> convert(const V& value, Error& error, Args&&...args) { +template <class T, class...Args> +optional<T> convert(const Convertible& value, Error& error, Args&&...args) { return Converter<T>()(value, error, std::forward<Args>(args)...); } diff --git a/include/mbgl/style/conversion/constant.hpp b/include/mbgl/style/conversion/constant.hpp index 07c0a35fae..7b3249da52 100644 --- a/include/mbgl/style/conversion/constant.hpp +++ b/include/mbgl/style/conversion/constant.hpp @@ -1,7 +1,6 @@ #pragma once #include <mbgl/style/conversion.hpp> -#include <mbgl/util/optional.hpp> #include <mbgl/util/color.hpp> #include <mbgl/util/enum.hpp> #include <mbgl/util/string.hpp> @@ -16,47 +15,22 @@ namespace conversion { template <> struct Converter<bool> { - template <class V> - optional<bool> operator()(const V& value, Error& error) const { - optional<bool> converted = toBool(value); - if (!converted) { - error = { "value must be a boolean" }; - return {}; - } - return *converted; - } + optional<bool> operator()(const Convertible& value, Error& error) const; }; template <> struct Converter<float> { - template <class V> - optional<float> operator()(const V& value, Error& error) const { - optional<float> converted = toNumber(value); - if (!converted) { - error = { "value must be a number" }; - return {}; - } - return *converted; - } + optional<float> operator()(const Convertible& value, Error& error) const; }; template <> struct Converter<std::string> { - template <class V> - optional<std::string> operator()(const V& value, Error& error) const { - optional<std::string> converted = toString(value); - if (!converted) { - error = { "value must be a string" }; - return {}; - } - return *converted; - } + optional<std::string> operator()(const Convertible& value, Error& error) const; }; template <class T> struct Converter<T, typename std::enable_if_t<std::is_enum<T>::value>> { - template <class V> - optional<T> operator()(const V& value, Error& error) const { + optional<T> operator()(const Convertible& value, Error& error) const { optional<std::string> string = toString(value); if (!string) { error = { "value must be a string" }; @@ -75,28 +49,12 @@ struct Converter<T, typename std::enable_if_t<std::is_enum<T>::value>> { template <> struct Converter<Color> { - template <class V> - optional<Color> operator()(const V& value, Error& error) const { - optional<std::string> string = toString(value); - if (!string) { - error = { "value must be a string" }; - return {}; - } - - optional<Color> color = Color::parse(*string); - if (!color) { - error = { "value must be a valid color" }; - return {}; - } - - return *color; - } + optional<Color> operator()(const Convertible& value, Error& error) const; }; template <size_t N> struct Converter<std::array<float, N>> { - template <class V> - optional<std::array<float, N>> operator()(const V& value, Error& error) const { + optional<std::array<float, N>> operator()(const Convertible& value, Error& error) const { if (!isArray(value) || arrayLength(value) != N) { error = { "value must be an array of " + util::toString(N) + " numbers" }; return {}; @@ -117,52 +75,12 @@ struct Converter<std::array<float, N>> { template <> struct Converter<std::vector<float>> { - template <class V> - optional<std::vector<float>> operator()(const V& value, Error& error) const { - if (!isArray(value)) { - error = { "value must be an array" }; - return {}; - } - - std::vector<float> result; - result.reserve(arrayLength(value)); - - for (std::size_t i = 0; i < arrayLength(value); ++i) { - optional<float> number = toNumber(arrayMember(value, i)); - if (!number) { - error = { "value must be an array of numbers" }; - return {}; - } - result.push_back(*number); - } - - return result; - } + optional<std::vector<float>> operator()(const Convertible& value, Error& error) const; }; template <> struct Converter<std::vector<std::string>> { - template <class V> - optional<std::vector<std::string>> operator()(const V& value, Error& error) const { - if (!isArray(value)) { - error = { "value must be an array" }; - return {}; - } - - std::vector<std::string> result; - result.reserve(arrayLength(value)); - - for (std::size_t i = 0; i < arrayLength(value); ++i) { - optional<std::string> string = toString(arrayMember(value, i)); - if (!string) { - error = { "value must be an array of strings" }; - return {}; - } - result.push_back(*string); - } - - return result; - } + optional<std::vector<std::string>> operator()(const Convertible& value, Error& error) const; }; } // namespace conversion diff --git a/include/mbgl/style/conversion/coordinate.hpp b/include/mbgl/style/conversion/coordinate.hpp index 732624e77f..e11db5e32f 100644 --- a/include/mbgl/style/conversion/coordinate.hpp +++ b/include/mbgl/style/conversion/coordinate.hpp @@ -10,26 +10,7 @@ namespace conversion { template<> struct Converter<LatLng> { public: - template <class V> - optional<LatLng> operator() (const V& value, Error& error) const { - if (!isArray(value) || arrayLength(value) < 2 ) { - error = { "coordinate array must contain numeric longitude and latitude values" }; - return {}; - } - //Style spec uses GeoJSON convention for specifying coordinates - optional<double> latitude = toDouble(arrayMember(value, 1)); - optional<double> longitude = toDouble(arrayMember(value, 0)); - - if (!latitude || !longitude) { - error = { "coordinate array must contain numeric longitude and latitude values" }; - return {}; - } - if (*latitude < -90 || *latitude > 90 ){ - error = { "coordinate latitude must be between -90 and 90" }; - return {}; - } - return LatLng(*latitude, *longitude); - } + optional<LatLng> operator() (const Convertible& value, Error& error) const; }; } // namespace conversion diff --git a/include/mbgl/style/conversion/data_driven_property_value.hpp b/include/mbgl/style/conversion/data_driven_property_value.hpp index 79b15dcfb0..1e54c15a49 100644 --- a/include/mbgl/style/conversion/data_driven_property_value.hpp +++ b/include/mbgl/style/conversion/data_driven_property_value.hpp @@ -11,8 +11,7 @@ namespace conversion { template <class T> struct Converter<DataDrivenPropertyValue<T>> { - template <class V> - optional<DataDrivenPropertyValue<T>> operator()(const V& value, Error& error) const { + optional<DataDrivenPropertyValue<T>> operator()(const Convertible& value, Error& error) const { if (isUndefined(value)) { return DataDrivenPropertyValue<T>(); } else if (!isObject(value)) { diff --git a/include/mbgl/style/conversion/filter.hpp b/include/mbgl/style/conversion/filter.hpp index 986d1bf80d..9daf6ea7a4 100644 --- a/include/mbgl/style/conversion/filter.hpp +++ b/include/mbgl/style/conversion/filter.hpp @@ -2,7 +2,6 @@ #include <mbgl/style/filter.hpp> #include <mbgl/style/conversion.hpp> -#include <mbgl/util/geometry.hpp> namespace mbgl { namespace style { @@ -11,247 +10,7 @@ namespace conversion { template <> struct Converter<Filter> { public: - template <class V> - optional<Filter> operator()(const V& value, Error& error) const { - if (!isArray(value)) { - error = { "filter expression must be an array" }; - return {}; - } - - if (arrayLength(value) < 1) { - error = { "filter expression must have at least 1 element" }; - return {}; - } - - optional<std::string> op = toString(arrayMember(value, 0)); - if (!op) { - error = { "filter operator must be a string" }; - return {}; - } - - if (*op == "==") { - return convertEqualityFilter<EqualsFilter, TypeEqualsFilter, IdentifierEqualsFilter>(value, error); - } else if (*op == "!=") { - return convertEqualityFilter<NotEqualsFilter, TypeNotEqualsFilter, IdentifierNotEqualsFilter>(value, error); - } else if (*op == ">") { - return convertBinaryFilter<GreaterThanFilter>(value, error); - } else if (*op == ">=") { - return convertBinaryFilter<GreaterThanEqualsFilter>(value, error); - } else if (*op == "<") { - return convertBinaryFilter<LessThanFilter>(value, error); - } else if (*op == "<=") { - return convertBinaryFilter<LessThanEqualsFilter>(value, error); - } else if (*op == "in") { - return convertSetFilter<InFilter, TypeInFilter, IdentifierInFilter>(value, error); - } else if (*op == "!in") { - return convertSetFilter<NotInFilter, TypeNotInFilter, IdentifierNotInFilter>(value, error); - } else if (*op == "all") { - return convertCompoundFilter<AllFilter>(value, error); - } else if (*op == "any") { - return convertCompoundFilter<AnyFilter>(value, error); - } else if (*op == "none") { - return convertCompoundFilter<NoneFilter>(value, error); - } else if (*op == "has") { - return convertUnaryFilter<HasFilter, HasIdentifierFilter>(value, error); - } else if (*op == "!has") { - return convertUnaryFilter<NotHasFilter, NotHasIdentifierFilter>(value, error); - } - - error = { R"(filter operator must be one of "==", "!=", ">", ">=", "<", "<=", "in", "!in", "all", "any", "none", "has", or "!has")" }; - return {}; - } - -private: - optional<Value> normalizeValue(const optional<Value>& value, Error& error) const { - if (!value) { - error = { "filter expression value must be a boolean, number, or string" }; - return {}; - } else { - return *value; - } - } - - template <class V> - optional<FeatureType> toFeatureType(const V& value, Error& error) const { - optional<std::string> type = toString(value); - if (!type) { - error = { "value for $type filter must be a string" }; - return {}; - } else if (*type == "Point") { - return FeatureType::Point; - } else if (*type == "LineString") { - return FeatureType::LineString; - } else if (*type == "Polygon") { - return FeatureType::Polygon; - } else { - error = { "value for $type filter must be Point, LineString, or Polygon" }; - return {}; - } - } - - template <class V> - optional<FeatureIdentifier> toFeatureIdentifier(const V& value, Error& error) const { - optional<Value> identifier = toValue(value); - if (!identifier) { - error = { "filter expression value must be a boolean, number, or string" }; - return {}; - } else { - return (*identifier).match( - [] (uint64_t t) -> optional<FeatureIdentifier> { return { t }; }, - [] ( int64_t t) -> optional<FeatureIdentifier> { return { t }; }, - [] ( double t) -> optional<FeatureIdentifier> { return { t }; }, - [] (const std::string& t) -> optional<FeatureIdentifier> { return { t }; }, - [&] (const auto&) -> optional<FeatureIdentifier> { - error = { "filter expression value must be a boolean, number, or string" }; - return {}; - }); - } - } - - template <class FilterType, class IdentifierFilterType, class V> - optional<Filter> convertUnaryFilter(const V& value, Error& error) const { - if (arrayLength(value) < 2) { - error = { "filter expression must have 2 elements" }; - return {}; - } - - optional<std::string> key = toString(arrayMember(value, 1)); - if (!key) { - error = { "filter expression key must be a string" }; - return {}; - } - - if (*key == "$id") { - return { IdentifierFilterType {} }; - } else { - return { FilterType { *key } }; - } - } - - template <class FilterType, class TypeFilterType, class IdentifierFilterType, class V> - optional<Filter> convertEqualityFilter(const V& value, Error& error) const { - if (arrayLength(value) < 3) { - error = { "filter expression must have 3 elements" }; - return {}; - } - - optional<std::string> key = toString(arrayMember(value, 1)); - if (!key) { - error = { "filter expression key must be a string" }; - return {}; - } - - if (*key == "$type") { - optional<FeatureType> filterValue = toFeatureType(arrayMember(value, 2), error); - if (!filterValue) { - return {}; - } - - return { TypeFilterType { *filterValue } }; - - } else if (*key == "$id") { - optional<FeatureIdentifier> filterValue = toFeatureIdentifier(arrayMember(value, 2), error); - if (!filterValue) { - return {}; - } - - return { IdentifierFilterType { *filterValue } }; - - } else { - optional<Value> filterValue = normalizeValue(toValue(arrayMember(value, 2)), error); - if (!filterValue) { - return {}; - } - - return { FilterType { *key, *filterValue } }; - } - } - - template <class FilterType, class V> - optional<Filter> convertBinaryFilter(const V& value, Error& error) const { - if (arrayLength(value) < 3) { - error = { "filter expression must have 3 elements" }; - return {}; - } - - optional<std::string> key = toString(arrayMember(value, 1)); - if (!key) { - error = { "filter expression key must be a string" }; - return {}; - } - - optional<Value> filterValue = normalizeValue(toValue(arrayMember(value, 2)), error); - if (!filterValue) { - return {}; - } - - return { FilterType { *key, *filterValue } }; - } - - template <class FilterType, class TypeFilterType, class IdentifierFilterType, class V> - optional<Filter> convertSetFilter(const V& value, Error& error) const { - if (arrayLength(value) < 2) { - error = { "filter expression must at least 2 elements" }; - return {}; - } - - optional<std::string> key = toString(arrayMember(value, 1)); - if (!key) { - error = { "filter expression key must be a string" }; - return {}; - } - - if (*key == "$type") { - std::vector<FeatureType> values; - for (std::size_t i = 2; i < arrayLength(value); ++i) { - optional<FeatureType> filterValue = toFeatureType(arrayMember(value, i), error); - if (!filterValue) { - return {}; - } - values.push_back(*filterValue); - } - - return { TypeFilterType { std::move(values) } }; - - } else if (*key == "$id") { - std::vector<FeatureIdentifier> values; - for (std::size_t i = 2; i < arrayLength(value); ++i) { - optional<FeatureIdentifier> filterValue = toFeatureIdentifier(arrayMember(value, i), error); - if (!filterValue) { - return {}; - } - values.push_back(*filterValue); - } - - return { IdentifierFilterType { std::move(values) } }; - - } else { - std::vector<Value> values; - for (std::size_t i = 2; i < arrayLength(value); ++i) { - optional<Value> filterValue = normalizeValue(toValue(arrayMember(value, i)), error); - if (!filterValue) { - return {}; - } - values.push_back(*filterValue); - } - - return { FilterType { *key, std::move(values) } }; - } - } - - template <class FilterType, class V> - optional<Filter> convertCompoundFilter(const V& value, Error& error) const { - std::vector<Filter> filters; - for (std::size_t i = 1; i < arrayLength(value); ++i) { - optional<Filter> element = operator()(arrayMember(value, i), error); - if (!element) { - return {}; - } - filters.push_back(*element); - } - - return { FilterType { std::move(filters) } }; - } + optional<Filter> operator()(const Convertible& value, Error& error) const; }; } // namespace conversion diff --git a/include/mbgl/style/conversion/function.hpp b/include/mbgl/style/conversion/function.hpp index 752b6dd045..e230884944 100644 --- a/include/mbgl/style/conversion/function.hpp +++ b/include/mbgl/style/conversion/function.hpp @@ -11,8 +11,8 @@ namespace mbgl { namespace style { namespace conversion { -template <class D, class R, class V> -optional<std::map<D, R>> convertStops(const V& value, Error& error) { +template <class D, class R> +optional<std::map<D, R>> convertStops(const Convertible& value, Error& error) { auto stopsValue = objectMember(value, "stops"); if (!stopsValue) { error = { "function value must specify stops" }; @@ -63,8 +63,7 @@ template <class T> struct Converter<ExponentialStops<T>> { static constexpr const char * type = "exponential"; - template <class V> - optional<ExponentialStops<T>> operator()(const V& value, Error& error) const { + optional<ExponentialStops<T>> operator()(const Convertible& value, Error& error) const { auto stops = convertStops<float, T>(value, error); if (!stops) { return {}; @@ -89,8 +88,7 @@ template <class T> struct Converter<IntervalStops<T>> { static constexpr const char * type = "interval"; - template <class V> - optional<IntervalStops<T>> operator()(const V& value, Error& error) const { + optional<IntervalStops<T>> operator()(const Convertible& value, Error& error) const { auto stops = convertStops<float, T>(value, error); if (!stops) { return {}; @@ -101,8 +99,7 @@ struct Converter<IntervalStops<T>> { template <> struct Converter<CategoricalValue> { - template <class V> - optional<CategoricalValue> operator()(const V& value, Error& error) const { + optional<CategoricalValue> operator()(const Convertible& value, Error& error) const { auto b = toBool(value); if (b) { return { *b }; @@ -127,8 +124,7 @@ template <class T> struct Converter<CategoricalStops<T>> { static constexpr const char * type = "categorical"; - template <class V> - optional<CategoricalStops<T>> operator()(const V& value, Error& error) const { + optional<CategoricalStops<T>> operator()(const Convertible& value, Error& error) const { auto stops = convertStops<CategoricalValue, T>(value, error); if (!stops) { return {}; @@ -142,8 +138,7 @@ template <class T> struct Converter<IdentityStops<T>> { static constexpr const char * type = "identity"; - template <class V> - optional<IdentityStops<T>> operator()(const V&, Error&) const { + optional<IdentityStops<T>> operator()(const Convertible&, Error&) const { return IdentityStops<T>(); } }; @@ -154,8 +149,7 @@ struct StopsConverter; template <class T, class... Ts> struct StopsConverter<T, variant<Ts...>> { public: - template <class V> - optional<variant<Ts...>> operator()(const V& value, Error& error) const { + optional<variant<Ts...>> operator()(const Convertible& value, Error& error) const { std::string type = util::Interpolatable<T>::value ? "exponential" : "interval"; auto typeValue = objectMember(value, "type"); @@ -193,8 +187,7 @@ public: template <class T> struct Converter<CameraFunction<T>> { - template <class V> - optional<CameraFunction<T>> operator()(const V& value, Error& error) const { + optional<CameraFunction<T>> operator()(const Convertible& value, Error& error) const { if (!isObject(value)) { error = { "function must be an object" }; return {}; @@ -209,8 +202,8 @@ struct Converter<CameraFunction<T>> { } }; -template <class T, class V> -optional<optional<T>> convertDefaultValue(const V& value, Error& error) { +template <class T> +optional<optional<T>> convertDefaultValue(const Convertible& value, Error& error) { auto defaultValueValue = objectMember(value, "default"); if (!defaultValueValue) { return optional<T>(); @@ -227,8 +220,7 @@ optional<optional<T>> convertDefaultValue(const V& value, Error& error) { template <class T> struct Converter<SourceFunction<T>> { - template <class V> - optional<SourceFunction<T>> operator()(const V& value, Error& error) const { + optional<SourceFunction<T>> operator()(const Convertible& value, Error& error) const { if (!isObject(value)) { error = { "function must be an object" }; return {}; @@ -267,8 +259,7 @@ struct CompositeValue : std::pair<float, S> { template <class S> struct Converter<CompositeValue<S>> { - template <class V> - optional<CompositeValue<S>> operator()(const V& value, Error& error) const { + optional<CompositeValue<S>> operator()(const Convertible& value, Error& error) const { if (!isObject(value)) { error = { "stop must be an object" }; return {}; @@ -304,8 +295,7 @@ template <class T> struct Converter<CompositeExponentialStops<T>> { static constexpr const char * type = "exponential"; - template <class V> - optional<CompositeExponentialStops<T>> operator()(const V& value, Error& error) const { + optional<CompositeExponentialStops<T>> operator()(const Convertible& value, Error& error) const { auto stops = convertStops<CompositeValue<float>, T>(value, error); if (!stops) { return {}; @@ -330,8 +320,7 @@ template <class T> struct Converter<CompositeIntervalStops<T>> { static constexpr const char * type = "interval"; - template <class V> - optional<CompositeIntervalStops<T>> operator()(const V& value, Error& error) const { + optional<CompositeIntervalStops<T>> operator()(const Convertible& value, Error& error) const { auto stops = convertStops<CompositeValue<float>, T>(value, error); if (!stops) { return {}; @@ -350,8 +339,7 @@ template <class T> struct Converter<CompositeCategoricalStops<T>> { static constexpr const char * type = "categorical"; - template <class V> - optional<CompositeCategoricalStops<T>> operator()(const V& value, Error& error) const { + optional<CompositeCategoricalStops<T>> operator()(const Convertible& value, Error& error) const { auto stops = convertStops<CompositeValue<CategoricalValue>, T>(value, error); if (!stops) { return {}; @@ -368,8 +356,7 @@ struct Converter<CompositeCategoricalStops<T>> { template <class T> struct Converter<CompositeFunction<T>> { - template <class V> - optional<CompositeFunction<T>> operator()(const V& value, Error& error) const { + optional<CompositeFunction<T>> operator()(const Convertible& value, Error& error) const { if (!isObject(value)) { error = { "function must be an object" }; return {}; diff --git a/include/mbgl/style/conversion/geojson.hpp b/include/mbgl/style/conversion/geojson.hpp index 0b594f066c..403c5f953b 100644 --- a/include/mbgl/style/conversion/geojson.hpp +++ b/include/mbgl/style/conversion/geojson.hpp @@ -7,15 +7,13 @@ namespace mbgl { namespace style { namespace conversion { +// Workaround until https://github.com/mapbox/mapbox-gl-native/issues/5623 is done. +optional<GeoJSON> parseGeoJSON(const std::string&, Error&); + template <> struct Converter<GeoJSON> { public: - optional<GeoJSON> operator()(const std::string&, Error&) const; - - // This is explicitly specialized in the .cpp file for JSValue. It may also be explicitly - // specialized for SDK-specific types (e.g. mbgl::android::Value). - template <class V> - optional<GeoJSON> operator()(const V&, Error&) const; + optional<GeoJSON> operator()(const Convertible&, Error&) const; }; } // namespace conversion diff --git a/include/mbgl/style/conversion/geojson_options.hpp b/include/mbgl/style/conversion/geojson_options.hpp index 1c9c18250c..3f625babb6 100644 --- a/include/mbgl/style/conversion/geojson_options.hpp +++ b/include/mbgl/style/conversion/geojson_options.hpp @@ -9,84 +9,7 @@ namespace conversion { template <> struct Converter<GeoJSONOptions> { - - template <class V> - optional<GeoJSONOptions> operator()(const V& value, Error& error) const { - GeoJSONOptions options; - - const auto minzoomValue = objectMember(value, "minzoom"); - if (minzoomValue) { - if (toNumber(*minzoomValue)) { - options.minzoom = static_cast<uint8_t>(*toNumber(*minzoomValue)); - } else { - error = { "GeoJSON source minzoom value must be a number" }; - return {}; - } - } - - const auto maxzoomValue = objectMember(value, "maxzoom"); - if (maxzoomValue) { - if (toNumber(*maxzoomValue)) { - options.maxzoom = static_cast<uint8_t>(*toNumber(*maxzoomValue)); - } else { - error = { "GeoJSON source maxzoom value must be a number" }; - return {}; - } - } - - const auto bufferValue = objectMember(value, "buffer"); - if (bufferValue) { - if (toNumber(*bufferValue)) { - options.buffer = static_cast<uint16_t>(*toNumber(*bufferValue)); - } else { - error = { "GeoJSON source buffer value must be a number" }; - return {}; - } - } - - const auto toleranceValue = objectMember(value, "tolerance"); - if (toleranceValue) { - if (toNumber(*toleranceValue)) { - options.tolerance = static_cast<double>(*toNumber(*toleranceValue)); - } else { - error = { "GeoJSON source tolerance value must be a number" }; - return {}; - } - } - - const auto clusterValue = objectMember(value, "cluster"); - if (clusterValue) { - if (toBool(*clusterValue)) { - options.cluster = *toBool(*clusterValue); - } else { - error = { "GeoJSON source cluster value must be a boolean" }; - return {}; - } - } - - const auto clusterMaxZoomValue = objectMember(value, "clusterMaxZoom"); - if (clusterMaxZoomValue) { - if (toNumber(*clusterMaxZoomValue)) { - options.clusterMaxZoom = static_cast<uint8_t>(*toNumber(*clusterMaxZoomValue)); - } else { - error = { "GeoJSON source clusterMaxZoom value must be a number" }; - return {}; - } - } - - const auto clusterRadiusValue = objectMember(value, "clusterRadius"); - if (clusterRadiusValue) { - if (toNumber(*clusterRadiusValue)) { - options.clusterRadius = static_cast<double>(*toNumber(*clusterRadiusValue)); - } else { - error = { "GeoJSON source clusterRadius value must be a number" }; - return {}; - } - } - - return { options }; - } - + optional<GeoJSONOptions> operator()(const Convertible& value, Error& error) const; }; } // namespace conversion diff --git a/include/mbgl/style/conversion/layer.hpp b/include/mbgl/style/conversion/layer.hpp index 1fe467165d..1c0e2e2f07 100644 --- a/include/mbgl/style/conversion/layer.hpp +++ b/include/mbgl/style/conversion/layer.hpp @@ -1,220 +1,24 @@ #pragma once #include <mbgl/style/layer.hpp> -#include <mbgl/style/layers/background_layer.hpp> -#include <mbgl/style/layers/circle_layer.hpp> -#include <mbgl/style/layers/fill_layer.hpp> -#include <mbgl/style/layers/fill_extrusion_layer.hpp> -#include <mbgl/style/layers/line_layer.hpp> -#include <mbgl/style/layers/raster_layer.hpp> -#include <mbgl/style/layers/symbol_layer.hpp> #include <mbgl/style/conversion.hpp> -#include <mbgl/style/conversion/constant.hpp> -#include <mbgl/style/conversion/filter.hpp> -#include <mbgl/style/conversion/make_property_setters.hpp> + +#include <memory> namespace mbgl { namespace style { namespace conversion { -template <class V> -optional<Error> setLayoutProperty(Layer& layer, const std::string& name, const V& value) { - static const auto setters = makeLayoutPropertySetters<V>(); - auto it = setters.find(name); - if (it == setters.end()) { - return Error { "property not found" }; - } - return it->second(layer, value); -} - -template <class V> -optional<Error> setPaintProperty(Layer& layer, const std::string& name, const V& value) { - static const auto setters = makePaintPropertySetters<V>(); - auto it = setters.find(name); - if (it == setters.end()) { - return Error { "property not found" }; - } - return it->second(layer, value); -} - -template <class V> -optional<Error> setPaintProperties(Layer& layer, const V& value) { - auto paintValue = objectMember(value, "paint"); - if (!paintValue) { - return {}; - } - return eachMember(*paintValue, [&] (const std::string& k, const V& v) { - return setPaintProperty(layer, k, v); - }); -} - template <> struct Converter<std::unique_ptr<Layer>> { public: - template <class V> - optional<std::unique_ptr<Layer>> operator()(const V& value, Error& error) const { - if (!isObject(value)) { - error = { "layer must be an object" }; - return {}; - } - - auto idValue = objectMember(value, "id"); - if (!idValue) { - error = { "layer must have an id" }; - return {}; - } - - optional<std::string> id = toString(*idValue); - if (!id) { - error = { "layer id must be a string" }; - return {}; - } - - auto typeValue = objectMember(value, "type"); - if (!typeValue) { - error = { "layer must have a type" }; - return {}; - } - - optional<std::string> type = toString(*typeValue); - if (!type) { - error = { "layer type must be a string" }; - return {}; - } - - optional<std::unique_ptr<Layer>> converted; - - if (*type == "fill") { - converted = convertVectorLayer<FillLayer>(*id, value, error); - } else if (*type == "fill-extrusion") { - converted = convertVectorLayer<FillExtrusionLayer>(*id, value, error); - } else if (*type == "line") { - converted = convertVectorLayer<LineLayer>(*id, value, error); - } else if (*type == "circle") { - converted = convertVectorLayer<CircleLayer>(*id, value, error); - } else if (*type == "symbol") { - converted = convertVectorLayer<SymbolLayer>(*id, value, error); - } else if (*type == "raster") { - converted = convertRasterLayer(*id, value, error); - } else if (*type == "background") { - converted = convertBackgroundLayer(*id, value, error); - } else { - error = { "invalid layer type" }; - return {}; - } - - if (!converted) { - return converted; - } - - std::unique_ptr<Layer> layer = std::move(*converted); - - auto minzoomValue = objectMember(value, "minzoom"); - if (minzoomValue) { - optional<float> minzoom = toNumber(*minzoomValue); - if (!minzoom) { - error = { "minzoom must be numeric" }; - return {}; - } - layer->setMinZoom(*minzoom); - } - - auto maxzoomValue = objectMember(value, "maxzoom"); - if (maxzoomValue) { - optional<float> maxzoom = toNumber(*maxzoomValue); - if (!maxzoom) { - error = { "maxzoom must be numeric" }; - return {}; - } - layer->setMaxZoom(*maxzoom); - } - - auto layoutValue = objectMember(value, "layout"); - if (layoutValue) { - if (!isObject(*layoutValue)) { - error = { "layout must be an object" }; - return {}; - } - optional<Error> error_ = eachMember(*layoutValue, [&] (const std::string& k, const V& v) { - return setLayoutProperty(*layer, k, v); - }); - if (error_) { - error = *error_; - return {}; - } - } - - optional<Error> error_ = setPaintProperties(*layer, value); - if (error_) { - error = *error_; - return {}; - } - - return std::move(layer); - } - -private: - template <class LayerType, class V> - optional<std::unique_ptr<Layer>> convertVectorLayer(const std::string& id, const V& value, Error& error) const { - auto sourceValue = objectMember(value, "source"); - if (!sourceValue) { - error = { "layer must have a source" }; - return {}; - } - - optional<std::string> source = toString(*sourceValue); - if (!source) { - error = { "layer source must be a string" }; - return {}; - } - - std::unique_ptr<LayerType> layer = std::make_unique<LayerType>(id, *source); - - auto sourceLayerValue = objectMember(value, "source-layer"); - if (sourceLayerValue) { - optional<std::string> sourceLayer = toString(*sourceLayerValue); - if (!sourceLayer) { - error = { "layer source-layer must be a string" }; - return {}; - } - layer->setSourceLayer(*sourceLayer); - } - - auto filterValue = objectMember(value, "filter"); - if (filterValue) { - optional<Filter> filter = convert<Filter>(*filterValue, error); - if (!filter) { - return {}; - } - layer->setFilter(*filter); - } - - return { std::move(layer) }; - } - - template <class V> - optional<std::unique_ptr<Layer>> convertRasterLayer(const std::string& id, const V& value, Error& error) const { - auto sourceValue = objectMember(value, "source"); - if (!sourceValue) { - error = { "layer must have a source" }; - return {}; - } - - optional<std::string> source = toString(*sourceValue); - if (!source) { - error = { "layer source must be a string" }; - return {}; - } - - return { std::make_unique<RasterLayer>(id, *source) }; - } - - template <class V> - optional<std::unique_ptr<Layer>> convertBackgroundLayer(const std::string& id, const V&, Error&) const { - return { std::make_unique<BackgroundLayer>(id) }; - } + optional<std::unique_ptr<Layer>> operator()(const Convertible& value, Error& error) const; }; +optional<Error> setLayoutProperty(Layer& layer, const std::string& name, const Convertible& value); +optional<Error> setPaintProperty(Layer& layer, const std::string& name, const Convertible& value); +optional<Error> setPaintProperties(Layer& layer, const Convertible& value); + } // namespace conversion } // namespace style } // namespace mbgl diff --git a/include/mbgl/style/conversion/light.hpp b/include/mbgl/style/conversion/light.hpp index ba162516c0..289fca2e31 100644 --- a/include/mbgl/style/conversion/light.hpp +++ b/include/mbgl/style/conversion/light.hpp @@ -2,9 +2,6 @@ #include <mbgl/style/light.hpp> #include <mbgl/style/conversion.hpp> -#include <mbgl/style/conversion/position.hpp> -#include <mbgl/style/conversion/property_value.hpp> -#include <mbgl/style/conversion/transition_options.hpp> namespace mbgl { namespace style { @@ -13,108 +10,7 @@ namespace conversion { template <> struct Converter<Light> { public: - template <class V> - optional<Light> operator()(const V& value, Error& error) const { - if (!isObject(value)) { - error = { "light must be an object" }; - return {}; - } - - Light light; - - const auto anchor = objectMember(value, "anchor"); - if (anchor) { - optional<PropertyValue<LightAnchorType>> convertedAnchor = - convert<PropertyValue<LightAnchorType>>(*anchor, error); - - if (convertedAnchor) { - light.setAnchor(*convertedAnchor); - } else { - return {}; - } - } - - const auto anchorTransition = objectMember(value, "anchor-transition"); - if (anchorTransition) { - optional<TransitionOptions> transition = - convert<TransitionOptions>(*anchorTransition, error); - if (transition) { - light.setAnchorTransition(*transition); - } else { - return {}; - } - } - - const auto color = objectMember(value, "color"); - if (color) { - optional<PropertyValue<Color>> convertedColor = - convert<PropertyValue<Color>>(*color, error); - - if (convertedColor) { - light.setColor(*convertedColor); - } else { - return {}; - } - } - - const auto colorTransition = objectMember(value, "color-transition"); - if (colorTransition) { - optional<TransitionOptions> transition = - convert<TransitionOptions>(*colorTransition, error); - if (transition) { - light.setColorTransition(*transition); - } else { - return {}; - } - } - - const auto position = objectMember(value, "position"); - if (position) { - optional<PropertyValue<Position>> convertedPosition = - convert<PropertyValue<Position>>(*position, error); - - if (convertedPosition) { - light.setPosition(*convertedPosition); - } else { - return {}; - } - } - - const auto positionTransition = objectMember(value, "position-transition"); - if (positionTransition) { - optional<TransitionOptions> transition = - convert<TransitionOptions>(*positionTransition, error); - if (transition) { - light.setPositionTransition(*transition); - } else { - return {}; - } - } - - const auto intensity = objectMember(value, "intensity"); - if (intensity) { - optional<PropertyValue<float>> convertedIntensity = - convert<PropertyValue<float>>(*intensity, error); - - if (convertedIntensity) { - light.setIntensity(*convertedIntensity); - } else { - return {}; - } - } - - const auto intensityTransition = objectMember(value, "intensity-transition"); - if (intensityTransition) { - optional<TransitionOptions> transition = - convert<TransitionOptions>(*intensityTransition, error); - if (transition) { - light.setIntensityTransition(*transition); - } else { - return {}; - } - } - return { std::move(light) }; - }; + optional<Light> operator()(const Convertible& value, Error& error) const; }; } // namespace conversion diff --git a/include/mbgl/style/conversion/make_property_setters.hpp b/include/mbgl/style/conversion/make_property_setters.hpp deleted file mode 100644 index 59b0e7be32..0000000000 --- a/include/mbgl/style/conversion/make_property_setters.hpp +++ /dev/null @@ -1,211 +0,0 @@ -#pragma once - -// This file is generated. Edit make_property_setters.hpp.ejs, then run `make style-code`. - -#include <mbgl/style/conversion/property_setter.hpp> - -#include <mbgl/style/layers/fill_layer.hpp> -#include <mbgl/style/layers/line_layer.hpp> -#include <mbgl/style/layers/symbol_layer.hpp> -#include <mbgl/style/layers/circle_layer.hpp> -#include <mbgl/style/layers/fill_extrusion_layer.hpp> -#include <mbgl/style/layers/raster_layer.hpp> -#include <mbgl/style/layers/background_layer.hpp> - -#include <unordered_map> - -namespace mbgl { -namespace style { -namespace conversion { - -template <class V> -auto makeLayoutPropertySetters() { - std::unordered_map<std::string, PropertySetter<V>> result; - - result["visibility"] = &setVisibility<V>; - - - result["line-cap"] = &setProperty<V, LineLayer, PropertyValue<LineCapType>, &LineLayer::setLineCap>; - result["line-join"] = &setProperty<V, LineLayer, DataDrivenPropertyValue<LineJoinType>, &LineLayer::setLineJoin>; - result["line-miter-limit"] = &setProperty<V, LineLayer, PropertyValue<float>, &LineLayer::setLineMiterLimit>; - result["line-round-limit"] = &setProperty<V, LineLayer, PropertyValue<float>, &LineLayer::setLineRoundLimit>; - - result["symbol-placement"] = &setProperty<V, SymbolLayer, PropertyValue<SymbolPlacementType>, &SymbolLayer::setSymbolPlacement>; - result["symbol-spacing"] = &setProperty<V, SymbolLayer, PropertyValue<float>, &SymbolLayer::setSymbolSpacing>; - result["symbol-avoid-edges"] = &setProperty<V, SymbolLayer, PropertyValue<bool>, &SymbolLayer::setSymbolAvoidEdges>; - result["icon-allow-overlap"] = &setProperty<V, SymbolLayer, PropertyValue<bool>, &SymbolLayer::setIconAllowOverlap>; - result["icon-ignore-placement"] = &setProperty<V, SymbolLayer, PropertyValue<bool>, &SymbolLayer::setIconIgnorePlacement>; - result["icon-optional"] = &setProperty<V, SymbolLayer, PropertyValue<bool>, &SymbolLayer::setIconOptional>; - result["icon-rotation-alignment"] = &setProperty<V, SymbolLayer, PropertyValue<AlignmentType>, &SymbolLayer::setIconRotationAlignment>; - result["icon-size"] = &setProperty<V, SymbolLayer, DataDrivenPropertyValue<float>, &SymbolLayer::setIconSize>; - result["icon-text-fit"] = &setProperty<V, SymbolLayer, PropertyValue<IconTextFitType>, &SymbolLayer::setIconTextFit>; - result["icon-text-fit-padding"] = &setProperty<V, SymbolLayer, PropertyValue<std::array<float, 4>>, &SymbolLayer::setIconTextFitPadding>; - result["icon-image"] = &setProperty<V, SymbolLayer, DataDrivenPropertyValue<std::string>, &SymbolLayer::setIconImage>; - result["icon-rotate"] = &setProperty<V, SymbolLayer, DataDrivenPropertyValue<float>, &SymbolLayer::setIconRotate>; - result["icon-padding"] = &setProperty<V, SymbolLayer, PropertyValue<float>, &SymbolLayer::setIconPadding>; - result["icon-keep-upright"] = &setProperty<V, SymbolLayer, PropertyValue<bool>, &SymbolLayer::setIconKeepUpright>; - result["icon-offset"] = &setProperty<V, SymbolLayer, DataDrivenPropertyValue<std::array<float, 2>>, &SymbolLayer::setIconOffset>; - result["icon-anchor"] = &setProperty<V, SymbolLayer, DataDrivenPropertyValue<SymbolAnchorType>, &SymbolLayer::setIconAnchor>; - result["icon-pitch-alignment"] = &setProperty<V, SymbolLayer, PropertyValue<AlignmentType>, &SymbolLayer::setIconPitchAlignment>; - result["text-pitch-alignment"] = &setProperty<V, SymbolLayer, PropertyValue<AlignmentType>, &SymbolLayer::setTextPitchAlignment>; - result["text-rotation-alignment"] = &setProperty<V, SymbolLayer, PropertyValue<AlignmentType>, &SymbolLayer::setTextRotationAlignment>; - result["text-field"] = &setProperty<V, SymbolLayer, DataDrivenPropertyValue<std::string>, &SymbolLayer::setTextField>; - result["text-font"] = &setProperty<V, SymbolLayer, PropertyValue<std::vector<std::string>>, &SymbolLayer::setTextFont>; - result["text-size"] = &setProperty<V, SymbolLayer, DataDrivenPropertyValue<float>, &SymbolLayer::setTextSize>; - result["text-max-width"] = &setProperty<V, SymbolLayer, DataDrivenPropertyValue<float>, &SymbolLayer::setTextMaxWidth>; - result["text-line-height"] = &setProperty<V, SymbolLayer, PropertyValue<float>, &SymbolLayer::setTextLineHeight>; - result["text-letter-spacing"] = &setProperty<V, SymbolLayer, DataDrivenPropertyValue<float>, &SymbolLayer::setTextLetterSpacing>; - result["text-justify"] = &setProperty<V, SymbolLayer, DataDrivenPropertyValue<TextJustifyType>, &SymbolLayer::setTextJustify>; - result["text-anchor"] = &setProperty<V, SymbolLayer, DataDrivenPropertyValue<SymbolAnchorType>, &SymbolLayer::setTextAnchor>; - result["text-max-angle"] = &setProperty<V, SymbolLayer, PropertyValue<float>, &SymbolLayer::setTextMaxAngle>; - result["text-rotate"] = &setProperty<V, SymbolLayer, DataDrivenPropertyValue<float>, &SymbolLayer::setTextRotate>; - result["text-padding"] = &setProperty<V, SymbolLayer, PropertyValue<float>, &SymbolLayer::setTextPadding>; - result["text-keep-upright"] = &setProperty<V, SymbolLayer, PropertyValue<bool>, &SymbolLayer::setTextKeepUpright>; - result["text-transform"] = &setProperty<V, SymbolLayer, DataDrivenPropertyValue<TextTransformType>, &SymbolLayer::setTextTransform>; - result["text-offset"] = &setProperty<V, SymbolLayer, DataDrivenPropertyValue<std::array<float, 2>>, &SymbolLayer::setTextOffset>; - result["text-allow-overlap"] = &setProperty<V, SymbolLayer, PropertyValue<bool>, &SymbolLayer::setTextAllowOverlap>; - result["text-ignore-placement"] = &setProperty<V, SymbolLayer, PropertyValue<bool>, &SymbolLayer::setTextIgnorePlacement>; - result["text-optional"] = &setProperty<V, SymbolLayer, PropertyValue<bool>, &SymbolLayer::setTextOptional>; - - - - - - return result; -} - -template <class V> -auto makePaintPropertySetters() { - std::unordered_map<std::string, PropertySetter<V>> result; - - result["fill-antialias"] = &setProperty<V, FillLayer, PropertyValue<bool>, &FillLayer::setFillAntialias>; - result["fill-antialias-transition"] = &setTransition<V, FillLayer, &FillLayer::setFillAntialiasTransition>; - result["fill-opacity"] = &setProperty<V, FillLayer, DataDrivenPropertyValue<float>, &FillLayer::setFillOpacity>; - result["fill-opacity-transition"] = &setTransition<V, FillLayer, &FillLayer::setFillOpacityTransition>; - result["fill-color"] = &setProperty<V, FillLayer, DataDrivenPropertyValue<Color>, &FillLayer::setFillColor>; - result["fill-color-transition"] = &setTransition<V, FillLayer, &FillLayer::setFillColorTransition>; - result["fill-outline-color"] = &setProperty<V, FillLayer, DataDrivenPropertyValue<Color>, &FillLayer::setFillOutlineColor>; - result["fill-outline-color-transition"] = &setTransition<V, FillLayer, &FillLayer::setFillOutlineColorTransition>; - result["fill-translate"] = &setProperty<V, FillLayer, PropertyValue<std::array<float, 2>>, &FillLayer::setFillTranslate>; - result["fill-translate-transition"] = &setTransition<V, FillLayer, &FillLayer::setFillTranslateTransition>; - result["fill-translate-anchor"] = &setProperty<V, FillLayer, PropertyValue<TranslateAnchorType>, &FillLayer::setFillTranslateAnchor>; - result["fill-translate-anchor-transition"] = &setTransition<V, FillLayer, &FillLayer::setFillTranslateAnchorTransition>; - result["fill-pattern"] = &setProperty<V, FillLayer, PropertyValue<std::string>, &FillLayer::setFillPattern>; - result["fill-pattern-transition"] = &setTransition<V, FillLayer, &FillLayer::setFillPatternTransition>; - - result["line-opacity"] = &setProperty<V, LineLayer, DataDrivenPropertyValue<float>, &LineLayer::setLineOpacity>; - result["line-opacity-transition"] = &setTransition<V, LineLayer, &LineLayer::setLineOpacityTransition>; - result["line-color"] = &setProperty<V, LineLayer, DataDrivenPropertyValue<Color>, &LineLayer::setLineColor>; - result["line-color-transition"] = &setTransition<V, LineLayer, &LineLayer::setLineColorTransition>; - result["line-translate"] = &setProperty<V, LineLayer, PropertyValue<std::array<float, 2>>, &LineLayer::setLineTranslate>; - result["line-translate-transition"] = &setTransition<V, LineLayer, &LineLayer::setLineTranslateTransition>; - result["line-translate-anchor"] = &setProperty<V, LineLayer, PropertyValue<TranslateAnchorType>, &LineLayer::setLineTranslateAnchor>; - result["line-translate-anchor-transition"] = &setTransition<V, LineLayer, &LineLayer::setLineTranslateAnchorTransition>; - result["line-width"] = &setProperty<V, LineLayer, DataDrivenPropertyValue<float>, &LineLayer::setLineWidth>; - result["line-width-transition"] = &setTransition<V, LineLayer, &LineLayer::setLineWidthTransition>; - result["line-gap-width"] = &setProperty<V, LineLayer, DataDrivenPropertyValue<float>, &LineLayer::setLineGapWidth>; - result["line-gap-width-transition"] = &setTransition<V, LineLayer, &LineLayer::setLineGapWidthTransition>; - result["line-offset"] = &setProperty<V, LineLayer, DataDrivenPropertyValue<float>, &LineLayer::setLineOffset>; - result["line-offset-transition"] = &setTransition<V, LineLayer, &LineLayer::setLineOffsetTransition>; - result["line-blur"] = &setProperty<V, LineLayer, DataDrivenPropertyValue<float>, &LineLayer::setLineBlur>; - result["line-blur-transition"] = &setTransition<V, LineLayer, &LineLayer::setLineBlurTransition>; - result["line-dasharray"] = &setProperty<V, LineLayer, PropertyValue<std::vector<float>>, &LineLayer::setLineDasharray>; - result["line-dasharray-transition"] = &setTransition<V, LineLayer, &LineLayer::setLineDasharrayTransition>; - result["line-pattern"] = &setProperty<V, LineLayer, PropertyValue<std::string>, &LineLayer::setLinePattern>; - result["line-pattern-transition"] = &setTransition<V, LineLayer, &LineLayer::setLinePatternTransition>; - - result["icon-opacity"] = &setProperty<V, SymbolLayer, DataDrivenPropertyValue<float>, &SymbolLayer::setIconOpacity>; - result["icon-opacity-transition"] = &setTransition<V, SymbolLayer, &SymbolLayer::setIconOpacityTransition>; - result["icon-color"] = &setProperty<V, SymbolLayer, DataDrivenPropertyValue<Color>, &SymbolLayer::setIconColor>; - result["icon-color-transition"] = &setTransition<V, SymbolLayer, &SymbolLayer::setIconColorTransition>; - result["icon-halo-color"] = &setProperty<V, SymbolLayer, DataDrivenPropertyValue<Color>, &SymbolLayer::setIconHaloColor>; - result["icon-halo-color-transition"] = &setTransition<V, SymbolLayer, &SymbolLayer::setIconHaloColorTransition>; - result["icon-halo-width"] = &setProperty<V, SymbolLayer, DataDrivenPropertyValue<float>, &SymbolLayer::setIconHaloWidth>; - result["icon-halo-width-transition"] = &setTransition<V, SymbolLayer, &SymbolLayer::setIconHaloWidthTransition>; - result["icon-halo-blur"] = &setProperty<V, SymbolLayer, DataDrivenPropertyValue<float>, &SymbolLayer::setIconHaloBlur>; - result["icon-halo-blur-transition"] = &setTransition<V, SymbolLayer, &SymbolLayer::setIconHaloBlurTransition>; - result["icon-translate"] = &setProperty<V, SymbolLayer, PropertyValue<std::array<float, 2>>, &SymbolLayer::setIconTranslate>; - result["icon-translate-transition"] = &setTransition<V, SymbolLayer, &SymbolLayer::setIconTranslateTransition>; - result["icon-translate-anchor"] = &setProperty<V, SymbolLayer, PropertyValue<TranslateAnchorType>, &SymbolLayer::setIconTranslateAnchor>; - result["icon-translate-anchor-transition"] = &setTransition<V, SymbolLayer, &SymbolLayer::setIconTranslateAnchorTransition>; - result["text-opacity"] = &setProperty<V, SymbolLayer, DataDrivenPropertyValue<float>, &SymbolLayer::setTextOpacity>; - result["text-opacity-transition"] = &setTransition<V, SymbolLayer, &SymbolLayer::setTextOpacityTransition>; - result["text-color"] = &setProperty<V, SymbolLayer, DataDrivenPropertyValue<Color>, &SymbolLayer::setTextColor>; - result["text-color-transition"] = &setTransition<V, SymbolLayer, &SymbolLayer::setTextColorTransition>; - result["text-halo-color"] = &setProperty<V, SymbolLayer, DataDrivenPropertyValue<Color>, &SymbolLayer::setTextHaloColor>; - result["text-halo-color-transition"] = &setTransition<V, SymbolLayer, &SymbolLayer::setTextHaloColorTransition>; - result["text-halo-width"] = &setProperty<V, SymbolLayer, DataDrivenPropertyValue<float>, &SymbolLayer::setTextHaloWidth>; - result["text-halo-width-transition"] = &setTransition<V, SymbolLayer, &SymbolLayer::setTextHaloWidthTransition>; - result["text-halo-blur"] = &setProperty<V, SymbolLayer, DataDrivenPropertyValue<float>, &SymbolLayer::setTextHaloBlur>; - result["text-halo-blur-transition"] = &setTransition<V, SymbolLayer, &SymbolLayer::setTextHaloBlurTransition>; - result["text-translate"] = &setProperty<V, SymbolLayer, PropertyValue<std::array<float, 2>>, &SymbolLayer::setTextTranslate>; - result["text-translate-transition"] = &setTransition<V, SymbolLayer, &SymbolLayer::setTextTranslateTransition>; - result["text-translate-anchor"] = &setProperty<V, SymbolLayer, PropertyValue<TranslateAnchorType>, &SymbolLayer::setTextTranslateAnchor>; - result["text-translate-anchor-transition"] = &setTransition<V, SymbolLayer, &SymbolLayer::setTextTranslateAnchorTransition>; - - result["circle-radius"] = &setProperty<V, CircleLayer, DataDrivenPropertyValue<float>, &CircleLayer::setCircleRadius>; - result["circle-radius-transition"] = &setTransition<V, CircleLayer, &CircleLayer::setCircleRadiusTransition>; - result["circle-color"] = &setProperty<V, CircleLayer, DataDrivenPropertyValue<Color>, &CircleLayer::setCircleColor>; - result["circle-color-transition"] = &setTransition<V, CircleLayer, &CircleLayer::setCircleColorTransition>; - result["circle-blur"] = &setProperty<V, CircleLayer, DataDrivenPropertyValue<float>, &CircleLayer::setCircleBlur>; - result["circle-blur-transition"] = &setTransition<V, CircleLayer, &CircleLayer::setCircleBlurTransition>; - result["circle-opacity"] = &setProperty<V, CircleLayer, DataDrivenPropertyValue<float>, &CircleLayer::setCircleOpacity>; - result["circle-opacity-transition"] = &setTransition<V, CircleLayer, &CircleLayer::setCircleOpacityTransition>; - result["circle-translate"] = &setProperty<V, CircleLayer, PropertyValue<std::array<float, 2>>, &CircleLayer::setCircleTranslate>; - result["circle-translate-transition"] = &setTransition<V, CircleLayer, &CircleLayer::setCircleTranslateTransition>; - result["circle-translate-anchor"] = &setProperty<V, CircleLayer, PropertyValue<TranslateAnchorType>, &CircleLayer::setCircleTranslateAnchor>; - result["circle-translate-anchor-transition"] = &setTransition<V, CircleLayer, &CircleLayer::setCircleTranslateAnchorTransition>; - result["circle-pitch-scale"] = &setProperty<V, CircleLayer, PropertyValue<CirclePitchScaleType>, &CircleLayer::setCirclePitchScale>; - result["circle-pitch-scale-transition"] = &setTransition<V, CircleLayer, &CircleLayer::setCirclePitchScaleTransition>; - result["circle-pitch-alignment"] = &setProperty<V, CircleLayer, PropertyValue<AlignmentType>, &CircleLayer::setCirclePitchAlignment>; - result["circle-pitch-alignment-transition"] = &setTransition<V, CircleLayer, &CircleLayer::setCirclePitchAlignmentTransition>; - result["circle-stroke-width"] = &setProperty<V, CircleLayer, DataDrivenPropertyValue<float>, &CircleLayer::setCircleStrokeWidth>; - result["circle-stroke-width-transition"] = &setTransition<V, CircleLayer, &CircleLayer::setCircleStrokeWidthTransition>; - result["circle-stroke-color"] = &setProperty<V, CircleLayer, DataDrivenPropertyValue<Color>, &CircleLayer::setCircleStrokeColor>; - result["circle-stroke-color-transition"] = &setTransition<V, CircleLayer, &CircleLayer::setCircleStrokeColorTransition>; - result["circle-stroke-opacity"] = &setProperty<V, CircleLayer, DataDrivenPropertyValue<float>, &CircleLayer::setCircleStrokeOpacity>; - result["circle-stroke-opacity-transition"] = &setTransition<V, CircleLayer, &CircleLayer::setCircleStrokeOpacityTransition>; - - result["fill-extrusion-opacity"] = &setProperty<V, FillExtrusionLayer, PropertyValue<float>, &FillExtrusionLayer::setFillExtrusionOpacity>; - result["fill-extrusion-opacity-transition"] = &setTransition<V, FillExtrusionLayer, &FillExtrusionLayer::setFillExtrusionOpacityTransition>; - result["fill-extrusion-color"] = &setProperty<V, FillExtrusionLayer, DataDrivenPropertyValue<Color>, &FillExtrusionLayer::setFillExtrusionColor>; - result["fill-extrusion-color-transition"] = &setTransition<V, FillExtrusionLayer, &FillExtrusionLayer::setFillExtrusionColorTransition>; - result["fill-extrusion-translate"] = &setProperty<V, FillExtrusionLayer, PropertyValue<std::array<float, 2>>, &FillExtrusionLayer::setFillExtrusionTranslate>; - result["fill-extrusion-translate-transition"] = &setTransition<V, FillExtrusionLayer, &FillExtrusionLayer::setFillExtrusionTranslateTransition>; - result["fill-extrusion-translate-anchor"] = &setProperty<V, FillExtrusionLayer, PropertyValue<TranslateAnchorType>, &FillExtrusionLayer::setFillExtrusionTranslateAnchor>; - result["fill-extrusion-translate-anchor-transition"] = &setTransition<V, FillExtrusionLayer, &FillExtrusionLayer::setFillExtrusionTranslateAnchorTransition>; - result["fill-extrusion-pattern"] = &setProperty<V, FillExtrusionLayer, PropertyValue<std::string>, &FillExtrusionLayer::setFillExtrusionPattern>; - result["fill-extrusion-pattern-transition"] = &setTransition<V, FillExtrusionLayer, &FillExtrusionLayer::setFillExtrusionPatternTransition>; - result["fill-extrusion-height"] = &setProperty<V, FillExtrusionLayer, DataDrivenPropertyValue<float>, &FillExtrusionLayer::setFillExtrusionHeight>; - result["fill-extrusion-height-transition"] = &setTransition<V, FillExtrusionLayer, &FillExtrusionLayer::setFillExtrusionHeightTransition>; - result["fill-extrusion-base"] = &setProperty<V, FillExtrusionLayer, DataDrivenPropertyValue<float>, &FillExtrusionLayer::setFillExtrusionBase>; - result["fill-extrusion-base-transition"] = &setTransition<V, FillExtrusionLayer, &FillExtrusionLayer::setFillExtrusionBaseTransition>; - - result["raster-opacity"] = &setProperty<V, RasterLayer, PropertyValue<float>, &RasterLayer::setRasterOpacity>; - result["raster-opacity-transition"] = &setTransition<V, RasterLayer, &RasterLayer::setRasterOpacityTransition>; - result["raster-hue-rotate"] = &setProperty<V, RasterLayer, PropertyValue<float>, &RasterLayer::setRasterHueRotate>; - result["raster-hue-rotate-transition"] = &setTransition<V, RasterLayer, &RasterLayer::setRasterHueRotateTransition>; - result["raster-brightness-min"] = &setProperty<V, RasterLayer, PropertyValue<float>, &RasterLayer::setRasterBrightnessMin>; - result["raster-brightness-min-transition"] = &setTransition<V, RasterLayer, &RasterLayer::setRasterBrightnessMinTransition>; - result["raster-brightness-max"] = &setProperty<V, RasterLayer, PropertyValue<float>, &RasterLayer::setRasterBrightnessMax>; - result["raster-brightness-max-transition"] = &setTransition<V, RasterLayer, &RasterLayer::setRasterBrightnessMaxTransition>; - result["raster-saturation"] = &setProperty<V, RasterLayer, PropertyValue<float>, &RasterLayer::setRasterSaturation>; - result["raster-saturation-transition"] = &setTransition<V, RasterLayer, &RasterLayer::setRasterSaturationTransition>; - result["raster-contrast"] = &setProperty<V, RasterLayer, PropertyValue<float>, &RasterLayer::setRasterContrast>; - result["raster-contrast-transition"] = &setTransition<V, RasterLayer, &RasterLayer::setRasterContrastTransition>; - result["raster-fade-duration"] = &setProperty<V, RasterLayer, PropertyValue<float>, &RasterLayer::setRasterFadeDuration>; - result["raster-fade-duration-transition"] = &setTransition<V, RasterLayer, &RasterLayer::setRasterFadeDurationTransition>; - - result["background-color"] = &setProperty<V, BackgroundLayer, PropertyValue<Color>, &BackgroundLayer::setBackgroundColor>; - result["background-color-transition"] = &setTransition<V, BackgroundLayer, &BackgroundLayer::setBackgroundColorTransition>; - result["background-pattern"] = &setProperty<V, BackgroundLayer, PropertyValue<std::string>, &BackgroundLayer::setBackgroundPattern>; - result["background-pattern-transition"] = &setTransition<V, BackgroundLayer, &BackgroundLayer::setBackgroundPatternTransition>; - result["background-opacity"] = &setProperty<V, BackgroundLayer, PropertyValue<float>, &BackgroundLayer::setBackgroundOpacity>; - result["background-opacity-transition"] = &setTransition<V, BackgroundLayer, &BackgroundLayer::setBackgroundOpacityTransition>; - - return result; -} - -} // namespace conversion -} // namespace style -} // namespace mbgl diff --git a/include/mbgl/style/conversion/make_property_setters.hpp.ejs b/include/mbgl/style/conversion/make_property_setters.hpp.ejs deleted file mode 100644 index 19c9f70538..0000000000 --- a/include/mbgl/style/conversion/make_property_setters.hpp.ejs +++ /dev/null @@ -1,48 +0,0 @@ -#pragma once - -// This file is generated. Edit make_property_setters.hpp.ejs, then run `make style-code`. - -#include <mbgl/style/conversion/property_setter.hpp> - -<% for (const layer of locals.layers) { -%> -#include <mbgl/style/layers/<%- layer.type.replace('-', '_') %>_layer.hpp> -<% } -%> - -#include <unordered_map> - -namespace mbgl { -namespace style { -namespace conversion { - -template <class V> -auto makeLayoutPropertySetters() { - std::unordered_map<std::string, PropertySetter<V>> result; - - result["visibility"] = &setVisibility<V>; - -<% for (const layer of locals.layers) { -%> -<% for (const property of layer.layoutProperties) { -%> - result["<%- property.name %>"] = &setProperty<V, <%- camelize(layer.type) %>Layer, <%- propertyValueType(property) %>, &<%- camelize(layer.type) %>Layer::set<%- camelize(property.name) %>>; -<% } -%> - -<% } -%> - return result; -} - -template <class V> -auto makePaintPropertySetters() { - std::unordered_map<std::string, PropertySetter<V>> result; - -<% for (const layer of locals.layers) { -%> -<% for (const property of layer.paintProperties) { -%> - result["<%- property.name %>"] = &setProperty<V, <%- camelize(layer.type) %>Layer, <%- propertyValueType(property) %>, &<%- camelize(layer.type) %>Layer::set<%- camelize(property.name) %>>; - result["<%- property.name %>-transition"] = &setTransition<V, <%- camelize(layer.type) %>Layer, &<%- camelize(layer.type) %>Layer::set<%- camelize(property.name) %>Transition>; -<% } -%> - -<% } -%> - return result; -} - -} // namespace conversion -} // namespace style -} // namespace mbgl diff --git a/include/mbgl/style/conversion/position.hpp b/include/mbgl/style/conversion/position.hpp index 7036b03822..044c45862d 100644 --- a/include/mbgl/style/conversion/position.hpp +++ b/include/mbgl/style/conversion/position.hpp @@ -2,9 +2,6 @@ #include <mbgl/style/conversion.hpp> #include <mbgl/style/position.hpp> -#include <mbgl/util/optional.hpp> - -#include <array> namespace mbgl { namespace style { @@ -12,16 +9,7 @@ namespace conversion { template <> struct Converter<Position> { - template <class V> - optional<Position> operator()(const V& value, Error& error) const { - optional<std::array<float, 3>> spherical = convert<std::array<float, 3>>(value, error); - - if (!spherical) { - return {}; - } - - return Position(*spherical); - } + optional<Position> operator()(const Convertible& value, Error& error) const; }; } // namespace conversion diff --git a/include/mbgl/style/conversion/property_setter.hpp b/include/mbgl/style/conversion/property_setter.hpp deleted file mode 100644 index 759c4512cc..0000000000 --- a/include/mbgl/style/conversion/property_setter.hpp +++ /dev/null @@ -1,72 +0,0 @@ -#pragma once - -#include <mbgl/style/layer.hpp> -#include <mbgl/style/conversion.hpp> -#include <mbgl/style/conversion/constant.hpp> -#include <mbgl/style/conversion/property_value.hpp> -#include <mbgl/style/conversion/data_driven_property_value.hpp> -#include <mbgl/style/conversion/transition_options.hpp> - -#include <string> - -namespace mbgl { -namespace style { -namespace conversion { - -template <class V> -using PropertySetter = optional<Error> (*) (Layer&, const V&); - -template <class V, class L, class PropertyValue, void (L::*setter)(PropertyValue)> -optional<Error> setProperty(Layer& layer, const V& value) { - auto* typedLayer = layer.as<L>(); - if (!typedLayer) { - return Error { "layer doesn't support this property" }; - } - - Error error; - optional<PropertyValue> typedValue = convert<PropertyValue>(value, error); - if (!typedValue) { - return error; - } - - (typedLayer->*setter)(*typedValue); - return {}; -} - -template <class V, class L, void (L::*setter)(const TransitionOptions&)> -optional<Error> setTransition(Layer& layer, const V& value) { - auto* typedLayer = layer.as<L>(); - if (!typedLayer) { - return Error { "layer doesn't support this property" }; - } - - Error error; - optional<TransitionOptions> transition = convert<TransitionOptions>(value, error); - if (!transition) { - return error; - } - - (typedLayer->*setter)(*transition); - return {}; -} - -template <class V> -optional<Error> setVisibility(Layer& layer, const V& value) { - if (isUndefined(value)) { - layer.setVisibility(VisibilityType::Visible); - return {}; - } - - Error error; - optional<VisibilityType> visibility = convert<VisibilityType>(value, error); - if (!visibility) { - return error; - } - - layer.setVisibility(*visibility); - return {}; -} - -} // namespace conversion -} // namespace style -} // namespace mbgl diff --git a/include/mbgl/style/conversion/property_value.hpp b/include/mbgl/style/conversion/property_value.hpp index f8937da07d..c7f971ec91 100644 --- a/include/mbgl/style/conversion/property_value.hpp +++ b/include/mbgl/style/conversion/property_value.hpp @@ -11,8 +11,7 @@ namespace conversion { template <class T> struct Converter<PropertyValue<T>> { - template <class V> - optional<PropertyValue<T>> operator()(const V& value, Error& error) const { + optional<PropertyValue<T>> operator()(const Convertible& value, Error& error) const { if (isUndefined(value)) { return PropertyValue<T>(); } else if (isObject(value)) { diff --git a/include/mbgl/style/conversion/source.hpp b/include/mbgl/style/conversion/source.hpp index e0563ac10b..2cf2e36da4 100644 --- a/include/mbgl/style/conversion/source.hpp +++ b/include/mbgl/style/conversion/source.hpp @@ -1,16 +1,9 @@ #pragma once #include <mbgl/style/conversion.hpp> -#include <mbgl/style/conversion/coordinate.hpp> -#include <mbgl/style/conversion/geojson.hpp> -#include <mbgl/style/conversion/geojson_options.hpp> -#include <mbgl/style/conversion/tileset.hpp> #include <mbgl/style/source.hpp> -#include <mbgl/style/sources/geojson_source.hpp> -#include <mbgl/style/sources/raster_source.hpp> -#include <mbgl/style/sources/vector_source.hpp> -#include <mbgl/style/sources/image_source.hpp> -#include <mbgl/util/geo.hpp> + +#include <memory> namespace mbgl { namespace style { @@ -19,170 +12,7 @@ namespace conversion { template <> struct Converter<std::unique_ptr<Source>> { public: - - template <class V> - optional<std::unique_ptr<Source>> operator()(const V& value, Error& error, const std::string& id) const { - if (!isObject(value)) { - error = { "source must be an object" }; - return {}; - } - - auto typeValue = objectMember(value, "type"); - if (!typeValue) { - error = { "source must have a type" }; - return {}; - } - - optional<std::string> type = toString(*typeValue); - if (!type) { - error = { "source type must be a string" }; - return {}; - } - - if (*type == "raster") { - return convertRasterSource(id, value, error); - } else if (*type == "vector") { - return convertVectorSource(id, value, error); - } else if (*type == "geojson") { - return convertGeoJSONSource(id, value, error); - } else if (*type == "image") { - return convertImageSource(id, value, error); - } else { - error = { "invalid source type" }; - return {}; - } - } - -private: - // A tile source can either specify a URL to TileJSON, or inline TileJSON. - template <class V> - optional<variant<std::string, Tileset>> convertURLOrTileset(const V& value, Error& error) const { - auto urlVal = objectMember(value, "url"); - if (!urlVal) { - optional<Tileset> tileset = convert<Tileset>(value, error); - if (!tileset) { - return {}; - } - return { *tileset }; - } - - optional<std::string> url = toString(*urlVal); - if (!url) { - error = { "source url must be a string" }; - return {}; - } - - return { *url }; - } - - template <class V> - optional<std::unique_ptr<Source>> convertRasterSource(const std::string& id, - const V& value, - Error& error) const { - optional<variant<std::string, Tileset>> urlOrTileset = convertURLOrTileset(value, error); - if (!urlOrTileset) { - return {}; - } - - uint16_t tileSize = util::tileSize; - auto tileSizeValue = objectMember(value, "tileSize"); - if (tileSizeValue) { - optional<float> size = toNumber(*tileSizeValue); - if (!size || *size < 0 || *size > std::numeric_limits<uint16_t>::max()) { - error = { "invalid tileSize" }; - return {}; - } - tileSize = *size; - } - - return { std::make_unique<RasterSource>(id, std::move(*urlOrTileset), tileSize) }; - } - - template <class V> - optional<std::unique_ptr<Source>> convertVectorSource(const std::string& id, - const V& value, - Error& error) const { - optional<variant<std::string, Tileset>> urlOrTileset = convertURLOrTileset(value, error); - if (!urlOrTileset) { - return {}; - } - - return { std::make_unique<VectorSource>(id, std::move(*urlOrTileset)) }; - } - - template <class V> - optional<std::unique_ptr<Source>> convertGeoJSONSource(const std::string& id, - const V& value, - Error& error) const { - auto dataValue = objectMember(value, "data"); - if (!dataValue) { - error = { "GeoJSON source must have a data value" }; - return {}; - } - - optional<GeoJSONOptions> options = convert<GeoJSONOptions>(value, error); - if (!options) { - return {}; - } - - auto result = std::make_unique<GeoJSONSource>(id, *options); - - if (isObject(*dataValue)) { - optional<GeoJSON> geoJSON = convert<GeoJSON>(*dataValue, error); - if (!geoJSON) { - return {}; - } - result->setGeoJSON(std::move(*geoJSON)); - } else if (toString(*dataValue)) { - result->setURL(*toString(*dataValue)); - } else { - error = { "GeoJSON data must be a URL or an object" }; - return {}; - } - - return { std::move(result) }; - } - - template <class V> - optional<std::unique_ptr<Source>> convertImageSource(const std::string& id, - const V& value, - Error& error) const { - auto urlValue = objectMember(value, "url"); - if (!urlValue) { - error = { "Image source must have a url value" }; - return {}; - } - - auto urlString = toString(*urlValue); - if (!urlString) { - error = { "Image url must be a URL string" }; - return {}; - } - - auto coordinatesValue = objectMember(value, "coordinates"); - if (!coordinatesValue) { - error = { "Image source must have a coordinates values" }; - return {}; - } - - if (!isArray(*coordinatesValue) || arrayLength(*coordinatesValue) != 4) { - error = { "Image coordinates must be an array of four longitude latitude pairs" }; - return {}; - } - - std::array<LatLng, 4> coordinates; - for (std::size_t i=0; i < 4; i++) { - auto latLng = conversion::convert<LatLng>(arrayMember(*coordinatesValue,i), error); - if (!latLng) { - return {}; - } - coordinates[i] = *latLng; - } - auto result = std::make_unique<ImageSource>(id, coordinates); - result->setURL(*urlString); - - return { std::move(result) }; - } + optional<std::unique_ptr<Source>> operator()(const Convertible& value, Error& error, const std::string& id) const; }; } // namespace conversion diff --git a/include/mbgl/style/conversion/tileset.hpp b/include/mbgl/style/conversion/tileset.hpp index 377170aa6a..1fb4acf70d 100644 --- a/include/mbgl/style/conversion/tileset.hpp +++ b/include/mbgl/style/conversion/tileset.hpp @@ -10,70 +10,7 @@ namespace conversion { template <> struct Converter<Tileset> { public: - template <class V> - optional<Tileset> operator()(const V& value, Error& error) const { - Tileset result; - - auto tiles = objectMember(value, "tiles"); - if (!tiles) { - error = { "source must have tiles" }; - return {}; - } - - if (!isArray(*tiles)) { - error = { "source tiles must be an array" }; - return {}; - } - - for (std::size_t i = 0; i < arrayLength(*tiles); i++) { - optional<std::string> urlTemplate = toString(arrayMember(*tiles, i)); - if (!urlTemplate) { - error = { "source tiles member must be a string" }; - return {}; - } - result.tiles.push_back(std::move(*urlTemplate)); - } - - auto schemeValue = objectMember(value, "scheme"); - if (schemeValue) { - optional<std::string> scheme = toString(*schemeValue); - if (scheme && *scheme == "tms") { - result.scheme = Tileset::Scheme::TMS; - } - } - - auto minzoomValue = objectMember(value, "minzoom"); - if (minzoomValue) { - optional<float> minzoom = toNumber(*minzoomValue); - if (!minzoom || *minzoom < 0 || *minzoom > std::numeric_limits<uint8_t>::max()) { - error = { "invalid minzoom" }; - return {}; - } - result.zoomRange.min = *minzoom; - } - - auto maxzoomValue = objectMember(value, "maxzoom"); - if (maxzoomValue) { - optional<float> maxzoom = toNumber(*maxzoomValue); - if (!maxzoom || *maxzoom < 0 || *maxzoom > std::numeric_limits<uint8_t>::max()) { - error = { "invalid maxzoom" }; - return {}; - } - result.zoomRange.max = *maxzoom; - } - - auto attributionValue = objectMember(value, "attribution"); - if (attributionValue) { - optional<std::string> attribution = toString(*attributionValue); - if (!attribution) { - error = { "source attribution must be a string" }; - return {}; - } - result.attribution = std::move(*attribution); - } - - return result; - } + optional<Tileset> operator()(const Convertible& value, Error& error) const; }; } // namespace conversion diff --git a/include/mbgl/style/conversion/transition_options.hpp b/include/mbgl/style/conversion/transition_options.hpp index de8834d578..0563f39ac3 100644 --- a/include/mbgl/style/conversion/transition_options.hpp +++ b/include/mbgl/style/conversion/transition_options.hpp @@ -10,37 +10,7 @@ namespace conversion { template <> struct Converter<TransitionOptions> { public: - template <class V> - optional<TransitionOptions> operator()(const V& value, Error& error) const { - if (!isObject(value)) { - error = { "transition must be an object" }; - return {}; - } - - TransitionOptions result; - - auto duration = objectMember(value, "duration"); - if (duration) { - auto number = toNumber(*duration); - if (!number) { - error = { "duration must be a number" }; - return {}; - } - result.duration = { std::chrono::milliseconds(int64_t(*number)) }; - } - - auto delay = objectMember(value, "delay"); - if (delay) { - auto number = toNumber(*delay); - if (!number) { - error = { "delay must be a number" }; - return {}; - } - result.delay = { std::chrono::milliseconds(int64_t(*number)) }; - } - - return result; - } + optional<TransitionOptions> operator()(const Convertible& value, Error& error) const; }; } // namespace conversion |