15#include <userver/compiler/demangle.hpp>
16#include <userver/formats/parse/to.hpp>
18USERVER_NAMESPACE_BEGIN
20namespace formats::
json {
24namespace formats::
parse {
26template <
typename ParseException,
typename Variant,
typename TypeA>
27[[noreturn]]
void ThrowVariantAmbiguousParse(
const std::string& path, std::type_index type_b) {
29 "Value of '" + path +
"' is ambiguous, it is parseable into multiple variants of '" +
30 compiler::GetTypeName<Variant>() +
"', at least '" +
compiler::GetTypeName<TypeA>() +
"' and '" +
35template <
class ParseException,
typename Variant>
36[[noreturn]]
void ThrowVariantParseException(
const std::string& path) {
37 throw ParseException(
"Value of '" + path +
"' cannot be parsed as " +
compiler::GetTypeName<Variant>());
41template <
class T,
class Value,
typename Result>
42void ParseVariantSingle(
const Value& value, std::optional<Result>& result) {
44 const auto old_type = std::visit([](
const auto& v) -> std::type_index {
return typeid(v); }, *result);
46 value.
template As<T>();
47 }
catch (
const std::exception&) {
51 ThrowVariantAmbiguousParse<
typename Value::ParseException, Result, T>(value.GetPath(), old_type);
55 result = value.
template As<T>();
56 }
catch (
const std::exception&) {
63template <
class Value,
typename... Types>
64auto Parse(
const Value& value, formats::
parse::
To<std::variant<Types...>>) {
65 std::optional<std::variant<
decltype(Parse(std::declval<Value>(),
To<Types>{}))...>> result;
67 if constexpr (std::is_same_v<Value, formats::
json::Value>) {
69 value2.DropRootPath();
70 (impl::ParseVariantSingle<Types>(value2, result), ...);
72 (impl::ParseVariantSingle<Types>(value, result), ...);
76 ThrowVariantParseException<
typename Value::ParseException, std::variant<Types...>>(value.GetPath());
79 return std::move(*result);