From 089c4e413fbe80711ebd874520d3b8fdcb997112 Mon Sep 17 00:00:00 2001 From: John Firebaugh Date: Wed, 22 Jun 2016 12:31:49 -0700 Subject: [core] Split up and clean up conversion.hpp --- include/mbgl/style/conversion/constant.hpp | 174 +++++++++++++++++++++++ include/mbgl/style/conversion/filter.hpp | 150 +++++++++++++++++++ include/mbgl/style/conversion/function.hpp | 69 +++++++++ include/mbgl/style/conversion/property_value.hpp | 34 +++++ 4 files changed, 427 insertions(+) create mode 100644 include/mbgl/style/conversion/constant.hpp create mode 100644 include/mbgl/style/conversion/filter.hpp create mode 100644 include/mbgl/style/conversion/function.hpp create mode 100644 include/mbgl/style/conversion/property_value.hpp (limited to 'include/mbgl/style/conversion') 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 +#include +#include +#include + +#include +#include +#include + +namespace mbgl { +namespace style { +namespace conversion { + +template <> +struct Converter { + template + Result operator()(const V& value) const { + optional converted = toBool(value); + if (!converted) { + return Error { "value must be a boolean" }; + } + return *converted; + } +}; + +template <> +struct Converter { + template + Result operator()(const V& value) const { + optional converted = toNumber(value); + if (!converted) { + return Error { "value must be a number" }; + } + return *converted; + } +}; + +template <> +struct Converter { + template + Result operator()(const V& value) const { + optional converted = toString(value); + if (!converted) { + return Error { "value must be a string" }; + } + return *converted; + } +}; + +template +struct Converter::value>> { + template + Result operator()(const V& value) const { + optional string = toString(value); + if (!string) { + return Error { "value must be a string" }; + } + + const auto result = Enum::toEnum(*string); + if (!result) { + return Error { "value must be a valid enumeration value" }; + } + + return *result; + } +}; + +template <> +struct Converter { + template + Result operator()(const V& value) const { + optional string = toString(value); + if (!string) { + return Error { "value must be a string" }; + } + + optional color = Color::parse(*string); + if (!color) { + return Error { "value must be a valid color" }; + } + + return *color; + } +}; + +template <> +struct Converter> { + template + Result> operator()(const V& value) const { + if (!isArray(value) || arrayLength(value) != 2) { + return Error { "value must be an array of two numbers" }; + } + + optional first = toNumber(arrayMember(value, 0)); + optional second = toNumber(arrayMember(value, 1)); + if (!first || !second) { + return Error { "value must be an array of two numbers" }; + } + + return std::array {{ *first, *second }}; + } +}; + +template <> +struct Converter> { + template + Result> operator()(const V& value) const { + if (!isArray(value) || arrayLength(value) != 4) { + return Error { "value must be an array of four numbers" }; + } + + optional first = toNumber(arrayMember(value, 0)); + optional second = toNumber(arrayMember(value, 1)); + optional third = toNumber(arrayMember(value, 2)); + optional fourth = toNumber(arrayMember(value, 3)); + if (!first || !second) { + return Error { "value must be an array of four numbers" }; + } + + return std::array {{ *first, *second, *third, *fourth }}; + } +}; + +template <> +struct Converter> { + template + Result> operator()(const V& value) const { + if (!isArray(value)) { + return Error { "value must be an array" }; + } + + std::vector result; + result.reserve(arrayLength(value)); + + for (std::size_t i = 0; i < arrayLength(value); ++i) { + optional 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> { + template + Result> operator()(const V& value) const { + if (!isArray(value)) { + return Error { "value must be an array" }; + } + + std::vector result; + result.reserve(arrayLength(value)); + + for (std::size_t i = 0; i < arrayLength(value); ++i) { + optional 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 +#include +#include + +namespace mbgl { +namespace style { +namespace conversion { + +template <> +struct Converter { +public: + template + Result 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 op = toString(arrayMember(value, 0)); + if (!op) { + return Error { "filter operator must be a string" }; + } + + if (*op == "==") { + return convertBinaryFilter(value); + } else if (*op == "!=") { + return convertBinaryFilter(value); + } else if (*op == ">") { + return convertBinaryFilter(value); + } else if (*op == ">=") { + return convertBinaryFilter(value); + } else if (*op == "<") { + return convertBinaryFilter(value); + } else if (*op == "<=") { + return convertBinaryFilter(value); + } else if (*op == "in") { + return convertSetFilter(value); + } else if (*op == "!in") { + return convertSetFilter(value); + } else if (*op == "all") { + return convertCompoundFilter(value); + } else if (*op == "any") { + return convertCompoundFilter(value); + } else if (*op == "none") { + return convertCompoundFilter(value); + } else if (*op == "has") { + return convertUnaryFilter(value); + } else if (*op == "!has") { + return convertUnaryFilter(value); + } + + return Error { "filter operator must be one of \"==\", \"!=\", \">\", \">=\", \"<\", \"<=\", \"in\", \"!in\", \"all\", \"any\", \"none\", \"has\", or \"!has\"" }; + } + +private: + Result normalizeValue(const std::string& key, const optional& 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 + Result convertUnaryFilter(const V& value) const { + if (arrayLength(value) < 2) { + return Error { "filter expression must have 2 elements" }; + } + + optional key = toString(arrayMember(value, 1)); + if (!key) { + return Error { "filter expression key must be a string" }; + } + + return FilterType { *key }; + } + + template + Result convertBinaryFilter(const V& value) const { + if (arrayLength(value) < 3) { + return Error { "filter expression must have 3 elements" }; + } + + optional key = toString(arrayMember(value, 1)); + if (!key) { + return Error { "filter expression key must be a string" }; + } + + Result filterValue = normalizeValue(*key, toValue(arrayMember(value, 2))); + if (!filterValue) { + return filterValue.error(); + } + + return FilterType { *key, *filterValue }; + } + + template + Result convertSetFilter(const V& value) const { + if (arrayLength(value) < 2) { + return Error { "filter expression must at least 2 elements" }; + } + + optional key = toString(arrayMember(value, 1)); + if (!key) { + return Error { "filter expression key must be a string" }; + } + + std::vector values; + for (std::size_t i = 2; i < arrayLength(value); ++i) { + Result filterValue = normalizeValue(*key, toValue(arrayMember(value, i))); + if (!filterValue) { + return filterValue.error(); + } + values.push_back(*filterValue); + } + + return FilterType { *key, std::move(values) }; + } + + template + Result convertCompoundFilter(const V& value) const { + std::vector filters; + for (std::size_t i = 1; i < arrayLength(value); ++i) { + Result 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 +#include +#include + +namespace mbgl { +namespace style { +namespace conversion { + +template +struct Converter> { + template + Result> 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> 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 z = toNumber(arrayMember(stopValue, 0)); + if (!z) { + return Error { "function stop zoom level must be a number" }; + } + + Result v = convert(arrayMember(stopValue, 1)); + if (!v) { + return v.error(); + } + + stops.emplace_back(*z, *v); + } + + auto baseValue = objectMember(value, "base"); + if (!baseValue) { + return Function(stops, 1.0f); + } + + optional base = toNumber(*baseValue); + if (!base) { + return Error { "function base must be a number"}; + } + + return Function(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 +#include +#include +#include + +namespace mbgl { +namespace style { +namespace conversion { + +template +struct Converter> { + template + Result> operator()(const V& value) const { + if (isObject(value)) { + Result> function = convert>(value); + if (!function) { + return function.error(); + } + return *function; + } else { + Result constant = convert(value); + if (!constant) { + return constant.error(); + } + return *constant; + } + } +}; + +} // namespace conversion +} // namespace style +} // namespace mbgl -- cgit v1.2.1