xrpld
Loading...
Searching...
No Matches
MultiApiJson.h
1#pragma once
2
3#include <xrpl/beast/utility/instrumentation.h>
4#include <xrpl/json/json_value.h>
5#include <xrpl/protocol/ApiVersion.h>
6
7#include <array>
8#include <concepts>
9#include <cstdlib>
10#include <functional>
11#include <type_traits>
12#include <utility>
13
14namespace xrpl {
15
16namespace detail {
17template <typename T>
18constexpr bool kIsIntegralConstant = false;
19template <typename I, auto A>
21template <typename I, auto A>
23
24template <typename T>
26
27// This class is designed to wrap a collection of _almost_ identical json::Value
28// objects, indexed by version (i.e. there is some mapping of version to object
29// index). It is used e.g. when we need to publish JSON data to users supporting
30// different API versions. We allow manipulation and inspection of all objects
31// at once with `isMember` and `set`, and also individual inspection and updates
32// of an object selected by the user by version, using `visitor_t` nested type.
33template <unsigned MinVer, unsigned MaxVer>
35{
36 static_assert(MinVer <= MaxVer);
37
38 static constexpr auto
39 valid(unsigned int v) noexcept -> bool
40 {
41 return v >= MinVer && v <= MaxVer;
42 }
43
44 static constexpr auto
45 index(unsigned int v) noexcept -> std::size_t
46 {
47 return (v < MinVer) ? 0 : static_cast<std::size_t>(v - MinVer);
48 }
49
50 static constexpr std::size_t kSize = MaxVer + 1 - MinVer;
52
53 explicit MultiApiJson(json::Value const& init = {})
54 {
55 if (init == json::Value{})
56 return; // All elements are already default-initialized
57 for (auto& v : val)
58 v = init;
59 }
60
61 void
62 set(char const* key, auto const& v)
63 requires std::constructible_from<json::Value, decltype(v)>
64 {
65 for (auto& a : this->val)
66 a[key] = v;
67 }
68
69 enum class IsMemberResult : int { None = 0, Some, All };
70
71 [[nodiscard]] IsMemberResult
72 isMember(char const* key) const
73 {
74 int count = 0;
75 for (auto& a : this->val)
76 {
77 if (a.isMember(key))
78 count += 1;
79 }
80
81 if (count == 0)
84 }
85
86 static constexpr struct VisitorT final
87 {
88 // integral_constant version, extra arguments
89 template <typename Json, unsigned int Version, typename... Args, typename Fn>
90 requires std::same_as<std::remove_cvref_t<Json>, MultiApiJson>
91 auto
93 Json& json,
95 Fn fn,
96 Args&&... args) const
98 Fn,
99 decltype(json.val[0]),
101 Args&&...>
102 {
103 static_assert(valid(Version) && index(Version) >= 0 && index(Version) < kSize);
104 return std::invoke(fn, json.val[index(Version)], version, std::forward<Args>(args)...);
105 }
106
107 // integral_constant version, Json only
108 template <typename Json, unsigned int Version, typename Fn>
109 requires std::same_as<std::remove_cvref_t<Json>, MultiApiJson>
110 auto
112 -> std::invoke_result_t<Fn, decltype(json.val[0])>
113 {
114 static_assert(valid(Version) && index(Version) >= 0 && index(Version) < kSize);
115 return std::invoke(fn, json.val[index(Version)]);
116 }
117
118 // unsigned int version, extra arguments
119 template <typename Json, typename Version, typename... Args, typename Fn>
120 requires(!some_integral_constant<Version>) && std::convertible_to<Version, unsigned> &&
122 auto
123 operator()(Json& json, Version version, Fn fn, Args&&... args) const
124 -> std::invoke_result_t<Fn, decltype(json.val[0]), Version, Args&&...>
125 {
126 XRPL_ASSERT(
127 valid(version) && index(version) >= 0 && index(version) < kSize,
128 "xrpl::detail::MultiApijson::operator<Args...>() : valid "
129 "version");
130 return std::invoke(fn, json.val[index(version)], version, std::forward<Args>(args)...);
131 }
132
133 // unsigned int version, Json only
134 template <typename Json, typename Version, typename Fn>
135 requires(!some_integral_constant<Version>) && std::convertible_to<Version, unsigned> &&
137 auto
138 operator()(Json& json, Version version, Fn fn) const
139 -> std::invoke_result_t<Fn, decltype(json.val[0])>
140 {
141 XRPL_ASSERT(
142 valid(version) && index(version) >= 0 && index(version) < kSize,
143 "xrpl::detail::MultiApijson::operator() : valid version");
144 return std::invoke(fn, json.val[index(version)]);
145 }
146 } kVisitor = {};
147
148 auto
150 {
151 return [self = this](auto... args)
152 requires requires {
153 kVisitor(std::declval<MultiApiJson&>(), std::declval<decltype(args)>()...);
154 }
155 { return kVisitor(*self, std::forward<decltype(args)>(args)...); };
156 }
157
158 [[nodiscard]] auto
159 visit() const
160 {
161 return [self = this](auto... args)
162 requires requires {
164 }
165 { return kVisitor(*self, std::forward<decltype(args)>(args)...); };
166 }
167
168 template <typename... Args>
169 auto
170 visit(Args... args) -> std::invoke_result_t<VisitorT, MultiApiJson&, Args...>
171 requires(sizeof...(args) > 0) &&
172 requires { kVisitor(*this, std::forward<decltype(args)>(args)...); }
173 {
174 return kVisitor(*this, std::forward<decltype(args)>(args)...);
175 }
176
177 template <typename... Args>
178 [[nodiscard]] auto
179 visit(Args... args) const -> std::invoke_result_t<VisitorT, MultiApiJson const&, Args...>
180 requires(sizeof...(args) > 0) &&
181 requires { kVisitor(*this, std::forward<decltype(args)>(args)...); }
182 {
183 return kVisitor(*this, std::forward<decltype(args)>(args)...);
184 }
185};
186
187} // namespace detail
188
189// Wrapper for Json for all supported API versions.
192
193} // namespace xrpl
Represents a JSON value.
Definition json_value.h:130
T declval(T... args)
T forward(T... args)
T invoke(T... args)
JSON (JavaScript Object Notation).
Definition json_errors.h:5
constexpr bool kIsIntegralConstant
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition algorithm.h:5
detail::MultiApiJson< RPC::kApiMinimumSupportedVersion, RPC::kApiMaximumValidVersion > MultiApiJson
auto operator()(Json &json, std::integral_constant< unsigned int, Version > const, Fn fn) const -> std::invoke_result_t< Fn, decltype(json.val[0])>
auto operator()(Json &json, std::integral_constant< unsigned int, Version > const version, Fn fn, Args &&... args) const -> std::invoke_result_t< Fn, decltype(json.val[0]), std::integral_constant< unsigned int, Version >, Args &&... >
auto visit(Args... args) const -> std::invoke_result_t< VisitorT, MultiApiJson const &, Args... > requires(sizeof...(args) > 0) &&
void set(char const *key, auto const &v)
IsMemberResult isMember(char const *key) const
static constexpr struct xrpl::detail::MultiApiJson::VisitorT kVisitor
static constexpr auto valid(unsigned int v) noexcept -> bool
static constexpr auto index(unsigned int v) noexcept -> std::size_t
auto visit(Args... args) -> std::invoke_result_t< VisitorT, MultiApiJson &, Args... > requires(sizeof...(args) > 0) &&
MultiApiJson(json::Value const &init={})