summaryrefslogtreecommitdiff
path: root/include/mbgl/style
diff options
context:
space:
mode:
authorJohn Firebaugh <john.firebaugh@gmail.com>2017-09-26 14:14:44 -0700
committerJohn Firebaugh <john.firebaugh@gmail.com>2017-10-23 09:56:43 -0700
commit4b2e1cddb4645fb6d2c5f9634dbeb7c21516cede (patch)
treef11bd97ea5abf17bc6956f254796f1e8cf4a96f9 /include/mbgl/style
parentbb58ddaea8c2d9da9551601318944d9d143ee247 (diff)
downloadqtlocation-mapboxgl-4b2e1cddb4645fb6d2c5f9634dbeb7c21516cede.tar.gz
Replace compile-time polymorphism with runtime polymorphism in the conversion system
Diffstat (limited to 'include/mbgl/style')
-rw-r--r--include/mbgl/style/conversion.hpp254
-rw-r--r--include/mbgl/style/conversion/constant.hpp98
-rw-r--r--include/mbgl/style/conversion/coordinate.hpp21
-rw-r--r--include/mbgl/style/conversion/data_driven_property_value.hpp3
-rw-r--r--include/mbgl/style/conversion/filter.hpp243
-rw-r--r--include/mbgl/style/conversion/function.hpp47
-rw-r--r--include/mbgl/style/conversion/geojson.hpp10
-rw-r--r--include/mbgl/style/conversion/geojson_options.hpp79
-rw-r--r--include/mbgl/style/conversion/layer.hpp210
-rw-r--r--include/mbgl/style/conversion/light.hpp106
-rw-r--r--include/mbgl/style/conversion/make_property_setters.hpp211
-rw-r--r--include/mbgl/style/conversion/make_property_setters.hpp.ejs48
-rw-r--r--include/mbgl/style/conversion/position.hpp14
-rw-r--r--include/mbgl/style/conversion/property_setter.hpp72
-rw-r--r--include/mbgl/style/conversion/property_value.hpp3
-rw-r--r--include/mbgl/style/conversion/source.hpp176
-rw-r--r--include/mbgl/style/conversion/tileset.hpp65
-rw-r--r--include/mbgl/style/conversion/transition_options.hpp32
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