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 <type_traits>
32#include <utility>
33
34namespace ripple {
35
36namespace detail {
37template <typename T>
38constexpr bool is_integral_constant = false;
39template <typename I, auto A>
40constexpr bool is_integral_constant<std::integral_constant<I, A>&> = true;
41template <typename I, auto A>
42constexpr bool is_integral_constant<std::integral_constant<I, A> const&> = true;
43
44template <typename T>
45concept some_integral_constant = detail::is_integral_constant<T&>;
46
47// This class is designed to wrap a collection of _almost_ identical Json::Value
48// objects, indexed by version (i.e. there is some mapping of version to object
49// index). It is used e.g. when we need to publish JSON data to users supporting
50// different API versions. We allow manipulation and inspection of all objects
51// at once with `isMember` and `set`, and also individual inspection and updates
52// of an object selected by the user by version, using `visitor_t` nested type.
53template <unsigned MinVer, unsigned MaxVer>
55{
56 static_assert(MinVer <= MaxVer);
57
58 static constexpr auto
59 valid(unsigned int v) noexcept -> bool
60 {
61 return v >= MinVer && v <= MaxVer;
62 }
63
64 static constexpr auto
65 index(unsigned int v) noexcept -> std::size_t
66 {
67 return (v < MinVer) ? 0 : static_cast<std::size_t>(v - MinVer);
68 }
69
70 constexpr static std::size_t size = MaxVer + 1 - MinVer;
72
73 explicit MultiApiJson(Json::Value const& init = {})
74 {
75 if (init == Json::Value{})
76 return; // All elements are already default-initialized
77 for (auto& v : val)
78 v = init;
79 }
80
81 void
82 set(char const* key, auto const& v)
83 requires std::constructible_from<Json::Value, decltype(v)>
84 {
85 for (auto& a : this->val)
86 a[key] = v;
87 }
88
89 // Intentionally not using class enum here, MultivarJson is scope enough
90 enum IsMemberResult : int { none = 0, some, all };
91
92 [[nodiscard]] IsMemberResult
93 isMember(char const* key) const
94 {
95 int count = 0;
96 for (auto& a : this->val)
97 if (a.isMember(key))
98 count += 1;
99
100 return (count == 0 ? none : (count < size ? some : all));
101 }
102
103 static constexpr struct visitor_t final
104 {
105 // integral_constant version, extra arguments
106 template <
107 typename Json,
108 unsigned int Version,
109 typename... Args,
110 typename Fn>
112 auto
114 Json& json,
116 Fn fn,
117 Args&&... args) const
119 Fn,
120 decltype(json.val[0]),
122 Args&&...>
123 {
124 static_assert(
125 valid(Version) && index(Version) >= 0 && index(Version) < size);
126 return std::invoke(
127 fn,
128 json.val[index(Version)],
129 version,
130 std::forward<Args>(args)...);
131 }
132
133 // integral_constant version, Json only
134 template <typename Json, unsigned int Version, typename Fn>
136 auto
138 Json& json,
140 Fn fn) const -> std::invoke_result_t<Fn, decltype(json.val[0])>
141 {
142 static_assert(
143 valid(Version) && index(Version) >= 0 && index(Version) < size);
144 return std::invoke(fn, json.val[index(Version)]);
145 }
146
147 // unsigned int version, extra arguments
148 template <
149 typename Json,
150 typename Version,
151 typename... Args,
152 typename Fn>
156 auto
157 operator()(Json& json, Version version, Fn fn, Args&&... args) const
158 -> std::
159 invoke_result_t<Fn, decltype(json.val[0]), Version, Args&&...>
160 {
161 XRPL_ASSERT(
162 valid(version) && index(version) >= 0 && index(version) < size,
163 "ripple::detail::MultiApiJson::operator<Args...>() : valid "
164 "version");
165 return std::invoke(
166 fn,
167 json.val[index(version)],
168 version,
169 std::forward<Args>(args)...);
170 }
171
172 // unsigned int version, Json only
173 template <typename Json, typename Version, typename Fn>
177 auto
178 operator()(Json& json, Version version, Fn fn) const
179 -> std::invoke_result_t<Fn, decltype(json.val[0])>
180 {
181 XRPL_ASSERT(
182 valid(version) && index(version) >= 0 && index(version) < size,
183 "ripple::detail::MultiApiJson::operator() : valid version");
184 return std::invoke(fn, json.val[index(version)]);
185 }
186 } visitor = {};
187
188 auto
190 {
191 return [self = this](auto... args)
192 requires requires {
193 visitor(
195 std::declval<decltype(args)>()...);
196 }
197 { return visitor(*self, std::forward<decltype(args)>(args)...); };
198 }
199
200 auto
201 visit() const
202 {
203 return [self = this](auto... args)
204 requires requires {
205 visitor(
207 std::declval<decltype(args)>()...);
208 }
209 { return visitor(*self, std::forward<decltype(args)>(args)...); };
210 }
211
212 template <typename... Args>
213 auto
214 visit(Args... args)
216 requires(sizeof...(args) > 0) &&
217 requires { visitor(*this, std::forward<decltype(args)>(args)...); }
218 {
219 return visitor(*this, std::forward<decltype(args)>(args)...);
220 }
221
222 template <typename... Args>
223 auto
224 visit(Args... args) const
225 -> std::invoke_result_t<visitor_t, MultiApiJson const&, Args...>
226 requires(sizeof...(args) > 0) &&
227 requires { visitor(*this, std::forward<decltype(args)>(args)...); }
228 {
229 return visitor(*this, std::forward<decltype(args)>(args)...);
230 }
231};
232
233} // namespace detail
234
235// Wrapper for Json for all supported API versions.
236using MultiApiJson = detail::
237 MultiApiJson<RPC::apiMinimumSupportedVersion, RPC::apiMaximumValidVersion>;
238
239} // namespace ripple
240
241#endif
Represents a JSON value.
Definition json_value.h:149
T declval(T... args)
T forward(T... args)
T invoke(T... args)
T is_same_v
JSON (JavaScript Object Notation).
Definition json_errors.h:25
constexpr bool is_integral_constant
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition algorithm.h:25
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)