summaryrefslogtreecommitdiff
path: root/include/mbgl/style/conversion
diff options
context:
space:
mode:
authorJohn Firebaugh <john.firebaugh@gmail.com>2016-06-22 12:31:49 -0700
committerJohn Firebaugh <john.firebaugh@gmail.com>2016-06-24 09:39:15 -0700
commit089c4e413fbe80711ebd874520d3b8fdcb997112 (patch)
treea8088b0ed6cbd36b5cadf247a6e0fc524b6c3a3d /include/mbgl/style/conversion
parentcb6a519f7c1e59b584b84039ebf4803c1d7eee71 (diff)
downloadqtlocation-mapboxgl-089c4e413fbe80711ebd874520d3b8fdcb997112.tar.gz
[core] Split up and clean up conversion.hpp
Diffstat (limited to 'include/mbgl/style/conversion')
-rw-r--r--include/mbgl/style/conversion/constant.hpp174
-rw-r--r--include/mbgl/style/conversion/filter.hpp150
-rw-r--r--include/mbgl/style/conversion/function.hpp69
-rw-r--r--include/mbgl/style/conversion/property_value.hpp34
4 files changed, 427 insertions, 0 deletions
diff --git a/include/mbgl/style/conversion/constant.hpp b/include/mbgl/style/conversion/constant.hpp
new file mode 100644
index 0000000000..05bf968f4d
--- /dev/null
+++ b/include/mbgl/style/conversion/constant.hpp
@@ -0,0 +1,174 @@
+#pragma once
+
+#include <mbgl/style/conversion.hpp>
+#include <mbgl/util/optional.hpp>
+#include <mbgl/util/color.hpp>
+#include <mbgl/util/enum.hpp>
+
+#include <array>
+#include <string>
+#include <vector>
+
+namespace mbgl {
+namespace style {
+namespace conversion {
+
+template <>
+struct Converter<bool> {
+ template <class V>
+ Result<bool> operator()(const V& value) const {
+ optional<bool> converted = toBool(value);
+ if (!converted) {
+ return Error { "value must be a boolean" };
+ }
+ return *converted;
+ }
+};
+
+template <>
+struct Converter<float> {
+ template <class V>
+ Result<float> operator()(const V& value) const {
+ optional<float> converted = toNumber(value);
+ if (!converted) {
+ return Error { "value must be a number" };
+ }
+ return *converted;
+ }
+};
+
+template <>
+struct Converter<std::string> {
+ template <class V>
+ Result<std::string> operator()(const V& value) const {
+ optional<std::string> converted = toString(value);
+ if (!converted) {
+ return Error { "value must be a string" };
+ }
+ return *converted;
+ }
+};
+
+template <class T>
+struct Converter<T, typename std::enable_if_t<std::is_enum<T>::value>> {
+ template <class V>
+ Result<T> operator()(const V& value) const {
+ optional<std::string> string = toString(value);
+ if (!string) {
+ return Error { "value must be a string" };
+ }
+
+ const auto result = Enum<T>::toEnum(*string);
+ if (!result) {
+ return Error { "value must be a valid enumeration value" };
+ }
+
+ return *result;
+ }
+};
+
+template <>
+struct Converter<Color> {
+ template <class V>
+ Result<Color> operator()(const V& value) const {
+ optional<std::string> string = toString(value);
+ if (!string) {
+ return Error { "value must be a string" };
+ }
+
+ optional<Color> color = Color::parse(*string);
+ if (!color) {
+ return Error { "value must be a valid color" };
+ }
+
+ return *color;
+ }
+};
+
+template <>
+struct Converter<std::array<float, 2>> {
+ template <class V>
+ Result<std::array<float, 2>> operator()(const V& value) const {
+ if (!isArray(value) || arrayLength(value) != 2) {
+ return Error { "value must be an array of two numbers" };
+ }
+
+ optional<float> first = toNumber(arrayMember(value, 0));
+ optional<float> second = toNumber(arrayMember(value, 1));
+ if (!first || !second) {
+ return Error { "value must be an array of two numbers" };
+ }
+
+ return std::array<float, 2> {{ *first, *second }};
+ }
+};
+
+template <>
+struct Converter<std::array<float, 4>> {
+ template <class V>
+ Result<std::array<float, 4>> operator()(const V& value) const {
+ if (!isArray(value) || arrayLength(value) != 4) {
+ return Error { "value must be an array of four numbers" };
+ }
+
+ optional<float> first = toNumber(arrayMember(value, 0));
+ optional<float> second = toNumber(arrayMember(value, 1));
+ optional<float> third = toNumber(arrayMember(value, 2));
+ optional<float> fourth = toNumber(arrayMember(value, 3));
+ if (!first || !second) {
+ return Error { "value must be an array of four numbers" };
+ }
+
+ return std::array<float, 4> {{ *first, *second, *third, *fourth }};
+ }
+};
+
+template <>
+struct Converter<std::vector<float>> {
+ template <class V>
+ Result<std::vector<float>> operator()(const V& value) const {
+ if (!isArray(value)) {
+ return Error { "value must be an array" };
+ }
+
+ 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) {
+ return Error { "value must be an array of numbers" };
+ }
+ result.push_back(*number);
+ }
+
+ return result;
+ }
+};
+
+template <>
+struct Converter<std::vector<std::string>> {
+ template <class V>
+ Result<std::vector<std::string>> operator()(const V& value) const {
+ if (!isArray(value)) {
+ return Error { "value must be an array" };
+ }
+
+ 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) {
+ return Error { "value must be an array of strings" };
+ }
+ result.push_back(*string);
+ }
+
+ return result;
+ }
+};
+
+} // namespace conversion
+} // namespace style
+} // namespace mbgl
diff --git a/include/mbgl/style/conversion/filter.hpp b/include/mbgl/style/conversion/filter.hpp
new file mode 100644
index 0000000000..3ab91e5bbc
--- /dev/null
+++ b/include/mbgl/style/conversion/filter.hpp
@@ -0,0 +1,150 @@
+#pragma once
+
+#include <mbgl/style/filter.hpp>
+#include <mbgl/style/conversion.hpp>
+#include <mbgl/util/geometry.hpp>
+
+namespace mbgl {
+namespace style {
+namespace conversion {
+
+template <>
+struct Converter<Filter> {
+public:
+ template <class V>
+ Result<Filter> operator()(const V& value) const {
+ if (!isArray(value)) {
+ return Error { "filter expression must be an array" };
+ }
+
+ if (arrayLength(value) < 1) {
+ return Error { "filter expression must have at least 1 element" };
+ }
+
+ optional<std::string> op = toString(arrayMember(value, 0));
+ if (!op) {
+ return Error { "filter operator must be a string" };
+ }
+
+ if (*op == "==") {
+ return convertBinaryFilter<EqualsFilter>(value);
+ } else if (*op == "!=") {
+ return convertBinaryFilter<NotEqualsFilter>(value);
+ } else if (*op == ">") {
+ return convertBinaryFilter<GreaterThanFilter>(value);
+ } else if (*op == ">=") {
+ return convertBinaryFilter<GreaterThanEqualsFilter>(value);
+ } else if (*op == "<") {
+ return convertBinaryFilter<LessThanFilter>(value);
+ } else if (*op == "<=") {
+ return convertBinaryFilter<LessThanEqualsFilter>(value);
+ } else if (*op == "in") {
+ return convertSetFilter<InFilter>(value);
+ } else if (*op == "!in") {
+ return convertSetFilter<NotInFilter>(value);
+ } else if (*op == "all") {
+ return convertCompoundFilter<AllFilter>(value);
+ } else if (*op == "any") {
+ return convertCompoundFilter<AnyFilter>(value);
+ } else if (*op == "none") {
+ return convertCompoundFilter<NoneFilter>(value);
+ } else if (*op == "has") {
+ return convertUnaryFilter<HasFilter>(value);
+ } else if (*op == "!has") {
+ return convertUnaryFilter<NotHasFilter>(value);
+ }
+
+ return Error { "filter operator must be one of \"==\", \"!=\", \">\", \">=\", \"<\", \"<=\", \"in\", \"!in\", \"all\", \"any\", \"none\", \"has\", or \"!has\"" };
+ }
+
+private:
+ Result<Value> normalizeValue(const std::string& key, const optional<Value>& value) const {
+ if (!value) {
+ return Error { "filter expression value must be a boolean, number, or string" };
+ } else if (key != "$type") {
+ return *value;
+ } else if (*value == std::string("Point")) {
+ return Value(uint64_t(FeatureType::Point));
+ } else if (*value == std::string("LineString")) {
+ return Value(uint64_t(FeatureType::LineString));
+ } else if (*value == std::string("Polygon")) {
+ return Value(uint64_t(FeatureType::Polygon));
+ } else {
+ return Error { "value for $type filter must be Point, LineString, or Polygon" };
+ }
+ }
+
+ template <class FilterType, class V>
+ Result<Filter> convertUnaryFilter(const V& value) const {
+ if (arrayLength(value) < 2) {
+ return Error { "filter expression must have 2 elements" };
+ }
+
+ optional<std::string> key = toString(arrayMember(value, 1));
+ if (!key) {
+ return Error { "filter expression key must be a string" };
+ }
+
+ return FilterType { *key };
+ }
+
+ template <class FilterType, class V>
+ Result<Filter> convertBinaryFilter(const V& value) const {
+ if (arrayLength(value) < 3) {
+ return Error { "filter expression must have 3 elements" };
+ }
+
+ optional<std::string> key = toString(arrayMember(value, 1));
+ if (!key) {
+ return Error { "filter expression key must be a string" };
+ }
+
+ Result<Value> filterValue = normalizeValue(*key, toValue(arrayMember(value, 2)));
+ if (!filterValue) {
+ return filterValue.error();
+ }
+
+ return FilterType { *key, *filterValue };
+ }
+
+ template <class FilterType, class V>
+ Result<Filter> convertSetFilter(const V& value) const {
+ if (arrayLength(value) < 2) {
+ return Error { "filter expression must at least 2 elements" };
+ }
+
+ optional<std::string> key = toString(arrayMember(value, 1));
+ if (!key) {
+ return Error { "filter expression key must be a string" };
+ }
+
+ std::vector<Value> values;
+ for (std::size_t i = 2; i < arrayLength(value); ++i) {
+ Result<Value> filterValue = normalizeValue(*key, toValue(arrayMember(value, i)));
+ if (!filterValue) {
+ return filterValue.error();
+ }
+ values.push_back(*filterValue);
+ }
+
+ return FilterType { *key, std::move(values) };
+ }
+
+ template <class FilterType, class V>
+ Result<Filter> convertCompoundFilter(const V& value) const {
+ std::vector<Filter> filters;
+ for (std::size_t i = 1; i < arrayLength(value); ++i) {
+ Result<Filter> element = operator()(arrayMember(value, i));
+ if (!element) {
+ return element.error();
+ }
+ filters.push_back(*element);
+ }
+
+ return FilterType { std::move(filters) };
+ }
+};
+
+} // namespace conversion
+} // namespace style
+} // namespace mbgl
diff --git a/include/mbgl/style/conversion/function.hpp b/include/mbgl/style/conversion/function.hpp
new file mode 100644
index 0000000000..f14b5089be
--- /dev/null
+++ b/include/mbgl/style/conversion/function.hpp
@@ -0,0 +1,69 @@
+#pragma once
+
+#include <mbgl/style/function.hpp>
+#include <mbgl/style/conversion.hpp>
+#include <mbgl/style/conversion/constant.hpp>
+
+namespace mbgl {
+namespace style {
+namespace conversion {
+
+template <class T>
+struct Converter<Function<T>> {
+ template <class V>
+ Result<Function<T>> operator()(const V& value) const {
+ if (!isObject(value)) {
+ return Error { "function must be an object" };
+ }
+
+ auto stopsValue = objectMember(value, "stops");
+ if (!stopsValue) {
+ return Error { "function value must specify stops" };
+ }
+
+ if (!isArray(*stopsValue)) {
+ return Error { "function stops must be an array" };
+ }
+
+ std::vector<std::pair<float, T>> stops;
+ for (std::size_t i = 0; i < arrayLength(*stopsValue); ++i) {
+ const auto& stopValue = arrayMember(*stopsValue, i);
+
+ if (!isArray(stopValue)) {
+ return Error { "function stop must be an array" };
+ }
+
+ if (arrayLength(stopValue) != 2) {
+ return Error { "function stop must have two elements" };
+ }
+
+ optional<float> z = toNumber(arrayMember(stopValue, 0));
+ if (!z) {
+ return Error { "function stop zoom level must be a number" };
+ }
+
+ Result<T> v = convert<T>(arrayMember(stopValue, 1));
+ if (!v) {
+ return v.error();
+ }
+
+ stops.emplace_back(*z, *v);
+ }
+
+ auto baseValue = objectMember(value, "base");
+ if (!baseValue) {
+ return Function<T>(stops, 1.0f);
+ }
+
+ optional<float> base = toNumber(*baseValue);
+ if (!base) {
+ return Error { "function base must be a number"};
+ }
+
+ return Function<T>(stops, *base);
+ }
+};
+
+} // namespace conversion
+} // namespace style
+} // namespace mbgl
diff --git a/include/mbgl/style/conversion/property_value.hpp b/include/mbgl/style/conversion/property_value.hpp
new file mode 100644
index 0000000000..840643abbe
--- /dev/null
+++ b/include/mbgl/style/conversion/property_value.hpp
@@ -0,0 +1,34 @@
+#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>
+
+namespace mbgl {
+namespace style {
+namespace conversion {
+
+template <class T>
+struct Converter<PropertyValue<T>> {
+ template <class V>
+ Result<PropertyValue<T>> operator()(const V& value) const {
+ if (isObject(value)) {
+ Result<Function<T>> function = convert<Function<T>>(value);
+ if (!function) {
+ return function.error();
+ }
+ return *function;
+ } else {
+ Result<T> constant = convert<T>(value);
+ if (!constant) {
+ return constant.error();
+ }
+ return *constant;
+ }
+ }
+};
+
+} // namespace conversion
+} // namespace style
+} // namespace mbgl