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>) -> OneOfSettings<BuilderFunc>;
25
26template <const auto* Settings, typename... T>
28 const std::variant<formats::common::ParseType<formats::json::Value, T>...>& value;
29};
30
31template <const auto* Settings, typename... T, typename Value>
32std::variant<formats::common::ParseType<Value, T>...>
33Parse(Value value, formats::parse::To<OneOfWithDiscriminator<Settings, T...>>) {
34 const auto field = value[Settings->property_name].template As<std::string>();
35
36 const auto index = Settings->mapping.GetIndex(field);
37 if (!index.has_value()) {
38 throw formats::json::UnknownDiscriminatorException(value.GetPath(), field);
39 }
40
41 using Result = std::variant<formats::common::ParseType<formats::json::Value, T>...>;
42
43 Result result;
44 utils::WithConstexprIndex<sizeof...(T)>(index.value(), [&](auto index_constant) {
45 constexpr auto kIndex = decltype(index_constant)::value;
46 result.template emplace<kIndex>(value.template As<std::variant_alternative_t<kIndex, Result>>());
47 });
48 return result;
49}
50
51template <const auto* Settings, typename... T, typename Value>
52Value Serialize(const OneOfWithDiscriminator<Settings, T...>& var, formats::serialize::To<Value>) {
53 return std::visit(
54 USERVER_NAMESPACE::utils::Overloaded{[](const formats::common::ParseType<Value, T>& item) {
55 return typename Value::Builder(T{item}).ExtractValue();
56 }...},
57 var.value
58 );
59}
60
61} // namespace chaotic
62
63USERVER_NAMESPACE_END