summaryrefslogtreecommitdiff
path: root/platform/darwin/src
diff options
context:
space:
mode:
authorFredrik Karlsson <bjorn.fredrik.karlsson@gmail.com>2016-08-17 13:38:02 +0200
committerFredrik Karlsson <bjorn.fredrik.karlsson@gmail.com>2016-09-02 22:42:05 +0200
commitd77a13eb7320722c48c8a18240adf99615c4b85f (patch)
tree1017781b310e434f943e4ad38b57f319ad7a3a58 /platform/darwin/src
parent6a39cf5aaece81c7a531b12321dd503004cc45b8 (diff)
downloadqtlocation-mapboxgl-d77a13eb7320722c48c8a18240adf99615c4b85f.tar.gz
[ios] Added support for filters (NSPredicate)
[ios, macos] cleaned up filters [ios] added a filter example [ios] utest filters [ios, macos] nested predicates [ios] refactored [ios] filter -> NSPredicate [ios] fixed mbgl::Any/AllFilter -> NSPredicate [ios] translate nested mbgl::NotIn filters [ios] cleanup and added more utests [ios] fixed a bug in the None filter conversion and improved utests [ios, macos] doc [macos] added missing category [ios, macos] additional utests [ios, macos] updated documentation
Diffstat (limited to 'platform/darwin/src')
-rw-r--r--platform/darwin/src/MGLBaseStyleLayer_Private.h2
-rw-r--r--platform/darwin/src/MGLCircleStyleLayer.h8
-rw-r--r--platform/darwin/src/MGLCircleStyleLayer.mm10
-rw-r--r--platform/darwin/src/MGLFeature.mm51
-rw-r--r--platform/darwin/src/MGLFillStyleLayer.h8
-rw-r--r--platform/darwin/src/MGLFillStyleLayer.mm10
-rw-r--r--platform/darwin/src/MGLLineStyleLayer.h8
-rw-r--r--platform/darwin/src/MGLLineStyleLayer.mm10
-rw-r--r--platform/darwin/src/MGLStyleLayer.h.ejs12
-rw-r--r--platform/darwin/src/MGLStyleLayer.mm.ejs12
-rw-r--r--platform/darwin/src/MGLSymbolStyleLayer.h8
-rw-r--r--platform/darwin/src/MGLSymbolStyleLayer.mm10
-rw-r--r--platform/darwin/src/MGLValueEvaluator.h49
-rw-r--r--platform/darwin/src/NSComparisonPredicate+MGLAdditions.h7
-rw-r--r--platform/darwin/src/NSComparisonPredicate+MGLAdditions.mm67
-rw-r--r--platform/darwin/src/NSCompoundPredicate+MGLAdditions.h7
-rw-r--r--platform/darwin/src/NSCompoundPredicate+MGLAdditions.mm56
-rw-r--r--platform/darwin/src/NSExpression+MGLAdditions.h11
-rw-r--r--platform/darwin/src/NSExpression+MGLAdditions.mm43
-rw-r--r--platform/darwin/src/NSPredicate+MGLAdditions.h13
-rw-r--r--platform/darwin/src/NSPredicate+MGLAdditions.mm107
21 files changed, 462 insertions, 47 deletions
diff --git a/platform/darwin/src/MGLBaseStyleLayer_Private.h b/platform/darwin/src/MGLBaseStyleLayer_Private.h
index e3d43906a4..0cbb076b35 100644
--- a/platform/darwin/src/MGLBaseStyleLayer_Private.h
+++ b/platform/darwin/src/MGLBaseStyleLayer_Private.h
@@ -1,5 +1,7 @@
#import "MGLBaseStyleLayer.h"
+#import "NSPredicate+MGLAdditions.h"
+
@interface MGLBaseStyleLayer (MGLBaseStyleLayer_Private)
- (void)update;
diff --git a/platform/darwin/src/MGLCircleStyleLayer.h b/platform/darwin/src/MGLCircleStyleLayer.h
index 7d2ef05848..e4430044ad 100644
--- a/platform/darwin/src/MGLCircleStyleLayer.h
+++ b/platform/darwin/src/MGLCircleStyleLayer.h
@@ -18,6 +18,14 @@ typedef NS_ENUM(NSUInteger, MGLCircleStyleLayerCirclePitchScale) {
@interface MGLCircleStyleLayer : MGLBaseStyleLayer <MGLStyleLayer>
+/**
+ A predicate that corresponds to the layer's <a href='https://www.mapbox.com/mapbox-gl-style-spec/#types-filter'>filter</a>.
+
+ The predicate's left expression must be a string that identifies a feature
+ property, or one of the special keys.
+ */
+@property (nonatomic, nullable) NSPredicate *predicate;
+
#pragma mark - Accessing the Paint Attributes
/**
diff --git a/platform/darwin/src/MGLCircleStyleLayer.mm b/platform/darwin/src/MGLCircleStyleLayer.mm
index 27be01505c..6c038318cc 100644
--- a/platform/darwin/src/MGLCircleStyleLayer.mm
+++ b/platform/darwin/src/MGLCircleStyleLayer.mm
@@ -29,6 +29,16 @@
return self;
}
+- (void)setPredicate:(NSPredicate *)predicate
+{
+ self.layer->setFilter(predicate.mgl_filter);
+}
+
+- (NSPredicate *)predicate
+{
+ return [NSPredicate mgl_predicateWithFilter:self.layer->getFilter()];
+}
+
#pragma mark - Accessing the Paint Attributes
- (void)setCircleRadius:(id <MGLStyleAttributeValue, MGLStyleAttributeValue_Private>)circleRadius {
diff --git a/platform/darwin/src/MGLFeature.mm b/platform/darwin/src/MGLFeature.mm
index 3bf1e61153..6d4f76a71d 100644
--- a/platform/darwin/src/MGLFeature.mm
+++ b/platform/darwin/src/MGLFeature.mm
@@ -3,6 +3,7 @@
#import "MGLPointAnnotation.h"
#import "MGLPolyline.h"
#import "MGLPolygon.h"
+#import "MGLValueEvaluator.h"
#import "MGLMultiPoint_Private.h"
@@ -113,51 +114,7 @@
@end
-/**
- Recursively transforms a C++ type into the corresponding Foundation type.
- */
-class PropertyValueEvaluator {
-public:
- id operator()(const mbgl::NullValue &) const {
- return [NSNull null];
- }
-
- id operator()(const bool &value) const {
- return value ? @YES : @NO;
- }
-
- id operator()(const uint64_t &value) const {
- return @(value);
- }
-
- id operator()(const int64_t &value) const {
- return @(value);
- }
-
- id operator()(const double &value) const {
- return @(value);
- }
-
- id operator()(const std::string &value) const {
- return @(value.c_str());
- }
-
- id operator()(const std::vector<mbgl::Value> &values) const {
- NSMutableArray *objects = [NSMutableArray arrayWithCapacity:values.size()];
- for (const auto &v : values) {
- [objects addObject:mbgl::Value::visit(v, *this)];
- }
- return objects;
- }
-
- id operator()(const std::unordered_map<std::string, mbgl::Value> &items) const {
- NSMutableDictionary *attributes = [NSMutableDictionary dictionaryWithCapacity:items.size()];
- for (auto &item : items) {
- attributes[@(item.first.c_str())] = mbgl::Value::visit(item.second, *this);
- }
- return attributes;
- }
-};
+
/**
Transforms an `mbgl::geometry::geometry` type into an instance of the
@@ -253,14 +210,14 @@ NS_ARRAY_OF(MGLShape <MGLFeature> *) *MGLFeaturesFromMBGLFeatures(const std::vec
NSMutableDictionary *attributes = [NSMutableDictionary dictionaryWithCapacity:feature.properties.size()];
for (auto &pair : feature.properties) {
auto &value = pair.second;
- PropertyValueEvaluator evaluator;
+ ValueEvaluator evaluator;
attributes[@(pair.first.c_str())] = mbgl::Value::visit(value, evaluator);
}
GeometryEvaluator<double> evaluator;
MGLShape <MGLFeaturePrivate> *shape = mapbox::geometry::geometry<double>::visit(feature.geometry, evaluator);
if (feature.id) {
- shape.identifier = mbgl::FeatureIdentifier::visit(*feature.id, PropertyValueEvaluator());
+ shape.identifier = mbgl::FeatureIdentifier::visit(*feature.id, ValueEvaluator());
}
shape.attributes = attributes;
[shapes addObject:shape];
diff --git a/platform/darwin/src/MGLFillStyleLayer.h b/platform/darwin/src/MGLFillStyleLayer.h
index c03e8ecae1..2d51f071e5 100644
--- a/platform/darwin/src/MGLFillStyleLayer.h
+++ b/platform/darwin/src/MGLFillStyleLayer.h
@@ -13,6 +13,14 @@ typedef NS_ENUM(NSUInteger, MGLFillStyleLayerFillTranslateAnchor) {
@interface MGLFillStyleLayer : MGLBaseStyleLayer <MGLStyleLayer>
+/**
+ A predicate that corresponds to the layer's <a href='https://www.mapbox.com/mapbox-gl-style-spec/#types-filter'>filter</a>.
+
+ The predicate's left expression must be a string that identifies a feature
+ property, or one of the special keys.
+ */
+@property (nonatomic, nullable) NSPredicate *predicate;
+
#pragma mark - Accessing the Paint Attributes
/**
diff --git a/platform/darwin/src/MGLFillStyleLayer.mm b/platform/darwin/src/MGLFillStyleLayer.mm
index 192235f69e..c54ddba428 100644
--- a/platform/darwin/src/MGLFillStyleLayer.mm
+++ b/platform/darwin/src/MGLFillStyleLayer.mm
@@ -29,6 +29,16 @@
return self;
}
+- (void)setPredicate:(NSPredicate *)predicate
+{
+ self.layer->setFilter(predicate.mgl_filter);
+}
+
+- (NSPredicate *)predicate
+{
+ return [NSPredicate mgl_predicateWithFilter:self.layer->getFilter()];
+}
+
#pragma mark - Accessing the Paint Attributes
- (void)setFillAntialias:(id <MGLStyleAttributeValue, MGLStyleAttributeValue_Private>)fillAntialias {
diff --git a/platform/darwin/src/MGLLineStyleLayer.h b/platform/darwin/src/MGLLineStyleLayer.h
index 435829c502..5c2a3afc2e 100644
--- a/platform/darwin/src/MGLLineStyleLayer.h
+++ b/platform/darwin/src/MGLLineStyleLayer.h
@@ -25,6 +25,14 @@ typedef NS_ENUM(NSUInteger, MGLLineStyleLayerLineTranslateAnchor) {
@interface MGLLineStyleLayer : MGLBaseStyleLayer <MGLStyleLayer>
+/**
+ A predicate that corresponds to the layer's <a href='https://www.mapbox.com/mapbox-gl-style-spec/#types-filter'>filter</a>.
+
+ The predicate's left expression must be a string that identifies a feature
+ property, or one of the special keys.
+ */
+@property (nonatomic, nullable) NSPredicate *predicate;
+
#pragma mark - Accessing the Layout Attributes
/**
diff --git a/platform/darwin/src/MGLLineStyleLayer.mm b/platform/darwin/src/MGLLineStyleLayer.mm
index ffb0d4e394..ce9ad75f87 100644
--- a/platform/darwin/src/MGLLineStyleLayer.mm
+++ b/platform/darwin/src/MGLLineStyleLayer.mm
@@ -29,6 +29,16 @@
return self;
}
+- (void)setPredicate:(NSPredicate *)predicate
+{
+ self.layer->setFilter(predicate.mgl_filter);
+}
+
+- (NSPredicate *)predicate
+{
+ return [NSPredicate mgl_predicateWithFilter:self.layer->getFilter()];
+}
+
#pragma mark - Accessing the Layout Attributes
- (void)setLineCap:(id <MGLStyleAttributeValue, MGLStyleAttributeValue_Private>)lineCap {
diff --git a/platform/darwin/src/MGLStyleLayer.h.ejs b/platform/darwin/src/MGLStyleLayer.h.ejs
index 2b36a3067a..8acda024c4 100644
--- a/platform/darwin/src/MGLStyleLayer.h.ejs
+++ b/platform/darwin/src/MGLStyleLayer.h.ejs
@@ -35,6 +35,16 @@ typedef NS_ENUM(NSUInteger, MGL<%- camelize(type) %>StyleLayer<%- camelize(prope
<% } -%>
@interface MGL<%- camelize(type) %>StyleLayer : MGLBaseStyleLayer <MGLStyleLayer>
+<% if (type !== 'background' && type !== 'raster') { -%>
+/**
+ A predicate that corresponds to the layer's <a href='https://www.mapbox.com/mapbox-gl-style-spec/#types-filter'>filter</a>.
+
+ The predicate's left expression must be a string that identifies a feature
+ property, or one of the special keys.
+ */
+@property (nonatomic, nullable) NSPredicate *predicate;
+
+<% } -%>
<% if (layoutProperties.length) { -%>
#pragma mark - Accessing the Layout Attributes
@@ -53,6 +63,7 @@ typedef NS_ENUM(NSUInteger, MGL<%- camelize(type) %>StyleLayer<%- camelize(prope
<% } -%>
<% } -%>
+<% if (paintProperties.length) { -%>
#pragma mark - Accessing the Paint Attributes
<% for (const property of paintProperties) { -%>
@@ -69,6 +80,7 @@ typedef NS_ENUM(NSUInteger, MGL<%- camelize(type) %>StyleLayer<%- camelize(prope
@property (nonatomic<% if (!property.required) { %>, null_resettable<% } %>) <%- propertyType(property, false, type) %> <%- camelizeWithLeadingLowercase(property.name) %>;
<% } -%>
+<% } -%>
@end
NS_ASSUME_NONNULL_END
diff --git a/platform/darwin/src/MGLStyleLayer.mm.ejs b/platform/darwin/src/MGLStyleLayer.mm.ejs
index c35d254caf..4e59c3c6cb 100644
--- a/platform/darwin/src/MGLStyleLayer.mm.ejs
+++ b/platform/darwin/src/MGLStyleLayer.mm.ejs
@@ -34,6 +34,18 @@
return self;
}
+<% if (type !== 'background' && type !== 'raster') { -%>
+- (void)setPredicate:(NSPredicate *)predicate
+{
+ self.layer->setFilter(predicate.mgl_filter);
+}
+
+- (NSPredicate *)predicate
+{
+ return [NSPredicate mgl_predicateWithFilter:self.layer->getFilter()];
+}
+
+<% } -%>
<% if (layoutProperties.length) { -%>
#pragma mark - Accessing the Layout Attributes
diff --git a/platform/darwin/src/MGLSymbolStyleLayer.h b/platform/darwin/src/MGLSymbolStyleLayer.h
index ef88ff996e..eacd158dda 100644
--- a/platform/darwin/src/MGLSymbolStyleLayer.h
+++ b/platform/darwin/src/MGLSymbolStyleLayer.h
@@ -69,6 +69,14 @@ typedef NS_ENUM(NSUInteger, MGLSymbolStyleLayerTextTranslateAnchor) {
@interface MGLSymbolStyleLayer : MGLBaseStyleLayer <MGLStyleLayer>
+/**
+ A predicate that corresponds to the layer's <a href='https://www.mapbox.com/mapbox-gl-style-spec/#types-filter'>filter</a>.
+
+ The predicate's left expression must be a string that identifies a feature
+ property, or one of the special keys.
+ */
+@property (nonatomic, nullable) NSPredicate *predicate;
+
#pragma mark - Accessing the Layout Attributes
/**
diff --git a/platform/darwin/src/MGLSymbolStyleLayer.mm b/platform/darwin/src/MGLSymbolStyleLayer.mm
index 159e3c4d0b..b0553ea425 100644
--- a/platform/darwin/src/MGLSymbolStyleLayer.mm
+++ b/platform/darwin/src/MGLSymbolStyleLayer.mm
@@ -29,6 +29,16 @@
return self;
}
+- (void)setPredicate:(NSPredicate *)predicate
+{
+ self.layer->setFilter(predicate.mgl_filter);
+}
+
+- (NSPredicate *)predicate
+{
+ return [NSPredicate mgl_predicateWithFilter:self.layer->getFilter()];
+}
+
#pragma mark - Accessing the Layout Attributes
- (void)setSymbolPlacement:(id <MGLStyleAttributeValue, MGLStyleAttributeValue_Private>)symbolPlacement {
diff --git a/platform/darwin/src/MGLValueEvaluator.h b/platform/darwin/src/MGLValueEvaluator.h
new file mode 100644
index 0000000000..b53cdaa8d2
--- /dev/null
+++ b/platform/darwin/src/MGLValueEvaluator.h
@@ -0,0 +1,49 @@
+#import <Foundation/Foundation.h>
+
+#import <mbgl/util/geometry.hpp>
+
+/**
+ Recursively transforms a C++ type into the corresponding Foundation type.
+ */
+class ValueEvaluator {
+public:
+ id operator()(const mbgl::NullValue &) const {
+ return [NSNull null];
+ }
+
+ id operator()(const bool &value) const {
+ return value ? @YES : @NO;
+ }
+
+ id operator()(const uint64_t &value) const {
+ return @(value);
+ }
+
+ id operator()(const int64_t &value) const {
+ return @(value);
+ }
+
+ id operator()(const double &value) const {
+ return @(value);
+ }
+
+ id operator()(const std::string &value) const {
+ return @(value.c_str());
+ }
+
+ id operator()(const std::vector<mbgl::Value> &values) const {
+ NSMutableArray *objects = [NSMutableArray arrayWithCapacity:values.size()];
+ for (const auto &v : values) {
+ [objects addObject:mbgl::Value::visit(v, *this)];
+ }
+ return objects;
+ }
+
+ id operator()(const std::unordered_map<std::string, mbgl::Value> &items) const {
+ NSMutableDictionary *attributes = [NSMutableDictionary dictionaryWithCapacity:items.size()];
+ for (auto &item : items) {
+ attributes[@(item.first.c_str())] = mbgl::Value::visit(item.second, *this);
+ }
+ return attributes;
+ }
+};
diff --git a/platform/darwin/src/NSComparisonPredicate+MGLAdditions.h b/platform/darwin/src/NSComparisonPredicate+MGLAdditions.h
new file mode 100644
index 0000000000..2cd4dd1577
--- /dev/null
+++ b/platform/darwin/src/NSComparisonPredicate+MGLAdditions.h
@@ -0,0 +1,7 @@
+#import <Foundation/Foundation.h>
+
+#include <mbgl/style/filter.hpp>
+
+@interface NSComparisonPredicate (MGLAdditions)
+
+@end
diff --git a/platform/darwin/src/NSComparisonPredicate+MGLAdditions.mm b/platform/darwin/src/NSComparisonPredicate+MGLAdditions.mm
new file mode 100644
index 0000000000..ced6a1ac47
--- /dev/null
+++ b/platform/darwin/src/NSComparisonPredicate+MGLAdditions.mm
@@ -0,0 +1,67 @@
+#import "NSComparisonPredicate+MGLAdditions.h"
+
+#import "NSPredicate+MGLAdditions.h"
+#import "NSExpression+MGLAdditions.h"
+
+@implementation NSComparisonPredicate (MGLAdditions)
+
+- (mbgl::style::Filter)mgl_filter
+{
+ switch (self.predicateOperatorType) {
+ case NSEqualToPredicateOperatorType: {
+ auto filter = mbgl::style::EqualsFilter();
+ filter.key = self.leftExpression.keyPath.UTF8String;
+ filter.value = self.rightExpression.mgl_filterValue;
+ return filter;
+ }
+ case NSNotEqualToPredicateOperatorType: {
+ auto filter = mbgl::style::NotEqualsFilter();
+ filter.key = self.leftExpression.keyPath.UTF8String;
+ filter.value = self.rightExpression.mgl_filterValue;
+ return filter;
+ }
+ case NSGreaterThanPredicateOperatorType: {
+ auto filter = mbgl::style::GreaterThanFilter();
+ filter.key = self.leftExpression.keyPath.UTF8String;
+ filter.value = self.rightExpression.mgl_filterValue;
+ return filter;
+ }
+ case NSGreaterThanOrEqualToPredicateOperatorType: {
+ auto filter = mbgl::style::GreaterThanEqualsFilter();
+ filter.key = self.leftExpression.keyPath.UTF8String;
+ filter.value = self.rightExpression.mgl_filterValue;
+ return filter;
+ }
+ case NSLessThanPredicateOperatorType: {
+ auto filter = mbgl::style::LessThanFilter();
+ filter.key = self.leftExpression.keyPath.UTF8String;
+ filter.value = self.rightExpression.mgl_filterValue;
+ return filter;
+ }
+ case NSLessThanOrEqualToPredicateOperatorType: {
+ auto filter = mbgl::style::LessThanEqualsFilter();
+ filter.key = self.leftExpression.keyPath.UTF8String;
+ filter.value = self.rightExpression.mgl_filterValue;
+ return filter;
+ }
+ case NSInPredicateOperatorType: {
+ auto filter = mbgl::style::InFilter();
+ filter.key = self.leftExpression.keyPath.UTF8String;
+ filter.values = self.rightExpression.mgl_filterValues;
+ return filter;
+ }
+ case NSMatchesPredicateOperatorType:
+ case NSLikePredicateOperatorType:
+ case NSBeginsWithPredicateOperatorType:
+ case NSEndsWithPredicateOperatorType:
+ case NSCustomSelectorPredicateOperatorType:
+ case NSContainsPredicateOperatorType:
+ case NSBetweenPredicateOperatorType:
+ [NSException raise:@"Unsupported operator type"
+ format:@"NSPredicateOperatorType:%lu is not supported.", (unsigned long)self.predicateOperatorType];
+ }
+
+ return {};
+}
+
+@end
diff --git a/platform/darwin/src/NSCompoundPredicate+MGLAdditions.h b/platform/darwin/src/NSCompoundPredicate+MGLAdditions.h
new file mode 100644
index 0000000000..0f9909255d
--- /dev/null
+++ b/platform/darwin/src/NSCompoundPredicate+MGLAdditions.h
@@ -0,0 +1,7 @@
+#import <Foundation/Foundation.h>
+
+#include <mbgl/style/filter.hpp>
+
+@interface NSCompoundPredicate (MGLAdditions)
+
+@end
diff --git a/platform/darwin/src/NSCompoundPredicate+MGLAdditions.mm b/platform/darwin/src/NSCompoundPredicate+MGLAdditions.mm
new file mode 100644
index 0000000000..07114308c9
--- /dev/null
+++ b/platform/darwin/src/NSCompoundPredicate+MGLAdditions.mm
@@ -0,0 +1,56 @@
+#import "NSCompoundPredicate+MGLAdditions.h"
+
+#import "NSPredicate+MGLAdditions.h"
+#import "NSExpression+MGLAdditions.h"
+
+@implementation NSCompoundPredicate (MGLAdditions)
+
+- (std::vector<mbgl::style::Filter>)mgl_subfilters
+{
+ std::vector<mbgl::style::Filter>filters;
+ for (NSPredicate *predicate in self.subpredicates) {
+ filters.push_back(predicate.mgl_filter);
+ }
+ return filters;
+}
+
+- (mbgl::style::Filter)mgl_filter
+{
+ switch (self.compoundPredicateType) {
+ case NSNotPredicateType: {
+
+ // Translate a nested NSComparisonPredicate with operator type NSInPredicateOperatorType into a flat mbgl::NotIn filter.
+ NSArray<NSComparisonPredicate *> *comparisonPredicates = [self.subpredicates filteredArrayUsingPredicate:[NSPredicate predicateWithFormat:@"class == %@", [NSComparisonPredicate class]]];
+ NSArray<NSComparisonPredicate *> *notInPredicates = [comparisonPredicates filteredArrayUsingPredicate:[NSPredicate predicateWithBlock:^BOOL(NSComparisonPredicate *_Nonnull predicate, NSDictionary<NSString *,id> * _Nullable bindings) {
+ return predicate.predicateOperatorType == NSInPredicateOperatorType;
+ }]];
+
+ if (notInPredicates.count) {
+ auto filter = mbgl::style::NotInFilter();
+ filter.key = notInPredicates.firstObject.leftExpression.keyPath.UTF8String;
+ filter.values = notInPredicates.firstObject.rightExpression.mgl_filterValues;
+ return filter;
+ } else {
+ auto filter = mbgl::style::NoneFilter();
+ filter.filters = [self mgl_subfilters];
+ return filter;
+ }
+ }
+ case NSAndPredicateType: {
+ auto filter = mbgl::style::AllFilter();
+ filter.filters = [self mgl_subfilters];
+ return filter;
+ }
+ case NSOrPredicateType: {
+ auto filter = mbgl::style::AnyFilter();
+ filter.filters = [self mgl_subfilters];
+ return filter;
+ }
+ }
+
+ [NSException raise:@"Compound predicate type not handled"
+ format:@""];
+ return {};
+}
+
+@end
diff --git a/platform/darwin/src/NSExpression+MGLAdditions.h b/platform/darwin/src/NSExpression+MGLAdditions.h
new file mode 100644
index 0000000000..4e8c5ee071
--- /dev/null
+++ b/platform/darwin/src/NSExpression+MGLAdditions.h
@@ -0,0 +1,11 @@
+#import <Foundation/Foundation.h>
+
+#include <mbgl/style/filter.hpp>
+
+@interface NSExpression (MGLAdditions)
+
+- (mbgl::Value)mgl_filterValue;
+
+- (std::vector<mbgl::Value>)mgl_filterValues;
+
+@end
diff --git a/platform/darwin/src/NSExpression+MGLAdditions.mm b/platform/darwin/src/NSExpression+MGLAdditions.mm
new file mode 100644
index 0000000000..5f1a1e765a
--- /dev/null
+++ b/platform/darwin/src/NSExpression+MGLAdditions.mm
@@ -0,0 +1,43 @@
+#import "NSExpression+MGLAdditions.h"
+
+@implementation NSExpression (MGLAdditions)
+
+- (std::vector<mbgl::Value>)mgl_filterValues
+{
+ if ([self.constantValue isKindOfClass:NSArray.class]) {
+ NSArray *values = self.constantValue;
+ std::vector<mbgl::Value>convertedValues;
+ for (id value in values) {
+ convertedValues.push_back([self mgl_convertedValueWithValue:value]);
+ }
+ return convertedValues;
+ }
+ [NSException raise:@"Values not handled" format:@""];
+ return { };
+}
+
+- (mbgl::Value)mgl_filterValue
+{
+ return [self mgl_convertedValueWithValue:self.constantValue];
+}
+
+- (mbgl::Value)mgl_convertedValueWithValue:(id)value
+{
+ if ([value isKindOfClass:NSString.class]) {
+ return { std::string([(NSString *)value UTF8String]) };
+ } else if ([value isKindOfClass:NSNumber.class]) {
+ NSNumber *number = (NSNumber *)value;
+ if((strcmp([number objCType], @encode(int))) == 0) {
+ return { number.intValue };
+ } else if ((strcmp([number objCType], @encode(double))) == 0) {
+ return { number.doubleValue };
+ } else if ((strcmp([number objCType], @encode(bool))) == 0) {
+ return { number.boolValue };
+ }
+ }
+ [NSException raise:@"Value not handled"
+ format:@"Can’t convert %s:%@ to mbgl::Value", [value objCType], value];
+ return { };
+}
+
+@end
diff --git a/platform/darwin/src/NSPredicate+MGLAdditions.h b/platform/darwin/src/NSPredicate+MGLAdditions.h
new file mode 100644
index 0000000000..fd774dd58b
--- /dev/null
+++ b/platform/darwin/src/NSPredicate+MGLAdditions.h
@@ -0,0 +1,13 @@
+#import <Foundation/Foundation.h>
+
+#import "NSExpression+MGLAdditions.h"
+#include <mbgl/style/filter.hpp>
+
+@interface NSPredicate (MGLAdditions)
+
+- (mbgl::style::Filter)mgl_filter;
+
++ (instancetype)mgl_predicateWithFilter:(mbgl::style::Filter)filter;
+
+@end
+
diff --git a/platform/darwin/src/NSPredicate+MGLAdditions.mm b/platform/darwin/src/NSPredicate+MGLAdditions.mm
new file mode 100644
index 0000000000..9c3f9c888c
--- /dev/null
+++ b/platform/darwin/src/NSPredicate+MGLAdditions.mm
@@ -0,0 +1,107 @@
+#import "NSPredicate+MGLAdditions.h"
+
+#import "MGLValueEvaluator.h"
+
+class FilterEvaluator {
+public:
+
+ NSArray* getPredicates(std::vector<mbgl::style::Filter> filters) {
+ NSMutableArray *predicates = [NSMutableArray arrayWithCapacity:filters.size()];
+ for (auto filter : filters) {
+ [predicates addObject:mbgl::style::Filter::visit(filter, FilterEvaluator())];
+ }
+ return predicates;
+ }
+
+ NSArray* getValues(std::vector<mbgl::Value> values) {
+ NSMutableArray *array = [NSMutableArray arrayWithCapacity:values.size()];
+ for (auto value : values) {
+ [array addObject:mbgl::Value::visit(value, ValueEvaluator())];
+ }
+ return array;
+ }
+
+ NSPredicate* operator()(mbgl::style::NullFilter filter) {
+ return nil;
+ }
+
+ NSPredicate* operator()(mbgl::style::EqualsFilter filter) {
+ return [NSPredicate predicateWithFormat:@"%K == %@", @(filter.key.c_str()), mbgl::Value::visit(filter.value, ValueEvaluator())];
+ }
+
+ NSPredicate* operator()(mbgl::style::NotEqualsFilter filter) {
+ return [NSPredicate predicateWithFormat:@"%K != %@", @(filter.key.c_str()), mbgl::Value::visit(filter.value, ValueEvaluator())];
+ }
+
+ NSPredicate* operator()(mbgl::style::GreaterThanFilter filter) {
+ return [NSPredicate predicateWithFormat:@"%K > %@", @(filter.key.c_str()), mbgl::Value::visit(filter.value, ValueEvaluator())];
+ }
+
+ NSPredicate* operator()(mbgl::style::GreaterThanEqualsFilter filter) {
+ return [NSPredicate predicateWithFormat:@"%K >= %@", @(filter.key.c_str()), mbgl::Value::visit(filter.value, ValueEvaluator())];
+ }
+
+ NSPredicate* operator()(mbgl::style::LessThanFilter filter) {
+ return [NSPredicate predicateWithFormat:@"%K < %@", @(filter.key.c_str()), mbgl::Value::visit(filter.value, ValueEvaluator())];
+ }
+
+ NSPredicate* operator()(mbgl::style::LessThanEqualsFilter filter) {
+ return [NSPredicate predicateWithFormat:@"%K <= %@", @(filter.key.c_str()), mbgl::Value::visit(filter.value, ValueEvaluator())];
+ }
+
+ NSPredicate* operator()(mbgl::style::InFilter filter) {
+ return [NSPredicate predicateWithFormat:@"%K IN %@", @(filter.key.c_str()), getValues(filter.values)];
+ }
+
+ NSPredicate* operator()(mbgl::style::NotInFilter filter) {
+ return [NSPredicate predicateWithFormat:@"NOT %K IN %@", @(filter.key.c_str()), getValues(filter.values)];
+ }
+
+ NSPredicate* operator()(mbgl::style::AnyFilter filter) {
+ return [NSCompoundPredicate orPredicateWithSubpredicates:getPredicates(filter.filters)];
+ }
+
+ NSPredicate* operator()(mbgl::style::AllFilter filter) {
+ return [NSCompoundPredicate andPredicateWithSubpredicates:getPredicates(filter.filters)];
+ }
+
+ NSPredicate* operator()(mbgl::style::NoneFilter filter) {
+ NSArray *predicates = getPredicates(filter.filters);
+ if (predicates.count > 1) {
+ NSCompoundPredicate *predicate = [NSCompoundPredicate andPredicateWithSubpredicates:predicates];
+ return [NSCompoundPredicate notPredicateWithSubpredicate:predicate];
+ } else {
+ return [NSCompoundPredicate notPredicateWithSubpredicate:predicates.firstObject];
+ }
+ }
+
+ NSPredicate* operator()(mbgl::style::HasFilter filter) {
+ [NSException raise:@"Unsupported filter type"
+ format:@"Cannot convert mbgl::style::HasFilter to NSPredicate"];
+ return nil;
+ }
+
+ NSPredicate* operator()(mbgl::style::NotHasFilter filter) {
+ [NSException raise:@"Unsupported filter type"
+ format:@"Cannot convert mbgl::style::NotHasFilter to NSPredicate"];
+ return nil;
+ }
+
+};
+
+@implementation NSPredicate (MGLAdditions)
+
+- (mbgl::style::Filter)mgl_filter
+{
+ [NSException raise:@"Not supported"
+ format:@"NSPredicate doesn't implement ’-mgl_filter’. Try with NSComparisonPredicate or NSCompoundPredicate instead."];
+ return {};
+}
+
++ (instancetype)mgl_predicateWithFilter:(mbgl::style::Filter)filter
+{
+ FilterEvaluator evaluator;
+ return mbgl::style::Filter::visit(filter, evaluator);
+}
+
+@end