summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJohn Firebaugh <john.firebaugh@gmail.com>2017-03-07 17:00:53 -0800
committerJohn Firebaugh <john.firebaugh@gmail.com>2017-03-23 13:31:13 -0700
commitd7227e13a7a87cf50a4c8c1f0615fc565f5a2679 (patch)
treeeda76a2da3220f3cfeec901400369cf9c8361f58
parent1c757cce34344dfecc9a724034680225143f92b7 (diff)
downloadqtlocation-mapboxgl-d7227e13a7a87cf50a4c8c1f0615fc565f5a2679.tar.gz
[all] Replace Result<T> with optional<T> plus out Error parameter
-rw-r--r--benchmark/parse/filter.benchmark.cpp3
-rw-r--r--cmake/core-files.cmake2
-rw-r--r--include/mbgl/style/conversion.hpp39
-rw-r--r--include/mbgl/style/conversion/constant.hpp63
-rw-r--r--include/mbgl/style/conversion/data_driven_property_value.hpp18
-rw-r--r--include/mbgl/style/conversion/filter.hpp157
-rw-r--r--include/mbgl/style/conversion/function.hpp175
-rw-r--r--include/mbgl/style/conversion/geojson.hpp2
-rw-r--r--include/mbgl/style/conversion/geojson_options.hpp20
-rw-r--r--include/mbgl/style/conversion/layer.hpp88
-rw-r--r--include/mbgl/style/conversion/property_setter.hpp20
-rw-r--r--include/mbgl/style/conversion/property_value.hpp16
-rw-r--r--include/mbgl/style/conversion/source.hpp79
-rw-r--r--include/mbgl/style/conversion/tileset.hpp20
-rw-r--r--include/mbgl/style/conversion/transition_options.hpp11
-rw-r--r--platform/android/src/style/conversion/filter.hpp5
-rw-r--r--platform/android/src/style/conversion/geojson.hpp17
-rw-r--r--platform/android/src/style/conversion/url_or_tileset.hpp36
-rw-r--r--platform/android/src/style/layers/layer.cpp5
-rw-r--r--platform/android/src/style/sources/geojson_source.cpp26
-rw-r--r--platform/android/src/style/sources/raster_source.cpp2
-rw-r--r--platform/android/src/style/sources/vector_source.cpp2
-rw-r--r--platform/darwin/src/MGLStyleValue_Private.h5
-rw-r--r--platform/node/src/node_geojson.hpp5
-rw-r--r--platform/node/src/node_map.cpp30
-rw-r--r--platform/qt/src/qmapboxgl.cpp18
-rw-r--r--platform/qt/src/qt_geojson.hpp20
-rw-r--r--src/mbgl/style/parser.cpp22
-rw-r--r--src/mbgl/style/property_parsing.cpp29
-rw-r--r--src/mbgl/style/property_parsing.hpp26
-rw-r--r--src/mbgl/style/sources/geojson_source_impl.cpp10
-rw-r--r--src/mbgl/style/tile_source_impl.cpp5
-rw-r--r--test/style/conversion/function.test.cpp30
-rw-r--r--test/style/conversion/geojson_options.test.cpp12
-rw-r--r--test/style/conversion/layer.test.cpp13
-rw-r--r--test/style/filter.test.cpp5
36 files changed, 550 insertions, 486 deletions
diff --git a/benchmark/parse/filter.benchmark.cpp b/benchmark/parse/filter.benchmark.cpp
index 3918f03539..d650cb72c9 100644
--- a/benchmark/parse/filter.benchmark.cpp
+++ b/benchmark/parse/filter.benchmark.cpp
@@ -14,7 +14,8 @@ using namespace mbgl;
style::Filter parse(const char* expression) {
rapidjson::GenericDocument<rapidjson::UTF8<>, rapidjson::CrtAllocator> doc;
doc.Parse<0>(expression);
- return *style::conversion::convert<style::Filter, JSValue>(doc);
+ style::conversion::Error error;
+ return *style::conversion::convert<style::Filter, JSValue>(doc, error);
}
static void Parse_Filter(benchmark::State& state) {
diff --git a/cmake/core-files.cmake b/cmake/core-files.cmake
index 45a3ed25b3..e98f999116 100644
--- a/cmake/core-files.cmake
+++ b/cmake/core-files.cmake
@@ -276,8 +276,6 @@ set(MBGL_CORE_FILES
src/mbgl/style/possibly_evaluated_property_value.hpp
src/mbgl/style/property_evaluation_parameters.hpp
src/mbgl/style/property_evaluator.hpp
- src/mbgl/style/property_parsing.cpp
- src/mbgl/style/property_parsing.hpp
src/mbgl/style/rapidjson_conversion.hpp
src/mbgl/style/source.cpp
src/mbgl/style/source_impl.cpp
diff --git a/include/mbgl/style/conversion.hpp b/include/mbgl/style/conversion.hpp
index e53adcb942..d6fb3a6dd0 100644
--- a/include/mbgl/style/conversion.hpp
+++ b/include/mbgl/style/conversion.hpp
@@ -1,6 +1,6 @@
#pragma once
-#include <mbgl/util/variant.hpp>
+#include <mbgl/util/optional.hpp>
#include <string>
@@ -21,11 +21,11 @@ namespace conversion {
A single template function serves as the public interface:
template <class T, class V>
- Result<T> convert(const V& value);
+ optional<T> convert(const V& value, Error& error);
- Where `T` is one of the above types. If the conversion fails, the `Error` variant of `Result` is
- returned, which includes diagnostic text suitable for presentation to a library user. Otherwise,
- the `T` variant of `Result` is returned.
+ Where `T` is one of the above types. If the conversion fails, the result is empty, and the
+ error parameter includes diagnostic text suitable for presentation to a library user. Otherwise,
+ a filled optional is returned.
The implementation of `convert` requires that the following are legal expressions for a value `v`
of type `const V&`:
@@ -57,37 +57,12 @@ namespace conversion {
struct Error { std::string message; };
-template <class T>
-class Result : private variant<T, Error> {
-public:
- using variant<T, Error>::variant;
-
- explicit operator bool() const {
- return this->template is<T>();
- }
-
- T& operator*() {
- assert(this->template is<T>());
- return this->template get<T>();
- }
-
- const T& operator*() const {
- assert(this->template is<T>());
- return this->template get<T>();
- }
-
- const Error& error() const {
- assert(this->template is<Error>());
- return this->template get<Error>();
- }
-};
-
template <class T, class Enable = void>
struct Converter;
template <class T, class V, class...Args>
-Result<T> convert(const V& value, Args&&...args) {
- return Converter<T>()(value, std::forward<Args>(args)...);
+optional<T> convert(const V& value, Error& error, Args&&...args) {
+ return Converter<T>()(value, error, std::forward<Args>(args)...);
}
} // namespace conversion
diff --git a/include/mbgl/style/conversion/constant.hpp b/include/mbgl/style/conversion/constant.hpp
index 05bf968f4d..1e1fdc2ee8 100644
--- a/include/mbgl/style/conversion/constant.hpp
+++ b/include/mbgl/style/conversion/constant.hpp
@@ -16,10 +16,11 @@ namespace conversion {
template <>
struct Converter<bool> {
template <class V>
- Result<bool> operator()(const V& value) const {
+ optional<bool> operator()(const V& value, Error& error) const {
optional<bool> converted = toBool(value);
if (!converted) {
- return Error { "value must be a boolean" };
+ error = { "value must be a boolean" };
+ return {};
}
return *converted;
}
@@ -28,10 +29,11 @@ struct Converter<bool> {
template <>
struct Converter<float> {
template <class V>
- Result<float> operator()(const V& value) const {
+ optional<float> operator()(const V& value, Error& error) const {
optional<float> converted = toNumber(value);
if (!converted) {
- return Error { "value must be a number" };
+ error = { "value must be a number" };
+ return {};
}
return *converted;
}
@@ -40,10 +42,11 @@ struct Converter<float> {
template <>
struct Converter<std::string> {
template <class V>
- Result<std::string> operator()(const V& value) const {
+ optional<std::string> operator()(const V& value, Error& error) const {
optional<std::string> converted = toString(value);
if (!converted) {
- return Error { "value must be a string" };
+ error = { "value must be a string" };
+ return {};
}
return *converted;
}
@@ -52,15 +55,17 @@ struct Converter<std::string> {
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<T> operator()(const V& value, Error& error) const {
optional<std::string> string = toString(value);
if (!string) {
- return Error { "value must be a string" };
+ error = { "value must be a string" };
+ return {};
}
const auto result = Enum<T>::toEnum(*string);
if (!result) {
- return Error { "value must be a valid enumeration value" };
+ error = { "value must be a valid enumeration value" };
+ return {};
}
return *result;
@@ -70,15 +75,17 @@ struct Converter<T, typename std::enable_if_t<std::is_enum<T>::value>> {
template <>
struct Converter<Color> {
template <class V>
- Result<Color> operator()(const V& value) const {
+ optional<Color> operator()(const V& value, Error& error) const {
optional<std::string> string = toString(value);
if (!string) {
- return Error { "value must be a string" };
+ error = { "value must be a string" };
+ return {};
}
optional<Color> color = Color::parse(*string);
if (!color) {
- return Error { "value must be a valid color" };
+ error = { "value must be a valid color" };
+ return {};
}
return *color;
@@ -88,15 +95,17 @@ struct Converter<Color> {
template <>
struct Converter<std::array<float, 2>> {
template <class V>
- Result<std::array<float, 2>> operator()(const V& value) const {
+ optional<std::array<float, 2>> operator()(const V& value, Error& error) const {
if (!isArray(value) || arrayLength(value) != 2) {
- return Error { "value must be an array of two numbers" };
+ error = { "value must be an array of two numbers" };
+ return {};
}
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" };
+ error = { "value must be an array of two numbers" };
+ return {};
}
return std::array<float, 2> {{ *first, *second }};
@@ -106,9 +115,10 @@ struct Converter<std::array<float, 2>> {
template <>
struct Converter<std::array<float, 4>> {
template <class V>
- Result<std::array<float, 4>> operator()(const V& value) const {
+ optional<std::array<float, 4>> operator()(const V& value, Error& error) const {
if (!isArray(value) || arrayLength(value) != 4) {
- return Error { "value must be an array of four numbers" };
+ error = { "value must be an array of four numbers" };
+ return {};
}
optional<float> first = toNumber(arrayMember(value, 0));
@@ -116,7 +126,8 @@ struct Converter<std::array<float, 4>> {
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" };
+ error = { "value must be an array of four numbers" };
+ return {};
}
return std::array<float, 4> {{ *first, *second, *third, *fourth }};
@@ -126,9 +137,10 @@ struct Converter<std::array<float, 4>> {
template <>
struct Converter<std::vector<float>> {
template <class V>
- Result<std::vector<float>> operator()(const V& value) const {
+ optional<std::vector<float>> operator()(const V& value, Error& error) const {
if (!isArray(value)) {
- return Error { "value must be an array" };
+ error = { "value must be an array" };
+ return {};
}
std::vector<float> result;
@@ -137,7 +149,8 @@ struct Converter<std::vector<float>> {
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" };
+ error = { "value must be an array of numbers" };
+ return {};
}
result.push_back(*number);
}
@@ -149,9 +162,10 @@ struct Converter<std::vector<float>> {
template <>
struct Converter<std::vector<std::string>> {
template <class V>
- Result<std::vector<std::string>> operator()(const V& value) const {
+ optional<std::vector<std::string>> operator()(const V& value, Error& error) const {
if (!isArray(value)) {
- return Error { "value must be an array" };
+ error = { "value must be an array" };
+ return {};
}
std::vector<std::string> result;
@@ -160,7 +174,8 @@ struct Converter<std::vector<std::string>> {
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" };
+ error = { "value must be an array of strings" };
+ return {};
}
result.push_back(*string);
}
diff --git a/include/mbgl/style/conversion/data_driven_property_value.hpp b/include/mbgl/style/conversion/data_driven_property_value.hpp
index 83f44fdb27..79b15dcfb0 100644
--- a/include/mbgl/style/conversion/data_driven_property_value.hpp
+++ b/include/mbgl/style/conversion/data_driven_property_value.hpp
@@ -12,29 +12,29 @@ namespace conversion {
template <class T>
struct Converter<DataDrivenPropertyValue<T>> {
template <class V>
- Result<DataDrivenPropertyValue<T>> operator()(const V& value) const {
+ optional<DataDrivenPropertyValue<T>> operator()(const V& value, Error& error) const {
if (isUndefined(value)) {
- return {};
+ return DataDrivenPropertyValue<T>();
} else if (!isObject(value)) {
- Result<T> constant = convert<T>(value);
+ optional<T> constant = convert<T>(value, error);
if (!constant) {
- return constant.error();
+ return {};
}
return DataDrivenPropertyValue<T>(*constant);
} else if (!objectMember(value, "property")) {
- Result<CameraFunction<T>> function = convert<CameraFunction<T>>(value);
+ optional<CameraFunction<T>> function = convert<CameraFunction<T>>(value, error);
if (!function) {
- return function.error();
+ return {};
}
return DataDrivenPropertyValue<T>(*function);
} else {
- Result<CompositeFunction<T>> composite = convert<CompositeFunction<T>>(value);
+ optional<CompositeFunction<T>> composite = convert<CompositeFunction<T>>(value, error);
if (composite) {
return DataDrivenPropertyValue<T>(*composite);
}
- Result<SourceFunction<T>> source = convert<SourceFunction<T>>(value);
+ optional<SourceFunction<T>> source = convert<SourceFunction<T>>(value, error);
if (!source) {
- return source.error();
+ return {};
}
return DataDrivenPropertyValue<T>(*source);
}
diff --git a/include/mbgl/style/conversion/filter.hpp b/include/mbgl/style/conversion/filter.hpp
index 2c4eeb4ac7..1f8f0fd161 100644
--- a/include/mbgl/style/conversion/filter.hpp
+++ b/include/mbgl/style/conversion/filter.hpp
@@ -12,65 +12,71 @@ template <>
struct Converter<Filter> {
public:
template <class V>
- Result<Filter> operator()(const V& value) const {
+ optional<Filter> operator()(const V& value, Error& error) const {
if (!isArray(value)) {
- return Error { "filter expression must be an array" };
+ error = { "filter expression must be an array" };
+ return {};
}
if (arrayLength(value) < 1) {
- return Error { "filter expression must have at least 1 element" };
+ error = { "filter expression must have at least 1 element" };
+ return {};
}
optional<std::string> op = toString(arrayMember(value, 0));
if (!op) {
- return Error { "filter operator must be a string" };
+ error = { "filter operator must be a string" };
+ return {};
}
if (*op == "==") {
- return convertEqualityFilter<EqualsFilter, TypeEqualsFilter, IdentifierEqualsFilter>(value);
+ return convertEqualityFilter<EqualsFilter, TypeEqualsFilter, IdentifierEqualsFilter>(value, error);
} else if (*op == "!=") {
- return convertEqualityFilter<NotEqualsFilter, TypeNotEqualsFilter, IdentifierNotEqualsFilter>(value);
+ return convertEqualityFilter<NotEqualsFilter, TypeNotEqualsFilter, IdentifierNotEqualsFilter>(value, error);
} else if (*op == ">") {
- return convertBinaryFilter<GreaterThanFilter>(value);
+ return convertBinaryFilter<GreaterThanFilter>(value, error);
} else if (*op == ">=") {
- return convertBinaryFilter<GreaterThanEqualsFilter>(value);
+ return convertBinaryFilter<GreaterThanEqualsFilter>(value, error);
} else if (*op == "<") {
- return convertBinaryFilter<LessThanFilter>(value);
+ return convertBinaryFilter<LessThanFilter>(value, error);
} else if (*op == "<=") {
- return convertBinaryFilter<LessThanEqualsFilter>(value);
+ return convertBinaryFilter<LessThanEqualsFilter>(value, error);
} else if (*op == "in") {
- return convertSetFilter<InFilter, TypeInFilter, IdentifierInFilter>(value);
+ return convertSetFilter<InFilter, TypeInFilter, IdentifierInFilter>(value, error);
} else if (*op == "!in") {
- return convertSetFilter<NotInFilter, TypeNotInFilter, IdentifierNotInFilter>(value);
+ return convertSetFilter<NotInFilter, TypeNotInFilter, IdentifierNotInFilter>(value, error);
} else if (*op == "all") {
- return convertCompoundFilter<AllFilter>(value);
+ return convertCompoundFilter<AllFilter>(value, error);
} else if (*op == "any") {
- return convertCompoundFilter<AnyFilter>(value);
+ return convertCompoundFilter<AnyFilter>(value, error);
} else if (*op == "none") {
- return convertCompoundFilter<NoneFilter>(value);
+ return convertCompoundFilter<NoneFilter>(value, error);
} else if (*op == "has") {
- return convertUnaryFilter<HasFilter, HasIdentifierFilter>(value);
+ return convertUnaryFilter<HasFilter, HasIdentifierFilter>(value, error);
} else if (*op == "!has") {
- return convertUnaryFilter<NotHasFilter, NotHasIdentifierFilter>(value);
+ return convertUnaryFilter<NotHasFilter, NotHasIdentifierFilter>(value, error);
}
- return Error { "filter operator must be one of \"==\", \"!=\", \">\", \">=\", \"<\", \"<=\", \"in\", \"!in\", \"all\", \"any\", \"none\", \"has\", or \"!has\"" };
+ error = { "filter operator must be one of \"==\", \"!=\", \">\", \">=\", \"<\", \"<=\", \"in\", \"!in\", \"all\", \"any\", \"none\", \"has\", or \"!has\"" };
+ return {};
}
private:
- Result<Value> normalizeValue(const optional<Value>& value) const {
+ optional<Value> normalizeValue(const optional<Value>& value, Error& error) const {
if (!value) {
- return Error { "filter expression value must be a boolean, number, or string" };
+ error = { "filter expression value must be a boolean, number, or string" };
+ return {};
} else {
return *value;
}
}
template <class V>
- Result<FeatureType> toFeatureType(const V& value) const {
+ optional<FeatureType> toFeatureType(const V& value, Error& error) const {
optional<std::string> type = toString(value);
if (!type) {
- return Error { "value for $type filter must be a string" };
+ error = { "value for $type filter must be a string" };
+ return {};
} else if (*type == "Point") {
return FeatureType::Point;
} else if (*type == "LineString") {
@@ -78,162 +84,173 @@ private:
} else if (*type == "Polygon") {
return FeatureType::Polygon;
} else {
- return Error { "value for $type filter must be Point, LineString, or Polygon" };
+ error = { "value for $type filter must be Point, LineString, or Polygon" };
+ return {};
}
}
template <class V>
- Result<FeatureIdentifier> toFeatureIdentifier(const V& value) const {
+ optional<FeatureIdentifier> toFeatureIdentifier(const V& value, Error& error) const {
optional<Value> identifier = toValue(value);
if (!identifier) {
- return Error { "filter expression value must be a boolean, number, or string" };
+ error = { "filter expression value must be a boolean, number, or string" };
+ return {};
} else {
return (*identifier).match(
- [] (uint64_t t) -> Result<FeatureIdentifier> { return t; },
- [] ( int64_t t) -> Result<FeatureIdentifier> { return t; },
- [] ( double t) -> Result<FeatureIdentifier> { return t; },
- [] (const std::string& t) -> Result<FeatureIdentifier> { return t; },
- [] (const auto&) -> Result<FeatureIdentifier> {
- return Error { "filter expression value must be a boolean, number, or string" };
+ [] (uint64_t t) -> optional<FeatureIdentifier> { return { t }; },
+ [] ( int64_t t) -> optional<FeatureIdentifier> { return { t }; },
+ [] ( double t) -> optional<FeatureIdentifier> { return { t }; },
+ [] (const std::string& t) -> optional<FeatureIdentifier> { return { t }; },
+ [&] (const auto&) -> optional<FeatureIdentifier> {
+ error = { "filter expression value must be a boolean, number, or string" };
+ return {};
});
}
}
template <class FilterType, class IdentifierFilterType, class V>
- Result<Filter> convertUnaryFilter(const V& value) const {
+ optional<Filter> convertUnaryFilter(const V& value, Error& error) const {
if (arrayLength(value) < 2) {
- return Error { "filter expression must have 2 elements" };
+ error = { "filter expression must have 2 elements" };
+ return {};
}
optional<std::string> key = toString(arrayMember(value, 1));
if (!key) {
- return Error { "filter expression key must be a string" };
+ error = { "filter expression key must be a string" };
+ return {};
}
if (*key == "$id") {
- return IdentifierFilterType {};
+ return { IdentifierFilterType {} };
} else {
- return FilterType { *key };
+ return { FilterType { *key } };
}
}
template <class FilterType, class TypeFilterType, class IdentifierFilterType, class V>
- Result<Filter> convertEqualityFilter(const V& value) const {
+ optional<Filter> convertEqualityFilter(const V& value, Error& error) const {
if (arrayLength(value) < 3) {
- return Error { "filter expression must have 3 elements" };
+ error = { "filter expression must have 3 elements" };
+ return {};
}
optional<std::string> key = toString(arrayMember(value, 1));
if (!key) {
- return Error { "filter expression key must be a string" };
+ error = { "filter expression key must be a string" };
+ return {};
}
if (*key == "$type") {
- Result<FeatureType> filterValue = toFeatureType(arrayMember(value, 2));
+ optional<FeatureType> filterValue = toFeatureType(arrayMember(value, 2), error);
if (!filterValue) {
- return filterValue.error();
+ return {};
}
- return TypeFilterType { *filterValue };
+ return { TypeFilterType { *filterValue } };
} else if (*key == "$id") {
- Result<FeatureIdentifier> filterValue = toFeatureIdentifier(arrayMember(value, 2));
+ optional<FeatureIdentifier> filterValue = toFeatureIdentifier(arrayMember(value, 2), error);
if (!filterValue) {
- return filterValue.error();
+ return {};
}
- return IdentifierFilterType { *filterValue };
+ return { IdentifierFilterType { *filterValue } };
} else {
- Result<Value> filterValue = normalizeValue(toValue(arrayMember(value, 2)));
+ optional<Value> filterValue = normalizeValue(toValue(arrayMember(value, 2)), error);
if (!filterValue) {
- return filterValue.error();
+ return {};
}
- return FilterType { *key, *filterValue };
+ return { FilterType { *key, *filterValue } };
}
}
template <class FilterType, class V>
- Result<Filter> convertBinaryFilter(const V& value) const {
+ optional<Filter> convertBinaryFilter(const V& value, Error& error) const {
if (arrayLength(value) < 3) {
- return Error { "filter expression must have 3 elements" };
+ error = { "filter expression must have 3 elements" };
+ return {};
}
optional<std::string> key = toString(arrayMember(value, 1));
if (!key) {
- return Error { "filter expression key must be a string" };
+ error = { "filter expression key must be a string" };
+ return {};
}
- Result<Value> filterValue = normalizeValue(toValue(arrayMember(value, 2)));
+ optional<Value> filterValue = normalizeValue(toValue(arrayMember(value, 2)), error);
if (!filterValue) {
- return filterValue.error();
+ return {};
}
- return FilterType { *key, *filterValue };
+ return { FilterType { *key, *filterValue } };
}
template <class FilterType, class TypeFilterType, class IdentifierFilterType, class V>
- Result<Filter> convertSetFilter(const V& value) const {
+ optional<Filter> convertSetFilter(const V& value, Error& error) const {
if (arrayLength(value) < 2) {
- return Error { "filter expression must at least 2 elements" };
+ error = { "filter expression must at least 2 elements" };
+ return {};
}
optional<std::string> key = toString(arrayMember(value, 1));
if (!key) {
- return Error { "filter expression key must be a string" };
+ error = { "filter expression key must be a string" };
+ return {};
}
if (*key == "$type") {
std::vector<FeatureType> values;
for (std::size_t i = 2; i < arrayLength(value); ++i) {
- Result<FeatureType> filterValue = toFeatureType(arrayMember(value, i));
+ optional<FeatureType> filterValue = toFeatureType(arrayMember(value, i), error);
if (!filterValue) {
- return filterValue.error();
+ return {};
}
values.push_back(*filterValue);
}
- return TypeFilterType { std::move(values) };
+ return { TypeFilterType { std::move(values) } };
} else if (*key == "$id") {
std::vector<FeatureIdentifier> values;
for (std::size_t i = 2; i < arrayLength(value); ++i) {
- Result<FeatureIdentifier> filterValue = toFeatureIdentifier(arrayMember(value, i));
+ optional<FeatureIdentifier> filterValue = toFeatureIdentifier(arrayMember(value, i), error);
if (!filterValue) {
- return filterValue.error();
+ return {};
}
values.push_back(*filterValue);
}
- return IdentifierFilterType { std::move(values) };
+ return { IdentifierFilterType { std::move(values) } };
} else {
std::vector<Value> values;
for (std::size_t i = 2; i < arrayLength(value); ++i) {
- Result<Value> filterValue = normalizeValue(toValue(arrayMember(value, i)));
+ optional<Value> filterValue = normalizeValue(toValue(arrayMember(value, i)), error);
if (!filterValue) {
- return filterValue.error();
+ return {};
}
values.push_back(*filterValue);
}
- return FilterType { *key, std::move(values) };
+ return { FilterType { *key, std::move(values) } };
}
}
template <class FilterType, class V>
- Result<Filter> convertCompoundFilter(const V& value) const {
+ optional<Filter> convertCompoundFilter(const V& value, Error& error) const {
std::vector<Filter> filters;
for (std::size_t i = 1; i < arrayLength(value); ++i) {
- Result<Filter> element = operator()(arrayMember(value, i));
+ optional<Filter> element = operator()(arrayMember(value, i), error);
if (!element) {
- return element.error();
+ return {};
}
filters.push_back(*element);
}
- return FilterType { std::move(filters) };
+ return { FilterType { std::move(filters) } };
}
};
diff --git a/include/mbgl/style/conversion/function.hpp b/include/mbgl/style/conversion/function.hpp
index a5979e6799..fa8af1e2be 100644
--- a/include/mbgl/style/conversion/function.hpp
+++ b/include/mbgl/style/conversion/function.hpp
@@ -12,18 +12,21 @@ namespace style {
namespace conversion {
template <class D, class R, class V>
-Result<std::map<D, R>> convertStops(const V& value) {
+optional<std::map<D, R>> convertStops(const V& value, Error& error) {
auto stopsValue = objectMember(value, "stops");
if (!stopsValue) {
- return Error { "function value must specify stops" };
+ error = { "function value must specify stops" };
+ return {};
}
if (!isArray(*stopsValue)) {
- return Error { "function stops must be an array" };
+ error = { "function stops must be an array" };
+ return {};
}
if (arrayLength(*stopsValue) == 0) {
- return Error { "function must have at least one stop" };
+ error = { "function must have at least one stop" };
+ return {};
}
std::map<D, R> stops;
@@ -31,21 +34,23 @@ Result<std::map<D, R>> convertStops(const V& value) {
const auto& stopValue = arrayMember(*stopsValue, i);
if (!isArray(stopValue)) {
- return Error { "function stop must be an array" };
+ error = { "function stop must be an array" };
+ return {};
}
if (arrayLength(stopValue) != 2) {
- return Error { "function stop must have two elements" };
+ error = { "function stop must have two elements" };
+ return {};
}
- Result<D> d = convert<D>(arrayMember(stopValue, 0));
+ optional<D> d = convert<D>(arrayMember(stopValue, 0), error);
if (!d) {
- return d.error();
+ return {};
}
- Result<R> r = convert<R>(arrayMember(stopValue, 1));
+ optional<R> r = convert<R>(arrayMember(stopValue, 1), error);
if (!r) {
- return r.error();
+ return {};
}
stops.emplace(*d, *r);
@@ -59,10 +64,10 @@ struct Converter<ExponentialStops<T>> {
static constexpr const char * type = "exponential";
template <class V>
- Result<ExponentialStops<T>> operator()(const V& value) const {
- auto stops = convertStops<float, T>(value);
+ optional<ExponentialStops<T>> operator()(const V& value, Error& error) const {
+ auto stops = convertStops<float, T>(value, error);
if (!stops) {
- return stops.error();
+ return {};
}
auto baseValue = objectMember(value, "base");
@@ -72,7 +77,8 @@ struct Converter<ExponentialStops<T>> {
optional<float> base = toNumber(*baseValue);
if (!base) {
- return Error { "function base must be a number"};
+ error = { "function base must be a number"};
+ return {};
}
return ExponentialStops<T>(*stops, *base);
@@ -84,10 +90,10 @@ struct Converter<IntervalStops<T>> {
static constexpr const char * type = "interval";
template <class V>
- Result<IntervalStops<T>> operator()(const V& value) const {
- auto stops = convertStops<float, T>(value);
+ optional<IntervalStops<T>> operator()(const V& value, Error& error) const {
+ auto stops = convertStops<float, T>(value, error);
if (!stops) {
- return stops.error();
+ return {};
}
return IntervalStops<T>(*stops);
}
@@ -96,23 +102,24 @@ struct Converter<IntervalStops<T>> {
template <>
struct Converter<CategoricalValue> {
template <class V>
- Result<CategoricalValue> operator()(const V& value) const {
+ optional<CategoricalValue> operator()(const V& value, Error& error) const {
auto b = toBool(value);
if (b) {
- return *b;
+ return { *b };
}
auto n = toNumber(value);
if (n) {
- return int64_t(*n);
+ return { int64_t(*n) };
}
auto s = toString(value);
if (s) {
- return *s;
+ return { *s };
}
- return Error { "stop domain value must be a number, string, or boolean" };
+ error = { "stop domain value must be a number, string, or boolean" };
+ return {};
}
};
@@ -121,10 +128,10 @@ struct Converter<CategoricalStops<T>> {
static constexpr const char * type = "categorical";
template <class V>
- Result<CategoricalStops<T>> operator()(const V& value) const {
- auto stops = convertStops<CategoricalValue, T>(value);
+ optional<CategoricalStops<T>> operator()(const V& value, Error& error) const {
+ auto stops = convertStops<CategoricalValue, T>(value, error);
if (!stops) {
- return stops.error();
+ return {};
}
return CategoricalStops<T>(
std::map<CategoricalValue, T>((*stops).begin(), (*stops).end()));
@@ -136,7 +143,7 @@ struct Converter<IdentityStops<T>> {
static constexpr const char * type = "identity";
template <class V>
- Result<IdentityStops<T>> operator()(const V&) const {
+ optional<IdentityStops<T>> operator()(const V&, Error&) const {
return IdentityStops<T>();
}
};
@@ -148,7 +155,7 @@ template <class T, class... Ts>
struct StopsConverter<T, variant<Ts...>> {
public:
template <class V>
- Result<variant<Ts...>> operator()(const V& value) const {
+ optional<variant<Ts...>> operator()(const V& value, Error& error) const {
std::string type = util::Interpolatable<T> ? "exponential" : "interval";
auto typeValue = objectMember(value, "type");
@@ -156,16 +163,18 @@ public:
type = *toString(*typeValue);
}
- optional<Result<variant<Ts...>>> result;
+ bool matched = false;
+ optional<variant<Ts...>> result;
// Workaround for https://gcc.gnu.org/bugzilla/show_bug.cgi?id=47226
auto tryConvert = [&] (auto* tp) {
using Stops = std::decay_t<decltype(*tp)>;
if (type == Converter<Stops>::type) {
- auto stops = convert<Stops>(value);
- result = stops
- ? Result<variant<Ts...>>(*stops)
- : Result<variant<Ts...>>(stops.error());
+ matched = true;
+ optional<Stops> stops = convert<Stops>(value, error);
+ if (stops) {
+ result = variant<Ts...>(*stops);
+ }
}
};
@@ -173,25 +182,27 @@ public:
(tryConvert((Ts*)nullptr), 0)...
});
- if (!result) {
- return Error { "unsupported function type" };
+ if (!matched) {
+ error = { "unsupported function type" };
+ return {};
}
- return *result;
+ return result;
}
};
template <class T>
struct Converter<CameraFunction<T>> {
template <class V>
- Result<CameraFunction<T>> operator()(const V& value) const {
+ optional<CameraFunction<T>> operator()(const V& value, Error& error) const {
if (!isObject(value)) {
- return Error { "function must be an object" };
+ error = { "function must be an object" };
+ return {};
}
- auto stops = StopsConverter<T, typename CameraFunction<T>::Stops>()(value);
+ auto stops = StopsConverter<T, typename CameraFunction<T>::Stops>()(value, error);
if (!stops) {
- return stops.error();
+ return {};
}
return CameraFunction<T>(*stops);
@@ -199,46 +210,50 @@ struct Converter<CameraFunction<T>> {
};
template <class T, class V>
-Result<optional<T>> convertDefaultValue(const V& value) {
+optional<optional<T>> convertDefaultValue(const V& value, Error& error) {
auto defaultValueValue = objectMember(value, "default");
if (!defaultValueValue) {
- return {};
+ return optional<T>();
}
- auto defaultValue = convert<T>(*defaultValueValue);
+ auto defaultValue = convert<T>(*defaultValueValue, error);
if (!defaultValue) {
- return Error { "wrong type for \"default\": " + defaultValue.error().message };
+ error = { "wrong type for \"default\": " + error.message };
+ return {};
}
- return *defaultValue;
+ return { *defaultValue };
}
template <class T>
struct Converter<SourceFunction<T>> {
template <class V>
- Result<SourceFunction<T>> operator()(const V& value) const {
+ optional<SourceFunction<T>> operator()(const V& value, Error& error) const {
if (!isObject(value)) {
- return Error { "function must be an object" };
+ error = { "function must be an object" };
+ return {};
}
auto propertyValue = objectMember(value, "property");
if (!propertyValue) {
- return Error { "function must specify property" };
+ error = { "function must specify property" };
+ return {};
}
auto propertyString = toString(*propertyValue);
if (!propertyString) {
- return Error { "function property must be a string" };
+ error = { "function property must be a string" };
+ return {};
}
- auto stops = StopsConverter<T, typename SourceFunction<T>::Stops>()(value);
+ auto stops = StopsConverter<T, typename SourceFunction<T>::Stops>()(value, error);
if (!stops) {
- return stops.error();
+ return {};
}
- auto defaultValue = convertDefaultValue<T>(value);
+ auto defaultValue = convertDefaultValue<T>(value, error);
if (!defaultValue) {
- return defaultValue.error();
+ return {};
}
return SourceFunction<T>(*propertyString, *stops, *defaultValue);
@@ -253,29 +268,32 @@ struct CompositeValue : std::pair<float, S> {
template <class S>
struct Converter<CompositeValue<S>> {
template <class V>
- Result<CompositeValue<S>> operator()(const V& value) const {
+ optional<CompositeValue<S>> operator()(const V& value, Error& error) const {
if (!isObject(value)) {
- return Error { "stop must be an object" };
+ error = { "stop must be an object" };
+ return {};
}
auto zoomValue = objectMember(value, "zoom");
if (!zoomValue) {
- return Error { "stop must specify zoom" };
+ error = { "stop must specify zoom" };
+ return {};
}
auto propertyValue = objectMember(value, "value");
if (!propertyValue) {
- return Error { "stop must specify value" };
+ error = { "stop must specify value" };
+ return {};
}
- Result<float> z = convert<float>(*zoomValue);
+ optional<float> z = convert<float>(*zoomValue, error);
if (!z) {
- return z.error();
+ return {};
}
- Result<S> s = convert<S>(*propertyValue);
+ optional<S> s = convert<S>(*propertyValue, error);
if (!s) {
- return s.error();
+ return {};
}
return CompositeValue<S> { *z, *s };
@@ -287,10 +305,10 @@ struct Converter<CompositeExponentialStops<T>> {
static constexpr const char * type = "exponential";
template <class V>
- Result<CompositeExponentialStops<T>> operator()(const V& value) const {
- auto stops = convertStops<CompositeValue<float>, T>(value);
+ optional<CompositeExponentialStops<T>> operator()(const V& value, Error& error) const {
+ auto stops = convertStops<CompositeValue<float>, T>(value, error);
if (!stops) {
- return stops.error();
+ return {};
}
auto base = 1.0f;
@@ -313,10 +331,10 @@ struct Converter<CompositeIntervalStops<T>> {
static constexpr const char * type = "interval";
template <class V>
- Result<CompositeIntervalStops<T>> operator()(const V& value) const {
- auto stops = convertStops<CompositeValue<float>, T>(value);
+ optional<CompositeIntervalStops<T>> operator()(const V& value, Error& error) const {
+ auto stops = convertStops<CompositeValue<float>, T>(value, error);
if (!stops) {
- return stops.error();
+ return {};
}
std::map<float, std::map<float, T>> convertedStops;
@@ -333,10 +351,10 @@ struct Converter<CompositeCategoricalStops<T>> {
static constexpr const char * type = "categorical";
template <class V>
- Result<CompositeCategoricalStops<T>> operator()(const V& value) const {
- auto stops = convertStops<CompositeValue<CategoricalValue>, T>(value);
+ optional<CompositeCategoricalStops<T>> operator()(const V& value, Error& error) const {
+ auto stops = convertStops<CompositeValue<CategoricalValue>, T>(value, error);
if (!stops) {
- return stops.error();
+ return {};
}
std::map<float, std::map<CategoricalValue, T>> convertedStops;
@@ -351,29 +369,32 @@ struct Converter<CompositeCategoricalStops<T>> {
template <class T>
struct Converter<CompositeFunction<T>> {
template <class V>
- Result<CompositeFunction<T>> operator()(const V& value) const {
+ optional<CompositeFunction<T>> operator()(const V& value, Error& error) const {
if (!isObject(value)) {
- return Error { "function must be an object" };
+ error = { "function must be an object" };
+ return {};
}
auto propertyValue = objectMember(value, "property");
if (!propertyValue) {
- return Error { "function must specify property" };
+ error = { "function must specify property" };
+ return {};
}
auto propertyString = toString(*propertyValue);
if (!propertyString) {
- return Error { "function property must be a string" };
+ error = { "function property must be a string" };
+ return {};
}
- auto stops = StopsConverter<T, typename CompositeFunction<T>::Stops>()(value);
+ auto stops = StopsConverter<T, typename CompositeFunction<T>::Stops>()(value, error);
if (!stops) {
- return stops.error();
+ return {};
}
- auto defaultValue = convertDefaultValue<T>(value);
+ auto defaultValue = convertDefaultValue<T>(value, error);
if (!defaultValue) {
- return defaultValue.error();
+ return {};
}
return CompositeFunction<T>(*propertyString, *stops, *defaultValue);
diff --git a/include/mbgl/style/conversion/geojson.hpp b/include/mbgl/style/conversion/geojson.hpp
index ba10b3ecc8..6e6e97dbc0 100644
--- a/include/mbgl/style/conversion/geojson.hpp
+++ b/include/mbgl/style/conversion/geojson.hpp
@@ -8,7 +8,7 @@ namespace style {
namespace conversion {
template <class V>
-Result<GeoJSON> convertGeoJSON(const V& value);
+optional<GeoJSON> convertGeoJSON(const V& value, Error& error);
} // namespace conversion
} // namespace style
diff --git a/include/mbgl/style/conversion/geojson_options.hpp b/include/mbgl/style/conversion/geojson_options.hpp
index 880090b402..19383d90ce 100644
--- a/include/mbgl/style/conversion/geojson_options.hpp
+++ b/include/mbgl/style/conversion/geojson_options.hpp
@@ -11,7 +11,7 @@ template <>
struct Converter<GeoJSONOptions> {
template <class V>
- Result<GeoJSONOptions> operator()(const V& value) const {
+ optional<GeoJSONOptions> operator()(const V& value, Error& error) const {
GeoJSONOptions options;
const auto maxzoomValue = objectMember(value, "maxzoom");
@@ -19,7 +19,8 @@ struct Converter<GeoJSONOptions> {
if (toNumber(*maxzoomValue)) {
options.maxzoom = static_cast<uint8_t>(*toNumber(*maxzoomValue));
} else {
- return Error{ "GeoJSON source maxzoom value must be a number" };
+ error = { "GeoJSON source maxzoom value must be a number" };
+ return {};
}
}
@@ -28,7 +29,8 @@ struct Converter<GeoJSONOptions> {
if (toNumber(*bufferValue)) {
options.buffer = static_cast<uint16_t>(*toNumber(*bufferValue));
} else {
- return Error{ "GeoJSON source buffer value must be a number" };
+ error = { "GeoJSON source buffer value must be a number" };
+ return {};
}
}
@@ -37,7 +39,8 @@ struct Converter<GeoJSONOptions> {
if (toNumber(*toleranceValue)) {
options.tolerance = static_cast<double>(*toNumber(*toleranceValue));
} else {
- return Error{ "GeoJSON source tolerance value must be a number" };
+ error = { "GeoJSON source tolerance value must be a number" };
+ return {};
}
}
@@ -46,7 +49,8 @@ struct Converter<GeoJSONOptions> {
if (toBool(*clusterValue)) {
options.cluster = *toBool(*clusterValue);
} else {
- return Error{ "GeoJSON source cluster value must be a boolean" };
+ error = { "GeoJSON source cluster value must be a boolean" };
+ return {};
}
}
@@ -55,7 +59,8 @@ struct Converter<GeoJSONOptions> {
if (toNumber(*clusterMaxZoomValue)) {
options.clusterMaxZoom = static_cast<uint8_t>(*toNumber(*clusterMaxZoomValue));
} else {
- return Error{ "GeoJSON source clusterMaxZoom value must be a number" };
+ error = { "GeoJSON source clusterMaxZoom value must be a number" };
+ return {};
}
}
@@ -64,7 +69,8 @@ struct Converter<GeoJSONOptions> {
if (toNumber(*clusterRadiusValue)) {
options.clusterRadius = static_cast<double>(*toNumber(*clusterRadiusValue));
} else {
- return Error{ "GeoJSON source clusterRadius value must be a number" };
+ error = { "GeoJSON source clusterRadius value must be a number" };
+ return {};
}
}
diff --git a/include/mbgl/style/conversion/layer.hpp b/include/mbgl/style/conversion/layer.hpp
index 0539dcf9ad..efb1df8fef 100644
--- a/include/mbgl/style/conversion/layer.hpp
+++ b/include/mbgl/style/conversion/layer.hpp
@@ -58,47 +58,53 @@ template <>
struct Converter<std::unique_ptr<Layer>> {
public:
template <class V>
- Result<std::unique_ptr<Layer>> operator()(const V& value) const {
+ optional<std::unique_ptr<Layer>> operator()(const V& value, Error& error) const {
if (!isObject(value)) {
- return Error { "layer must be an object" };
+ error = { "layer must be an object" };
+ return {};
}
auto idValue = objectMember(value, "id");
if (!idValue) {
- return Error { "layer must have an id" };
+ error = { "layer must have an id" };
+ return {};
}
optional<std::string> id = toString(*idValue);
if (!id) {
- return Error { "layer id must be a string" };
+ error = { "layer id must be a string" };
+ return {};
}
auto typeValue = objectMember(value, "type");
if (!typeValue) {
- return Error { "layer must have a type" };
+ error = { "layer must have a type" };
+ return {};
}
optional<std::string> type = toString(*typeValue);
if (!type) {
- return Error { "layer type must be a string" };
+ error = { "layer type must be a string" };
+ return {};
}
- Result<std::unique_ptr<Layer>> converted;
+ optional<std::unique_ptr<Layer>> converted;
if (*type == "fill") {
- converted = convertVectorLayer<FillLayer>(*id, value);
+ converted = convertVectorLayer<FillLayer>(*id, value, error);
} else if (*type == "line") {
- converted = convertVectorLayer<LineLayer>(*id, value);
+ converted = convertVectorLayer<LineLayer>(*id, value, error);
} else if (*type == "circle") {
- converted = convertVectorLayer<CircleLayer>(*id, value);
+ converted = convertVectorLayer<CircleLayer>(*id, value, error);
} else if (*type == "symbol") {
- converted = convertVectorLayer<SymbolLayer>(*id, value);
+ converted = convertVectorLayer<SymbolLayer>(*id, value, error);
} else if (*type == "raster") {
- converted = convertRasterLayer(*id, value);
+ converted = convertRasterLayer(*id, value, error);
} else if (*type == "background") {
- converted = convertBackgroundLayer(*id, value);
+ converted = convertBackgroundLayer(*id, value, error);
} else {
- return Error { "invalid layer type" };
+ error = { "invalid layer type" };
+ return {};
}
if (!converted) {
@@ -111,7 +117,8 @@ public:
if (minzoomValue) {
optional<float> minzoom = toNumber(*minzoomValue);
if (!minzoom) {
- return Error { "minzoom must be numeric" };
+ error = { "minzoom must be numeric" };
+ return {};
}
layer->setMinZoom(*minzoom);
}
@@ -120,7 +127,8 @@ public:
if (maxzoomValue) {
optional<float> maxzoom = toNumber(*maxzoomValue);
if (!maxzoom) {
- return Error { "maxzoom must be numeric" };
+ error = { "maxzoom must be numeric" };
+ return {};
}
layer->setMaxZoom(*maxzoom);
}
@@ -128,19 +136,22 @@ public:
auto layoutValue = objectMember(value, "layout");
if (layoutValue) {
if (!isObject(*layoutValue)) {
- return Error { "layout must be an object" };
+ error = { "layout must be an object" };
+ return {};
}
- optional<Error> error = eachMember(*layoutValue, [&] (const std::string& k, const V& v) {
+ optional<Error> error_ = eachMember(*layoutValue, [&] (const std::string& k, const V& v) {
return setLayoutProperty(*layer, k, v);
});
- if (error) {
- return *error;
+ if (error_) {
+ error = *error_;
+ return {};
}
}
- optional<Error> error = setPaintProperties(*layer, value);
- if (error) {
- return *error;
+ optional<Error> error_ = setPaintProperties(*layer, value);
+ if (error_) {
+ error = *error_;
+ return {};
}
return std::move(layer);
@@ -148,15 +159,17 @@ public:
private:
template <class LayerType, class V>
- Result<std::unique_ptr<Layer>> convertVectorLayer(const std::string& id, const V& value) const {
+ optional<std::unique_ptr<Layer>> convertVectorLayer(const std::string& id, const V& value, Error& error) const {
auto sourceValue = objectMember(value, "source");
if (!sourceValue) {
- return Error { "layer must have a source" };
+ error = { "layer must have a source" };
+ return {};
}
optional<std::string> source = toString(*sourceValue);
if (!source) {
- return Error { "layer source must be a string" };
+ error = { "layer source must be a string" };
+ return {};
}
std::unique_ptr<LayerType> layer = std::make_unique<LayerType>(id, *source);
@@ -165,41 +178,44 @@ private:
if (sourceLayerValue) {
optional<std::string> sourceLayer = toString(*sourceLayerValue);
if (!sourceLayer) {
- return Error { "layer source-layer must be a string" };
+ error = { "layer source-layer must be a string" };
+ return {};
}
layer->setSourceLayer(*sourceLayer);
}
auto filterValue = objectMember(value, "filter");
if (filterValue) {
- Result<Filter> filter = convert<Filter>(*filterValue);
+ optional<Filter> filter = convert<Filter>(*filterValue, error);
if (!filter) {
- return filter.error();
+ return {};
}
layer->setFilter(*filter);
}
- return std::move(layer);
+ return { std::move(layer) };
}
template <class V>
- Result<std::unique_ptr<Layer>> convertRasterLayer(const std::string& id, const V& value) const {
+ optional<std::unique_ptr<Layer>> convertRasterLayer(const std::string& id, const V& value, Error& error) const {
auto sourceValue = objectMember(value, "source");
if (!sourceValue) {
- return Error { "layer must have a source" };
+ error = { "layer must have a source" };
+ return {};
}
optional<std::string> source = toString(*sourceValue);
if (!source) {
- return Error { "layer source must be a string" };
+ error = { "layer source must be a string" };
+ return {};
}
- return std::make_unique<RasterLayer>(id, *source);
+ return { std::make_unique<RasterLayer>(id, *source) };
}
template <class V>
- Result<std::unique_ptr<Layer>> convertBackgroundLayer(const std::string& id, const V&) const {
- return std::make_unique<BackgroundLayer>(id);
+ optional<std::unique_ptr<Layer>> convertBackgroundLayer(const std::string& id, const V&, Error&) const {
+ return { std::make_unique<BackgroundLayer>(id) };
}
};
diff --git a/include/mbgl/style/conversion/property_setter.hpp b/include/mbgl/style/conversion/property_setter.hpp
index 51ec4778d9..1f537f3c4d 100644
--- a/include/mbgl/style/conversion/property_setter.hpp
+++ b/include/mbgl/style/conversion/property_setter.hpp
@@ -26,9 +26,10 @@ optional<Error> setLayoutProperty(Layer& layer, const V& value) {
return Error { "layer doesn't support this property" };
}
- Result<PropertyValue> typedValue = convert<PropertyValue>(value);
+ Error error;
+ optional<PropertyValue> typedValue = convert<PropertyValue>(value, error);
if (!typedValue) {
- return typedValue.error();
+ return error;
}
(typedLayer->*setter)(*typedValue);
@@ -42,9 +43,10 @@ optional<Error> setPaintProperty(Layer& layer, const V& value, const optional<st
return Error { "layer doesn't support this property" };
}
- Result<PropertyValue> typedValue = convert<PropertyValue>(value);
+ Error error;
+ optional<PropertyValue> typedValue = convert<PropertyValue>(value, error);
if (!typedValue) {
- return typedValue.error();
+ return error;
}
(typedLayer->*setter)(*typedValue, klass);
@@ -58,9 +60,10 @@ optional<Error> setTransition(Layer& layer, const V& value, const optional<std::
return Error { "layer doesn't support this property" };
}
- Result<TransitionOptions> transition = convert<TransitionOptions>(value);
+ Error error;
+ optional<TransitionOptions> transition = convert<TransitionOptions>(value, error);
if (!transition) {
- return transition.error();
+ return error;
}
(typedLayer->*setter)(*transition, klass);
@@ -74,9 +77,10 @@ optional<Error> setVisibility(Layer& layer, const V& value) {
return {};
}
- Result<VisibilityType> visibility = convert<VisibilityType>(value);
+ Error error;
+ optional<VisibilityType> visibility = convert<VisibilityType>(value, error);
if (!visibility) {
- return visibility.error();
+ return error;
}
layer.setVisibility(*visibility);
diff --git a/include/mbgl/style/conversion/property_value.hpp b/include/mbgl/style/conversion/property_value.hpp
index d5e2a5c3c8..f8937da07d 100644
--- a/include/mbgl/style/conversion/property_value.hpp
+++ b/include/mbgl/style/conversion/property_value.hpp
@@ -12,21 +12,21 @@ namespace conversion {
template <class T>
struct Converter<PropertyValue<T>> {
template <class V>
- Result<PropertyValue<T>> operator()(const V& value) const {
+ optional<PropertyValue<T>> operator()(const V& value, Error& error) const {
if (isUndefined(value)) {
- return {};
+ return PropertyValue<T>();
} else if (isObject(value)) {
- Result<CameraFunction<T>> function = convert<CameraFunction<T>>(value);
+ optional<CameraFunction<T>> function = convert<CameraFunction<T>>(value, error);
if (!function) {
- return function.error();
+ return {};
}
- return *function;
+ return { *function };
} else {
- Result<T> constant = convert<T>(value);
+ optional<T> constant = convert<T>(value, error);
if (!constant) {
- return constant.error();
+ return {};
}
- return *constant;
+ return { *constant };
}
}
};
diff --git a/include/mbgl/style/conversion/source.hpp b/include/mbgl/style/conversion/source.hpp
index 6e1b4347c3..2371183b1c 100644
--- a/include/mbgl/style/conversion/source.hpp
+++ b/include/mbgl/style/conversion/source.hpp
@@ -17,59 +17,65 @@ template <>
struct Converter<std::unique_ptr<Source>> {
public:
template <class V>
- Result<std::unique_ptr<Source>> operator()(const V& value, const std::string& id) const {
+ optional<std::unique_ptr<Source>> operator()(const V& value, Error& error, const std::string& id) const {
if (!isObject(value)) {
- return Error{ "source must be an object" };
+ error = { "source must be an object" };
+ return {};
}
auto typeValue = objectMember(value, "type");
if (!typeValue) {
- return Error{ "source must have a type" };
+ error = { "source must have a type" };
+ return {};
}
optional<std::string> type = toString(*typeValue);
if (!type) {
- return Error{ "source type must be a string" };
+ error = { "source type must be a string" };
+ return {};
}
if (*type == "raster") {
- return convertRasterSource(id, value);
+ return convertRasterSource(id, value, error);
} else if (*type == "vector") {
- return convertVectorSource(id, value);
+ return convertVectorSource(id, value, error);
} else if (*type == "geojson") {
- return convertGeoJSONSource(id, value);
+ return convertGeoJSONSource(id, value, error);
} else {
- return Error{ "invalid source type" };
+ error = { "invalid source type" };
+ return {};
}
}
private:
// A tile source can either specify a URL to TileJSON, or inline TileJSON.
template <class V>
- Result<variant<std::string, Tileset>> convertURLOrTileset(const V& value) const {
+ optional<variant<std::string, Tileset>> convertURLOrTileset(const V& value, Error& error) const {
auto urlVal = objectMember(value, "url");
if (!urlVal) {
- Result<Tileset> tileset = convert<Tileset>(value);
+ optional<Tileset> tileset = convert<Tileset>(value, error);
if (!tileset) {
- return tileset.error();
+ return {};
}
- return *tileset;
+ return { *tileset };
}
optional<std::string> url = toString(*urlVal);
if (!url) {
- return Error{ "source url must be a string" };
+ error = { "source url must be a string" };
+ return {};
}
- return *url;
+ return { *url };
}
template <class V>
- Result<std::unique_ptr<Source>> convertRasterSource(const std::string& id,
- const V& value) const {
- Result<variant<std::string, Tileset>> urlOrTileset = convertURLOrTileset(value);
+ optional<std::unique_ptr<Source>> convertRasterSource(const std::string& id,
+ const V& value,
+ Error& error) const {
+ optional<variant<std::string, Tileset>> urlOrTileset = convertURLOrTileset(value, error);
if (!urlOrTileset) {
- return urlOrTileset.error();
+ return {};
}
uint16_t tileSize = util::tileSize;
@@ -77,53 +83,58 @@ private:
if (tileSizeValue) {
optional<float> size = toNumber(*tileSizeValue);
if (!size || *size < 0 || *size > std::numeric_limits<uint16_t>::max()) {
- return Error{ "invalid tileSize" };
+ error = { "invalid tileSize" };
+ return {};
}
tileSize = *size;
}
- return std::make_unique<RasterSource>(id, std::move(*urlOrTileset), tileSize);
+ return { std::make_unique<RasterSource>(id, std::move(*urlOrTileset), tileSize) };
}
template <class V>
- Result<std::unique_ptr<Source>> convertVectorSource(const std::string& id,
- const V& value) const {
- Result<variant<std::string, Tileset>> urlOrTileset = convertURLOrTileset(value);
+ optional<std::unique_ptr<Source>> convertVectorSource(const std::string& id,
+ const V& value,
+ Error& error) const {
+ optional<variant<std::string, Tileset>> urlOrTileset = convertURLOrTileset(value, error);
if (!urlOrTileset) {
- return urlOrTileset.error();
+ return {};
}
- return std::make_unique<VectorSource>(id, std::move(*urlOrTileset));
+ return { std::make_unique<VectorSource>(id, std::move(*urlOrTileset)) };
}
template <class V>
- Result<std::unique_ptr<Source>> convertGeoJSONSource(const std::string& id,
- const V& value) const {
+ optional<std::unique_ptr<Source>> convertGeoJSONSource(const std::string& id,
+ const V& value,
+ Error& error) const {
auto dataValue = objectMember(value, "data");
if (!dataValue) {
- return Error{ "GeoJSON source must have a data value" };
+ error = { "GeoJSON source must have a data value" };
+ return {};
}
- Result<GeoJSONOptions> options = convert<GeoJSONOptions>(value);
+ optional<GeoJSONOptions> options = convert<GeoJSONOptions>(value, error);
if (!options) {
- return options.error();
+ return {};
}
auto result = std::make_unique<GeoJSONSource>(id, *options);
if (isObject(*dataValue)) {
- Result<GeoJSON> geoJSON = convertGeoJSON(*dataValue);
+ optional<GeoJSON> geoJSON = convertGeoJSON(*dataValue, error);
if (!geoJSON) {
- return geoJSON.error();
+ return {};
}
result->setGeoJSON(std::move(*geoJSON));
} else if (toString(*dataValue)) {
result->setURL(*toString(*dataValue));
} else {
- return Error{ "GeoJSON data must be a URL or an object" };
+ error = { "GeoJSON data must be a URL or an object" };
+ return {};
}
- return std::move(result);
+ return { std::move(result) };
}
};
diff --git a/include/mbgl/style/conversion/tileset.hpp b/include/mbgl/style/conversion/tileset.hpp
index 1955cc16cf..377170aa6a 100644
--- a/include/mbgl/style/conversion/tileset.hpp
+++ b/include/mbgl/style/conversion/tileset.hpp
@@ -11,22 +11,25 @@ template <>
struct Converter<Tileset> {
public:
template <class V>
- Result<Tileset> operator()(const V& value) const {
+ optional<Tileset> operator()(const V& value, Error& error) const {
Tileset result;
auto tiles = objectMember(value, "tiles");
if (!tiles) {
- return Error { "source must have tiles" };
+ error = { "source must have tiles" };
+ return {};
}
if (!isArray(*tiles)) {
- return Error { "source tiles must be an array" };
+ error = { "source tiles must be an array" };
+ return {};
}
for (std::size_t i = 0; i < arrayLength(*tiles); i++) {
optional<std::string> urlTemplate = toString(arrayMember(*tiles, i));
if (!urlTemplate) {
- return Error { "source tiles member must be a string" };
+ error = { "source tiles member must be a string" };
+ return {};
}
result.tiles.push_back(std::move(*urlTemplate));
}
@@ -43,7 +46,8 @@ public:
if (minzoomValue) {
optional<float> minzoom = toNumber(*minzoomValue);
if (!minzoom || *minzoom < 0 || *minzoom > std::numeric_limits<uint8_t>::max()) {
- return Error { "invalid minzoom" };
+ error = { "invalid minzoom" };
+ return {};
}
result.zoomRange.min = *minzoom;
}
@@ -52,7 +56,8 @@ public:
if (maxzoomValue) {
optional<float> maxzoom = toNumber(*maxzoomValue);
if (!maxzoom || *maxzoom < 0 || *maxzoom > std::numeric_limits<uint8_t>::max()) {
- return Error { "invalid maxzoom" };
+ error = { "invalid maxzoom" };
+ return {};
}
result.zoomRange.max = *maxzoom;
}
@@ -61,7 +66,8 @@ public:
if (attributionValue) {
optional<std::string> attribution = toString(*attributionValue);
if (!attribution) {
- return Error { "source attribution must be a string" };
+ error = { "source attribution must be a string" };
+ return {};
}
result.attribution = std::move(*attribution);
}
diff --git a/include/mbgl/style/conversion/transition_options.hpp b/include/mbgl/style/conversion/transition_options.hpp
index cdd65cfe9f..de8834d578 100644
--- a/include/mbgl/style/conversion/transition_options.hpp
+++ b/include/mbgl/style/conversion/transition_options.hpp
@@ -11,9 +11,10 @@ template <>
struct Converter<TransitionOptions> {
public:
template <class V>
- Result<TransitionOptions> operator()(const V& value) const {
+ optional<TransitionOptions> operator()(const V& value, Error& error) const {
if (!isObject(value)) {
- return Error { "transition must be an object" };
+ error = { "transition must be an object" };
+ return {};
}
TransitionOptions result;
@@ -22,7 +23,8 @@ public:
if (duration) {
auto number = toNumber(*duration);
if (!number) {
- return Error { "duration must be a number" };
+ error = { "duration must be a number" };
+ return {};
}
result.duration = { std::chrono::milliseconds(int64_t(*number)) };
}
@@ -31,7 +33,8 @@ public:
if (delay) {
auto number = toNumber(*delay);
if (!number) {
- return Error { "delay must be a number" };
+ error = { "delay must be a number" };
+ return {};
}
result.delay = { std::chrono::milliseconds(int64_t(*number)) };
}
diff --git a/platform/android/src/style/conversion/filter.hpp b/platform/android/src/style/conversion/filter.hpp
index fc36d3a044..1f0abcf3a4 100644
--- a/platform/android/src/style/conversion/filter.hpp
+++ b/platform/android/src/style/conversion/filter.hpp
@@ -17,9 +17,10 @@ inline optional<mbgl::style::Filter> toFilter(jni::JNIEnv& env, jni::Array<jni::
mbgl::optional<mbgl::style::Filter> filter;
if (jfilter) {
Value filterValue(env, jfilter);
- auto converted = mbgl::style::conversion::convert<mbgl::style::Filter>(filterValue);
+ mbgl::style::conversion::Error error;
+ auto converted = mbgl::style::conversion::convert<mbgl::style::Filter>(filterValue, error);
if (!converted) {
- mbgl::Log::Error(mbgl::Event::JNI, "Error converting filter: " + converted.error().message);
+ mbgl::Log::Error(mbgl::Event::JNI, "Error converting filter: " + error.message);
}
filter = std::move(*converted);
}
diff --git a/platform/android/src/style/conversion/geojson.hpp b/platform/android/src/style/conversion/geojson.hpp
index 415d96f467..6ac6abcd7c 100644
--- a/platform/android/src/style/conversion/geojson.hpp
+++ b/platform/android/src/style/conversion/geojson.hpp
@@ -17,12 +17,13 @@ namespace style {
namespace conversion {
template <>
-Result<GeoJSON> convertGeoJSON(const mbgl::android::Value& value) {
+optional<GeoJSON> convertGeoJSON(const mbgl::android::Value& value, Error& error) {
// Value should be a string wrapped in an object
mbgl::android::Value jsonValue = value.get("data");
if(value.isNull()) {
- return Error { "no json data found" };
+ error = { "no json data found" };
+ return {};
}
std::string jsonString = value.get("data").toString();
@@ -32,12 +33,14 @@ Result<GeoJSON> convertGeoJSON(const mbgl::android::Value& value) {
if (d.HasParseError()) {
std::stringstream message;
message << d.GetErrorOffset() << " - " << rapidjson::GetParseError_En(d.GetParseError());
- return Error { message.str() };
+ error = { message.str() };
+ return {};
}
- conversion::Result<GeoJSON> geoJSON = conversion::convertGeoJSON<JSValue>(d);
+ optional<GeoJSON> geoJSON = conversion::convertGeoJSON<JSValue>(d, error);
if (!geoJSON) {
- return Error { geoJSON.error().message };
+ error = { error.message };
+ return {};
}
return geoJSON;
@@ -46,8 +49,8 @@ Result<GeoJSON> convertGeoJSON(const mbgl::android::Value& value) {
template <>
struct Converter<GeoJSON> {
- Result<GeoJSON> operator()(const mbgl::android::Value& value) const {
- return convertGeoJSON(value);
+ optional<GeoJSON> operator()(const mbgl::android::Value& value, Error& error) const {
+ return convertGeoJSON(value, error);
}
};
diff --git a/platform/android/src/style/conversion/url_or_tileset.hpp b/platform/android/src/style/conversion/url_or_tileset.hpp
index 4e502324d0..00ef913d41 100644
--- a/platform/android/src/style/conversion/url_or_tileset.hpp
+++ b/platform/android/src/style/conversion/url_or_tileset.hpp
@@ -12,27 +12,25 @@
#include <string>
namespace mbgl {
-namespace style {
-namespace conversion {
-
-template <>
-struct Converter<variant<std::string, Tileset>> {
-
- template <class V>
- Result<variant<std::string, Tileset>> operator()(const V& value) const {
- if (isObject(value)) {
- Result<Tileset> tileset = convert<Tileset>(value);
- if (!tileset) {
- return tileset.error();
- }
- return *tileset;
- } else {
- return *toString(value);
+namespace android {
+
+// This conversion is expected not to fail because it's used only in contexts where
+// the value was originally a String or TileSet object on the Java side. If it fails
+// to convert, it's a bug in our serialization or Java-side static typing.
+inline variant<std::string, Tileset> convertURLOrTileset(const Value& value) {
+ using namespace mbgl::style::conversion;
+
+ if (isObject(value)) {
+ Error error;
+ optional<Tileset> tileset = convert<Tileset>(value, error);
+ if (!tileset) {
+ throw std::logic_error(error.message);
}
+ return { *tileset };
+ } else {
+ return { *toString(value) };
}
-
-};
-
}
+
}
}
diff --git a/platform/android/src/style/layers/layer.cpp b/platform/android/src/style/layers/layer.cpp
index dbf71fd2af..6e93cf4daf 100644
--- a/platform/android/src/style/layers/layer.cpp
+++ b/platform/android/src/style/layers/layer.cpp
@@ -104,9 +104,10 @@ namespace android {
Value wrapped(env, jfilter);
Filter filter;
- Result<Filter> converted = convert<Filter>(wrapped);
+ Error error;
+ optional<Filter> converted = convert<Filter>(wrapped, error);
if (!converted) {
- mbgl::Log::Error(mbgl::Event::JNI, "Error setting filter: " + converted.error().message);
+ mbgl::Log::Error(mbgl::Event::JNI, "Error setting filter: " + error.message);
return;
}
filter = std::move(*converted);
diff --git a/platform/android/src/style/sources/geojson_source.cpp b/platform/android/src/style/sources/geojson_source.cpp
index 7ab98e47c0..0c2d25f9fc 100644
--- a/platform/android/src/style/sources/geojson_source.cpp
+++ b/platform/android/src/style/sources/geojson_source.cpp
@@ -9,7 +9,7 @@
#include "../../conversion/conversion.hpp"
#include "../../conversion/collection.hpp"
#include "../../geometry/conversion/feature.hpp"
-#include "../conversion/url_or_tileset.hpp"
+
#include <mbgl/style/conversion.hpp>
#include <mbgl/style/conversion/geojson_options.hpp>
@@ -18,11 +18,26 @@
namespace mbgl {
namespace android {
+ // This conversion is expected not to fail because it's used only in contexts where
+ // the value was originally a GeoJsonOptions object on the Java side. If it fails
+ // to convert, it's a bug in our serialization or Java-side static typing.
+ static style::GeoJSONOptions convertGeoJSONOptions(jni::JNIEnv& env, jni::Object<> options) {
+ using namespace mbgl::style::conversion;
+ if (!options) {
+ return style::GeoJSONOptions();
+ }
+ Error error;
+ optional<style::GeoJSONOptions> result = convert<style::GeoJSONOptions>(Value(env, options), error);
+ if (!result) {
+ throw std::logic_error(error.message);
+ }
+ return *result;
+ }
+
GeoJSONSource::GeoJSONSource(jni::JNIEnv& env, jni::String sourceId, jni::Object<> options)
: Source(env, std::make_unique<mbgl::style::GeoJSONSource>(
jni::Make<std::string>(env, sourceId),
- options ? *style::conversion::convert<style::GeoJSONOptions>(Value(env, options)) : style::GeoJSONOptions()
- )
+ convertGeoJSONOptions(env, options))
) {
}
@@ -36,9 +51,10 @@ namespace android {
using namespace mbgl::style::conversion;
// Convert the jni object
- Result<GeoJSON> converted = convert<GeoJSON>(Value(env, json));
+ Error error;
+ optional<GeoJSON> converted = convert<GeoJSON>(Value(env, json), error);
if(!converted) {
- mbgl::Log::Error(mbgl::Event::JNI, "Error setting geo json: " + converted.error().message);
+ mbgl::Log::Error(mbgl::Event::JNI, "Error setting geo json: " + error.message);
return;
}
diff --git a/platform/android/src/style/sources/raster_source.cpp b/platform/android/src/style/sources/raster_source.cpp
index 42ac4cda99..0234901a77 100644
--- a/platform/android/src/style/sources/raster_source.cpp
+++ b/platform/android/src/style/sources/raster_source.cpp
@@ -16,7 +16,7 @@ namespace android {
env,
std::make_unique<mbgl::style::RasterSource>(
jni::Make<std::string>(env, sourceId),
- *style::conversion::convert<variant<std::string, Tileset>>(Value(env, urlOrTileSet)),
+ convertURLOrTileset(Value(env, urlOrTileSet)),
tileSize
)
) {
diff --git a/platform/android/src/style/sources/vector_source.cpp b/platform/android/src/style/sources/vector_source.cpp
index 67777f50d4..4852a9b84f 100644
--- a/platform/android/src/style/sources/vector_source.cpp
+++ b/platform/android/src/style/sources/vector_source.cpp
@@ -23,7 +23,7 @@ namespace android {
env,
std::make_unique<mbgl::style::VectorSource>(
jni::Make<std::string>(env, sourceId),
- *style::conversion::convert<variant<std::string, Tileset>>(Value(env, urlOrTileSet))
+ convertURLOrTileset(Value(env, urlOrTileSet))
)
) {
}
diff --git a/platform/darwin/src/MGLStyleValue_Private.h b/platform/darwin/src/MGLStyleValue_Private.h
index 90d6622c93..263b54d7e5 100644
--- a/platform/darwin/src/MGLStyleValue_Private.h
+++ b/platform/darwin/src/MGLStyleValue_Private.h
@@ -123,8 +123,9 @@ public:
return toMBGLConstantValue((MGLConstantStyleValue<ObjCType> *)value);
} else if ([value isKindOfClass:[MGLStyleFunction class]]) {
auto rawValue = toRawStyleSpecValue((MGLStyleFunction<ObjCType> *) value);
- auto result = mbgl::style::conversion::convert<mbgl::style::DataDrivenPropertyValue<MBGLType>>(rawValue);
- NSCAssert(result, @(result.error().message.c_str()));
+ mbgl::style::conversion::Error error;
+ auto result = mbgl::style::conversion::convert<mbgl::style::DataDrivenPropertyValue<MBGLType>>(rawValue, error);
+ NSCAssert(result, @(error.message.c_str()));
return *result;
} else {
return {};
diff --git a/platform/node/src/node_geojson.hpp b/platform/node/src/node_geojson.hpp
index ace4c91426..e4b2ca47e7 100644
--- a/platform/node/src/node_geojson.hpp
+++ b/platform/node/src/node_geojson.hpp
@@ -5,8 +5,9 @@ namespace style {
namespace conversion {
template <>
-Result<GeoJSON> convertGeoJSON(const v8::Local<v8::Value>&) {
- return Error { "not implemented" };
+optional<GeoJSON> convertGeoJSON(const v8::Local<v8::Value>&, Error& error) {
+ error = { "not implemented" };
+ return {};
}
} // namespace conversion
diff --git a/platform/node/src/node_map.cpp b/platform/node/src/node_map.cpp
index a3a11a1907..881c1b2fb7 100644
--- a/platform/node/src/node_map.cpp
+++ b/platform/node/src/node_map.cpp
@@ -538,9 +538,10 @@ void NodeMap::AddSource(const Nan::FunctionCallbackInfo<v8::Value>& info) {
return Nan::ThrowTypeError("First argument must be a string");
}
- Result<std::unique_ptr<Source>> source = convert<std::unique_ptr<Source>>(info[1], *Nan::Utf8String(info[0]));
+ Error error;
+ mbgl::optional<std::unique_ptr<Source>> source = convert<std::unique_ptr<Source>>(info[1], error, *Nan::Utf8String(info[0]));
if (!source) {
- Nan::ThrowTypeError(source.error().message.c_str());
+ Nan::ThrowTypeError(error.message.c_str());
return;
}
@@ -558,9 +559,10 @@ void NodeMap::AddLayer(const Nan::FunctionCallbackInfo<v8::Value>& info) {
return Nan::ThrowTypeError("One argument required");
}
- Result<std::unique_ptr<Layer>> layer = convert<std::unique_ptr<Layer>>(info[0]);
+ Error error;
+ mbgl::optional<std::unique_ptr<Layer>> layer = convert<std::unique_ptr<Layer>>(info[0], error);
if (!layer) {
- Nan::ThrowTypeError(layer.error().message.c_str());
+ Nan::ThrowTypeError(error.message.c_str());
return;
}
@@ -774,9 +776,10 @@ void NodeMap::SetFilter(const Nan::FunctionCallbackInfo<v8::Value>& info) {
Filter filter;
if (!info[1]->IsNull() && !info[1]->IsUndefined()) {
- Result<Filter> converted = convert<Filter>(info[1]);
+ Error error;
+ mbgl::optional<Filter> converted = convert<Filter>(info[1], error);
if (!converted) {
- Nan::ThrowTypeError(converted.error().message.c_str());
+ Nan::ThrowTypeError(error.message.c_str());
return;
}
filter = std::move(*converted);
@@ -908,23 +911,24 @@ void NodeMap::QueryRenderedFeatures(const Nan::FunctionCallbackInfo<v8::Value>&
//Check if filter is provided. If set it must be a valid Filter object
if (Nan::Has(options, Nan::New("filter").ToLocalChecked()).FromJust()) {
auto filterOption = Nan::Get(options, Nan::New("filter").ToLocalChecked()).ToLocalChecked();
- Result<Filter> converted = convert<Filter>(filterOption);
+ Error error;
+ mbgl::optional<Filter> converted = convert<Filter>(filterOption, error);
if (!converted) {
- return Nan::ThrowTypeError(converted.error().message.c_str());
+ return Nan::ThrowTypeError(error.message.c_str());
}
queryOptions.filter = std::move(*converted);
}
}
try {
- std::vector<mbgl::Feature> result;
+ std::vector<mbgl::Feature> optional;
if (Nan::Get(posOrBox, 0).ToLocalChecked()->IsArray()) {
auto pos0 = Nan::Get(posOrBox, 0).ToLocalChecked().As<v8::Array>();
auto pos1 = Nan::Get(posOrBox, 1).ToLocalChecked().As<v8::Array>();
- result = nodeMap->map->queryRenderedFeatures(mbgl::ScreenBox {
+ optional = nodeMap->map->queryRenderedFeatures(mbgl::ScreenBox {
{
Nan::Get(pos0, 0).ToLocalChecked()->NumberValue(),
Nan::Get(pos0, 1).ToLocalChecked()->NumberValue()
@@ -935,15 +939,15 @@ void NodeMap::QueryRenderedFeatures(const Nan::FunctionCallbackInfo<v8::Value>&
}, queryOptions);
} else {
- result = nodeMap->map->queryRenderedFeatures(mbgl::ScreenCoordinate {
+ optional = nodeMap->map->queryRenderedFeatures(mbgl::ScreenCoordinate {
Nan::Get(posOrBox, 0).ToLocalChecked()->NumberValue(),
Nan::Get(posOrBox, 1).ToLocalChecked()->NumberValue()
}, queryOptions);
}
auto array = Nan::New<v8::Array>();
- for (unsigned int i = 0; i < result.size(); i++) {
- array->Set(i, toJS(result[i]));
+ for (unsigned int i = 0; i < optional.size(); i++) {
+ array->Set(i, toJS(optional[i]));
}
info.GetReturnValue().Set(array);
} catch (const std::exception &ex) {
diff --git a/platform/qt/src/qmapboxgl.cpp b/platform/qt/src/qmapboxgl.cpp
index b1c0a11ee1..3d5da10c36 100644
--- a/platform/qt/src/qmapboxgl.cpp
+++ b/platform/qt/src/qmapboxgl.cpp
@@ -1250,9 +1250,10 @@ void QMapboxGL::addSource(const QString &id, const QVariantMap &params)
using namespace mbgl::style;
using namespace mbgl::style::conversion;
- Result<std::unique_ptr<Source>> source = convert<std::unique_ptr<Source>>(QVariant(params), id.toStdString());
+ Error error;
+ mbgl::optional<std::unique_ptr<Source>> source = convert<std::unique_ptr<Source>>(QVariant(params), error, id.toStdString());
if (!source) {
- qWarning() << "Unable to add source:" << source.error().message.c_str();
+ qWarning() << "Unable to add source:" << error.message.c_str();
return;
}
@@ -1291,7 +1292,8 @@ void QMapboxGL::updateSource(const QString &id, const QVariantMap &params)
}
if (params.contains("data")) {
- auto result = convertGeoJSON(params["data"]);
+ Error error;
+ auto result = convertGeoJSON(params["data"], error);
if (result) {
sourceGeoJSON->setGeoJSON(*result);
}
@@ -1362,9 +1364,10 @@ void QMapboxGL::addLayer(const QVariantMap &params)
using namespace mbgl::style;
using namespace mbgl::style::conversion;
- Result<std::unique_ptr<Layer>> layer = convert<std::unique_ptr<Layer>>(QVariant(params));
+ Error error;
+ mbgl::optional<std::unique_ptr<Layer>> layer = convert<std::unique_ptr<Layer>>(QVariant(params), error);
if (!layer) {
- qWarning() << "Unable to add layer:" << layer.error().message.c_str();
+ qWarning() << "Unable to add layer:" << error.message.c_str();
return;
}
@@ -1445,9 +1448,10 @@ void QMapboxGL::setFilter(const QString& layer, const QVariant& filter)
Filter filter_;
- Result<Filter> converted = convert<Filter>(filter);
+ Error error;
+ mbgl::optional<Filter> converted = convert<Filter>(filter, error);
if (!converted) {
- qWarning() << "Error parsing filter:" << converted.error().message.c_str();
+ qWarning() << "Error parsing filter:" << error.message.c_str();
return;
}
filter_ = std::move(*converted);
diff --git a/platform/qt/src/qt_geojson.hpp b/platform/qt/src/qt_geojson.hpp
index 038b051941..7c50c663dd 100644
--- a/platform/qt/src/qt_geojson.hpp
+++ b/platform/qt/src/qt_geojson.hpp
@@ -180,20 +180,21 @@ namespace style {
namespace conversion {
template <>
-Result<GeoJSON> convertGeoJSON(const QMapbox::Feature& feature) {
- return Result<GeoJSON> { GeoJSON { asMapboxGLFeature(feature) } };
+optional<GeoJSON> convertGeoJSON(const QMapbox::Feature& feature, Error&) {
+ return GeoJSON { asMapboxGLFeature(feature) };
}
template <>
-Result<GeoJSON> convertGeoJSON(const QVariant& value) {
+optional<GeoJSON> convertGeoJSON(const QVariant& value, Error& error) {
#if QT_VERSION >= 0x050000
if (value.typeName() == QStringLiteral("QMapbox::Feature")) {
#else
if (value.typeName() == QString("QMapbox::Feature")) {
#endif
- return convertGeoJSON(value.value<QMapbox::Feature>());
+ return convertGeoJSON(value.value<QMapbox::Feature>(), error);
} else if (value.type() != QVariant::ByteArray) {
- return Error { "JSON data must be in QByteArray" };
+ error = { "JSON data must be in QByteArray" };
+ return {};
}
auto data = value.toByteArray();
@@ -208,13 +209,14 @@ Result<GeoJSON> convertGeoJSON(const QVariant& value) {
if (d.HasParseError()) {
std::stringstream message;
message << d.GetErrorOffset() << " - " << rapidjson::GetParseError_En(d.GetParseError());
-
- return Error { message.str() };
+ error = { message.str() };
+ return {};
}
- Result<GeoJSON> geoJSON = convertGeoJSON<JSValue>(d);
+ optional<GeoJSON> geoJSON = convertGeoJSON<JSValue>(d, error);
if (!geoJSON) {
- return Error { geoJSON.error().message };
+ error = { error.message };
+ return {};
}
return geoJSON;
diff --git a/src/mbgl/style/parser.cpp b/src/mbgl/style/parser.cpp
index 926c243733..d970d8bbc0 100644
--- a/src/mbgl/style/parser.cpp
+++ b/src/mbgl/style/parser.cpp
@@ -116,10 +116,11 @@ void Parser::parseSources(const JSValue& value) {
for (const auto& property : value.GetObject()) {
std::string id = *conversion::toString(property.name);
- conversion::Result<std::unique_ptr<Source>> source =
- conversion::convert<std::unique_ptr<Source>>(property.value, id);
+ conversion::Error error;
+ optional<std::unique_ptr<Source>> source =
+ conversion::convert<std::unique_ptr<Source>>(property.value, error, id);
if (!source) {
- Log::Warning(Event::ParseStyle, source.error().message);
+ Log::Warning(Event::ParseStyle, error.message);
continue;
}
@@ -222,9 +223,10 @@ void Parser::parseLayer(const std::string& id, const JSValue& value, std::unique
layer = reference->baseImpl->cloneRef(id);
conversion::setPaintProperties(*layer, value);
} else {
- conversion::Result<std::unique_ptr<Layer>> converted = conversion::convert<std::unique_ptr<Layer>>(value);
+ conversion::Error error;
+ optional<std::unique_ptr<Layer>> converted = conversion::convert<std::unique_ptr<Layer>>(value, error);
if (!converted) {
- Log::Warning(Event::ParseStyle, converted.error().message);
+ Log::Warning(Event::ParseStyle, error.message);
return;
}
layer = std::move(*converted);
@@ -232,20 +234,20 @@ void Parser::parseLayer(const std::string& id, const JSValue& value, std::unique
}
std::vector<FontStack> Parser::fontStacks() const {
- std::set<FontStack> result;
+ std::set<FontStack> optional;
for (const auto& layer : layers) {
if (layer->is<SymbolLayer>()) {
PropertyValue<FontStack> textFont = layer->as<SymbolLayer>()->getTextFont();
if (textFont.isUndefined()) {
- result.insert({"Open Sans Regular", "Arial Unicode MS Regular"});
+ optional.insert({"Open Sans Regular", "Arial Unicode MS Regular"});
} else if (textFont.isConstant()) {
- result.insert(textFont.asConstant());
+ optional.insert(textFont.asConstant());
} else if (textFont.isCameraFunction()) {
textFont.asCameraFunction().stops.match(
[&] (const auto& stops) {
for (const auto& stop : stops.stops) {
- result.insert(stop.second);
+ optional.insert(stop.second);
}
}
);
@@ -253,7 +255,7 @@ std::vector<FontStack> Parser::fontStacks() const {
}
}
- return std::vector<FontStack>(result.begin(), result.end());
+ return std::vector<FontStack>(optional.begin(), optional.end());
}
} // namespace style
diff --git a/src/mbgl/style/property_parsing.cpp b/src/mbgl/style/property_parsing.cpp
deleted file mode 100644
index 16ce0f4adc..0000000000
--- a/src/mbgl/style/property_parsing.cpp
+++ /dev/null
@@ -1,29 +0,0 @@
-#include <mbgl/style/property_parsing.hpp>
-
-namespace mbgl {
-namespace style {
-
-optional<TransitionOptions> parseTransitionOptions(const char *, const JSValue& value) {
- if (!value.IsObject()) {
- return {};
- }
-
- optional<Duration> duration;
- if (value.HasMember("duration") && value["duration"].IsNumber()) {
- duration.emplace(Milliseconds(value["duration"].GetUint()));
- }
-
- optional<Duration> delay;
- if (value.HasMember("delay") && value["delay"].IsNumber()) {
- delay.emplace(Milliseconds(value["delay"].GetUint()));
- }
-
- if (!duration && !delay) {
- return {};
- }
-
- return TransitionOptions { duration, delay };
-}
-
-} // namespace style
-} // namespace mbgl
diff --git a/src/mbgl/style/property_parsing.hpp b/src/mbgl/style/property_parsing.hpp
deleted file mode 100644
index b542c8ae47..0000000000
--- a/src/mbgl/style/property_parsing.hpp
+++ /dev/null
@@ -1,26 +0,0 @@
-#pragma once
-
-#include <mbgl/style/property_value.hpp>
-#include <mbgl/style/transition_options.hpp>
-#include <mbgl/style/rapidjson_conversion.hpp>
-#include <mbgl/style/conversion/property_value.hpp>
-
-#include <mbgl/util/logging.hpp>
-
-namespace mbgl {
-namespace style {
-
-template <typename T>
-PropertyValue<T> parseProperty(const char* name, const JSValue& value) {
- conversion::Result<PropertyValue<T>> result = conversion::convert<PropertyValue<T>>(value);
- if (!result) {
- Log::Warning(Event::ParseStyle, "%s: %s", name, result.error().message);
- return {};
- }
- return *result;
-}
-
-optional<TransitionOptions> parseTransitionOptions(const char * name, const JSValue&);
-
-} // namespace style
-} // namespace mbgl
diff --git a/src/mbgl/style/sources/geojson_source_impl.cpp b/src/mbgl/style/sources/geojson_source_impl.cpp
index b050e5482e..6431d5faa4 100644
--- a/src/mbgl/style/sources/geojson_source_impl.cpp
+++ b/src/mbgl/style/sources/geojson_source_impl.cpp
@@ -21,11 +21,12 @@ namespace style {
namespace conversion {
template <>
-Result<GeoJSON> convertGeoJSON(const JSValue& value) {
+optional<GeoJSON> convertGeoJSON(const JSValue& value, Error& error) {
try {
return mapbox::geojson::convert(value);
} catch (const std::exception& ex) {
- return Error{ ex.what() };
+ error = { ex.what() };
+ return {};
}
}
} // namespace conversion
@@ -136,10 +137,11 @@ void GeoJSONSource::Impl::loadDescription(FileSource& fileSource) {
invalidateTiles();
- conversion::Result<GeoJSON> geoJSON = conversion::convertGeoJSON<JSValue>(d);
+ conversion::Error error;
+ optional<GeoJSON> geoJSON = conversion::convertGeoJSON<JSValue>(d, error);
if (!geoJSON) {
Log::Error(Event::ParseStyle, "Failed to parse GeoJSON data: %s",
- geoJSON.error().message.c_str());
+ error.message.c_str());
// Create an empty GeoJSON VT object to make sure we're not infinitely waiting for
// tiles to load.
_setGeoJSON(GeoJSON{ FeatureCollection{} });
diff --git a/src/mbgl/style/tile_source_impl.cpp b/src/mbgl/style/tile_source_impl.cpp
index daa6389a8e..9ea596d38b 100644
--- a/src/mbgl/style/tile_source_impl.cpp
+++ b/src/mbgl/style/tile_source_impl.cpp
@@ -24,9 +24,10 @@ Tileset TileSourceImpl::parseTileJSON(const std::string& json, const std::string
throw std::runtime_error(message.str());
}
- conversion::Result<Tileset> result = conversion::convert<Tileset, JSValue>(document);
+ conversion::Error error;
+ optional<Tileset> result = conversion::convert<Tileset, JSValue>(document, error);
if (!result) {
- throw std::runtime_error(result.error().message);
+ throw std::runtime_error(error.message);
}
// TODO: Remove this hack by delivering proper URLs in the TileJSON to begin with.
diff --git a/test/style/conversion/function.test.cpp b/test/style/conversion/function.test.cpp
index 4dc6549c78..08637d40cb 100644
--- a/test/style/conversion/function.test.cpp
+++ b/test/style/conversion/function.test.cpp
@@ -10,45 +10,47 @@ using namespace mbgl;
using namespace mbgl::style;
using namespace mbgl::style::conversion;
-auto parseFunction(const std::string& src) {
- JSDocument doc;
- doc.Parse<0>(src);
- return convert<CameraFunction<float>, JSValue>(doc);
-}
-
TEST(StyleConversion, Function) {
+ Error error;
+
+ auto parseFunction = [&](const std::string& src) {
+ JSDocument doc;
+ doc.Parse<0>(src);
+ return convert<CameraFunction<float>, JSValue>(doc, error);
+ };
+
auto fn1 = parseFunction("{\"stops\":[]}");
ASSERT_FALSE(fn1);
- ASSERT_EQ("function must have at least one stop", fn1.error().message);
+ ASSERT_EQ("function must have at least one stop", error.message);
auto fn2 = parseFunction("{\"stops\":[1]}");
ASSERT_FALSE(fn2);
- ASSERT_EQ("function stop must be an array", fn2.error().message);
+ ASSERT_EQ("function stop must be an array", error.message);
auto fn3 = parseFunction("{\"stops\":[[]]}");
ASSERT_FALSE(fn3);
- ASSERT_EQ("function stop must have two elements", fn3.error().message);
+ ASSERT_EQ("function stop must have two elements", error.message);
auto fn4 = parseFunction("{\"stops\":[[-1,-1]]}");
ASSERT_TRUE(bool(fn4));
auto fn5 = parseFunction("{\"stops\":[[0,1,2]]}");
ASSERT_FALSE(fn5);
- ASSERT_EQ("function stop must have two elements", fn5.error().message);
+ ASSERT_EQ("function stop must have two elements", error.message);
auto fn6 = parseFunction("{\"stops\":[[0,\"x\"]]}");
ASSERT_FALSE(fn6);
- ASSERT_EQ("value must be a number", fn6.error().message);
+ ASSERT_EQ("value must be a number", error.message);
auto fn7 = parseFunction("{}");
ASSERT_FALSE(fn7);
- ASSERT_EQ("function value must specify stops", fn7.error().message);
+ ASSERT_EQ("function value must specify stops", error.message);
auto fn8 = parseFunction("[]");
ASSERT_FALSE(fn8);
- ASSERT_EQ("function must be an object", fn8.error().message);
+ ASSERT_EQ("function must be an object", error.message);
auto fn9 = parseFunction("{\"stops\":[[0,0]],\"base\":false}");
ASSERT_FALSE(fn9);
- ASSERT_EQ("function base must be a number", fn9.error().message);
+ ASSERT_EQ("function base must be a number", error.message);
}
diff --git a/test/style/conversion/geojson_options.test.cpp b/test/style/conversion/geojson_options.test.cpp
index ddf261ea52..e6bd984f36 100644
--- a/test/style/conversion/geojson_options.test.cpp
+++ b/test/style/conversion/geojson_options.test.cpp
@@ -12,21 +12,24 @@ using namespace mbgl::style::conversion;
TEST(GeoJSONOptions, Basic) {
ValueMap map;
Value raw(map);
- Result<GeoJSONOptions> converted = convert<GeoJSONOptions>(raw);
+ Error error;
+ mbgl::optional<GeoJSONOptions> converted = convert<GeoJSONOptions>(raw, error);
ASSERT_TRUE((bool) converted);
}
TEST(GeoJSONOptions, ErrorHandling) {
ValueMap map {{"maxzoom", std::string{"should not be a string"}}};
Value raw(map);
- Result<GeoJSONOptions> converted = convert<GeoJSONOptions>(raw);
+ Error error;
+ mbgl::optional<GeoJSONOptions> converted = convert<GeoJSONOptions>(raw, error);
ASSERT_FALSE((bool) converted);
}
TEST(GeoJSONOptions, RetainsDefaults) {
ValueMap map;
Value raw(map);
- GeoJSONOptions converted = *convert<GeoJSONOptions>(raw);
+ Error error;
+ GeoJSONOptions converted = *convert<GeoJSONOptions>(raw, error);
GeoJSONOptions defaults;
// GeoJSON-VT
@@ -54,7 +57,8 @@ TEST(GeoJSONOptions, FullConversion) {
{"clusterMaxZoom", 5.0f}
};
Value raw(map);
- GeoJSONOptions converted = *convert<GeoJSONOptions>(raw);
+ Error error;
+ GeoJSONOptions converted = *convert<GeoJSONOptions>(raw, error);
// GeoJSON-VT
ASSERT_EQ(converted.maxzoom, 1);
diff --git a/test/style/conversion/layer.test.cpp b/test/style/conversion/layer.test.cpp
index b27c1841ee..cfe2662fb8 100644
--- a/test/style/conversion/layer.test.cpp
+++ b/test/style/conversion/layer.test.cpp
@@ -11,10 +11,11 @@ using namespace mbgl::style;
using namespace mbgl::style::conversion;
using namespace std::literals::chrono_literals;
-auto parseLayer(const std::string& src) {
+std::unique_ptr<Layer> parseLayer(const std::string& src) {
JSDocument doc;
doc.Parse<0>(src);
- return convert<std::unique_ptr<Layer>, JSValue>(doc);
+ Error error;
+ return std::move(*convert<std::unique_ptr<Layer>, JSValue>(doc, error));
}
TEST(StyleConversion, LayerTransition) {
@@ -34,13 +35,13 @@ TEST(StyleConversion, LayerTransition) {
}
})JSON");
- ASSERT_EQ(400ms, *(*layer)->as<BackgroundLayer>()->impl->paint.cascading
+ ASSERT_EQ(400ms, *layer->as<BackgroundLayer>()->impl->paint.cascading
.get<BackgroundColor>().getTransition({}).duration);
- ASSERT_EQ(500ms, *(*layer)->as<BackgroundLayer>()->impl->paint.cascading
+ ASSERT_EQ(500ms, *layer->as<BackgroundLayer>()->impl->paint.cascading
.get<BackgroundColor>().getTransition({}).delay);
- ASSERT_EQ(100ms, *(*layer)->as<BackgroundLayer>()->impl->paint.cascading
+ ASSERT_EQ(100ms, *layer->as<BackgroundLayer>()->impl->paint.cascading
.get<BackgroundColor>().getTransition({"class"}).duration);
- ASSERT_FALSE(bool((*layer)->as<BackgroundLayer>()->impl->paint.cascading
+ ASSERT_FALSE(bool(layer->as<BackgroundLayer>()->impl->paint.cascading
.get<BackgroundColor>().getTransition({"class"}).delay));
}
diff --git a/test/style/filter.test.cpp b/test/style/filter.test.cpp
index 2f12246078..c70792d8ef 100644
--- a/test/style/filter.test.cpp
+++ b/test/style/filter.test.cpp
@@ -16,7 +16,10 @@ using namespace mbgl::style;
Filter parse(const char * expression) {
rapidjson::GenericDocument<rapidjson::UTF8<>, rapidjson::CrtAllocator> doc;
doc.Parse<0>(expression);
- return *conversion::convert<Filter, JSValue>(doc);
+ conversion::Error error;
+ optional<Filter> filter = conversion::convert<Filter, JSValue>(doc, error);
+ EXPECT_TRUE(bool(filter));
+ return *filter;
}
Feature feature(const PropertyMap& properties, const Geometry<double>& geometry = Point<double>()) {