diff options
author | Anand Thakker <github@anandthakker.net> | 2017-10-18 11:41:18 -0400 |
---|---|---|
committer | Anand Thakker <github@anandthakker.net> | 2017-10-25 11:53:47 -0400 |
commit | 39e0cb6eab8efe17be777db033b6300021fc4174 (patch) | |
tree | cbd7fcd52742195e835d77870872d18bb14eeb50 | |
parent | 9568ccbbd59cb40fc006bf5d3f6937d5aeb49d49 (diff) | |
download | qtlocation-mapboxgl-39e0cb6eab8efe17be777db033b6300021fc4174.tar.gz |
Add special forms for assertions & coercions with fallbacks
-rw-r--r-- | cmake/core-files.cmake | 8 | ||||
-rw-r--r-- | include/mbgl/style/expression/array_assertion.hpp | 2 | ||||
-rw-r--r-- | include/mbgl/style/expression/assertion.hpp | 27 | ||||
-rw-r--r-- | include/mbgl/style/expression/boolean_operator.hpp | 43 | ||||
-rw-r--r-- | include/mbgl/style/expression/coercion.hpp | 30 | ||||
-rw-r--r-- | include/mbgl/style/expression/expression.hpp | 1 | ||||
-rw-r--r-- | include/mbgl/style/expression/type.hpp | 2 | ||||
-rw-r--r-- | src/mbgl/style/expression/assertion.cpp | 66 | ||||
-rw-r--r-- | src/mbgl/style/expression/boolean_operator.cpp | 0 | ||||
-rw-r--r-- | src/mbgl/style/expression/coercion.cpp | 136 | ||||
-rw-r--r-- | src/mbgl/style/expression/compound_expression.cpp | 115 | ||||
-rw-r--r-- | src/mbgl/style/expression/parsing_context.cpp | 26 | ||||
-rw-r--r-- | src/mbgl/style/expression/util.cpp | 39 | ||||
-rw-r--r-- | src/mbgl/style/expression/util.hpp | 14 |
14 files changed, 396 insertions, 113 deletions
diff --git a/cmake/core-files.cmake b/cmake/core-files.cmake index b0a4741873..18ac5831dc 100644 --- a/cmake/core-files.cmake +++ b/cmake/core-files.cmake @@ -395,10 +395,13 @@ set(MBGL_CORE_FILES # style/expression include/mbgl/style/expression/array_assertion.hpp + include/mbgl/style/expression/assertion.hpp include/mbgl/style/expression/at.hpp + include/mbgl/style/expression/boolean_operator.hpp include/mbgl/style/expression/case.hpp include/mbgl/style/expression/check_subtype.hpp include/mbgl/style/expression/coalesce.hpp + include/mbgl/style/expression/coercion.hpp include/mbgl/style/expression/compound_expression.hpp include/mbgl/style/expression/curve.hpp include/mbgl/style/expression/expression.hpp @@ -409,16 +412,21 @@ set(MBGL_CORE_FILES include/mbgl/style/expression/type.hpp include/mbgl/style/expression/value.hpp src/mbgl/style/expression/array_assertion.cpp + src/mbgl/style/expression/assertion.cpp src/mbgl/style/expression/at.cpp + src/mbgl/style/expression/boolean_operator.cpp src/mbgl/style/expression/case.cpp src/mbgl/style/expression/check_subtype.cpp src/mbgl/style/expression/coalesce.cpp + src/mbgl/style/expression/coercion.cpp src/mbgl/style/expression/compound_expression.cpp src/mbgl/style/expression/curve.cpp src/mbgl/style/expression/let.cpp src/mbgl/style/expression/literal.cpp src/mbgl/style/expression/match.cpp src/mbgl/style/expression/parsing_context.cpp + src/mbgl/style/expression/util.cpp + src/mbgl/style/expression/util.hpp src/mbgl/style/expression/value.cpp # style/function diff --git a/include/mbgl/style/expression/array_assertion.hpp b/include/mbgl/style/expression/array_assertion.hpp index 6bf23f14da..038300341e 100644 --- a/include/mbgl/style/expression/array_assertion.hpp +++ b/include/mbgl/style/expression/array_assertion.hpp @@ -10,12 +10,10 @@ #include <mbgl/style/expression/parsing_context.hpp> #include <mbgl/style/conversion.hpp> - namespace mbgl { namespace style { namespace expression { - class ArrayAssertion : public Expression { public: ArrayAssertion(type::Array type_, std::unique_ptr<Expression> input_) : diff --git a/include/mbgl/style/expression/assertion.hpp b/include/mbgl/style/expression/assertion.hpp new file mode 100644 index 0000000000..7df0d1f440 --- /dev/null +++ b/include/mbgl/style/expression/assertion.hpp @@ -0,0 +1,27 @@ +#pragma once +#include <mbgl/style/expression/expression.hpp> + +namespace mbgl { +namespace style { +namespace expression { + +class Assertion : public Expression { +public: + Assertion(type::Type type_, std::vector<std::unique_ptr<Expression>> inputs_) : + Expression(type_), + inputs(std::move(inputs_)) + {} + + static ParseResult parse(const mbgl::style::conversion::Convertible& value, ParsingContext ctx); + + EvaluationResult evaluate(const EvaluationParameters& params) const override; + void accept(std::function<void(const Expression*)> visit) const override; + +private: + std::vector<std::unique_ptr<Expression>> inputs; +}; + +} // namespace expression +} // namespace style +} // namespace mbgl + diff --git a/include/mbgl/style/expression/boolean_operator.hpp b/include/mbgl/style/expression/boolean_operator.hpp new file mode 100644 index 0000000000..ad24725422 --- /dev/null +++ b/include/mbgl/style/expression/boolean_operator.hpp @@ -0,0 +1,43 @@ +#pragma once +#include <mbgl/style/expression/expression.hpp> + +namespace mbgl { +namespace style { +namespace expression { + +class Any : public Expression { +public: + Any(type::Array type_, std::vector<std::unique_ptr<Expression>> inputs_) : + Expression(type_), + inputs(std::move(inputs_)) + {} + + static ParseResult parse(const mbgl::style::conversion::Convertible& value, ParsingContext ctx); + + EvaluationResult evaluate(const EvaluationParameters& params) const override; + void accept(std::function<void(const Expression*)> visit) const override; + +private: + std::unique_ptr<Expression> inputs; +}; + +class All : public Expression { +public: + All(type::Array type_, std::vector<std::unique_ptr<Expression>> inputs_) : + Expression(type_), + inputs(std::move(inputs_)) + {} + + static ParseResult parse(const mbgl::style::conversion::Convertible& value, ParsingContext ctx); + + EvaluationResult evaluate(const EvaluationParameters& params) const override; + void accept(std::function<void(const Expression*)> visit) const override; + +private: + std::unique_ptr<Expression> inputs; +}; + +} // namespace expression +} // namespace style +} // namespace mbgl + diff --git a/include/mbgl/style/expression/coercion.hpp b/include/mbgl/style/expression/coercion.hpp new file mode 100644 index 0000000000..30c5167258 --- /dev/null +++ b/include/mbgl/style/expression/coercion.hpp @@ -0,0 +1,30 @@ +#pragma once +#include <mbgl/style/expression/expression.hpp> + +namespace mbgl { +namespace style { +namespace expression { + +/** + * Special form for error-coalescing coercion expressions "to-number", + * "to-color". Since these coercions can fail at runtime, they accept multiple + * arguments, only evaluating one at a time until one succeeds. + */ +class Coercion : public Expression { +public: + Coercion(type::Type type_, std::vector<std::unique_ptr<Expression>> inputs_); + + static ParseResult parse(const mbgl::style::conversion::Convertible& value, ParsingContext ctx); + + EvaluationResult evaluate(const EvaluationParameters& params) const override; + void accept(std::function<void(const Expression*)> visit) const override; + +private: + EvaluationResult (*coerceSingleValue) (const Value& v); + std::vector<std::unique_ptr<Expression>> inputs; +}; + +} // namespace expression +} // namespace style +} // namespace mbgl + diff --git a/include/mbgl/style/expression/expression.hpp b/include/mbgl/style/expression/expression.hpp index 9441c0e818..b57af0906b 100644 --- a/include/mbgl/style/expression/expression.hpp +++ b/include/mbgl/style/expression/expression.hpp @@ -30,6 +30,7 @@ struct EvaluationParameters { optional<float> zoom; GeometryTileFeature const * feature; + optional<double> heatmapDensity; }; template<typename T> diff --git a/include/mbgl/style/expression/type.hpp b/include/mbgl/style/expression/type.hpp index a730b884a3..6f011676a1 100644 --- a/include/mbgl/style/expression/type.hpp +++ b/include/mbgl/style/expression/type.hpp @@ -85,7 +85,7 @@ using Type = variant< ErrorType>; struct Array { - Array(Type itemType_) : itemType(std::move(itemType_)) {} + explicit Array(Type itemType_) : itemType(std::move(itemType_)) {} Array(Type itemType_, std::size_t N_) : itemType(std::move(itemType_)), N(N_) {} Array(Type itemType_, optional<std::size_t> N_) : itemType(std::move(itemType_)), N(std::move(N_)) {} std::string getName() const { diff --git a/src/mbgl/style/expression/assertion.cpp b/src/mbgl/style/expression/assertion.cpp new file mode 100644 index 0000000000..acef342e6f --- /dev/null +++ b/src/mbgl/style/expression/assertion.cpp @@ -0,0 +1,66 @@ +#include <mbgl/style/expression/assertion.hpp> +#include <mbgl/style/expression/check_subtype.hpp> + +namespace mbgl { +namespace style { +namespace expression { + +ParseResult Assertion::parse(const mbgl::style::conversion::Convertible& value, ParsingContext ctx) { + using namespace mbgl::style::conversion; + static std::unordered_map<std::string, type::Type> types { + {"string", type::String}, + {"number", type::Number}, + {"boolean", type::Boolean}, + {"object", type::Object} + }; + + std::size_t length = arrayLength(value); + + if (length < 2) { + ctx.error("Expected at least one argument."); + return ParseResult(); + } + + auto it = types.find(*toString(arrayMember(value, 0))); + assert(it != types.end()); + + std::vector<std::unique_ptr<Expression>> parsed; + for (std::size_t i = 1; i < length; i++) { + ParseResult input = ctx.concat(i, {type::Value}).parse(arrayMember(value, i)); + if (!input) return ParseResult(); + parsed.push_back(std::move(*input)); + } + + return ParseResult(std::make_unique<Assertion>(it->second, std::move(parsed))); +} + +EvaluationResult Assertion::evaluate(const EvaluationParameters& params) const { + for (std::size_t i = 0; i < inputs.size(); i++) { + EvaluationResult value = inputs[i]->evaluate(params); + if (!value) return value; + if (!type::checkSubtype(getType(), typeOf(*value))) { + return value; + } else if (i == inputs.size() - 1) { + return EvaluationError { + "Expected value to be of type " + toString(getType()) + + ", but found " + toString(typeOf(*value)) + " instead." + }; + } + } + + assert(false); + return EvaluationResult(); +}; + +void Assertion::accept(std::function<void(const Expression*)> visit) const { + visit(this); + for(const std::unique_ptr<Expression>& input : inputs) { + input->accept(visit); + } +}; + +} // namespace expression +} // namespace style +} // namespace mbgl + + diff --git a/src/mbgl/style/expression/boolean_operator.cpp b/src/mbgl/style/expression/boolean_operator.cpp new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/src/mbgl/style/expression/boolean_operator.cpp diff --git a/src/mbgl/style/expression/coercion.cpp b/src/mbgl/style/expression/coercion.cpp new file mode 100644 index 0000000000..3a0ef7fc1f --- /dev/null +++ b/src/mbgl/style/expression/coercion.cpp @@ -0,0 +1,136 @@ +#include <mbgl/style/expression/coercion.hpp> +#include <mbgl/style/expression/check_subtype.hpp> +#include <mbgl/style/expression/util.hpp> + +namespace mbgl { +namespace style { +namespace expression { + +EvaluationResult toNumber(const Value& v) { + optional<double> result = v.match( + [](const double f) -> optional<double> { return f; }, + [](const std::string& s) -> optional<double> { + try { + return std::stof(s); + } catch(std::exception) { + return optional<double>(); + } + }, + [](const auto&) { return optional<double>(); } + ); + if (!result) { + return EvaluationError { + "Could not convert " + stringify(v) + " to number." + }; + } + return *result; +} + +EvaluationResult toColor(const Value& colorValue) { + return colorValue.match( + [&](const std::string& colorString) -> EvaluationResult { + const optional<mbgl::Color> result = mbgl::Color::parse(colorString); + if (result) { + return *result; + } else { + return EvaluationError{ + "Could not parse color from value '" + colorString + "'" + }; + } + }, + [&](const std::vector<Value>& components) -> EvaluationResult { + std::size_t len = components.size(); + bool isNumeric = std::all_of(components.begin(), components.end(), [](const Value& item) { + return item.template is<double>(); + }); + if ((len == 3 || len == 4) && isNumeric) { + Result<mbgl::Color> c = {rgba( + components[0].template get<double>(), + components[1].template get<double>(), + components[2].template get<double>(), + len == 4 ? components[3].template get<double>() : 1.0 + )}; + if (!c) return c.error(); + return *c; + } else { + return EvaluationError{ + "Invalid rbga value " + stringify(colorValue) + ": expected an array containing either three or four numeric values." + }; + } + }, + [&](const auto&) -> EvaluationResult { + return EvaluationError{ + "Could not parse color from value '" + stringify(colorValue) + "'" + }; + } + ); +} + +Coercion::Coercion(type::Type type_, std::vector<std::unique_ptr<Expression>> inputs_) : + Expression(std::move(type_)), + inputs(std::move(inputs_)) +{ + type::Type t = getType(); + if (t.is<type::NumberType>()) { + coerceSingleValue = toNumber; + } else if (t.is<type::ColorType>()) { + coerceSingleValue = toColor; + } else { + assert(false); + } +} + +ParseResult Coercion::parse(const mbgl::style::conversion::Convertible& value, ParsingContext ctx) { + using namespace mbgl::style::conversion; + static std::unordered_map<std::string, type::Type> types { + {"to-number", type::Number}, + {"to-color", type::Color} + }; + + std::size_t length = arrayLength(value); + + if (length < 2) { + ctx.error("Expected at least one argument."); + return ParseResult(); + } + + auto it = types.find(*toString(arrayMember(value, 0))); + assert(it != types.end()); + + std::vector<std::unique_ptr<Expression>> parsed; + for (std::size_t i = 1; i < length; i++) { + ParseResult input = ctx.concat(i, {type::Value}).parse(arrayMember(value, i)); + if (!input) return ParseResult(); + parsed.push_back(std::move(*input)); + } + + return ParseResult(std::make_unique<Coercion>(it->second, std::move(parsed))); +} + +EvaluationResult Coercion::evaluate(const EvaluationParameters& params) const { + for (std::size_t i = 0; i < inputs.size(); i++) { + EvaluationResult value = inputs[i]->evaluate(params); + if (!value) return value; + EvaluationResult coerced = coerceSingleValue(*value); + if (coerced || i == inputs.size() - 1) { + return coerced; + } + } + + assert(false); + return EvaluationResult(); +}; + +void Coercion::accept(std::function<void(const Expression*)> visit) const { + visit(this); + for(const std::unique_ptr<Expression>& input : inputs) { + input->accept(visit); + } +}; + +} // namespace expression +} // namespace style +} // namespace mbgl + + + diff --git a/src/mbgl/style/expression/compound_expression.cpp b/src/mbgl/style/expression/compound_expression.cpp index d6f0e4c553..0673f07736 100644 --- a/src/mbgl/style/expression/compound_expression.cpp +++ b/src/mbgl/style/expression/compound_expression.cpp @@ -1,4 +1,5 @@ #include <mbgl/style/expression/compound_expression.hpp> +#include <mbgl/style/expression/util.hpp> #include <mbgl/tile/geometry_tile_data.hpp> #include <mbgl/util/ignore.hpp> @@ -6,7 +7,6 @@ namespace mbgl { namespace style { namespace expression { - namespace detail { /* @@ -181,32 +181,6 @@ Result<T> assertion(const Value& v) { return v.get<T>(); } -std::string stringifyColor(double r, double g, double b, double a) { - return stringify(r) + ", " + - stringify(g) + ", " + - stringify(b) + ", " + - stringify(a); -} -Result<mbgl::Color> rgba(double r, double g, double b, double a) { - if ( - r < 0 || r > 255 || - g < 0 || g > 255 || - b < 0 || b > 255 - ) { - return EvaluationError { - "Invalid rgba value [" + stringifyColor(r, g, b, a) + - "]: 'r', 'g', and 'b' must be between 0 and 255." - }; - } - if (a < 0 || a > 1) { - return EvaluationError { - "Invalid rgba value [" + stringifyColor(r, g, b, a) + - "]: 'a' must be between 0 and 1." - }; - } - return mbgl::Color(r / 255, g / 255, b / 255, a); -} - template <typename T> Result<bool> equal(const T& lhs, const T& rhs) { return lhs == rhs; } @@ -236,38 +210,11 @@ std::unordered_map<std::string, CompoundExpressionRegistry::Definition> initiali define("to-string", [](const Value& value) -> Result<std::string> { return value.match( - [](const std::unordered_map<std::string, Value>&) -> Result<std::string> { - return EvaluationError { - R"(Expected a primitive value in ["string", ...], but found Object instead.)" - }; - }, - [](const std::vector<Value>& v) -> Result<std::string> { - return EvaluationError { - R"(Expected a primitive value in ["string", ...], but found )" + toString(typeOf(v)) + " instead." - }; - }, + [](const mbgl::Color& c) -> Result<std::string> { return c.stringify(); }, // avoid quoting [](const auto& v) -> Result<std::string> { return stringify(v); } ); }); - define("to-number", [](const Value& v) -> Result<double> { - optional<double> result = v.match( - [](const double f) -> optional<double> { return f; }, - [](const std::string& s) -> optional<double> { - try { - return std::stof(s); - } catch(std::exception) { - return optional<double>(); - } - }, - [](const auto&) { return optional<double>(); } - ); - if (!result) { - return EvaluationError { - "Could not convert " + stringify(v) + " to number." - }; - } - return *result; - }); + define("to-boolean", [](const Value& v) -> Result<bool> { return v.match( [&] (double f) { return (bool)f; }, @@ -281,45 +228,6 @@ std::unordered_map<std::string, CompoundExpressionRegistry::Definition> initiali return std::array<double, 4> {{ color.r, color.g, color.b, color.a }}; }); - define("to-color", [](const Value& colorValue) -> Result<mbgl::Color> { - return colorValue.match( - [&](const std::string& colorString) -> Result<mbgl::Color> { - const optional<mbgl::Color> result = mbgl::Color::parse(colorString); - if (result) { - return *result; - } else { - return EvaluationError{ - "Could not parse color from value '" + colorString + "'" - }; - } - }, - [&](const std::vector<Value>& components) -> Result<mbgl::Color> { - std::size_t len = components.size(); - bool isNumeric = std::all_of(components.begin(), components.end(), [](const Value& item) { - return item.template is<double>(); - }); - if ((len == 3 || len == 4) && isNumeric) { - return {rgba( - components[0].template get<double>(), - components[1].template get<double>(), - components[2].template get<double>(), - len == 4 ? components[3].template get<double>() : 1.0 - )}; - } else { - return EvaluationError{ - "Could not parse color from value '" + stringify(colorValue) + "'" - }; - } - }, - [&](const auto&) -> Result<mbgl::Color> { - return EvaluationError{ - "Could not parse color from value '" + stringify(colorValue) + "'" - }; - } - ); - - }); - define("rgba", rgba); define("rgb", [](double r, double g, double b) { return rgba(r, g, b, 1.0f); }); @@ -332,6 +240,15 @@ std::unordered_map<std::string, CompoundExpressionRegistry::Definition> initiali return *(params.zoom); }); + define("heatmap-density", [](const EvaluationParameters& params) -> Result<double> { + if (!params.heatmapDensity) { + return EvaluationError { + "The 'heatmap-density' expression is unavailable in the current evaluation context." + }; + } + return *(params.heatmapDensity); + }); + define("has", [](const EvaluationParameters& params, const std::string& key) -> Result<bool> { if (!params.feature) { return EvaluationError { @@ -472,10 +389,10 @@ std::unordered_map<std::string, CompoundExpressionRegistry::Definition> initiali define("==", equal<bool>); define("==", equal<NullValue>); - define("==", notEqual<double>); - define("==", notEqual<const std::string&>); - define("==", notEqual<bool>); - define("==", notEqual<NullValue>); + define("!=", notEqual<double>); + define("!=", notEqual<const std::string&>); + define("!=", notEqual<bool>); + define("!=", notEqual<NullValue>); define(">", [](double lhs, double rhs) -> Result<bool> { return lhs > rhs; }); define(">", [](const std::string& lhs, const std::string& rhs) -> Result<bool> { return lhs > rhs; }); diff --git a/src/mbgl/style/expression/parsing_context.cpp b/src/mbgl/style/expression/parsing_context.cpp index 4e7a9dedad..2c00bbfb22 100644 --- a/src/mbgl/style/expression/parsing_context.cpp +++ b/src/mbgl/style/expression/parsing_context.cpp @@ -2,8 +2,10 @@ #include <mbgl/style/expression/parsing_context.hpp> #include <mbgl/style/expression/at.hpp> #include <mbgl/style/expression/array_assertion.hpp> +#include <mbgl/style/expression/assertion.hpp> #include <mbgl/style/expression/case.hpp> #include <mbgl/style/expression/coalesce.hpp> +#include <mbgl/style/expression/coercion.hpp> #include <mbgl/style/expression/compound_expression.hpp> #include <mbgl/style/expression/curve.hpp> #include <mbgl/style/expression/let.hpp> @@ -65,6 +67,10 @@ ParseResult ParsingContext::parse(const mbgl::style::conversion::Convertible& va parsed = Var::parse(value, *this); } else if (*op == "at") { parsed = At::parse(value, *this); + } else if (*op == "string" || *op == "number" || *op == "boolean" || *op == "object") { + parsed = Assertion::parse(value, *this); + } else if (*op == "to-color" || *op == "to-number") { + parsed = Coercion::parse(value, *this); } else { parsed = parseCompoundExpression(*op, value, *this); } @@ -80,23 +86,21 @@ ParseResult ParsingContext::parse(const mbgl::style::conversion::Convertible& va if (!parsed) { assert(errors.size() > 0); } else if (expected) { - auto wrapForType = [&](const std::string& wrapper, std::unique_ptr<Expression> expression) { + auto wrapForType = [&](const type::Type& target, std::unique_ptr<Expression> expression) -> std::unique_ptr<Expression> { std::vector<std::unique_ptr<Expression>> args; args.push_back(std::move(expression)); - return createCompoundExpression(wrapper, std::move(args), *this); + if (target == type::Color) { + return std::make_unique<Coercion>(target, std::move(args)); + } else { + return std::make_unique<Assertion>(target, std::move(args)); + } }; const type::Type actual = (*parsed)->getType(); if (*expected == type::Color && (actual == type::String || actual == type::Value)) { - parsed = wrapForType("to-color", std::move(*parsed)); - } else if (*expected != type::Value && actual == type::Value) { - if (*expected == type::String) { - parsed = wrapForType("string", std::move(*parsed)); - } else if (*expected == type::Number) { - parsed = wrapForType("number", std::move(*parsed)); - } else if (*expected == type::Boolean) { - parsed = wrapForType("boolean", std::move(*parsed)); - } + parsed = wrapForType(type::Color, std::move(*parsed)); + } else if ((*expected == type::String || *expected == type::Number || *expected == type::Boolean) && actual == type::Value) { + parsed = wrapForType(*expected, std::move(*parsed)); } checkType((*parsed)->getType()); diff --git a/src/mbgl/style/expression/util.cpp b/src/mbgl/style/expression/util.cpp new file mode 100644 index 0000000000..09c6c3c23d --- /dev/null +++ b/src/mbgl/style/expression/util.cpp @@ -0,0 +1,39 @@ + +#include "util.hpp" +#include <mbgl/style/expression/value.hpp> + +namespace mbgl { +namespace style { +namespace expression { + +std::string stringifyColor(double r, double g, double b, double a) { + return stringify(r) + ", " + + stringify(g) + ", " + + stringify(b) + ", " + + stringify(a); +} + +Result<mbgl::Color> rgba(double r, double g, double b, double a) { + if ( + r < 0 || r > 255 || + g < 0 || g > 255 || + b < 0 || b > 255 + ) { + return EvaluationError { + "Invalid rgba value [" + stringifyColor(r, g, b, a) + + "]: 'r', 'g', and 'b' must be between 0 and 255." + }; + } + if (a < 0 || a > 1) { + return EvaluationError { + "Invalid rgba value [" + stringifyColor(r, g, b, a) + + "]: 'a' must be between 0 and 1." + }; + } + return mbgl::Color(r / 255, g / 255, b / 255, a); +} + +} // namespace expression +} // namespace style +} // namespace mbgl + diff --git a/src/mbgl/style/expression/util.hpp b/src/mbgl/style/expression/util.hpp new file mode 100644 index 0000000000..192e11da4e --- /dev/null +++ b/src/mbgl/style/expression/util.hpp @@ -0,0 +1,14 @@ +#pragma once + +#include <mbgl/style/expression/expression.hpp> +#include <mbgl/util/color.hpp> + +namespace mbgl { +namespace style { +namespace expression { + +Result<mbgl::Color> rgba(double r, double g, double b, double a); + +} // namespace expression +} // namespace style +} // namespace mbgl |