rippled
Loading...
Searching...
No Matches
MultiApiJson.h
1#ifndef XRPL_JSON_MULTIAPIJSON_H_INCLUDED
2#define XRPL_JSON_MULTIAPIJSON_H_INCLUDED
3
4#include <xrpl/beast/utility/instrumentation.h>
5#include <xrpl/json/json_value.h>
6#include <xrpl/protocol/ApiVersion.h>
7
8#include <array>
9#include <concepts>
10#include <cstdlib>
11#include <functional>
12#include <type_traits>
13#include <utility>
14
15namespace ripple {
16
17namespace detail {
18template <typename T>
19constexpr bool is_integral_constant = false;
20template <typename I, auto A>
21constexpr bool is_integral_constant<std::integral_constant<I, A>&> = true;
22template <typename I, auto A>
23constexpr bool is_integral_constant<std::integral_constant<I, A> const&> = true;
24
25template <typename T>
26concept some_integral_constant = detail::is_integral_constant<T&>;
27
28// This class is designed to wrap a collection of _almost_ identical Json::Value
29// objects, indexed by version (i.e. there is some mapping of version to object
30// index). It is used e.g. when we need to publish JSON data to users supporting
31// different API versions. We allow manipulation and inspection of all objects
32// at once with `isMember` and `set`, and also individual inspection and updates
33// of an object selected by the user by version, using `visitor_t` nested type.
34template <unsigned MinVer, unsigned MaxVer>
36{
37 static_assert(MinVer <= MaxVer);
38
39 static constexpr auto
40 valid(unsigned int v) noexcept -> bool
41 {
42 return v >= MinVer && v <= MaxVer;
43 }
44
45 static constexpr auto
46 index(unsigned int v) noexcept -> std::size_t
47 {
48 return (v < MinVer) ? 0 : static_cast<std::size_t>(v - MinVer);
49 }
50
51 constexpr static std::size_t size = MaxVer + 1 - MinVer;
53
54 explicit MultiApiJson(Json::Value const& init = {})
55 {
56 if (init == Json::Value{})
57 return; // All elements are already default-initialized
58 for (auto& v : val)
59 v = init;
60 }
61
62 void
63 set(char const* key, auto const& v)
64 requires std::constructible_from<Json::Value, decltype(v)>
65 {
66 for (auto& a : this->val)
67 a[key] = v;
68 }
69
70 // Intentionally not using class enum here, MultivarJson is scope enough
71 enum IsMemberResult : int { none = 0, some, all };
72
73 [[nodiscard]] IsMemberResult
74 isMember(char const* key) const
75 {
76 int count = 0;
77 for (auto& a : this->val)
78 if (a.isMember(key))
79 count += 1;
80
81 return (count == 0 ? none : (count < size ? some : all));
82 }
83
84 static constexpr struct visitor_t final
85 {
86 // integral_constant version, extra arguments
87 template <
88 typename Json,
89 unsigned int Version,
90 typename... Args,
91 typename Fn>
93 auto
95 Json& json,
97 Fn fn,
98 Args&&... args) const
100 Fn,
101 decltype(json.val[0]),
103 Args&&...>
104 {
105 static_assert(
106 valid(Version) && index(Version) >= 0 && index(Version) < size);
107 return std::invoke(
108 fn,
109 json.val[index(Version)],
110 version,
111 std::forward<Args>(args)...);
112 }
113
114 // integral_constant version, Json only
115 template <typename Json, unsigned int Version, typename Fn>
117 auto
119 Json& json,
121 Fn fn) const -> std::invoke_result_t<Fn, decltype(json.val[0])>
122 {
123 static_assert(
124 valid(Version) && index(Version) >= 0 && index(Version) < size);
125 return std::invoke(fn, json.val[index(Version)]);
126 }
127
128 // unsigned int version, extra arguments
129 template <
130 typename Json,
131 typename Version,
132 typename... Args,
133 typename Fn>
137 auto
138 operator()(Json& json, Version version, Fn fn, Args&&... args) const
139 -> std::
140 invoke_result_t<Fn, decltype(json.val[0]), Version, Args&&...>
141 {
142 XRPL_ASSERT(
143 valid(version) && index(version) >= 0 && index(version) < size,
144 "ripple::detail::MultiApiJson::operator<Args...>() : valid "
145 "version");
146 return std::invoke(
147 fn,
148 json.val[index(version)],
149 version,
150 std::forward<Args>(args)...);
151 }
152
153 // unsigned int version, Json only
154 template <typename Json, typename Version, typename Fn>
158 auto
159 operator()(Json& json, Version version, Fn fn) const
160 -> std::invoke_result_t<Fn, decltype(json.val[0])>
161 {
162 XRPL_ASSERT(
163 valid(version) && index(version) >= 0 && index(version) < size,
164 "ripple::detail::MultiApiJson::operator() : valid version");
165 return std::invoke(fn, json.val[index(version)]);
166 }
167 } visitor = {};
168
169 auto
171 {
172 return [self = this](auto... args)
173 requires requires {
174 visitor(
176 std::declval<decltype(args)>()...);
177 }
178 { return visitor(*self, std::forward<decltype(args)>(args)...); };
179 }
180
181 auto
182 visit() const
183 {
184 return [self = this](auto... args)
185 requires requires {
186 visitor(
188 std::declval<decltype(args)>()...);
189 }
190 { return visitor(*self, std::forward<decltype(args)>(args)...); };
191 }
192
193 template <typename... Args>
194 auto
195 visit(Args... args)
197 requires(sizeof...(args) > 0) &&
198 requires { visitor(*this, std::forward<decltype(args)>(args)...); }
199 {
200 return visitor(*this, std::forward<decltype(args)>(args)...);
201 }
202
203 template <typename... Args>
204 auto
205 visit(Args... args) const
206 -> std::invoke_result_t<visitor_t, MultiApiJson const&, Args...>
207 requires(sizeof...(args) > 0) &&
208 requires { visitor(*this, std::forward<decltype(args)>(args)...); }
209 {
210 return visitor(*this, std::forward<decltype(args)>(args)...);
211 }
212};
213
214} // namespace detail
215
216// Wrapper for Json for all supported API versions.
217using MultiApiJson = detail::
218 MultiApiJson<RPC::apiMinimumSupportedVersion, RPC::apiMaximumValidVersion>;
219
220} // namespace ripple
221
222#endif
Represents a JSON value.
Definition json_value.h:131
T declval(T... args)
T forward(T... args)
T invoke(T... args)
T is_same_v
JSON (JavaScript Object Notation).
Definition json_errors.h:6
constexpr bool is_integral_constant
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition algorithm.h:6
STL namespace.
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 operator()(Json &json, std::integral_constant< unsigned int, Version > const, Fn fn) const -> std::invoke_result_t< Fn, decltype(json.val[0])>
IsMemberResult isMember(char const *key) const
static constexpr std::size_t size
static constexpr struct ripple::detail::MultiApiJson::visitor_t visitor
static constexpr auto index(unsigned int v) noexcept -> std::size_t
auto visit(Args... args) -> std::invoke_result_t< visitor_t, MultiApiJson &, Args... > requires(sizeof...(args) > 0) &&
static constexpr auto valid(unsigned int v) noexcept -> bool
MultiApiJson(Json::Value const &init={})
auto visit(Args... args) const -> std::invoke_result_t< visitor_t, MultiApiJson const &, Args... > requires(sizeof...(args) > 0) &&
std::array< Json::Value, size > val
void set(char const *key, auto const &v)