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
89 operator()(Json& json, std::integral_constant<unsigned int, Version> const version, Fn fn, Args&&... args) const
90 -> std::invoke_result_t<Fn, decltype(json.val[0]), std::integral_constant<unsigned int, Version>, Args&&...>
91 {
92 static_assert(valid(Version) && index(Version) >= 0 && index(Version) < size);
93 return std::invoke(fn, json.val[index(Version)], version, std::forward<Args>(args)...);
94 }
95
96 // integral_constant version, Json only
97 template <typename Json, unsigned int Version, typename Fn>
99 auto
101 -> std::invoke_result_t<Fn, decltype(json.val[0])>
102 {
103 static_assert(valid(Version) && index(Version) >= 0 && index(Version) < size);
104 return std::invoke(fn, json.val[index(Version)]);
105 }
106
107 // unsigned int version, extra arguments
108 template <typename Json, typename Version, typename... Args, typename Fn>
111 auto
112 operator()(Json& json, Version version, Fn fn, Args&&... args) const
113 -> std::invoke_result_t<Fn, decltype(json.val[0]), Version, Args&&...>
114 {
115 XRPL_ASSERT(
116 valid(version) && index(version) >= 0 && index(version) < size,
117 "xrpl::detail::MultiApiJson::operator<Args...>() : valid "
118 "version");
119 return std::invoke(fn, json.val[index(version)], version, std::forward<Args>(args)...);
120 }
121
122 // unsigned int version, Json only
123 template <typename Json, typename Version, typename Fn>
126 auto
127 operator()(Json& json, Version version, Fn fn) const -> std::invoke_result_t<Fn, decltype(json.val[0])>
128 {
129 XRPL_ASSERT(
130 valid(version) && index(version) >= 0 && index(version) < size,
131 "xrpl::detail::MultiApiJson::operator() : valid version");
132 return std::invoke(fn, json.val[index(version)]);
133 }
134 } visitor = {};
135
136 auto
138 {
139 return [self = this](auto... args)
140 requires requires { visitor(std::declval<MultiApiJson&>(), std::declval<decltype(args)>()...); }
141 { return visitor(*self, std::forward<decltype(args)>(args)...); };
142 }
143
144 auto
145 visit() const
146 {
147 return [self = this](auto... args)
148 requires requires { visitor(std::declval<MultiApiJson const&>(), std::declval<decltype(args)>()...); }
149 { return visitor(*self, std::forward<decltype(args)>(args)...); };
150 }
151
152 template <typename... Args>
153 auto
155 requires(sizeof...(args) > 0) && requires { visitor(*this, std::forward<decltype(args)>(args)...); }
156 {
157 return visitor(*this, std::forward<decltype(args)>(args)...);
158 }
159
160 template <typename... Args>
161 auto
162 visit(Args... args) const -> std::invoke_result_t<visitor_t, MultiApiJson const&, Args...>
163 requires(sizeof...(args) > 0) && requires { visitor(*this, std::forward<decltype(args)>(args)...); }
164 {
165 return visitor(*this, std::forward<decltype(args)>(args)...);
166 }
167};
168
169} // namespace detail
170
171// Wrapper for Json for all supported API versions.
173
174} // 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={})