rippled
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 is_integral_constant = false;
19template <typename I, auto A>
20constexpr bool is_integral_constant<std::integral_constant<I, A>&> = true;
21template <typename I, auto A>
22constexpr bool is_integral_constant<std::integral_constant<I, A> const&> = true;
23
24template <typename T>
25concept some_integral_constant = detail::is_integral_constant<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 constexpr static std::size_t size = 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 // Intentionally not using class enum here, MultivarJson is scope enough
70 enum IsMemberResult : int { none = 0, some, all };
71
72 [[nodiscard]] IsMemberResult
73 isMember(char const* key) const
74 {
75 int count = 0;
76 for (auto& a : this->val)
77 if (a.isMember(key))
78 count += 1;
79
80 return (count == 0 ? none : (count < size ? some : all));
81 }
82
83 static constexpr struct visitor_t final
84 {
85 // integral_constant version, extra arguments
86 template <typename Json, unsigned int Version, typename... Args, typename Fn>
88 auto
90 Json& json,
92 Fn fn,
93 Args&&... args) const
95 Fn,
96 decltype(json.val[0]),
98 Args&&...>
99 {
100 static_assert(valid(Version) && index(Version) >= 0 && index(Version) < size);
101 return std::invoke(fn, json.val[index(Version)], version, std::forward<Args>(args)...);
102 }
103
104 // integral_constant version, Json only
105 template <typename Json, unsigned int Version, typename Fn>
107 auto
109 -> std::invoke_result_t<Fn, decltype(json.val[0])>
110 {
111 static_assert(valid(Version) && index(Version) >= 0 && index(Version) < size);
112 return std::invoke(fn, json.val[index(Version)]);
113 }
114
115 // unsigned int version, extra arguments
116 template <typename Json, typename Version, typename... Args, typename Fn>
119 auto
120 operator()(Json& json, Version version, Fn fn, Args&&... args) const
121 -> std::invoke_result_t<Fn, decltype(json.val[0]), Version, Args&&...>
122 {
123 XRPL_ASSERT(
124 valid(version) && index(version) >= 0 && index(version) < size,
125 "xrpl::detail::MultiApiJson::operator<Args...>() : valid "
126 "version");
127 return std::invoke(fn, json.val[index(version)], version, std::forward<Args>(args)...);
128 }
129
130 // unsigned int version, Json only
131 template <typename Json, typename Version, typename Fn>
134 auto
135 operator()(Json& json, Version version, Fn fn) const
136 -> std::invoke_result_t<Fn, decltype(json.val[0])>
137 {
138 XRPL_ASSERT(
139 valid(version) && index(version) >= 0 && index(version) < size,
140 "xrpl::detail::MultiApiJson::operator() : valid version");
141 return std::invoke(fn, json.val[index(version)]);
142 }
143 } visitor = {};
144
145 auto
147 {
148 return [self = this](auto... args)
149 requires requires {
150 visitor(std::declval<MultiApiJson&>(), std::declval<decltype(args)>()...);
151 }
152 { return visitor(*self, std::forward<decltype(args)>(args)...); };
153 }
154
155 auto
156 visit() const
157 {
158 return [self = this](auto... args)
159 requires requires {
161 }
162 { return visitor(*self, std::forward<decltype(args)>(args)...); };
163 }
164
165 template <typename... Args>
166 auto
168 requires(sizeof...(args) > 0) &&
169 requires { visitor(*this, std::forward<decltype(args)>(args)...); }
170 {
171 return visitor(*this, std::forward<decltype(args)>(args)...);
172 }
173
174 template <typename... Args>
175 auto
176 visit(Args... args) const -> std::invoke_result_t<visitor_t, MultiApiJson const&, Args...>
177 requires(sizeof...(args) > 0) &&
178 requires { visitor(*this, std::forward<decltype(args)>(args)...); }
179 {
180 return visitor(*this, std::forward<decltype(args)>(args)...);
181 }
182};
183
184} // namespace detail
185
186// Wrapper for Json for all supported API versions.
189
190} // namespace xrpl
Represents a JSON value.
Definition json_value.h:130
T declval(T... args)
T forward(T... args)
T invoke(T... args)
T is_same_v
JSON (JavaScript Object Notation).
Definition json_errors.h:5
constexpr bool is_integral_constant
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition algorithm.h:5
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])>
static constexpr std::size_t size
std::array< Json::Value, size > val
void set(char const *key, auto const &v)
IsMemberResult isMember(char const *key) const
static constexpr auto valid(unsigned int v) noexcept -> bool
static constexpr struct xrpl::detail::MultiApiJson::visitor_t visitor
auto visit(Args... args) -> std::invoke_result_t< visitor_t, MultiApiJson &, Args... > requires(sizeof...(args) > 0) &&
static constexpr auto index(unsigned int v) noexcept -> std::size_t
auto visit(Args... args) const -> std::invoke_result_t< visitor_t, MultiApiJson const &, Args... > requires(sizeof...(args) > 0) &&
MultiApiJson(Json::Value const &init={})