15#include <fmt/format.h>
17#include <userver/compiler/demangle.hpp>
18#include <userver/formats/parse/to.hpp>
20USERVER_NAMESPACE_BEGIN
22namespace formats::
json {
26namespace formats::
parse {
28template <
typename ParseException,
typename Variant,
typename TypeA>
29[[noreturn]]
void ThrowVariantAmbiguousParse(std::string_view path, std::type_index type_b) {
30 throw ParseException(fmt::format(
31 "Value of '{}' is ambiguous, it is parseable into multiple variants of '{}', at least '{}' and '{}'",
33 compiler::GetTypeName<Variant>(),
34 compiler::GetTypeName<TypeA>(),
35 compiler::GetTypeName(type_b)
39template <
class ParseException,
typename Variant>
40[[noreturn]]
void ThrowVariantParseException(std::string_view path, std::string_view errors) {
41 throw ParseException(fmt::format(
42 "Value of '{}' cannot be parsed as {}. Issues during parsing follow: {}",
44 compiler::GetTypeName<Variant>(),
51template <
class T,
class Value,
typename Result>
52void ParseVariantSingle(
const Value& value, std::optional<Result>& result, std::string& errors) {
54 const auto old_type = std::visit([](
const auto& v) -> std::type_index {
return typeid(v); }, *result);
56 value.
template As<T>();
57 }
catch (
const std::exception&) {
61 using ParseException =
typename Value::ParseException;
62 formats::
parse::ThrowVariantAmbiguousParse<ParseException, Result, T>(value.GetPath(), old_type);
66 result = value.
template As<T>();
67 }
catch (
const std::exception& e) {
68 errors = fmt::format(
"{}\n* Failed to parse as {}: {}", errors, compiler::GetTypeName<T>(), e.what());
75template <
class Value,
typename... Types>
76std::variant<
decltype(Parse(std::declval<Value>(), To<Types>{}))...>
77Parse(
const Value& value, formats::parse::To<std::variant<Types...>>) {
78 std::optional<std::variant<
decltype(Parse(std::declval<Value>(), To<Types>{}))...>> result;
82 if constexpr (std::is_same_v<Value, formats::
json::
Value>) {
84 value2.DropRootPath();
85 (impl::ParseVariantSingle<Types>(value2, result, errors), ...);
87 (impl::ParseVariantSingle<Types>(value, result, errors), ...);
91 formats::
parse::ThrowVariantParseException<
92 typename Value::ParseException,
93 std::variant<Types...>>(value.GetPath(), errors);
96 return std::move(*result);