File indexing completed on 2026-08-26 08:38:39
0001
0002
0003
0004
0005
0006
0007
0008
0009 #pragma once
0010
0011 #include <cstddef>
0012 #include <functional>
0013 #include <stdexcept>
0014 #include <string>
0015 #include <string_view>
0016 #include <type_traits>
0017 #include <unordered_map>
0018 #include <utility>
0019
0020 #include <nlohmann/json.hpp>
0021
0022 namespace Acts {
0023
0024
0025
0026 template <typename return_t, typename... args_t>
0027 class JsonKindDispatcher {
0028 public:
0029
0030 using self_type = JsonKindDispatcher<return_t, args_t...>;
0031
0032 using decoder_signature = return_t(const nlohmann::json&, args_t...);
0033
0034 using decoder_type = std::function<decoder_signature>;
0035
0036 using decoder_pointer_type = return_t (*)(args_t...);
0037
0038
0039
0040
0041
0042 explicit JsonKindDispatcher(std::string kindKey = "kind",
0043 std::string context = "JSON payload")
0044 : m_kindKey(std::move(kindKey)), m_context(std::move(context)) {
0045 if (m_kindKey.empty()) {
0046 throw std::invalid_argument(
0047 "JsonKindDispatcher kind key must be non-empty");
0048 }
0049 if (m_context.empty()) {
0050 m_context = "JSON payload";
0051 }
0052 }
0053
0054
0055
0056
0057
0058
0059
0060 self_type& registerKind(std::string kind, decoder_type decoder) {
0061 if (kind.empty()) {
0062 throw std::invalid_argument("JsonKindDispatcher kind must be non-empty");
0063 }
0064 if (!decoder) {
0065 throw std::invalid_argument("JsonKindDispatcher decoder must be valid");
0066 }
0067 auto [_, inserted] =
0068 m_decoders.emplace(std::move(kind), std::move(decoder));
0069 if (!inserted) {
0070 throw std::invalid_argument(
0071 "JsonKindDispatcher duplicate kind registration");
0072 }
0073 return *this;
0074 }
0075
0076
0077
0078
0079
0080
0081
0082 template <typename... func_args_t>
0083 return_t operator()(const nlohmann::json& encoded,
0084 func_args_t&&... args) const
0085 requires std::invocable<decoder_pointer_type, func_args_t...>
0086 {
0087 if (!encoded.contains(m_kindKey)) {
0088 throw std::invalid_argument("Missing '" + m_kindKey + "' in " +
0089 m_context);
0090 }
0091
0092 const auto& kindValue = encoded.at(m_kindKey);
0093 if (!kindValue.is_string()) {
0094 throw std::invalid_argument("Invalid '" + m_kindKey + "' type in " +
0095 m_context);
0096 }
0097
0098 const auto kind = kindValue.template get<std::string>();
0099 auto decoder = m_decoders.find(kind);
0100 if (decoder == m_decoders.end()) {
0101 throw std::invalid_argument("Unsupported " + m_context +
0102 " kind: " + kind);
0103 }
0104
0105 if constexpr (std::is_void_v<return_t>) {
0106 decoder->second(encoded, std::forward<func_args_t>(args)...);
0107 return;
0108 } else {
0109 return decoder->second(encoded, std::forward<func_args_t>(args)...);
0110 }
0111 }
0112
0113
0114
0115
0116
0117
0118 bool hasKind(std::string_view kind) const {
0119 return m_decoders.contains(std::string{kind});
0120 }
0121
0122
0123 void clear() { m_decoders.clear(); }
0124
0125
0126
0127
0128 std::size_t size() const { return m_decoders.size(); }
0129
0130 private:
0131 std::string m_kindKey;
0132 std::string m_context;
0133 std::unordered_map<std::string, decoder_type> m_decoders;
0134 };
0135
0136 }