diff --git a/phlex/configuration.cpp b/phlex/configuration.cpp index 03cb6daa..3be6f390 100644 --- a/phlex/configuration.cpp +++ b/phlex/configuration.cpp @@ -1,8 +1,58 @@ #include "phlex/configuration.hpp" #include "phlex/core/product_query.hpp" +#include "phlex/model/product_specification.hpp" -#include +#include +#include #include +#include + +namespace { + [[maybe_unused]] std::optional value_if_exists( + boost::json::object const& obj, // will be used later for new product_query + std::string_view parameter) + { + if (!obj.contains(parameter)) { + return std::nullopt; + } + auto const& val = obj.at(parameter); + if (!val.is_string()) { + std::string_view kind; + switch (val.kind()) { + case boost::json::kind::null: + // seems reasonable to interpret this as if the value were not provided + return std::nullopt; + break; + case boost::json::kind::bool_: + kind = "bool"; + break; + case boost::json::kind::int64: + kind = "std::int64_t"; + break; + case boost::json::kind::uint64: + kind = "std::uint64_t"; + break; + case boost::json::kind::double_: + kind = "double"; + break; + case boost::json::kind::array: + kind = "array"; + break; + case boost::json::kind::object: + kind = "object"; + break; + default: + // std::unreachable(); + break; + } + throw std::runtime_error( + fmt::format("Error retrieving parameter '{}'. Should be a string but is instead a {}", + parameter, + kind)); + } + return boost::json::value_to(val); + } +} namespace phlex { std::vector configuration::keys() const @@ -25,7 +75,8 @@ namespace phlex { { using detail::value_decorate_exception; auto query_object = jv.as_object(); - return product_query{{value_decorate_exception(query_object, "product")}, - value_decorate_exception(query_object, "layer")}; + auto product = value_decorate_exception(query_object, "product"); + auto layer = value_decorate_exception(query_object, "layer"); + return product_query{experimental::product_specification::create(product), layer}; } } diff --git a/phlex/configuration.hpp b/phlex/configuration.hpp index 1fa142b8..82ef7aa3 100644 --- a/phlex/configuration.hpp +++ b/phlex/configuration.hpp @@ -19,6 +19,14 @@ namespace phlex { } catch (std::exception const& e) { throw std::runtime_error("Error retrieving parameter '" + key + "':\n" + e.what()); } + + // helper for unpacking json array + template + std::array unpack_json_array(boost::json::array const& array, + std::index_sequence) + { + return std::array{boost::json::value_to(array.at(I))...}; + } } class configuration { @@ -81,6 +89,19 @@ namespace phlex { product_query tag_invoke(boost::json::value_to_tag const&, boost::json::value const& jv); + + template + std::array tag_invoke( + boost::json::value_to_tag> const&, boost::json::value const& jv) + { + auto const& array = jv.as_array(); + return detail::unpack_json_array(array, std::make_index_sequence()); + } } +// The below is a better long term fix but it requires a Boost JSON bug (#1140) to be fixed +// namespace boost::json { +// template +// struct is_sequence_like> : std::false_type {}; +// } #endif // PHLEX_CONFIGURATION_HPP diff --git a/phlex/core/product_query.cpp b/phlex/core/product_query.cpp index 5f442e70..01e08fc4 100644 --- a/phlex/core/product_query.cpp +++ b/phlex/core/product_query.cpp @@ -5,8 +5,6 @@ #include namespace phlex { - product_query::product_query() = default; - product_query::product_query(experimental::product_specification spec, std::string layer) : spec_{std::move(spec)}, layer_{std::move(layer)} { diff --git a/phlex/core/product_query.hpp b/phlex/core/product_query.hpp index 55cc3956..d11b9b69 100644 --- a/phlex/core/product_query.hpp +++ b/phlex/core/product_query.hpp @@ -10,9 +10,6 @@ namespace phlex { class product_query { public: - // FIXME: Boost JSON's parameter retrieval facilities require a default constructor - // whenever the type is (e.g.) std::array. - product_query(); product_query(experimental::product_specification spec, std::string layer); auto const& spec() const noexcept { return spec_; }