#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