summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKonstantin Käfer <mail@kkaefer.com>2018-08-17 15:38:47 -0700
committerKonstantin Käfer <mail@kkaefer.com>2018-08-17 17:12:17 -0700
commitcc2ab6806c3f58b46da8d252d3f21eda53d185a7 (patch)
tree229af7a6d7610e20edea65d565adbff9c9cd5f06
parentd53c1ee3795496ff4db488aba754bf50419148db (diff)
downloadqtlocation-mapboxgl-upstream/conversion-private.tar.gz
[core] make style/conversion.hpp implementation privateupstream/conversion-private
-rw-r--r--benchmark/function/camera_function.benchmark.cpp2
-rw-r--r--benchmark/function/composite_function.benchmark.cpp2
-rw-r--r--benchmark/function/source_function.benchmark.cpp2
-rw-r--r--benchmark/parse/filter.benchmark.cpp2
-rw-r--r--cmake/core-files.cmake2
-rw-r--r--include/mbgl/style/conversion.hpp290
-rw-r--r--include/mbgl/style/conversion/constant.hpp35
-rw-r--r--include/mbgl/style/conversion/coordinate.hpp1
-rw-r--r--include/mbgl/style/conversion/custom_geometry_source_options.hpp1
-rw-r--r--include/mbgl/style/conversion/filter.hpp1
-rw-r--r--include/mbgl/style/conversion/function.hpp22
-rw-r--r--include/mbgl/style/conversion/geojson.hpp3
-rw-r--r--include/mbgl/style/conversion/geojson_options.hpp3
-rw-r--r--include/mbgl/style/conversion/layer.hpp1
-rw-r--r--include/mbgl/style/conversion/light.hpp1
-rw-r--r--include/mbgl/style/conversion/position.hpp3
-rw-r--r--include/mbgl/style/conversion/property_value.hpp50
-rw-r--r--include/mbgl/style/conversion/source.hpp3
-rw-r--r--include/mbgl/style/conversion/tileset.hpp1
-rw-r--r--include/mbgl/style/conversion/transition_options.hpp1
-rw-r--r--include/mbgl/style/conversion_impl.hpp302
-rw-r--r--include/mbgl/style/expression/assertion.hpp2
-rw-r--r--include/mbgl/style/expression/case.hpp2
-rw-r--r--include/mbgl/style/expression/coalesce.hpp2
-rw-r--r--include/mbgl/style/expression/compound_expression.hpp2
-rw-r--r--include/mbgl/style/expression/parsing_context.hpp1
-rw-r--r--include/mbgl/style/layer.hpp1
-rw-r--r--platform/android/config.cmake7
-rwxr-xr-xplatform/android/src/native_map_view.cpp2
-rw-r--r--platform/android/src/style/android_conversion.hpp2
-rw-r--r--platform/android/src/style/conversion/filter.hpp2
-rw-r--r--platform/android/src/style/conversion/latlngquad.hpp2
-rw-r--r--platform/android/src/style/conversion/url_or_tileset.hpp2
-rw-r--r--platform/android/src/style/layers/layer.cpp2
-rw-r--r--platform/android/src/style/sources/geojson_source.cpp2
-rw-r--r--platform/android/src/style/sources/image_source.cpp2
-rw-r--r--platform/android/src/style/sources/source.cpp2
-rw-r--r--platform/darwin/src/MGLConversion.h2
-rw-r--r--platform/node/src/node_conversion.hpp2
-rw-r--r--platform/node/src/node_expression.hpp2
-rw-r--r--platform/qt/src/qmapboxgl.cpp2
-rw-r--r--platform/qt/src/qt_conversion.hpp2
-rw-r--r--src/mbgl/style/conversion/color_ramp_property_value.cpp2
-rw-r--r--src/mbgl/style/conversion/constant.cpp56
-rw-r--r--src/mbgl/style/conversion/coordinate.cpp1
-rw-r--r--src/mbgl/style/conversion/custom_geometry_source_options.cpp1
-rw-r--r--src/mbgl/style/conversion/filter.cpp3
-rw-r--r--src/mbgl/style/conversion/function.cpp68
-rw-r--r--src/mbgl/style/conversion/geojson.cpp1
-rw-r--r--src/mbgl/style/conversion/geojson_options.cpp1
-rw-r--r--src/mbgl/style/conversion/get_json_type.cpp1
-rw-r--r--src/mbgl/style/conversion/json.hpp2
-rw-r--r--src/mbgl/style/conversion/layer.cpp1
-rw-r--r--src/mbgl/style/conversion/light.cpp1
-rw-r--r--src/mbgl/style/conversion/position.cpp1
-rw-r--r--src/mbgl/style/conversion/property_value.cpp83
-rw-r--r--src/mbgl/style/conversion/source.cpp1
-rw-r--r--src/mbgl/style/conversion/tileset.cpp1
-rw-r--r--src/mbgl/style/conversion/transition_options.cpp1
-rw-r--r--src/mbgl/style/expression/array_assertion.cpp1
-rw-r--r--src/mbgl/style/expression/assertion.cpp1
-rw-r--r--src/mbgl/style/expression/at.cpp1
-rw-r--r--src/mbgl/style/expression/boolean_operator.cpp1
-rw-r--r--src/mbgl/style/expression/case.cpp1
-rw-r--r--src/mbgl/style/expression/coalesce.cpp1
-rw-r--r--src/mbgl/style/expression/coercion.cpp1
-rw-r--r--src/mbgl/style/expression/collator_expression.cpp1
-rw-r--r--src/mbgl/style/expression/comparison.cpp1
-rw-r--r--src/mbgl/style/expression/compound_expression.cpp1
-rw-r--r--src/mbgl/style/expression/interpolate.cpp1
-rw-r--r--src/mbgl/style/expression/is_expression.cpp3
-rw-r--r--src/mbgl/style/expression/length.cpp1
-rw-r--r--src/mbgl/style/expression/let.cpp1
-rw-r--r--src/mbgl/style/expression/literal.cpp1
-rw-r--r--src/mbgl/style/expression/match.cpp1
-rw-r--r--src/mbgl/style/expression/parsing_context.cpp1
-rw-r--r--src/mbgl/style/expression/step.cpp1
-rw-r--r--src/mbgl/style/layer.cpp1
-rw-r--r--src/mbgl/style/layers/background_layer.cpp2
-rw-r--r--src/mbgl/style/layers/circle_layer.cpp2
-rw-r--r--src/mbgl/style/layers/fill_extrusion_layer.cpp2
-rw-r--r--src/mbgl/style/layers/fill_layer.cpp2
-rw-r--r--src/mbgl/style/layers/heatmap_layer.cpp2
-rw-r--r--src/mbgl/style/layers/hillshade_layer.cpp2
-rw-r--r--src/mbgl/style/layers/layer.cpp.ejs2
-rw-r--r--src/mbgl/style/layers/line_layer.cpp2
-rw-r--r--src/mbgl/style/layers/raster_layer.cpp2
-rw-r--r--src/mbgl/style/layers/symbol_layer.cpp2
-rw-r--r--src/mbgl/style/parser.cpp2
-rw-r--r--src/mbgl/style/rapidjson_conversion.hpp2
-rw-r--r--test/style/conversion/light.test.cpp2
-rw-r--r--test/style/expression/expression.test.cpp2
92 files changed, 616 insertions, 431 deletions
diff --git a/benchmark/function/camera_function.benchmark.cpp b/benchmark/function/camera_function.benchmark.cpp
index 51d2e22293..0ce7d7c763 100644
--- a/benchmark/function/camera_function.benchmark.cpp
+++ b/benchmark/function/camera_function.benchmark.cpp
@@ -1,9 +1,9 @@
#include <benchmark/benchmark.h>
-#include <mbgl/style/conversion.hpp>
#include <mbgl/style/conversion/json.hpp>
#include <mbgl/style/conversion/function.hpp>
#include <mbgl/style/conversion/property_value.hpp>
+#include <mbgl/style/conversion_impl.hpp>
using namespace mbgl;
using namespace mbgl::style;
diff --git a/benchmark/function/composite_function.benchmark.cpp b/benchmark/function/composite_function.benchmark.cpp
index f16254641f..8064d548fa 100644
--- a/benchmark/function/composite_function.benchmark.cpp
+++ b/benchmark/function/composite_function.benchmark.cpp
@@ -2,10 +2,10 @@
#include <mbgl/benchmark/stub_geometry_tile_feature.hpp>
-#include <mbgl/style/conversion.hpp>
#include <mbgl/style/conversion/json.hpp>
#include <mbgl/style/conversion/function.hpp>
#include <mbgl/style/conversion/property_value.hpp>
+#include <mbgl/style/conversion_impl.hpp>
using namespace mbgl;
using namespace mbgl::style;
diff --git a/benchmark/function/source_function.benchmark.cpp b/benchmark/function/source_function.benchmark.cpp
index 2164b2a418..b75cc143d2 100644
--- a/benchmark/function/source_function.benchmark.cpp
+++ b/benchmark/function/source_function.benchmark.cpp
@@ -2,9 +2,9 @@
#include <mbgl/benchmark/stub_geometry_tile_feature.hpp>
-#include <mbgl/style/conversion.hpp>
#include <mbgl/style/conversion/json.hpp>
#include <mbgl/style/conversion/property_value.hpp>
+#include <mbgl/style/conversion_impl.hpp>
using namespace mbgl;
using namespace mbgl::style;
diff --git a/benchmark/parse/filter.benchmark.cpp b/benchmark/parse/filter.benchmark.cpp
index 4e39237138..1ae2b0f2bc 100644
--- a/benchmark/parse/filter.benchmark.cpp
+++ b/benchmark/parse/filter.benchmark.cpp
@@ -1,9 +1,9 @@
#include <benchmark/benchmark.h>
#include <mbgl/style/filter.hpp>
-#include <mbgl/style/conversion.hpp>
#include <mbgl/style/conversion/json.hpp>
#include <mbgl/style/conversion/filter.hpp>
+#include <mbgl/style/conversion_impl.hpp>
#include <mbgl/tile/geometry_tile_data.hpp>
#include <mbgl/benchmark/stub_geometry_tile_feature.hpp>
diff --git a/cmake/core-files.cmake b/cmake/core-files.cmake
index 02335fef7a..2d0bd003c7 100644
--- a/cmake/core-files.cmake
+++ b/cmake/core-files.cmake
@@ -363,6 +363,7 @@ set(MBGL_CORE_FILES
# style
include/mbgl/style/color_ramp_property_value.hpp
include/mbgl/style/conversion.hpp
+ include/mbgl/style/conversion_impl.hpp
include/mbgl/style/filter.hpp
include/mbgl/style/image.hpp
include/mbgl/style/layer.hpp
@@ -437,6 +438,7 @@ set(MBGL_CORE_FILES
src/mbgl/style/conversion/layer.cpp
src/mbgl/style/conversion/light.cpp
src/mbgl/style/conversion/position.cpp
+ src/mbgl/style/conversion/property_value.cpp
src/mbgl/style/conversion/source.cpp
src/mbgl/style/conversion/stringify.hpp
src/mbgl/style/conversion/tileset.cpp
diff --git a/include/mbgl/style/conversion.hpp b/include/mbgl/style/conversion.hpp
index 71c2cec237..2c83d1561b 100644
--- a/include/mbgl/style/conversion.hpp
+++ b/include/mbgl/style/conversion.hpp
@@ -1,306 +1,26 @@
#pragma once
-#include <mbgl/util/optional.hpp>
-#include <mbgl/util/feature.hpp>
-#include <mbgl/util/geojson.hpp>
-
#include <string>
namespace mbgl {
namespace style {
namespace conversion {
-/*
- 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>`
- * `Filter`
- * `PropertyValue<T>`
-
- A single template function serves as the public interface:
-
- 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.
-
- `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
-
- * `isArray(v)` -- returns a boolean indicating whether `v` represents a JSON array
- * `arrayLength(v)` -- called only if `isArray(v)`; returns a size_t length
- * `arrayMember(v)` -- called only if `isArray(v)`; returns `V` or `V&`
-
- * `isObject(v)` -- returns a boolean indicating whether `v` represents a JSON object
- * `objectMember(v, name)` -- called only if `isObject(v)`; `name` is `const char *`; return value:
- * is true when evaluated in a boolean context iff the named member exists
- * is convertable to a `V` or `V&` when dereferenced
- * `eachMember(v, [] (const std::string&, const V&) -> optional<Error> {...})` -- called
- only if `isObject(v)`; calls the provided lambda once for each key and value of the object;
- short-circuits if any call returns an `Error`
-
- * `toBool(v)` -- returns `optional<bool>`, absence indicating `v` is not a JSON boolean
- * `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<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.
-
- 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.
-*/
+// This is a forward-declaration only header intended to minimize dependencies and to improve
+// compilation speed. In order to specialize implementations and get access to the actual
+// implementation, include <mbgl/style/conversion_impl.hpp>.
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&);
- };
-
- // Extracted this function from the table below to work around a GCC bug with differing
- // visibility settings for capturing lambdas: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=80947
- template <typename T>
- static auto vtableEachMember(const Storage& s, const std::function<optional<Error>(const std::string&, const Convertible&)>& fn) {
- return ConversionTraits<T>::eachMember(reinterpret_cast<const T&>(s), [&](const std::string& k, T&& v) {
- return fn(k, Convertible(std::move(v)));
- });
- }
-
- 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>();
- }
- },
- vtableEachMember<T>,
- [] (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;
-};
+class Convertible;
template <class T, class Enable = void>
struct Converter;
-template <class T, class...Args>
-optional<T> convert(const Convertible& value, Error& error, Args&&...args) {
- return Converter<T>()(value, error, std::forward<Args>(args)...);
-}
-
} // namespace conversion
} // namespace style
} // namespace mbgl
+
diff --git a/include/mbgl/style/conversion/constant.hpp b/include/mbgl/style/conversion/constant.hpp
index 7d74ec42ce..40657528c4 100644
--- a/include/mbgl/style/conversion/constant.hpp
+++ b/include/mbgl/style/conversion/constant.hpp
@@ -1,6 +1,7 @@
#pragma once
#include <mbgl/style/conversion.hpp>
+#include <mbgl/style/types.hpp>
#include <mbgl/util/color.hpp>
#include <mbgl/util/enum.hpp>
#include <mbgl/util/string.hpp>
@@ -30,21 +31,7 @@ struct Converter<std::string> {
template <class T>
struct Converter<T, typename std::enable_if_t<std::is_enum<T>::value>> {
- optional<T> operator()(const Convertible& value, Error& error) const {
- optional<std::string> string = toString(value);
- if (!string) {
- error.message = "value must be a string";
- return nullopt;
- }
-
- const auto result = Enum<T>::toEnum(*string);
- if (!result) {
- error.message = "value must be a valid enumeration value";
- return nullopt;
- }
-
- return *result;
- }
+ optional<T> operator()(const Convertible& value, Error& error) const;
};
template <>
@@ -54,23 +41,7 @@ struct Converter<Color> {
template <size_t N>
struct Converter<std::array<float, N>> {
- optional<std::array<float, N>> operator()(const Convertible& value, Error& error) const {
- if (!isArray(value) || arrayLength(value) != N) {
- error.message = "value must be an array of " + util::toString(N) + " numbers";
- return nullopt;
- }
-
- std::array<float, N> result;
- for (size_t i = 0; i < N; i++) {
- optional<float> n = toNumber(arrayMember(value, i));
- if (!n) {
- error.message = "value must be an array of " + util::toString(N) + " numbers";
- return nullopt;
- }
- result[i] = *n;
- }
- return result;
- }
+ optional<std::array<float, N>> operator()(const Convertible& value, Error& error) const;
};
template <>
diff --git a/include/mbgl/style/conversion/coordinate.hpp b/include/mbgl/style/conversion/coordinate.hpp
index e11db5e32f..1346ed738a 100644
--- a/include/mbgl/style/conversion/coordinate.hpp
+++ b/include/mbgl/style/conversion/coordinate.hpp
@@ -2,6 +2,7 @@
#include <mbgl/style/conversion.hpp>
#include <mbgl/util/geo.hpp>
+#include <mbgl/util/optional.hpp>
namespace mbgl {
namespace style {
diff --git a/include/mbgl/style/conversion/custom_geometry_source_options.hpp b/include/mbgl/style/conversion/custom_geometry_source_options.hpp
index f0f505e54f..090e5b6239 100644
--- a/include/mbgl/style/conversion/custom_geometry_source_options.hpp
+++ b/include/mbgl/style/conversion/custom_geometry_source_options.hpp
@@ -2,6 +2,7 @@
#include <mbgl/style/conversion.hpp>
#include <mbgl/style/sources/custom_geometry_source.hpp>
+#include <mbgl/util/optional.hpp>
namespace mbgl {
namespace style {
diff --git a/include/mbgl/style/conversion/filter.hpp b/include/mbgl/style/conversion/filter.hpp
index 9daf6ea7a4..2d7ad0afc7 100644
--- a/include/mbgl/style/conversion/filter.hpp
+++ b/include/mbgl/style/conversion/filter.hpp
@@ -2,6 +2,7 @@
#include <mbgl/style/filter.hpp>
#include <mbgl/style/conversion.hpp>
+#include <mbgl/util/optional.hpp>
namespace mbgl {
namespace style {
diff --git a/include/mbgl/style/conversion/function.hpp b/include/mbgl/style/conversion/function.hpp
index 49825a3410..ba9acd7a3b 100644
--- a/include/mbgl/style/conversion/function.hpp
+++ b/include/mbgl/style/conversion/function.hpp
@@ -1,8 +1,8 @@
#pragma once
#include <mbgl/style/property_expression.hpp>
-#include <mbgl/style/conversion.hpp>
#include <mbgl/style/conversion/constant.hpp>
+#include <mbgl/style/conversion.hpp>
#include <mbgl/style/expression/expression.hpp>
#include <mbgl/style/expression/value.hpp>
@@ -16,25 +16,7 @@ std::unique_ptr<expression::Expression> convertTokenStringToExpression(const std
optional<std::unique_ptr<expression::Expression>> convertFunctionToExpression(expression::type::Type, const Convertible&, Error&, bool convertTokens);
template <class T>
-optional<PropertyExpression<T>> convertFunctionToExpression(const Convertible& value, Error& error, bool convertTokens) {
- auto expression = convertFunctionToExpression(expression::valueTypeToExpressionType<T>(), value, error, convertTokens);
- if (!expression) {
- return nullopt;
- }
-
- optional<T> defaultValue;
-
- auto defaultValueValue = objectMember(value, "default");
- if (defaultValueValue) {
- defaultValue = convert<T>(*defaultValueValue, error);
- if (!defaultValue) {
- error.message = R"(wrong type for "default": )" + error.message;
- return nullopt;
- }
- }
-
- return PropertyExpression<T>(std::move(*expression), defaultValue);
-}
+optional<PropertyExpression<T>> convertFunctionToExpression(const Convertible& value, Error& error, bool convertTokens);
} // namespace conversion
} // namespace style
diff --git a/include/mbgl/style/conversion/geojson.hpp b/include/mbgl/style/conversion/geojson.hpp
index 403c5f953b..90c1d64197 100644
--- a/include/mbgl/style/conversion/geojson.hpp
+++ b/include/mbgl/style/conversion/geojson.hpp
@@ -1,7 +1,8 @@
#pragma once
-#include <mbgl/style/conversion.hpp>
#include <mbgl/util/geojson.hpp>
+#include <mbgl/style/conversion.hpp>
+#include <mbgl/util/optional.hpp>
namespace mbgl {
namespace style {
diff --git a/include/mbgl/style/conversion/geojson_options.hpp b/include/mbgl/style/conversion/geojson_options.hpp
index 3f625babb6..89511848dd 100644
--- a/include/mbgl/style/conversion/geojson_options.hpp
+++ b/include/mbgl/style/conversion/geojson_options.hpp
@@ -1,7 +1,8 @@
#pragma once
-#include <mbgl/style/conversion.hpp>
#include <mbgl/style/sources/geojson_source.hpp>
+#include <mbgl/style/conversion.hpp>
+#include <mbgl/util/optional.hpp>
namespace mbgl {
namespace style {
diff --git a/include/mbgl/style/conversion/layer.hpp b/include/mbgl/style/conversion/layer.hpp
index 2df6c9e381..9cf019378b 100644
--- a/include/mbgl/style/conversion/layer.hpp
+++ b/include/mbgl/style/conversion/layer.hpp
@@ -2,6 +2,7 @@
#include <mbgl/style/layer.hpp>
#include <mbgl/style/conversion.hpp>
+#include <mbgl/util/optional.hpp>
#include <memory>
diff --git a/include/mbgl/style/conversion/light.hpp b/include/mbgl/style/conversion/light.hpp
index 289fca2e31..2f6f8628b8 100644
--- a/include/mbgl/style/conversion/light.hpp
+++ b/include/mbgl/style/conversion/light.hpp
@@ -2,6 +2,7 @@
#include <mbgl/style/light.hpp>
#include <mbgl/style/conversion.hpp>
+#include <mbgl/util/optional.hpp>
namespace mbgl {
namespace style {
diff --git a/include/mbgl/style/conversion/position.hpp b/include/mbgl/style/conversion/position.hpp
index 044c45862d..10db5c6ec1 100644
--- a/include/mbgl/style/conversion/position.hpp
+++ b/include/mbgl/style/conversion/position.hpp
@@ -1,7 +1,8 @@
#pragma once
-#include <mbgl/style/conversion.hpp>
#include <mbgl/style/position.hpp>
+#include <mbgl/style/conversion.hpp>
+#include <mbgl/util/optional.hpp>
namespace mbgl {
namespace style {
diff --git a/include/mbgl/style/conversion/property_value.hpp b/include/mbgl/style/conversion/property_value.hpp
index fa6752867b..f6f36db983 100644
--- a/include/mbgl/style/conversion/property_value.hpp
+++ b/include/mbgl/style/conversion/property_value.hpp
@@ -1,9 +1,9 @@
#pragma once
#include <mbgl/style/property_value.hpp>
-#include <mbgl/style/conversion.hpp>
#include <mbgl/style/conversion/constant.hpp>
#include <mbgl/style/conversion/function.hpp>
+#include <mbgl/style/conversion.hpp>
#include <mbgl/style/expression/value.hpp>
#include <mbgl/style/expression/is_constant.hpp>
#include <mbgl/style/expression/is_expression.hpp>
@@ -16,53 +16,7 @@ namespace conversion {
template <class T>
struct Converter<PropertyValue<T>> {
- optional<PropertyValue<T>> operator()(const Convertible& value, Error& error, bool allowDataExpressions, bool convertTokens) const {
- using namespace mbgl::style::expression;
-
- if (isUndefined(value)) {
- return PropertyValue<T>();
- }
-
- optional<PropertyExpression<T>> expression;
-
- if (isExpression(value)) {
- ParsingContext ctx(valueTypeToExpressionType<T>());
- ParseResult parsed = ctx.parseLayerPropertyExpression(value);
- if (!parsed) {
- error.message = ctx.getCombinedErrors();
- return nullopt;
- }
- expression = PropertyExpression<T>(std::move(*parsed));
- } else if (isObject(value)) {
- expression = convertFunctionToExpression<T>(value, error, convertTokens);
- } else {
- optional<T> constant = convert<T>(value, error);
- if (!constant) {
- return nullopt;
- }
- return convertTokens ? maybeConvertTokens(*constant) : PropertyValue<T>(*constant);
- }
-
- if (!expression) {
- return nullopt;
- } else if (!allowDataExpressions && !(*expression).isFeatureConstant()) {
- error.message = "data expressions not supported";
- return nullopt;
- } else if (!(*expression).isFeatureConstant() || !(*expression).isZoomConstant()) {
- return { std::move(*expression) };
- } else if ((*expression).getExpression().getKind() == Kind::Literal) {
- optional<T> constant = fromExpressionValue<T>(
- static_cast<const Literal&>((*expression).getExpression()).getValue());
- if (!constant) {
- return nullopt;
- }
- return PropertyValue<T>(*constant);
- } else {
- assert(false);
- error.message = "expected a literal expression";
- return nullopt;
- }
- }
+ optional<PropertyValue<T>> operator()(const Convertible& value, Error& error, bool allowDataExpressions, bool convertTokens) const;
template <class S>
PropertyValue<T> maybeConvertTokens(const S& t) const {
diff --git a/include/mbgl/style/conversion/source.hpp b/include/mbgl/style/conversion/source.hpp
index 2cf2e36da4..19bc1ce6b6 100644
--- a/include/mbgl/style/conversion/source.hpp
+++ b/include/mbgl/style/conversion/source.hpp
@@ -1,7 +1,8 @@
#pragma once
-#include <mbgl/style/conversion.hpp>
#include <mbgl/style/source.hpp>
+#include <mbgl/style/conversion.hpp>
+#include <mbgl/util/optional.hpp>
#include <memory>
diff --git a/include/mbgl/style/conversion/tileset.hpp b/include/mbgl/style/conversion/tileset.hpp
index 1fb4acf70d..88661c358c 100644
--- a/include/mbgl/style/conversion/tileset.hpp
+++ b/include/mbgl/style/conversion/tileset.hpp
@@ -2,6 +2,7 @@
#include <mbgl/util/tileset.hpp>
#include <mbgl/style/conversion.hpp>
+#include <mbgl/util/optional.hpp>
namespace mbgl {
namespace style {
diff --git a/include/mbgl/style/conversion/transition_options.hpp b/include/mbgl/style/conversion/transition_options.hpp
index 0563f39ac3..a72d757d3c 100644
--- a/include/mbgl/style/conversion/transition_options.hpp
+++ b/include/mbgl/style/conversion/transition_options.hpp
@@ -2,6 +2,7 @@
#include <mbgl/style/transition_options.hpp>
#include <mbgl/style/conversion.hpp>
+#include <mbgl/util/optional.hpp>
namespace mbgl {
namespace style {
diff --git a/include/mbgl/style/conversion_impl.hpp b/include/mbgl/style/conversion_impl.hpp
new file mode 100644
index 0000000000..27b2ee1917
--- /dev/null
+++ b/include/mbgl/style/conversion_impl.hpp
@@ -0,0 +1,302 @@
+#pragma once
+
+#include <mbgl/style/conversion.hpp>
+#include <mbgl/util/optional.hpp>
+#include <mbgl/util/feature.hpp>
+#include <mbgl/util/geojson.hpp>
+
+#include <string>
+
+namespace mbgl {
+namespace style {
+namespace conversion {
+
+/*
+ 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>`
+ * `Filter`
+ * `PropertyValue<T>`
+
+ A single template function serves as the public interface:
+
+ 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.
+
+ `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
+
+ * `isArray(v)` -- returns a boolean indicating whether `v` represents a JSON array
+ * `arrayLength(v)` -- called only if `isArray(v)`; returns a size_t length
+ * `arrayMember(v)` -- called only if `isArray(v)`; returns `V` or `V&`
+
+ * `isObject(v)` -- returns a boolean indicating whether `v` represents a JSON object
+ * `objectMember(v, name)` -- called only if `isObject(v)`; `name` is `const char *`; return value:
+ * is true when evaluated in a boolean context iff the named member exists
+ * is convertable to a `V` or `V&` when dereferenced
+ * `eachMember(v, [] (const std::string&, const V&) -> optional<Error> {...})` -- called
+ only if `isObject(v)`; calls the provided lambda once for each key and value of the object;
+ short-circuits if any call returns an `Error`
+
+ * `toBool(v)` -- returns `optional<bool>`, absence indicating `v` is not a JSON boolean
+ * `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<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.
+
+ 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.
+*/
+
+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&);
+ };
+
+ // Extracted this function from the table below to work around a GCC bug with differing
+ // visibility settings for capturing lambdas: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=80947
+ template <typename T>
+ static auto vtableEachMember(const Storage& s, const std::function<optional<Error>(const std::string&, const Convertible&)>& fn) {
+ return ConversionTraits<T>::eachMember(reinterpret_cast<const T&>(s), [&](const std::string& k, T&& v) {
+ return fn(k, Convertible(std::move(v)));
+ });
+ }
+
+ 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>();
+ }
+ },
+ vtableEachMember<T>,
+ [] (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...Args>
+optional<T> convert(const Convertible& value, Error& error, Args&&...args) {
+ return Converter<T>()(value, error, std::forward<Args>(args)...);
+}
+
+} // namespace conversion
+} // namespace style
+} // namespace mbgl
diff --git a/include/mbgl/style/expression/assertion.hpp b/include/mbgl/style/expression/assertion.hpp
index 90da16b068..239cdf2ea6 100644
--- a/include/mbgl/style/expression/assertion.hpp
+++ b/include/mbgl/style/expression/assertion.hpp
@@ -1,8 +1,8 @@
#pragma once
#include <mbgl/style/expression/expression.hpp>
-#include <mbgl/style/conversion.hpp>
#include <mbgl/style/expression/parsing_context.hpp>
+#include <mbgl/style/conversion.hpp>
#include <memory>
#include <vector>
diff --git a/include/mbgl/style/expression/case.hpp b/include/mbgl/style/expression/case.hpp
index 02dc3bc4c2..7cd007d3c7 100644
--- a/include/mbgl/style/expression/case.hpp
+++ b/include/mbgl/style/expression/case.hpp
@@ -1,8 +1,8 @@
#pragma once
#include <mbgl/style/expression/expression.hpp>
-#include <mbgl/style/conversion.hpp>
#include <mbgl/style/expression/parsing_context.hpp>
+#include <mbgl/style/conversion.hpp>
#include <memory>
#include <vector>
diff --git a/include/mbgl/style/expression/coalesce.hpp b/include/mbgl/style/expression/coalesce.hpp
index cd60cee02e..c4216f234f 100644
--- a/include/mbgl/style/expression/coalesce.hpp
+++ b/include/mbgl/style/expression/coalesce.hpp
@@ -1,8 +1,8 @@
#pragma once
#include <mbgl/style/expression/expression.hpp>
-#include <mbgl/style/conversion.hpp>
#include <mbgl/style/expression/parsing_context.hpp>
+#include <mbgl/style/conversion.hpp>
#include <memory>
#include <map>
diff --git a/include/mbgl/style/expression/compound_expression.hpp b/include/mbgl/style/expression/compound_expression.hpp
index ef10dadb55..b54720a258 100644
--- a/include/mbgl/style/expression/compound_expression.hpp
+++ b/include/mbgl/style/expression/compound_expression.hpp
@@ -1,10 +1,10 @@
#pragma once
#include <mbgl/style/expression/expression.hpp>
-#include <mbgl/style/conversion.hpp>
#include <mbgl/style/expression/parsing_context.hpp>
#include <mbgl/style/expression/type.hpp>
#include <mbgl/style/expression/value.hpp>
+#include <mbgl/style/conversion.hpp>
#include <mbgl/util/optional.hpp>
#include <memory>
diff --git a/include/mbgl/style/expression/parsing_context.hpp b/include/mbgl/style/expression/parsing_context.hpp
index c19974a4f7..66014e33d4 100644
--- a/include/mbgl/style/expression/parsing_context.hpp
+++ b/include/mbgl/style/expression/parsing_context.hpp
@@ -7,6 +7,7 @@
#include <iterator>
#include <map>
+#include <unordered_map>
#include <string>
#include <vector>
#include <memory>
diff --git a/include/mbgl/style/layer.hpp b/include/mbgl/style/layer.hpp
index e0f71d2689..3b7969ea79 100644
--- a/include/mbgl/style/layer.hpp
+++ b/include/mbgl/style/layer.hpp
@@ -3,6 +3,7 @@
#include <mbgl/util/noncopyable.hpp>
#include <mbgl/util/peer.hpp>
#include <mbgl/util/immutable.hpp>
+#include <mbgl/util/optional.hpp>
#include <mbgl/style/layer_type.hpp>
#include <mbgl/style/types.hpp>
#include <mbgl/style/conversion.hpp>
diff --git a/platform/android/config.cmake b/platform/android/config.cmake
index e76a447c88..be9d95ef0a 100644
--- a/platform/android/config.cmake
+++ b/platform/android/config.cmake
@@ -345,6 +345,11 @@ add_library(example-custom-layer SHARED
platform/android/src/example_custom_layer.cpp
)
+target_include_directories(example-custom-layer
+ PRIVATE include
+)
+
target_link_libraries(example-custom-layer
- PRIVATE mbgl-core
+ PRIVATE -llog
+ PRIVATE -lGLESv2
)
diff --git a/platform/android/src/native_map_view.cpp b/platform/android/src/native_map_view.cpp
index 8da44c10cb..8c76332b39 100755
--- a/platform/android/src/native_map_view.cpp
+++ b/platform/android/src/native_map_view.cpp
@@ -30,8 +30,8 @@
// Java -> C++ conversion
#include "style/android_conversion.hpp"
-#include <mbgl/style/conversion.hpp>
#include <mbgl/style/conversion/filter.hpp>
+#include <mbgl/style/conversion_impl.hpp>
// C++ -> Java conversion
#include "conversion/conversion.hpp"
diff --git a/platform/android/src/style/android_conversion.hpp b/platform/android/src/style/android_conversion.hpp
index 510a9f8444..8559720b2f 100644
--- a/platform/android/src/style/android_conversion.hpp
+++ b/platform/android/src/style/android_conversion.hpp
@@ -5,8 +5,8 @@
#include <mbgl/util/feature.hpp>
#include <mbgl/util/logging.hpp>
#include <mbgl/util/optional.hpp>
-#include <mbgl/style/conversion.hpp>
#include <mbgl/style/conversion/geojson.hpp>
+#include <mbgl/style/conversion_impl.hpp>
#include <jni/jni.hpp>
diff --git a/platform/android/src/style/conversion/filter.hpp b/platform/android/src/style/conversion/filter.hpp
index c154e88e7c..241c98713a 100644
--- a/platform/android/src/style/conversion/filter.hpp
+++ b/platform/android/src/style/conversion/filter.hpp
@@ -1,8 +1,8 @@
#pragma once
#include "../android_conversion.hpp"
-#include <mbgl/style/conversion.hpp>
#include <mbgl/style/conversion/filter.hpp>
+#include <mbgl/style/conversion_impl.hpp>
#include <jni/jni.hpp>
diff --git a/platform/android/src/style/conversion/latlngquad.hpp b/platform/android/src/style/conversion/latlngquad.hpp
index 9d1a83e164..9588336855 100644
--- a/platform/android/src/style/conversion/latlngquad.hpp
+++ b/platform/android/src/style/conversion/latlngquad.hpp
@@ -1,8 +1,8 @@
#pragma once
#include <mapbox/geojson.hpp>
-#include <mbgl/style/conversion.hpp>
#include <mbgl/style/conversion/geojson.hpp>
+#include <mbgl/style/conversion_impl.hpp>
#include <jni/jni.hpp>
namespace mbgl {
diff --git a/platform/android/src/style/conversion/url_or_tileset.hpp b/platform/android/src/style/conversion/url_or_tileset.hpp
index 92c1182a63..d6bf86639c 100644
--- a/platform/android/src/style/conversion/url_or_tileset.hpp
+++ b/platform/android/src/style/conversion/url_or_tileset.hpp
@@ -4,8 +4,8 @@
#include <mbgl/util/variant.hpp>
#include <mbgl/util/tileset.hpp>
-#include <mbgl/style/conversion.hpp>
#include <mbgl/style/conversion/tileset.hpp>
+#include <mbgl/style/conversion_impl.hpp>
#include <jni/jni.hpp>
diff --git a/platform/android/src/style/layers/layer.cpp b/platform/android/src/style/layers/layer.cpp
index c3ae9e40cd..6c08893411 100644
--- a/platform/android/src/style/layers/layer.cpp
+++ b/platform/android/src/style/layers/layer.cpp
@@ -18,10 +18,10 @@
#include <mbgl/util/logging.hpp>
// Java -> C++ conversion
-#include <mbgl/style/conversion.hpp>
#include <mbgl/style/conversion/filter.hpp>
#include <mbgl/style/conversion/layer.hpp>
#include <mbgl/style/conversion/source.hpp>
+#include <mbgl/style/conversion_impl.hpp>
// C++ -> Java conversion
#include "../conversion/property_value.hpp"
diff --git a/platform/android/src/style/sources/geojson_source.cpp b/platform/android/src/style/sources/geojson_source.cpp
index 6d9ab9e22c..14067503f1 100644
--- a/platform/android/src/style/sources/geojson_source.cpp
+++ b/platform/android/src/style/sources/geojson_source.cpp
@@ -5,9 +5,9 @@
// Java -> C++ conversion
#include "../android_conversion.hpp"
#include "../conversion/filter.hpp"
-#include <mbgl/style/conversion.hpp>
#include <mbgl/style/conversion/geojson.hpp>
#include <mbgl/style/conversion/geojson_options.hpp>
+#include <mbgl/style/conversion_impl.hpp>
// C++ -> Java conversion
#include "../../conversion/conversion.hpp"
diff --git a/platform/android/src/style/sources/image_source.cpp b/platform/android/src/style/sources/image_source.cpp
index 249387ea51..278564485d 100644
--- a/platform/android/src/style/sources/image_source.cpp
+++ b/platform/android/src/style/sources/image_source.cpp
@@ -5,7 +5,7 @@
// C++ -> Java conversion
#include "../../conversion/conversion.hpp"
-#include <mbgl/style/conversion.hpp>
+#include <mbgl/style/conversion_impl.hpp>
#include <mbgl/util/premultiply.hpp>
#include "../../bitmap.hpp"
diff --git a/platform/android/src/style/sources/source.cpp b/platform/android/src/style/sources/source.cpp
index 8f14ebc43e..d2e2426c0b 100644
--- a/platform/android/src/style/sources/source.cpp
+++ b/platform/android/src/style/sources/source.cpp
@@ -7,8 +7,8 @@
#include <mbgl/util/logging.hpp>
// Java -> C++ conversion
-#include <mbgl/style/conversion.hpp>
#include <mbgl/style/conversion/source.hpp>
+#include <mbgl/style/conversion_impl.hpp>
// C++ -> Java conversion
#include "../conversion/property_value.hpp"
diff --git a/platform/darwin/src/MGLConversion.h b/platform/darwin/src/MGLConversion.h
index 92a6720e6a..9057ed7824 100644
--- a/platform/darwin/src/MGLConversion.h
+++ b/platform/darwin/src/MGLConversion.h
@@ -1,4 +1,4 @@
-#include <mbgl/style/conversion.hpp>
+#include <mbgl/style/conversion_impl.hpp>
NS_ASSUME_NONNULL_BEGIN
diff --git a/platform/node/src/node_conversion.hpp b/platform/node/src/node_conversion.hpp
index 7c5bbf4386..ea6652c5e2 100644
--- a/platform/node/src/node_conversion.hpp
+++ b/platform/node/src/node_conversion.hpp
@@ -8,8 +8,8 @@
#include <mbgl/util/optional.hpp>
#include <mbgl/util/feature.hpp>
-#include <mbgl/style/conversion.hpp>
#include <mbgl/style/conversion/geojson.hpp>
+#include <mbgl/style/conversion_impl.hpp>
namespace mbgl {
namespace style {
diff --git a/platform/node/src/node_expression.hpp b/platform/node/src/node_expression.hpp
index 05af217bde..a53f8c18db 100644
--- a/platform/node/src/node_expression.hpp
+++ b/platform/node/src/node_expression.hpp
@@ -1,6 +1,6 @@
#pragma once
-#include <mbgl/style/conversion.hpp>
+#include <mbgl/style/conversion_impl.hpp>
#include <mbgl/style/expression/expression.hpp>
#include <exception>
#include <memory>
diff --git a/platform/qt/src/qmapboxgl.cpp b/platform/qt/src/qmapboxgl.cpp
index 480174810c..d584012830 100644
--- a/platform/qt/src/qmapboxgl.cpp
+++ b/platform/qt/src/qmapboxgl.cpp
@@ -13,11 +13,11 @@
#include <mbgl/math/log2.hpp>
#include <mbgl/math/minmax.hpp>
#include <mbgl/style/style.hpp>
-#include <mbgl/style/conversion.hpp>
#include <mbgl/style/conversion/layer.hpp>
#include <mbgl/style/conversion/source.hpp>
#include <mbgl/style/conversion/filter.hpp>
#include <mbgl/style/conversion/geojson.hpp>
+#include <mbgl/style/conversion_impl.hpp>
#include <mbgl/style/filter.hpp>
#include <mbgl/style/layers/custom_layer.hpp>
#include <mbgl/style/layers/background_layer.hpp>
diff --git a/platform/qt/src/qt_conversion.hpp b/platform/qt/src/qt_conversion.hpp
index 19b0cb54fc..99a262be54 100644
--- a/platform/qt/src/qt_conversion.hpp
+++ b/platform/qt/src/qt_conversion.hpp
@@ -1,7 +1,7 @@
#pragma once
-#include <mbgl/style/conversion.hpp>
#include <mbgl/style/conversion/geojson.hpp>
+#include <mbgl/style/conversion_impl.hpp>
#include <mbgl/util/optional.hpp>
#include <QVariant>
diff --git a/src/mbgl/style/conversion/color_ramp_property_value.cpp b/src/mbgl/style/conversion/color_ramp_property_value.cpp
index f29438b6a2..0da16c67ee 100644
--- a/src/mbgl/style/conversion/color_ramp_property_value.cpp
+++ b/src/mbgl/style/conversion/color_ramp_property_value.cpp
@@ -1,6 +1,6 @@
#include <mbgl/style/conversion/color_ramp_property_value.hpp>
-#include <mbgl/style/conversion.hpp>
#include <mbgl/style/conversion/constant.hpp>
+#include <mbgl/style/conversion_impl.hpp>
#include <mbgl/style/expression/value.hpp>
#include <mbgl/style/expression/is_constant.hpp>
#include <mbgl/style/expression/is_expression.hpp>
diff --git a/src/mbgl/style/conversion/constant.cpp b/src/mbgl/style/conversion/constant.cpp
index d432b5f051..de4ab22269 100644
--- a/src/mbgl/style/conversion/constant.cpp
+++ b/src/mbgl/style/conversion/constant.cpp
@@ -1,4 +1,5 @@
#include <mbgl/style/conversion/constant.hpp>
+#include <mbgl/style/conversion_impl.hpp>
namespace mbgl {
namespace style {
@@ -31,6 +32,38 @@ optional<std::string> Converter<std::string>::operator()(const Convertible& valu
return *converted;
}
+template <class T>
+optional<T> Converter<T, typename std::enable_if_t<std::is_enum<T>::value>>::operator()(const Convertible& value, Error& error) const {
+ optional<std::string> string = toString(value);
+ if (!string) {
+ error.message = "value must be a string";
+ return nullopt;
+ }
+
+ const auto result = Enum<T>::toEnum(*string);
+ if (!result) {
+ error.message = "value must be a valid enumeration value";
+ return nullopt;
+ }
+
+ return *result;
+}
+
+template optional<AlignmentType> Converter<AlignmentType>::operator()(const Convertible&, Error&) const;
+template optional<CirclePitchScaleType> Converter<CirclePitchScaleType>::operator()(const Convertible&, Error&) const;
+template optional<HillshadeIlluminationAnchorType> Converter<HillshadeIlluminationAnchorType>::operator()(const Convertible&, Error&) const;
+template optional<IconTextFitType> Converter<IconTextFitType>::operator()(const Convertible&, Error&) const;
+template optional<LightAnchorType> Converter<LightAnchorType>::operator()(const Convertible&, Error&) const;
+template optional<LineCapType> Converter<LineCapType>::operator()(const Convertible&, Error&) const;
+template optional<LineJoinType> Converter<LineJoinType>::operator()(const Convertible&, Error&) const;
+template optional<RasterResamplingType> Converter<RasterResamplingType>::operator()(const Convertible&, Error&) const;
+template optional<SymbolAnchorType> Converter<SymbolAnchorType>::operator()(const Convertible&, Error&) const;
+template optional<SymbolPlacementType> Converter<SymbolPlacementType>::operator()(const Convertible&, Error&) const;
+template optional<TextJustifyType> Converter<TextJustifyType>::operator()(const Convertible&, Error&) const;
+template optional<TextTransformType> Converter<TextTransformType>::operator()(const Convertible&, Error&) const;
+template optional<TranslateAnchorType> Converter<TranslateAnchorType>::operator()(const Convertible&, Error&) const;
+template optional<VisibilityType> Converter<VisibilityType>::operator()(const Convertible&, Error&) const;
+
optional<Color> Converter<Color>::operator()(const Convertible& value, Error& error) const {
optional<std::string> string = toString(value);
if (!string) {
@@ -47,6 +80,29 @@ optional<Color> Converter<Color>::operator()(const Convertible& value, Error& er
return *color;
}
+template <size_t N>
+optional<std::array<float, N>> Converter<std::array<float, N>>::operator()(const Convertible& value, Error& error) const {
+ if (!isArray(value) || arrayLength(value) != N) {
+ error.message = "value must be an array of " + util::toString(N) + " numbers";
+ return nullopt;
+ }
+
+ std::array<float, N> result;
+ for (size_t i = 0; i < N; i++) {
+ optional<float> n = toNumber(arrayMember(value, i));
+ if (!n) {
+ error.message = "value must be an array of " + util::toString(N) + " numbers";
+ return nullopt;
+ }
+ result[i] = *n;
+ }
+ return result;
+}
+
+template optional<std::array<float, 2>> Converter<std::array<float, 2>>::operator()(const Convertible&, Error&) const;
+template optional<std::array<float, 3>> Converter<std::array<float, 3>>::operator()(const Convertible&, Error&) const;
+template optional<std::array<float, 4>> Converter<std::array<float, 4>>::operator()(const Convertible&, Error&) const;
+
optional<std::vector<float>> Converter<std::vector<float>>::operator()(const Convertible& value, Error& error) const {
if (!isArray(value)) {
error.message = "value must be an array";
diff --git a/src/mbgl/style/conversion/coordinate.cpp b/src/mbgl/style/conversion/coordinate.cpp
index 20abd45e26..ee03bffb30 100644
--- a/src/mbgl/style/conversion/coordinate.cpp
+++ b/src/mbgl/style/conversion/coordinate.cpp
@@ -1,4 +1,5 @@
#include <mbgl/style/conversion/coordinate.hpp>
+#include <mbgl/style/conversion_impl.hpp>
namespace mbgl {
namespace style {
diff --git a/src/mbgl/style/conversion/custom_geometry_source_options.cpp b/src/mbgl/style/conversion/custom_geometry_source_options.cpp
index 8983f9f479..491509c28f 100644
--- a/src/mbgl/style/conversion/custom_geometry_source_options.cpp
+++ b/src/mbgl/style/conversion/custom_geometry_source_options.cpp
@@ -1,4 +1,5 @@
#include <mbgl/style/conversion/custom_geometry_source_options.hpp>
+#include <mbgl/style/conversion_impl.hpp>
namespace mbgl {
namespace style {
diff --git a/src/mbgl/style/conversion/filter.cpp b/src/mbgl/style/conversion/filter.cpp
index 5114c61778..fc25ab0b0d 100644
--- a/src/mbgl/style/conversion/filter.cpp
+++ b/src/mbgl/style/conversion/filter.cpp
@@ -1,10 +1,11 @@
#include <mbgl/style/conversion/filter.hpp>
+#include <mbgl/style/conversion_impl.hpp>
#include <mbgl/style/expression/literal.hpp>
-#include <mbgl/util/geometry.hpp>
#include <mbgl/style/expression/expression.hpp>
#include <mbgl/style/expression/type.hpp>
#include <mbgl/style/expression/compound_expression.hpp>
#include <mbgl/style/expression/boolean_operator.hpp>
+#include <mbgl/util/geometry.hpp>
namespace mbgl {
namespace style {
diff --git a/src/mbgl/style/conversion/function.cpp b/src/mbgl/style/conversion/function.cpp
index 1cc49e483a..6aadaad3b3 100644
--- a/src/mbgl/style/conversion/function.cpp
+++ b/src/mbgl/style/conversion/function.cpp
@@ -1,4 +1,6 @@
#include <mbgl/style/conversion/function.hpp>
+#include <mbgl/style/conversion/position.hpp>
+#include <mbgl/style/conversion_impl.hpp>
#include <mbgl/style/expression/dsl.hpp>
#include <mbgl/style/expression/step.hpp>
#include <mbgl/style/expression/interpolate.hpp>
@@ -70,6 +72,72 @@ std::unique_ptr<Expression> convertTokenStringToExpression(const std::string& so
}
}
+template <class T>
+optional<PropertyExpression<T>> convertFunctionToExpression(const Convertible& value, Error& error, bool convertTokens) {
+ auto expression = convertFunctionToExpression(expression::valueTypeToExpressionType<T>(), value, error, convertTokens);
+ if (!expression) {
+ return nullopt;
+ }
+
+ optional<T> defaultValue;
+
+ auto defaultValueValue = objectMember(value, "default");
+ if (defaultValueValue) {
+ defaultValue = convert<T>(*defaultValueValue, error);
+ if (!defaultValue) {
+ error.message = R"(wrong type for "default": )" + error.message;
+ return nullopt;
+ }
+ }
+
+ return PropertyExpression<T>(std::move(*expression), defaultValue);
+}
+
+template optional<PropertyExpression<AlignmentType>>
+ convertFunctionToExpression<AlignmentType>(const Convertible&, Error&, bool);
+template optional<PropertyExpression<bool>>
+ convertFunctionToExpression<bool>(const Convertible&, Error&, bool);
+template optional<PropertyExpression<CirclePitchScaleType>>
+ convertFunctionToExpression<CirclePitchScaleType>(const Convertible&, Error&, bool);
+template optional<PropertyExpression<float>>
+ convertFunctionToExpression<float>(const Convertible&, Error&, bool);
+template optional<PropertyExpression<HillshadeIlluminationAnchorType>>
+ convertFunctionToExpression<HillshadeIlluminationAnchorType>(const Convertible&, Error&, bool);
+template optional<PropertyExpression<IconTextFitType>>
+ convertFunctionToExpression<IconTextFitType>(const Convertible&, Error&, bool);
+template optional<PropertyExpression<LightAnchorType>>
+ convertFunctionToExpression<LightAnchorType>(const Convertible&, Error&, bool);
+template optional<PropertyExpression<LineCapType>>
+ convertFunctionToExpression<LineCapType>(const Convertible&, Error&, bool);
+template optional<PropertyExpression<LineJoinType>>
+ convertFunctionToExpression<LineJoinType>(const Convertible&, Error&, bool);
+template optional<PropertyExpression<Color>>
+ convertFunctionToExpression<Color>(const Convertible&, Error&, bool);
+template optional<PropertyExpression<Position>>
+ convertFunctionToExpression<Position>(const Convertible&, Error&, bool);
+template optional<PropertyExpression<RasterResamplingType>>
+ convertFunctionToExpression<RasterResamplingType>(const Convertible&, Error&, bool);
+template optional<PropertyExpression<std::array<float, 2>>>
+ convertFunctionToExpression<std::array<float, 2>>(const Convertible&, Error&, bool);
+template optional<PropertyExpression<std::array<float, 4>>>
+ convertFunctionToExpression<std::array<float, 4>>(const Convertible&, Error&, bool);
+template optional<PropertyExpression<std::string>>
+ convertFunctionToExpression<std::string>(const Convertible&, Error&, bool);
+template optional<PropertyExpression<std::vector<float>>>
+ convertFunctionToExpression<std::vector<float>>(const Convertible&, Error&, bool);
+template optional<PropertyExpression<std::vector<std::string>>>
+ convertFunctionToExpression<std::vector<std::string>>(const Convertible&, Error&, bool);
+template optional<PropertyExpression<SymbolAnchorType>>
+ convertFunctionToExpression<SymbolAnchorType>(const Convertible&, Error&, bool);
+template optional<PropertyExpression<SymbolPlacementType>>
+ convertFunctionToExpression<SymbolPlacementType>(const Convertible&, Error&, bool);
+template optional<PropertyExpression<TextJustifyType>>
+ convertFunctionToExpression<TextJustifyType>(const Convertible&, Error&, bool);
+template optional<PropertyExpression<TextTransformType>>
+ convertFunctionToExpression<TextTransformType>(const Convertible&, Error&, bool);
+template optional<PropertyExpression<TranslateAnchorType>>
+ convertFunctionToExpression<TranslateAnchorType>(const Convertible&, Error&, bool);
+
// Ad-hoc Converters for double and int64_t. We should replace float with double wholesale,
// and promote the int64_t Converter to general use (and it should check that the input is
// an integer).
diff --git a/src/mbgl/style/conversion/geojson.cpp b/src/mbgl/style/conversion/geojson.cpp
index e39a1a80eb..c2d34c5491 100644
--- a/src/mbgl/style/conversion/geojson.cpp
+++ b/src/mbgl/style/conversion/geojson.cpp
@@ -1,5 +1,6 @@
#include <mbgl/style/conversion/geojson.hpp>
#include <mbgl/style/conversion/json.hpp>
+#include <mbgl/style/conversion_impl.hpp>
namespace mbgl {
namespace style {
diff --git a/src/mbgl/style/conversion/geojson_options.cpp b/src/mbgl/style/conversion/geojson_options.cpp
index 77340e5f1d..11bd7cc507 100644
--- a/src/mbgl/style/conversion/geojson_options.cpp
+++ b/src/mbgl/style/conversion/geojson_options.cpp
@@ -1,4 +1,5 @@
#include <mbgl/style/conversion/geojson_options.hpp>
+#include <mbgl/style/conversion_impl.hpp>
namespace mbgl {
namespace style {
diff --git a/src/mbgl/style/conversion/get_json_type.cpp b/src/mbgl/style/conversion/get_json_type.cpp
index cd3b4608b1..2e9d35a957 100644
--- a/src/mbgl/style/conversion/get_json_type.cpp
+++ b/src/mbgl/style/conversion/get_json_type.cpp
@@ -1,4 +1,5 @@
#include <mbgl/style/conversion/get_json_type.hpp>
+#include <mbgl/style/conversion_impl.hpp>
#include <mbgl/util/feature.hpp>
namespace mbgl {
diff --git a/src/mbgl/style/conversion/json.hpp b/src/mbgl/style/conversion/json.hpp
index a823f6d383..3a7bf2b557 100644
--- a/src/mbgl/style/conversion/json.hpp
+++ b/src/mbgl/style/conversion/json.hpp
@@ -1,6 +1,6 @@
#pragma once
-#include <mbgl/style/conversion.hpp>
+#include <mbgl/style/conversion_impl.hpp>
#include <mbgl/style/rapidjson_conversion.hpp>
#include <string>
diff --git a/src/mbgl/style/conversion/layer.cpp b/src/mbgl/style/conversion/layer.cpp
index d36ca494da..085d7ae4c6 100644
--- a/src/mbgl/style/conversion/layer.cpp
+++ b/src/mbgl/style/conversion/layer.cpp
@@ -1,6 +1,7 @@
#include <mbgl/style/conversion/layer.hpp>
#include <mbgl/style/conversion/constant.hpp>
#include <mbgl/style/conversion/filter.hpp>
+#include <mbgl/style/conversion_impl.hpp>
#include <mbgl/style/layers/background_layer.hpp>
#include <mbgl/style/layers/circle_layer.hpp>
#include <mbgl/style/layers/fill_layer.hpp>
diff --git a/src/mbgl/style/conversion/light.cpp b/src/mbgl/style/conversion/light.cpp
index 7b96c89a1c..e8723216ee 100644
--- a/src/mbgl/style/conversion/light.cpp
+++ b/src/mbgl/style/conversion/light.cpp
@@ -2,6 +2,7 @@
#include <mbgl/style/conversion/position.hpp>
#include <mbgl/style/conversion/property_value.hpp>
#include <mbgl/style/conversion/transition_options.hpp>
+#include <mbgl/style/conversion_impl.hpp>
namespace mbgl {
namespace style {
diff --git a/src/mbgl/style/conversion/position.cpp b/src/mbgl/style/conversion/position.cpp
index a19f57bff3..df6c868ee8 100644
--- a/src/mbgl/style/conversion/position.cpp
+++ b/src/mbgl/style/conversion/position.cpp
@@ -1,5 +1,6 @@
#include <mbgl/style/conversion/position.hpp>
#include <mbgl/style/conversion/constant.hpp>
+#include <mbgl/style/conversion_impl.hpp>
#include <array>
diff --git a/src/mbgl/style/conversion/property_value.cpp b/src/mbgl/style/conversion/property_value.cpp
new file mode 100644
index 0000000000..8a93c24767
--- /dev/null
+++ b/src/mbgl/style/conversion/property_value.cpp
@@ -0,0 +1,83 @@
+#include <mbgl/style/conversion/property_value.hpp>
+#include <mbgl/style/conversion/position.hpp>
+#include <mbgl/style/conversion_impl.hpp>
+
+namespace mbgl {
+namespace style {
+namespace conversion {
+
+template <class T>
+optional<PropertyValue<T>> Converter<PropertyValue<T>>::operator()(const Convertible& value, Error& error, bool allowDataExpressions, bool convertTokens) const {
+ using namespace mbgl::style::expression;
+
+ if (isUndefined(value)) {
+ return PropertyValue<T>();
+ }
+
+ optional<PropertyExpression<T>> expression;
+
+ if (isExpression(value)) {
+ ParsingContext ctx(valueTypeToExpressionType<T>());
+ ParseResult parsed = ctx.parseLayerPropertyExpression(value);
+ if (!parsed) {
+ error.message = ctx.getCombinedErrors();
+ return nullopt;
+ }
+ expression = PropertyExpression<T>(std::move(*parsed));
+ } else if (isObject(value)) {
+ expression = convertFunctionToExpression<T>(value, error, convertTokens);
+ } else {
+ optional<T> constant = convert<T>(value, error);
+ if (!constant) {
+ return nullopt;
+ }
+ return convertTokens ? maybeConvertTokens(*constant) : PropertyValue<T>(*constant);
+ }
+
+ if (!expression) {
+ return nullopt;
+ } else if (!allowDataExpressions && !(*expression).isFeatureConstant()) {
+ error.message = "data expressions not supported";
+ return nullopt;
+ } else if (!(*expression).isFeatureConstant() || !(*expression).isZoomConstant()) {
+ return { std::move(*expression) };
+ } else if ((*expression).getExpression().getKind() == Kind::Literal) {
+ optional<T> constant = fromExpressionValue<T>(
+ static_cast<const Literal&>((*expression).getExpression()).getValue());
+ if (!constant) {
+ return nullopt;
+ }
+ return PropertyValue<T>(*constant);
+ } else {
+ assert(false);
+ error.message = "expected a literal expression";
+ return nullopt;
+ }
+}
+
+template optional<PropertyValue<bool>> Converter<PropertyValue<bool>>::operator()(conversion::Convertible const&, conversion::Error&, bool, bool) const;
+template optional<PropertyValue<float>> Converter<PropertyValue<float>>::operator()(conversion::Convertible const&, conversion::Error&, bool, bool) const;
+template optional<PropertyValue<std::array<float, 2>>> Converter<PropertyValue<std::array<float, 2>>>::operator()(conversion::Convertible const&, conversion::Error&, bool, bool) const;
+template optional<PropertyValue<std::array<float, 4>>> Converter<PropertyValue<std::array<float, 4>>>::operator()(conversion::Convertible const&, conversion::Error&, bool, bool) const;
+template optional<PropertyValue<std::vector<float>>> Converter<PropertyValue<std::vector<float>>>::operator()(conversion::Convertible const&, conversion::Error&, bool, bool) const;
+template optional<PropertyValue<Color>> Converter<PropertyValue<Color>>::operator()(conversion::Convertible const&, conversion::Error&, bool, bool) const;
+template optional<PropertyValue<std::string>> Converter<PropertyValue<std::string>>::operator()(conversion::Convertible const&, conversion::Error&, bool, bool) const;
+template optional<PropertyValue<std::vector<std::string>>> Converter<PropertyValue<std::vector<std::string>>>::operator()(conversion::Convertible const&, conversion::Error&, bool, bool) const;
+template optional<PropertyValue<AlignmentType>> Converter<PropertyValue<AlignmentType>>::operator()(conversion::Convertible const&, conversion::Error&, bool, bool) const;
+template optional<PropertyValue<CirclePitchScaleType>> Converter<PropertyValue<CirclePitchScaleType>>::operator()(conversion::Convertible const&, conversion::Error&, bool, bool) const;
+template optional<PropertyValue<HillshadeIlluminationAnchorType>> Converter<PropertyValue<HillshadeIlluminationAnchorType>>::operator()(conversion::Convertible const&, conversion::Error&, bool, bool) const;
+template optional<PropertyValue<IconTextFitType>> Converter<PropertyValue<IconTextFitType>>::operator()(conversion::Convertible const&, conversion::Error&, bool, bool) const;
+template optional<PropertyValue<LightAnchorType>> Converter<PropertyValue<LightAnchorType>>::operator()(conversion::Convertible const&, conversion::Error&, bool, bool) const;
+template optional<PropertyValue<LineCapType>> Converter<PropertyValue<LineCapType>>::operator()(conversion::Convertible const&, conversion::Error&, bool, bool) const;
+template optional<PropertyValue<LineJoinType>> Converter<PropertyValue<LineJoinType>>::operator()(conversion::Convertible const&, conversion::Error&, bool, bool) const;
+template optional<PropertyValue<Position>> Converter<PropertyValue<Position>>::operator()(conversion::Convertible const&, conversion::Error&, bool, bool) const;
+template optional<PropertyValue<RasterResamplingType>> Converter<PropertyValue<RasterResamplingType>>::operator()(conversion::Convertible const&, conversion::Error&, bool, bool) const;
+template optional<PropertyValue<SymbolAnchorType>> Converter<PropertyValue<SymbolAnchorType>>::operator()(conversion::Convertible const&, conversion::Error&, bool, bool) const;
+template optional<PropertyValue<SymbolPlacementType>> Converter<PropertyValue<SymbolPlacementType>>::operator()(conversion::Convertible const&, conversion::Error&, bool, bool) const;
+template optional<PropertyValue<TextJustifyType>> Converter<PropertyValue<TextJustifyType>>::operator()(conversion::Convertible const&, conversion::Error&, bool, bool) const;
+template optional<PropertyValue<TextTransformType>> Converter<PropertyValue<TextTransformType>>::operator()(conversion::Convertible const&, conversion::Error&, bool, bool) const;
+template optional<PropertyValue<TranslateAnchorType>> Converter<PropertyValue<TranslateAnchorType>>::operator()(conversion::Convertible const&, conversion::Error&, bool, bool) const;
+
+} // namespace conversion
+} // namespace style
+} // namespace mbgl
diff --git a/src/mbgl/style/conversion/source.cpp b/src/mbgl/style/conversion/source.cpp
index ce0cb24ce0..5ecbd3b474 100644
--- a/src/mbgl/style/conversion/source.cpp
+++ b/src/mbgl/style/conversion/source.cpp
@@ -3,6 +3,7 @@
#include <mbgl/style/conversion/geojson.hpp>
#include <mbgl/style/conversion/geojson_options.hpp>
#include <mbgl/style/conversion/tileset.hpp>
+#include <mbgl/style/conversion_impl.hpp>
#include <mbgl/style/sources/geojson_source.hpp>
#include <mbgl/style/sources/raster_source.hpp>
#include <mbgl/style/sources/raster_dem_source.hpp>
diff --git a/src/mbgl/style/conversion/tileset.cpp b/src/mbgl/style/conversion/tileset.cpp
index b566af0a18..40575838ea 100644
--- a/src/mbgl/style/conversion/tileset.cpp
+++ b/src/mbgl/style/conversion/tileset.cpp
@@ -1,4 +1,5 @@
#include <mbgl/style/conversion/tileset.hpp>
+#include <mbgl/style/conversion_impl.hpp>
#include <mbgl/util/geo.hpp>
#include <mbgl/math/clamp.hpp>
diff --git a/src/mbgl/style/conversion/transition_options.cpp b/src/mbgl/style/conversion/transition_options.cpp
index 924032a0c0..6e39dca24f 100644
--- a/src/mbgl/style/conversion/transition_options.cpp
+++ b/src/mbgl/style/conversion/transition_options.cpp
@@ -1,4 +1,5 @@
#include <mbgl/style/conversion/transition_options.hpp>
+#include <mbgl/style/conversion_impl.hpp>
namespace mbgl {
namespace style {
diff --git a/src/mbgl/style/expression/array_assertion.cpp b/src/mbgl/style/expression/array_assertion.cpp
index 4049301b0b..9df586bdc3 100644
--- a/src/mbgl/style/expression/array_assertion.cpp
+++ b/src/mbgl/style/expression/array_assertion.cpp
@@ -1,5 +1,6 @@
#include <mbgl/style/expression/array_assertion.hpp>
#include <mbgl/style/expression/check_subtype.hpp>
+#include <mbgl/style/conversion_impl.hpp>
#include <mbgl/util/string.hpp>
namespace mbgl {
diff --git a/src/mbgl/style/expression/assertion.cpp b/src/mbgl/style/expression/assertion.cpp
index 2434d7a2f8..7e93003ac3 100644
--- a/src/mbgl/style/expression/assertion.cpp
+++ b/src/mbgl/style/expression/assertion.cpp
@@ -1,5 +1,6 @@
#include <mbgl/style/expression/assertion.hpp>
#include <mbgl/style/expression/check_subtype.hpp>
+#include <mbgl/style/conversion_impl.hpp>
namespace mbgl {
namespace style {
diff --git a/src/mbgl/style/expression/at.cpp b/src/mbgl/style/expression/at.cpp
index 725e5ddb51..648f247830 100644
--- a/src/mbgl/style/expression/at.cpp
+++ b/src/mbgl/style/expression/at.cpp
@@ -1,4 +1,5 @@
#include <mbgl/style/expression/at.hpp>
+#include <mbgl/style/conversion_impl.hpp>
#include <mbgl/util/string.hpp>
diff --git a/src/mbgl/style/expression/boolean_operator.cpp b/src/mbgl/style/expression/boolean_operator.cpp
index 68e96129aa..fa472270ce 100644
--- a/src/mbgl/style/expression/boolean_operator.cpp
+++ b/src/mbgl/style/expression/boolean_operator.cpp
@@ -1,4 +1,5 @@
#include <mbgl/style/expression/boolean_operator.hpp>
+#include <mbgl/style/conversion_impl.hpp>
namespace mbgl {
namespace style {
diff --git a/src/mbgl/style/expression/case.cpp b/src/mbgl/style/expression/case.cpp
index e885c0ce6b..0c2ff0d7cd 100644
--- a/src/mbgl/style/expression/case.cpp
+++ b/src/mbgl/style/expression/case.cpp
@@ -1,4 +1,5 @@
#include <mbgl/style/expression/case.hpp>
+#include <mbgl/style/conversion_impl.hpp>
#include <mbgl/util/string.hpp>
namespace mbgl {
diff --git a/src/mbgl/style/expression/coalesce.cpp b/src/mbgl/style/expression/coalesce.cpp
index 0090f16009..cdbf452f7f 100644
--- a/src/mbgl/style/expression/coalesce.cpp
+++ b/src/mbgl/style/expression/coalesce.cpp
@@ -1,5 +1,6 @@
#include <mbgl/style/expression/coalesce.hpp>
#include <mbgl/style/expression/check_subtype.hpp>
+#include <mbgl/style/conversion_impl.hpp>
namespace mbgl {
namespace style {
diff --git a/src/mbgl/style/expression/coercion.cpp b/src/mbgl/style/expression/coercion.cpp
index f5a4d70f66..486658ddda 100644
--- a/src/mbgl/style/expression/coercion.cpp
+++ b/src/mbgl/style/expression/coercion.cpp
@@ -1,6 +1,7 @@
#include <mbgl/style/expression/coercion.hpp>
#include <mbgl/style/expression/check_subtype.hpp>
#include <mbgl/style/expression/util.hpp>
+#include <mbgl/style/conversion_impl.hpp>
#include <mbgl/util/string.hpp>
namespace mbgl {
diff --git a/src/mbgl/style/expression/collator_expression.cpp b/src/mbgl/style/expression/collator_expression.cpp
index b27eedbc76..07346633a2 100644
--- a/src/mbgl/style/expression/collator_expression.cpp
+++ b/src/mbgl/style/expression/collator_expression.cpp
@@ -1,6 +1,7 @@
#include <mbgl/style/expression/collator.hpp>
#include <mbgl/style/expression/collator_expression.hpp>
#include <mbgl/style/expression/literal.hpp>
+#include <mbgl/style/conversion_impl.hpp>
#include <mbgl/util/string.hpp>
namespace mbgl {
diff --git a/src/mbgl/style/expression/comparison.cpp b/src/mbgl/style/expression/comparison.cpp
index 6179c3ce88..cdcdb5d59c 100644
--- a/src/mbgl/style/expression/comparison.cpp
+++ b/src/mbgl/style/expression/comparison.cpp
@@ -1,6 +1,7 @@
#include <mbgl/style/expression/collator.hpp>
#include <mbgl/style/expression/comparison.hpp>
#include <mbgl/style/expression/dsl.hpp>
+#include <mbgl/style/conversion_impl.hpp>
namespace mbgl {
namespace style {
diff --git a/src/mbgl/style/expression/compound_expression.cpp b/src/mbgl/style/expression/compound_expression.cpp
index 4c476a3749..f8c2376cb3 100644
--- a/src/mbgl/style/expression/compound_expression.cpp
+++ b/src/mbgl/style/expression/compound_expression.cpp
@@ -3,6 +3,7 @@
#include <mbgl/style/expression/compound_expression.hpp>
#include <mbgl/style/expression/check_subtype.hpp>
#include <mbgl/style/expression/util.hpp>
+#include <mbgl/style/conversion_impl.hpp>
#include <mbgl/tile/geometry_tile_data.hpp>
#include <mbgl/math/log2.hpp>
#include <mbgl/util/i18n.hpp>
diff --git a/src/mbgl/style/expression/interpolate.cpp b/src/mbgl/style/expression/interpolate.cpp
index 54fbc6e1d7..8725e9e86d 100644
--- a/src/mbgl/style/expression/interpolate.cpp
+++ b/src/mbgl/style/expression/interpolate.cpp
@@ -1,4 +1,5 @@
#include <mbgl/style/expression/interpolate.hpp>
+#include <mbgl/style/conversion_impl.hpp>
#include <mbgl/util/string.hpp>
namespace mbgl {
diff --git a/src/mbgl/style/expression/is_expression.cpp b/src/mbgl/style/expression/is_expression.cpp
index 77212f6a1e..acf074c25b 100644
--- a/src/mbgl/style/expression/is_expression.cpp
+++ b/src/mbgl/style/expression/is_expression.cpp
@@ -1,8 +1,7 @@
#include <mbgl/style/expression/is_expression.hpp>
#include <mbgl/style/expression/compound_expression.hpp>
#include <mbgl/style/expression/parsing_context.hpp>
-
-#include <mbgl/style/conversion.hpp>
+#include <mbgl/style/conversion_impl.hpp>
#include <unordered_set>
diff --git a/src/mbgl/style/expression/length.cpp b/src/mbgl/style/expression/length.cpp
index ad7a15675a..f1b58d7952 100644
--- a/src/mbgl/style/expression/length.cpp
+++ b/src/mbgl/style/expression/length.cpp
@@ -1,4 +1,5 @@
#include <mbgl/style/expression/length.hpp>
+#include <mbgl/style/conversion_impl.hpp>
#include <mbgl/util/string.hpp>
namespace mbgl {
diff --git a/src/mbgl/style/expression/let.cpp b/src/mbgl/style/expression/let.cpp
index 242a995b0b..592ceed58a 100644
--- a/src/mbgl/style/expression/let.cpp
+++ b/src/mbgl/style/expression/let.cpp
@@ -1,5 +1,6 @@
#include <mbgl/style/expression/let.hpp>
#include <mbgl/style/conversion/get_json_type.hpp>
+#include <mbgl/style/conversion_impl.hpp>
#include <mbgl/util/string.hpp>
namespace mbgl {
diff --git a/src/mbgl/style/expression/literal.cpp b/src/mbgl/style/expression/literal.cpp
index 345a52de9b..c69341d298 100644
--- a/src/mbgl/style/expression/literal.cpp
+++ b/src/mbgl/style/expression/literal.cpp
@@ -1,4 +1,5 @@
#include <mbgl/style/expression/literal.hpp>
+#include <mbgl/style/conversion_impl.hpp>
#include <mbgl/util/string.hpp>
namespace mbgl {
diff --git a/src/mbgl/style/expression/match.cpp b/src/mbgl/style/expression/match.cpp
index 4b4984811f..0f05001a97 100644
--- a/src/mbgl/style/expression/match.cpp
+++ b/src/mbgl/style/expression/match.cpp
@@ -1,6 +1,7 @@
#include <mbgl/style/expression/match.hpp>
#include <mbgl/style/expression/check_subtype.hpp>
#include <mbgl/style/expression/parsing_context.hpp>
+#include <mbgl/style/conversion_impl.hpp>
#include <mbgl/util/string.hpp>
namespace mbgl {
diff --git a/src/mbgl/style/expression/parsing_context.cpp b/src/mbgl/style/expression/parsing_context.cpp
index b3f6b1acee..ef17caed33 100644
--- a/src/mbgl/style/expression/parsing_context.cpp
+++ b/src/mbgl/style/expression/parsing_context.cpp
@@ -24,6 +24,7 @@
#include <mbgl/style/expression/find_zoom_curve.hpp>
#include <mbgl/style/conversion/get_json_type.hpp>
+#include <mbgl/style/conversion_impl.hpp>
#include <mbgl/util/string.hpp>
diff --git a/src/mbgl/style/expression/step.cpp b/src/mbgl/style/expression/step.cpp
index a1ca0a702e..39b04c04a0 100644
--- a/src/mbgl/style/expression/step.cpp
+++ b/src/mbgl/style/expression/step.cpp
@@ -1,5 +1,6 @@
#include <mbgl/style/expression/step.hpp>
#include <mbgl/style/expression/get_covering_stops.hpp>
+#include <mbgl/style/conversion_impl.hpp>
#include <mbgl/util/string.hpp>
#include <cmath>
diff --git a/src/mbgl/style/layer.cpp b/src/mbgl/style/layer.cpp
index 31ff5bf47a..e08b71e6b3 100644
--- a/src/mbgl/style/layer.cpp
+++ b/src/mbgl/style/layer.cpp
@@ -2,6 +2,7 @@
#include <mbgl/style/layer_impl.hpp>
#include <mbgl/style/layer_observer.hpp>
#include <mbgl/style/conversion/constant.hpp>
+#include <mbgl/style/conversion_impl.hpp>
namespace mbgl {
namespace style {
diff --git a/src/mbgl/style/layers/background_layer.cpp b/src/mbgl/style/layers/background_layer.cpp
index e47b41daa8..f2e85ce7e7 100644
--- a/src/mbgl/style/layers/background_layer.cpp
+++ b/src/mbgl/style/layers/background_layer.cpp
@@ -3,12 +3,12 @@
#include <mbgl/style/layers/background_layer.hpp>
#include <mbgl/style/layers/background_layer_impl.hpp>
#include <mbgl/style/layer_observer.hpp>
-#include <mbgl/style/conversion.hpp>
#include <mbgl/style/conversion/color_ramp_property_value.hpp>
#include <mbgl/style/conversion/constant.hpp>
#include <mbgl/style/conversion/property_value.hpp>
#include <mbgl/style/conversion/transition_options.hpp>
#include <mbgl/style/conversion/json.hpp>
+#include <mbgl/style/conversion_impl.hpp>
#include <mbgl/util/fnv_hash.hpp>
namespace mbgl {
diff --git a/src/mbgl/style/layers/circle_layer.cpp b/src/mbgl/style/layers/circle_layer.cpp
index 1dae77547b..c301a83c9e 100644
--- a/src/mbgl/style/layers/circle_layer.cpp
+++ b/src/mbgl/style/layers/circle_layer.cpp
@@ -3,12 +3,12 @@
#include <mbgl/style/layers/circle_layer.hpp>
#include <mbgl/style/layers/circle_layer_impl.hpp>
#include <mbgl/style/layer_observer.hpp>
-#include <mbgl/style/conversion.hpp>
#include <mbgl/style/conversion/color_ramp_property_value.hpp>
#include <mbgl/style/conversion/constant.hpp>
#include <mbgl/style/conversion/property_value.hpp>
#include <mbgl/style/conversion/transition_options.hpp>
#include <mbgl/style/conversion/json.hpp>
+#include <mbgl/style/conversion_impl.hpp>
#include <mbgl/util/fnv_hash.hpp>
namespace mbgl {
diff --git a/src/mbgl/style/layers/fill_extrusion_layer.cpp b/src/mbgl/style/layers/fill_extrusion_layer.cpp
index db90415daa..74cdb9abe6 100644
--- a/src/mbgl/style/layers/fill_extrusion_layer.cpp
+++ b/src/mbgl/style/layers/fill_extrusion_layer.cpp
@@ -3,12 +3,12 @@
#include <mbgl/style/layers/fill_extrusion_layer.hpp>
#include <mbgl/style/layers/fill_extrusion_layer_impl.hpp>
#include <mbgl/style/layer_observer.hpp>
-#include <mbgl/style/conversion.hpp>
#include <mbgl/style/conversion/color_ramp_property_value.hpp>
#include <mbgl/style/conversion/constant.hpp>
#include <mbgl/style/conversion/property_value.hpp>
#include <mbgl/style/conversion/transition_options.hpp>
#include <mbgl/style/conversion/json.hpp>
+#include <mbgl/style/conversion_impl.hpp>
#include <mbgl/util/fnv_hash.hpp>
namespace mbgl {
diff --git a/src/mbgl/style/layers/fill_layer.cpp b/src/mbgl/style/layers/fill_layer.cpp
index 2da131b6b2..bdfc000736 100644
--- a/src/mbgl/style/layers/fill_layer.cpp
+++ b/src/mbgl/style/layers/fill_layer.cpp
@@ -3,12 +3,12 @@
#include <mbgl/style/layers/fill_layer.hpp>
#include <mbgl/style/layers/fill_layer_impl.hpp>
#include <mbgl/style/layer_observer.hpp>
-#include <mbgl/style/conversion.hpp>
#include <mbgl/style/conversion/color_ramp_property_value.hpp>
#include <mbgl/style/conversion/constant.hpp>
#include <mbgl/style/conversion/property_value.hpp>
#include <mbgl/style/conversion/transition_options.hpp>
#include <mbgl/style/conversion/json.hpp>
+#include <mbgl/style/conversion_impl.hpp>
#include <mbgl/util/fnv_hash.hpp>
namespace mbgl {
diff --git a/src/mbgl/style/layers/heatmap_layer.cpp b/src/mbgl/style/layers/heatmap_layer.cpp
index df00558135..a90aab7009 100644
--- a/src/mbgl/style/layers/heatmap_layer.cpp
+++ b/src/mbgl/style/layers/heatmap_layer.cpp
@@ -3,12 +3,12 @@
#include <mbgl/style/layers/heatmap_layer.hpp>
#include <mbgl/style/layers/heatmap_layer_impl.hpp>
#include <mbgl/style/layer_observer.hpp>
-#include <mbgl/style/conversion.hpp>
#include <mbgl/style/conversion/color_ramp_property_value.hpp>
#include <mbgl/style/conversion/constant.hpp>
#include <mbgl/style/conversion/property_value.hpp>
#include <mbgl/style/conversion/transition_options.hpp>
#include <mbgl/style/conversion/json.hpp>
+#include <mbgl/style/conversion_impl.hpp>
#include <mbgl/util/fnv_hash.hpp>
namespace mbgl {
diff --git a/src/mbgl/style/layers/hillshade_layer.cpp b/src/mbgl/style/layers/hillshade_layer.cpp
index fb96c681cc..aed49f6441 100644
--- a/src/mbgl/style/layers/hillshade_layer.cpp
+++ b/src/mbgl/style/layers/hillshade_layer.cpp
@@ -3,12 +3,12 @@
#include <mbgl/style/layers/hillshade_layer.hpp>
#include <mbgl/style/layers/hillshade_layer_impl.hpp>
#include <mbgl/style/layer_observer.hpp>
-#include <mbgl/style/conversion.hpp>
#include <mbgl/style/conversion/color_ramp_property_value.hpp>
#include <mbgl/style/conversion/constant.hpp>
#include <mbgl/style/conversion/property_value.hpp>
#include <mbgl/style/conversion/transition_options.hpp>
#include <mbgl/style/conversion/json.hpp>
+#include <mbgl/style/conversion_impl.hpp>
#include <mbgl/util/fnv_hash.hpp>
namespace mbgl {
diff --git a/src/mbgl/style/layers/layer.cpp.ejs b/src/mbgl/style/layers/layer.cpp.ejs
index 4e80a7bf74..b5fb1a97a4 100644
--- a/src/mbgl/style/layers/layer.cpp.ejs
+++ b/src/mbgl/style/layers/layer.cpp.ejs
@@ -8,12 +8,12 @@
#include <mbgl/style/layers/<%- type.replace('-', '_') %>_layer.hpp>
#include <mbgl/style/layers/<%- type.replace('-', '_') %>_layer_impl.hpp>
#include <mbgl/style/layer_observer.hpp>
-#include <mbgl/style/conversion.hpp>
#include <mbgl/style/conversion/color_ramp_property_value.hpp>
#include <mbgl/style/conversion/constant.hpp>
#include <mbgl/style/conversion/property_value.hpp>
#include <mbgl/style/conversion/transition_options.hpp>
#include <mbgl/style/conversion/json.hpp>
+#include <mbgl/style/conversion_impl.hpp>
#include <mbgl/util/fnv_hash.hpp>
namespace mbgl {
diff --git a/src/mbgl/style/layers/line_layer.cpp b/src/mbgl/style/layers/line_layer.cpp
index c744adad95..1b84c2d73e 100644
--- a/src/mbgl/style/layers/line_layer.cpp
+++ b/src/mbgl/style/layers/line_layer.cpp
@@ -3,12 +3,12 @@
#include <mbgl/style/layers/line_layer.hpp>
#include <mbgl/style/layers/line_layer_impl.hpp>
#include <mbgl/style/layer_observer.hpp>
-#include <mbgl/style/conversion.hpp>
#include <mbgl/style/conversion/color_ramp_property_value.hpp>
#include <mbgl/style/conversion/constant.hpp>
#include <mbgl/style/conversion/property_value.hpp>
#include <mbgl/style/conversion/transition_options.hpp>
#include <mbgl/style/conversion/json.hpp>
+#include <mbgl/style/conversion_impl.hpp>
#include <mbgl/util/fnv_hash.hpp>
namespace mbgl {
diff --git a/src/mbgl/style/layers/raster_layer.cpp b/src/mbgl/style/layers/raster_layer.cpp
index 45d3240833..7bd01c92e1 100644
--- a/src/mbgl/style/layers/raster_layer.cpp
+++ b/src/mbgl/style/layers/raster_layer.cpp
@@ -3,12 +3,12 @@
#include <mbgl/style/layers/raster_layer.hpp>
#include <mbgl/style/layers/raster_layer_impl.hpp>
#include <mbgl/style/layer_observer.hpp>
-#include <mbgl/style/conversion.hpp>
#include <mbgl/style/conversion/color_ramp_property_value.hpp>
#include <mbgl/style/conversion/constant.hpp>
#include <mbgl/style/conversion/property_value.hpp>
#include <mbgl/style/conversion/transition_options.hpp>
#include <mbgl/style/conversion/json.hpp>
+#include <mbgl/style/conversion_impl.hpp>
#include <mbgl/util/fnv_hash.hpp>
namespace mbgl {
diff --git a/src/mbgl/style/layers/symbol_layer.cpp b/src/mbgl/style/layers/symbol_layer.cpp
index 48af6b13aa..4ea138a7f5 100644
--- a/src/mbgl/style/layers/symbol_layer.cpp
+++ b/src/mbgl/style/layers/symbol_layer.cpp
@@ -3,12 +3,12 @@
#include <mbgl/style/layers/symbol_layer.hpp>
#include <mbgl/style/layers/symbol_layer_impl.hpp>
#include <mbgl/style/layer_observer.hpp>
-#include <mbgl/style/conversion.hpp>
#include <mbgl/style/conversion/color_ramp_property_value.hpp>
#include <mbgl/style/conversion/constant.hpp>
#include <mbgl/style/conversion/property_value.hpp>
#include <mbgl/style/conversion/transition_options.hpp>
#include <mbgl/style/conversion/json.hpp>
+#include <mbgl/style/conversion_impl.hpp>
#include <mbgl/util/fnv_hash.hpp>
namespace mbgl {
diff --git a/src/mbgl/style/parser.cpp b/src/mbgl/style/parser.cpp
index 0a90919f0b..114a666f08 100644
--- a/src/mbgl/style/parser.cpp
+++ b/src/mbgl/style/parser.cpp
@@ -1,12 +1,12 @@
#include <mbgl/style/parser.hpp>
#include <mbgl/style/layer_impl.hpp>
#include <mbgl/style/rapidjson_conversion.hpp>
-#include <mbgl/style/conversion.hpp>
#include <mbgl/style/conversion/coordinate.hpp>
#include <mbgl/style/conversion/source.hpp>
#include <mbgl/style/conversion/layer.hpp>
#include <mbgl/style/conversion/light.hpp>
#include <mbgl/style/conversion/transition_options.hpp>
+#include <mbgl/style/conversion_impl.hpp>
#include <mbgl/util/logging.hpp>
#include <mbgl/util/string.hpp>
diff --git a/src/mbgl/style/rapidjson_conversion.hpp b/src/mbgl/style/rapidjson_conversion.hpp
index 79bd9c928b..be335101e9 100644
--- a/src/mbgl/style/rapidjson_conversion.hpp
+++ b/src/mbgl/style/rapidjson_conversion.hpp
@@ -1,7 +1,7 @@
#pragma once
#include <mbgl/util/rapidjson.hpp>
-#include <mbgl/style/conversion.hpp>
+#include <mbgl/style/conversion_impl.hpp>
#include <mapbox/geojson.hpp>
#include <mapbox/geojson/rapidjson.hpp>
diff --git a/test/style/conversion/light.test.cpp b/test/style/conversion/light.test.cpp
index f111e40ff3..092c476277 100644
--- a/test/style/conversion/light.test.cpp
+++ b/test/style/conversion/light.test.cpp
@@ -1,9 +1,9 @@
#include <mbgl/test/util.hpp>
-#include <mbgl/style/conversion.hpp>
#include <mbgl/style/conversion/json.hpp>
#include <mbgl/style/conversion/constant.hpp>
#include <mbgl/style/conversion/light.hpp>
+#include <mbgl/style/conversion_impl.hpp>
#include <mbgl/style/position.hpp>
#include <mbgl/util/color.hpp>
#include <mbgl/util/chrono.hpp>
diff --git a/test/style/expression/expression.test.cpp b/test/style/expression/expression.test.cpp
index 0b46facf42..982a769b93 100644
--- a/test/style/expression/expression.test.cpp
+++ b/test/style/expression/expression.test.cpp
@@ -1,6 +1,6 @@
#include <mbgl/test/util.hpp>
#include <mbgl/util/io.hpp>
-#include <mbgl/style/conversion.hpp>
+#include <mbgl/style/conversion_impl.hpp>
#include <mbgl/util/rapidjson.hpp>
#include <mbgl/style/rapidjson_conversion.hpp>
#include <mbgl/style/expression/is_expression.hpp>