/* * Copyright (c) 2024, Tim Flynn * * SPDX-License-Identifier: BSD-2-Clause */ #pragma once #include #include #include #include #include #include namespace Web::WebDriver { template static ErrorOr get_property(JsonObject const& payload, StringView key) { auto property = payload.get(key); if (!property.has_value()) return WebDriver::Error::from_code(ErrorCode::InvalidArgument, MUST(String::formatted("No property called '{}' present", key))); auto is_safe_number = [](T value) { if constexpr (sizeof(T) >= 8) { if (value > static_cast(JS::MAX_ARRAY_LIKE_INDEX)) return false; if constexpr (IsSigned) { if (value < -static_cast(JS::MAX_ARRAY_LIKE_INDEX)) return false; } } return true; }; if constexpr (IsSame) { if (!property->is_string()) return WebDriver::Error::from_code(ErrorCode::InvalidArgument, MUST(String::formatted("Property '{}' is not a String", key))); return property->as_string(); } else if constexpr (IsSame) { if (!property->is_bool()) return WebDriver::Error::from_code(ErrorCode::InvalidArgument, MUST(String::formatted("Property '{}' is not a Boolean", key))); return property->as_bool(); } else if constexpr (IsIntegral) { if (auto maybe_number = property->get_integer(); maybe_number.has_value() && is_safe_number(*maybe_number)) return *maybe_number; return WebDriver::Error::from_code(ErrorCode::InvalidArgument, MUST(String::formatted("Property '{}' is not an Integer", key))); } else if constexpr (IsSame) { if (auto maybe_number = property->get_double_with_precision_loss(); maybe_number.has_value() && is_safe_number(*maybe_number)) return *maybe_number; return WebDriver::Error::from_code(ErrorCode::InvalidArgument, MUST(String::formatted("Property '{}' is not a Number", key))); } else if constexpr (IsSame) { if (!property->is_array()) return WebDriver::Error::from_code(ErrorCode::InvalidArgument, MUST(String::formatted("Property '{}' is not an Array", key))); return &property->as_array(); } else if constexpr (IsSame) { if (!property->is_object()) return WebDriver::Error::from_code(ErrorCode::InvalidArgument, MUST(String::formatted("Property '{}' is not an Object", key))); return &property->as_object(); } else { static_assert(DependentFalse, "get_property invoked with unknown property type"); VERIFY_NOT_REACHED(); } } template static ErrorOr get_property(JsonValue const& payload, StringView key) { if (!payload.is_object()) return WebDriver::Error::from_code(ErrorCode::InvalidArgument, "Payload is not a JSON object"sv); return get_property(payload.as_object(), key); } template static ErrorOr, WebDriver::Error> get_optional_property(JsonObject const& object, StringView key) { if (!object.has(key)) return OptionalNone {}; return get_property(object, key); } template static ErrorOr get_property_with_limits(JsonObject const& object, StringView key, Optional min, Optional max) { auto value = TRY(get_property(object, key)); if (min.has_value() && value < *min) return WebDriver::Error::from_code(WebDriver::ErrorCode::InvalidArgument, MUST(String::formatted("Property '{}' must not be less than {}", key, *min))); if (max.has_value() && value > *max) return WebDriver::Error::from_code(WebDriver::ErrorCode::InvalidArgument, MUST(String::formatted("Property '{}' must not be greater than {}", key, *max))); return value; } template static ErrorOr, WebDriver::Error> get_optional_property_with_limits(JsonObject const& object, StringView key, Optional min, Optional max) { if (!object.has(key)) return OptionalNone {}; return get_property_with_limits(object, key, min, max); } }