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,
28 std::type_index type_b) {
31 "' is ambiguous, it is parseable into multiple variants of '" +
32 compiler::GetTypeName<Variant>() +
"', at least '" +
33 compiler::GetTypeName<TypeA>() +
"' and '" +
37template <
class ParseException,
typename Variant>
38[[noreturn]]
void ThrowVariantParseException(
const std::string& path) {
39 throw ParseException(
"Value of '" + path +
"' cannot be parsed as " +
44template <
class T,
class Value,
typename Result>
45void ParseVariantSingle(
const Value& value, std::optional<Result>& result) {
47 const auto old_type = std::visit(
48 [](
const auto& v) -> std::type_index {
return typeid(v); }, *result);
50 value.
template As<T>();
51 }
catch (
const std::exception&) {
55 ThrowVariantAmbiguousParse<
typename Value::ParseException, Result, T>(
56 value.GetPath(), old_type);
60 result = value.
template As<T>();
61 }
catch (
const std::exception&) {
68template <
class Value,
typename... Types>
69std::variant<Types...> Parse(
const Value& value,
70 formats::
parse::
To<std::variant<Types...>>) {
71 std::optional<std::variant<Types...>> result;
73 if constexpr (std::is_same_v<Value, formats::
json::Value>) {
75 value2.DropRootPath();
76 (impl::ParseVariantSingle<Types>(value2, result), ...);
78 (impl::ParseVariantSingle<Types>(value, result), ...);
82 ThrowVariantParseException<
typename Value::ParseException,
83 std::variant<Types...>>(value.GetPath());
86 return std::move(*result);