userver: userver/chaotic/oneof_with_discriminator.hpp Source File
Loading...
Searching...
No Matches
oneof_with_discriminator.hpp
1#pragma once
2
3#include <string>
4#include <variant>
5
6#include <userver/formats/json/value.hpp>
7#include <userver/formats/parse/to.hpp>
8#include <userver/formats/serialize/to.hpp>
9#include <userver/utils/constexpr_indices.hpp>
10#include <userver/utils/overloaded.hpp>
11#include <userver/utils/trivial_map.hpp>
12
13USERVER_NAMESPACE_BEGIN
14
15namespace chaotic {
16
17template <typename BuilderFunc>
18struct OneOfSettings {
19 std::string_view property_name;
20 utils::TrivialSet<BuilderFunc> mapping;
21};
22
23template <typename BuilderFunc>
24OneOfSettings(const char*, utils::TrivialSet<BuilderFunc>)
25 -> OneOfSettings<BuilderFunc>;
26
27template <const auto* Settings, typename... T>
29 const std::variant<formats::common::ParseType<formats::json::Value, T>...>&
30 value;
31};
32
33template <const auto* Settings, typename... T, typename Value>
34std::variant<formats::common::ParseType<Value, T>...> Parse(
35 Value value, formats::parse::To<OneOfWithDiscriminator<Settings, T...>>) {
36 const auto field = value[Settings->property_name].template As<std::string>();
37
38 const auto index = Settings->mapping.GetIndex(field);
39 if (!index.has_value()) {
40 throw formats::json::UnknownDiscriminatorException(value.GetPath(), field);
41 }
42
43 using Result =
44 std::variant<formats::common::ParseType<formats::json::Value, T>...>;
45
46 Result result;
47 utils::WithConstexprIndex<sizeof...(T)>(
48 index.value(), [&](auto index_constant) {
49 constexpr auto kIndex = decltype(index_constant)::value;
50 result.template emplace<kIndex>(
51 value.template As<std::variant_alternative_t<kIndex, Result>>());
52 });
53 return result;
54}
55
56template <const auto* Settings, typename... T, typename Value>
57Value Serialize(const OneOfWithDiscriminator<Settings, T...>& var,
58 formats::serialize::To<Value>) {
59 return std::visit(
60 USERVER_NAMESPACE::utils::Overloaded{
61 [](const formats::common::ParseType<Value, T>& item) {
62 return typename Value::Builder(T{item}).ExtractValue();
63 }...},
64 var.value);
65}
66
67} // namespace chaotic
68
69USERVER_NAMESPACE_END