From 3459b83736f0e4eedfb95a1394d9e4ee1523b917 Mon Sep 17 00:00:00 2001 From: John Firebaugh Date: Tue, 21 Jun 2016 17:22:51 -0700 Subject: [core, node] Node bindings for setFilter --- include/mbgl/style/conversion.hpp | 132 +++++++++++++++++++++++++++++++++++++- 1 file changed, 131 insertions(+), 1 deletion(-) (limited to 'include/mbgl/style/conversion.hpp') diff --git a/include/mbgl/style/conversion.hpp b/include/mbgl/style/conversion.hpp index 0507d452fd..18326c8dd1 100644 --- a/include/mbgl/style/conversion.hpp +++ b/include/mbgl/style/conversion.hpp @@ -2,7 +2,7 @@ #include #include -#include +#include #include #include @@ -27,6 +27,12 @@ namespace conversion { This is used concretely for conversions from RapidJSON types in mbgl core, and from v8 types in the node bindings. + It also defines a convertion from `V` to `Filter`, representing a JSON object conforming to a Style + Specification filter object: + + template + Result convertFilter(const V& value); + The requirements are that the following are legal expressions for a value `v` of type `const V&`: * `isArray(v)` -- returns a boolean indicating whether `v` represents a JSON array @@ -41,6 +47,9 @@ namespace conversion { * `toBool(v)` -- returns `optional`, absence indicating `v` is not a JSON boolean * `toNumber(v)` -- returns `optional`, absence indicating `v` is not a JSON number * `toString(v)` -- returns `optional`, absence indicating `v` is not a JSON string + * `toValue(v)` -- returns `optional`, 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. If for any reason the conversion fails, the result of `convertPropertyValue` will be the `Error` variant, which includes explanatory text. @@ -258,6 +267,127 @@ Result> convertPropertyValue(const V& value) { return Function(stops, *base); } +Result normalizeFilterValue(const std::string& key, const optional&); + +template +Result convertFilter(const V& value); + +template +Result parseUnaryFilter(const V& value) { + 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 parseBinaryFilter(const V& value) { + 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 = normalizeFilterValue(*key, toValue(arrayMember(value, 2))); + if (filterValue.is()) { + return filterValue.get(); + } + + return FilterType { *key, filterValue.get() }; +} + +template +Result parseSetFilter(const V& value) { + 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 = normalizeFilterValue(*key, toValue(arrayMember(value, i))); + if (filterValue.is()) { + return filterValue.get(); + } + values.push_back(filterValue.get()); + } + + return FilterType { *key, std::move(values) }; +} + +template +Result parseCompoundFilter(const V& value) { + std::vector filters; + for (std::size_t i = 1; i < arrayLength(value); ++i) { + Result element = convertFilter(arrayMember(value, i)); + if (element.is()) { + return element; + } + filters.push_back(element.get()); + } + + return FilterType { std::move(filters) }; +} + +template +Result convertFilter(const V& value) { + 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 parseBinaryFilter(value); + } else if (*op == "!=") { + return parseBinaryFilter(value); + } else if (*op == ">") { + return parseBinaryFilter(value); + } else if (*op == ">=") { + return parseBinaryFilter(value); + } else if (*op == "<") { + return parseBinaryFilter(value); + } else if (*op == "<=") { + return parseBinaryFilter(value); + } else if (*op == "in") { + return parseSetFilter(value); + } else if (*op == "!in") { + return parseSetFilter(value); + } else if (*op == "all") { + return parseCompoundFilter(value); + } else if (*op == "any") { + return parseCompoundFilter(value); + } else if (*op == "none") { + return parseCompoundFilter(value); + } else if (*op == "has") { + return parseUnaryFilter(value); + } else if (*op == "!has") { + return parseUnaryFilter(value); + } + + return Error { "filter operator must be one of \"==\", \"!=\", \">\", \">=\", \"<\", \"<=\", \"in\", \"!in\", \"all\", \"any\", \"none\", \"has\", or \"!has\"" }; +} + } // namespace conversion } // namespace style } // namespace mbgl -- cgit v1.2.1