rippled
Loading...
Searching...
No Matches
MultiApiJson.h
1//------------------------------------------------------------------------------
2/*
3 This file is part of rippled: https://github.com/ripple/rippled
4 Copyright (c) 2023 Ripple Labs Inc.
5
6 Permission to use, copy, modify, and/or distribute this software for any
7 purpose with or without fee is hereby granted, provided that the above
8 copyright notice and this permission notice appear in all copies.
9
10 THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13 ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16 OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17*/
18//==============================================================================
19
20#ifndef RIPPLE_JSON_MULTIAPIJSON_H_INCLUDED
21#define RIPPLE_JSON_MULTIAPIJSON_H_INCLUDED
22
23#include <xrpl/beast/utility/instrumentation.h>
24#include <xrpl/json/json_value.h>
25#include <xrpl/protocol/ApiVersion.h>
26
27#include <array>
28#include <concepts>
29#include <cstdlib>
30#include <functional>
31#include <limits>
32#include <type_traits>
33#include <utility>
34
35namespace ripple {
36
37namespace detail {
38template <typename T>
39constexpr bool is_integral_constant = false;
40template <typename I, auto A>
41constexpr bool is_integral_constant<std::integral_constant<I, A>&> = true;
42template <typename I, auto A>
43constexpr bool is_integral_constant<std::integral_constant<I, A> const&> = true;
44
45template <typename T>
46concept some_integral_constant = detail::is_integral_constant<T&>;
47
48// This class is designed to wrap a collection of _almost_ identical Json::Value
49// objects, indexed by version (i.e. there is some mapping of version to object
50// index). It is used e.g. when we need to publish JSON data to users supporting
51// different API versions. We allow manipulation and inspection of all objects
52// at once with `isMember` and `set`, and also individual inspection and updates
53// of an object selected by the user by version, using `visitor_t` nested type.
54template <unsigned MinVer, unsigned MaxVer>
56{
57 static_assert(MinVer <= MaxVer);
58
59 static constexpr auto
60 valid(unsigned int v) noexcept -> bool
61 {
62 return v >= MinVer && v <= MaxVer;
63 }
64
65 static constexpr auto
66 index(unsigned int v) noexcept -> std::size_t
67 {
68 return (v < MinVer) ? 0 : static_cast<std::size_t>(v - MinVer);
69 }
70
71 constexpr static std::size_t size = MaxVer + 1 - MinVer;
73
74 explicit MultiApiJson(Json::Value const& init = {})
75 {
76 if (init == Json::Value{})
77 return; // All elements are already default-initialized
78 for (auto& v : val)
79 v = init;
80 }
81
82 void
83 set(char const* key, auto const& v)
84 requires std::constructible_from<Json::Value, decltype(v)>
85 {
86 for (auto& a : this->val)
87 a[key] = v;
88 }
89
90 // Intentionally not using class enum here, MultivarJson is scope enough
91 enum IsMemberResult : int { none = 0, some, all };
92
93 [[nodiscard]] IsMemberResult
94 isMember(char const* key) const
95 {
96 int count = 0;
97 for (auto& a : this->val)
98 if (a.isMember(key))
99 count += 1;
100
101 return (count == 0 ? none : (count < size ? some : all));
102 }
103
104 static constexpr struct visitor_t final
105 {
106 // integral_constant version, extra arguments
107 template <
108 typename Json,
109 unsigned int Version,
110 typename... Args,
111 typename Fn>
112 requires std::same_as<std::remove_cvref_t<Json>, MultiApiJson>
113 auto
115 Json& json,
117 Fn fn,
118 Args&&... args) const
120 Fn,
121 decltype(json.val[0]),
123 Args&&...>
124 {
125 static_assert(
126 valid(Version) && index(Version) >= 0 && index(Version) < size);
127 return std::invoke(
128 fn,
129 json.val[index(Version)],
130 version,
131 std::forward<Args>(args)...);
132 }
133
134 // integral_constant version, Json only
135 template <typename Json, unsigned int Version, typename Fn>
136 requires std::same_as<std::remove_cvref_t<Json>, MultiApiJson>
137 auto
139 Json& json,
141 Fn fn) const -> std::invoke_result_t<Fn, decltype(json.val[0])>
142 {
143 static_assert(
144 valid(Version) && index(Version) >= 0 && index(Version) < size);
145 return std::invoke(fn, json.val[index(Version)]);
146 }
147
148 // unsigned int version, extra arguments
149 template <
150 typename Json,
151 typename Version,
152 typename... Args,
153 typename Fn>
155 std::convertible_to<Version, unsigned> &&
157 auto
158 operator()(Json& json, Version version, Fn fn, Args&&... args) const
159 -> std::
160 invoke_result_t<Fn, decltype(json.val[0]), Version, Args&&...>
161 {
162 XRPL_ASSERT(
163 valid(version) && index(version) >= 0 && index(version) < size,
164 "ripple::detail::MultiApiJson::operator<Args...>() : valid "
165 "version");
166 return std::invoke(
167 fn,
168 json.val[index(version)],
169 version,
170 std::forward<Args>(args)...);
171 }
172
173 // unsigned int version, Json only
174 template <typename Json, typename Version, typename Fn>
176 std::convertible_to<Version, unsigned> &&
178 auto
179 operator()(Json& json, Version version, Fn fn) const
180 -> std::invoke_result_t<Fn, decltype(json.val[0])>
181 {
182 XRPL_ASSERT(
183 valid(version) && index(version) >= 0 && index(version) < size,
184 "ripple::detail::MultiApiJson::operator() : valid version");
185 return std::invoke(fn, json.val[index(version)]);
186 }
187 } visitor = {};
188
189 auto
191 {
192 return [self = this](auto... args)
193 requires requires {
194 visitor(
195 std::declval<MultiApiJson&>(),
196 std::declval<decltype(args)>()...);
197 }
198 { return visitor(*self, std::forward<decltype(args)>(args)...); };
199 }
200
201 auto
202 visit() const
203 {
204 return [self = this](auto... args)
205 requires requires {
206 visitor(
207 std::declval<MultiApiJson const&>(),
208 std::declval<decltype(args)>()...);
209 }
210 { return visitor(*self, std::forward<decltype(args)>(args)...); };
211 }
212
213 template <typename... Args>
214 auto
215 visit(Args... args)
217 requires(sizeof...(args) > 0) &&
218 requires { visitor(*this, std::forward<decltype(args)>(args)...); }
219 {
220 return visitor(*this, std::forward<decltype(args)>(args)...);
221 }
222
223 template <typename... Args>
224 auto
225 visit(Args... args) const
226 -> std::invoke_result_t<visitor_t, MultiApiJson const&, Args...>
227 requires(sizeof...(args) > 0) &&
228 requires { visitor(*this, std::forward<decltype(args)>(args)...); }
229 {
230 return visitor(*this, std::forward<decltype(args)>(args)...);
231 }
232};
233
234} // namespace detail
235
236// Wrapper for Json for all supported API versions.
237using MultiApiJson = detail::
238 MultiApiJson<RPC::apiMinimumSupportedVersion, RPC::apiMaximumValidVersion>;
239
240} // namespace ripple
241
242#endif
Represents a JSON value.
Definition: json_value.h:150
Inject raw JSON.
Definition: jtx_json.h:33
T declval(T... args)
T forward(T... args)
T invoke(T... args)
JSON (JavaScript Object Notation).
Definition: json_errors.h:25
constexpr bool is_integral_constant
Definition: MultiApiJson.h:39
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition: algorithm.h:26
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 &&... >
Definition: MultiApiJson.h:114
auto operator()(Json &json, std::integral_constant< unsigned int, Version > const, Fn fn) const -> std::invoke_result_t< Fn, decltype(json.val[0])>
Definition: MultiApiJson.h:138
IsMemberResult isMember(char const *key) const
Definition: MultiApiJson.h:94
static constexpr std::size_t size
Definition: MultiApiJson.h:71
static constexpr struct ripple::detail::MultiApiJson::visitor_t visitor
static constexpr auto index(unsigned int v) noexcept -> std::size_t
Definition: MultiApiJson.h:66
auto visit(Args... args) -> std::invoke_result_t< visitor_t, MultiApiJson &, Args... > requires(sizeof...(args) > 0) &&
Definition: MultiApiJson.h:215
static constexpr auto valid(unsigned int v) noexcept -> bool
Definition: MultiApiJson.h:60
MultiApiJson(Json::Value const &init={})
Definition: MultiApiJson.h:74
auto visit(Args... args) const -> std::invoke_result_t< visitor_t, MultiApiJson const &, Args... > requires(sizeof...(args) > 0) &&
Definition: MultiApiJson.h:225
std::array< Json::Value, size > val
Definition: MultiApiJson.h:72
void set(char const *key, auto const &v)
Definition: MultiApiJson.h:83