#pragma once #include #include #include #include #include #include namespace mbgl { namespace style { namespace conversion { template Result> convertStops(const V& value) { auto stopsValue = objectMember(value, "stops"); if (!stopsValue) { return Error { "function value must specify stops" }; } if (!isArray(*stopsValue)) { return Error { "function stops must be an array" }; } if (arrayLength(*stopsValue) == 0) { return Error { "function must have at least one stop" }; } std::map stops; for (std::size_t i = 0; i < arrayLength(*stopsValue); ++i) { const auto& stopValue = arrayMember(*stopsValue, i); if (!isArray(stopValue)) { return Error { "function stop must be an array" }; } if (arrayLength(stopValue) != 2) { return Error { "function stop must have two elements" }; } Result d = convert(arrayMember(stopValue, 0)); if (!d) { return d.error(); } Result r = convert(arrayMember(stopValue, 1)); if (!r) { return r.error(); } stops.emplace(*d, *r); } return stops; } template struct Converter> { static constexpr const char * type = "exponential"; template Result> operator()(const V& value) const { auto stops = convertStops(value); if (!stops) { return stops.error(); } auto baseValue = objectMember(value, "base"); if (!baseValue) { return ExponentialStops(*stops); } optional base = toNumber(*baseValue); if (!base) { return Error { "function base must be a number"}; } return ExponentialStops(*stops, *base); } }; template struct Converter> { static constexpr const char * type = "interval"; template Result> operator()(const V& value) const { auto stops = convertStops(value); if (!stops) { return stops.error(); } return IntervalStops(*stops); } }; template <> struct Converter { template Result operator()(const V& value) const { auto b = toBool(value); if (b) { return *b; } auto n = toNumber(value); if (n) { return int64_t(*n); } auto s = toString(value); if (s) { return *s; } return Error { "stop domain value must be a number, string, or boolean" }; } }; template struct Converter> { static constexpr const char * type = "categorical"; template Result> operator()(const V& value) const { auto stops = convertStops(value); if (!stops) { return stops.error(); } return CategoricalStops( std::map((*stops).begin(), (*stops).end())); } }; template struct Converter> { static constexpr const char * type = "identity"; template Result> operator()(const V&) const { return IdentityStops(); } }; template struct StopsConverter; template struct StopsConverter> { public: template Result> operator()(const V& value) const { std::string type = util::Interpolatable ? "exponential" : "interval"; auto typeValue = objectMember(value, "type"); if (typeValue && toString(*typeValue)) { type = *toString(*typeValue); } optional>> result; // Workaround for https://gcc.gnu.org/bugzilla/show_bug.cgi?id=47226 auto tryConvert = [&] (auto* tp) { using Stops = std::decay_t; if (type == Converter::type) { auto stops = convert(value); result = stops ? Result>(*stops) : Result>(stops.error()); } }; util::ignore({ (tryConvert((Ts*)nullptr), 0)... }); if (!result) { return Error { "unsupported function type" }; } return *result; } }; template struct Converter> { template Result> operator()(const V& value) const { if (!isObject(value)) { return Error { "function must be an object" }; } auto stops = StopsConverter::Stops>()(value); if (!stops) { return stops.error(); } return CameraFunction(*stops); } }; template Result> convertDefaultValue(const V& value) { auto defaultValueValue = objectMember(value, "defaultValue"); if (!defaultValueValue) { return {}; } auto defaultValue = convert(*defaultValueValue); if (!defaultValue) { return Error { "wrong type for \"default\": " + defaultValue.error().message }; } return *defaultValue; } template struct Converter> { template Result> operator()(const V& value) const { if (!isObject(value)) { return Error { "function must be an object" }; } auto propertyValue = objectMember(value, "property"); if (!propertyValue) { return Error { "function must specify property" }; } auto propertyString = toString(*propertyValue); if (!propertyString) { return Error { "function property must be a string" }; } auto stops = StopsConverter::Stops>()(value); if (!stops) { return stops.error(); } auto defaultValue = convertDefaultValue(value); if (!defaultValue) { return defaultValue.error(); } return SourceFunction(*propertyString, *stops, *defaultValue); } }; template struct CompositeValue : std::pair { using std::pair::pair; }; template struct Converter> { template Result> operator()(const V& value) const { if (!isObject(value)) { return Error { "stop must be an object" }; } auto zoomValue = objectMember(value, "zoom"); if (!zoomValue) { return Error { "stop must specify zoom" }; } auto propertyValue = objectMember(value, "value"); if (!propertyValue) { return Error { "stop must specify value" }; } Result z = convert(*zoomValue); if (!z) { return z.error(); } Result s = convert(*propertyValue); if (!s) { return s.error(); } return CompositeValue { *z, *s }; } }; template struct Converter> { template Result> operator()(const V& value) const { if (!isObject(value)) { return Error { "function must be an object" }; } auto propertyValue = objectMember(value, "property"); if (!propertyValue) { return Error { "function must specify property" }; } auto propertyString = toString(*propertyValue); if (!propertyString) { return Error { "function property must be a string" }; } auto defaultValue = convertDefaultValue(value); if (!defaultValue) { return defaultValue.error(); } std::string type = "exponential"; auto typeValue = objectMember(value, "type"); if (typeValue && toString(*typeValue)) { type = *toString(*typeValue); } if (type == "exponential") { auto stops = convertStops, T>(value); if (!stops) { return stops.error(); } auto base = 1.0f; auto baseValue = objectMember(value, "base"); if (baseValue && toNumber(*baseValue)) { base = *toNumber(*baseValue); } std::map> convertedStops; for (const auto& stop : *stops) { auto& inner = convertedStops[stop.first.first]; inner.base = base; inner.stops.emplace(stop.first.second, stop.second); } return CompositeFunction(*propertyString, convertedStops, *defaultValue); } else if (type == "interval") { auto stops = convertStops, T>(value); if (!stops) { return stops.error(); } std::map> convertedStops; for (const auto& stop : *stops) { auto& inner = convertedStops[stop.first.first]; inner.stops.emplace(stop.first.second, stop.second); } return CompositeFunction(*propertyString, convertedStops, *defaultValue); } else if (type == "categorical") { auto stops = convertStops, T>(value); if (!stops) { return stops.error(); } std::map> convertedStops; for (const auto& stop : *stops) { auto& inner = convertedStops[stop.first.first]; inner.stops.emplace(stop.first.second, stop.second); } return CompositeFunction(*propertyString, convertedStops, *defaultValue); } else { return Error { "unsupported function type" }; } } }; } // namespace conversion } // namespace style } // namespace mbgl