JSON RPC
JSON-RPC 2.0 library for C++
details.h
Go to the documentation of this file.
1#ifndef DE443A53_EEA9_4918_BCFB_AE76A19FB197
2#define DE443A53_EEA9_4918_BCFB_AE76A19FB197
3
4/**
5 * @file
6 * @brief Contains implementation details for the JSON RPC library.
7 *
8 * This file includes type traits for extracting function return types and argument types,
9 * as well as utilities for creating offset sequences and handling handler parameters.
10 * These details are used internally by the JSON RPC library to facilitate various operations.
11 *
12 * It includes:
13 * - Type traits for function return types and argument types.
14 * - Utilities for creating offset sequences.
15 * - Helper functions for handling handler parameters.
16 *
17 * @internal
18 */
19
20#include <functional>
21#include <tuple>
22#include <type_traits>
23#include <utility>
24#include <nlohmann/json.hpp>
25#include "exception.h"
26
27/**
28 * @brief Contains the implementation details of the JSON RPC library.
29 * @internal
30 */
31namespace wwa::json_rpc::details {
32
33/**
34 * @defgroup function_traits Function Traits
35 * @brief Type traits for extracting function return types and argument types.
36 * @internal
37 * @{
38 */
39
40/**
41 * @brief Primary template for function traits.
42 *
43 * This template is specialized for various function types to extract the return type and argument types.
44 *
45 * @tparam T The function type.
46 */
47template<typename T>
48struct function_traits;
49
50/**
51 * @brief Specialization for function pointers.
52 *
53 * @tparam R The return type of the function.
54 * @tparam Args The argument types of the function.
55 */
56template<typename R, typename... Args>
57struct function_traits<R (*)(Args...)> {
58 using return_type = R; ///< The return type of the function.
59 using args_tuple = std::tuple<Args...>; ///< A tuple of the argument types.
60};
61
62/**
63 * @brief Specialization for noexcept function pointers.
64 *
65 * @tparam R The return type of the function.
66 * @tparam Args The argument types of the function.
67 */
68template<typename R, typename... Args>
69struct function_traits<R (*)(Args...) noexcept> : function_traits<R (*)(Args...)> {};
70
71/**
72 * @brief Specialization for member function pointers.
73 *
74 * @tparam R The return type of the member function.
75 * @tparam C The class type.
76 * @tparam Args The argument types of the member function.
77 */
78template<typename R, typename C, typename... Args>
79struct function_traits<R (C::*)(Args...)> : function_traits<R (*)(Args...)> {};
80
81/**
82 * @brief Specialization for noexcept member function pointers.
83 *
84 * @tparam R The return type of the member function.
85 * @tparam C The class type.
86 * @tparam Args The argument types of the member function.
87 */
88template<typename R, typename C, typename... Args>
89struct function_traits<R (C::*)(Args...) noexcept> : function_traits<R (C::*)(Args...)> {};
90
91/**
92 * @brief Specialization for const member function pointers.
93 *
94 * @tparam R The return type of the member function.
95 * @tparam C The class type.
96 * @tparam Args The argument types of the member function.
97 */
98template<typename R, typename C, typename... Args>
99struct function_traits<R (C::*)(Args...) const> : function_traits<R (C::*)(Args...)> {};
100
101/**
102 * @brief Specialization for const noexcept member function pointers.
103 *
104 * @tparam R The return type of the member function.
105 * @tparam C The class type.
106 * @tparam Args The argument types of the member function.
107 */
108template<typename R, typename C, typename... Args>
109struct function_traits<R (C::*)(Args...) const noexcept> : function_traits<R (C::*)(Args...)> {};
110
111/**
112 * @brief Specialization for volatile member function pointers.
113 *
114 * @tparam R The return type of the member function.
115 * @tparam C The class type.
116 * @tparam Args The argument types of the member function.
117 */
118template<typename R, typename C, typename... Args>
119struct function_traits<R (C::*)(Args...) volatile> : function_traits<R (C::*)(Args...)> {};
120
121/**
122 * @brief Specialization for volatile noexcept member function pointers.
123 *
124 * @tparam R The return type of the member function.
125 * @tparam C The class type.
126 * @tparam Args The argument types of the member function.
127 */
128template<typename R, typename C, typename... Args>
129struct function_traits<R (C::*)(Args...) volatile noexcept> : function_traits<R (C::*)(Args...)> {};
130
131/**
132 * @brief Specialization for const volatile member function pointers.
133 *
134 * @tparam R The return type of the member function.
135 * @tparam C The class type.
136 * @tparam Args The argument types of the member function.
137 */
138template<typename R, typename C, typename... Args>
139struct function_traits<R (C::*)(Args...) const volatile> : function_traits<R (C::*)(Args...)> {};
140
141/**
142 * @brief Specialization for const volatile noexcept member function pointers.
143 *
144 * @tparam R The return type of the member function.
145 * @tparam C The class type.
146 * @tparam Args The argument types of the member function.
147 */
148template<typename R, typename C, typename... Args>
149struct function_traits<R (C::*)(Args...) const volatile noexcept> : function_traits<R (C::*)(Args...)> {};
150
151/**
152 * @brief Specialization for lvalue reference member function pointers.
153 *
154 * @tparam R The return type of the member function.
155 * @tparam C The class type.
156 * @tparam Args The argument types of the member function.
157 */
158template<typename R, typename C, typename... Args>
159struct function_traits<R (C::*)(Args...) &> : function_traits<R (C::*)(Args...)> {};
160
161/**
162 * @brief Specialization for lvalue reference noexcept member function pointers.
163 *
164 * @tparam R The return type of the member function.
165 * @tparam C The class type.
166 * @tparam Args The argument types of the member function.
167 */
168template<typename R, typename C, typename... Args>
169struct function_traits<R (C::*)(Args...) & noexcept> : function_traits<R (C::*)(Args...)> {};
170
171/**
172 * @brief Specialization for const lvalue reference member function pointers.
173 *
174 * @tparam R The return type of the member function.
175 * @tparam C The class type.
176 * @tparam Args The argument types of the member function.
177 */
178template<typename R, typename C, typename... Args>
179struct function_traits<R (C::*)(Args...) const&> : function_traits<R (C::*)(Args...)> {};
180
181/**
182 * @brief Specialization for const lvalue reference noexcept member function pointers.
183 *
184 * @tparam R The return type of the member function.
185 * @tparam C The class type.
186 * @tparam Args The argument types of the member function.
187 */
188template<typename R, typename C, typename... Args>
189struct function_traits<R (C::*)(Args...) const & noexcept> : function_traits<R (C::*)(Args...)> {};
190
191/**
192 * @brief Specialization for volatile lvalue reference member function pointers.
193 *
194 * @tparam R The return type of the member function.
195 * @tparam C The class type.
196 * @tparam Args The argument types of the member function.
197 */
198template<typename R, typename C, typename... Args>
199struct function_traits<R (C::*)(Args...) volatile&> : function_traits<R (C::*)(Args...)> {};
200
201/**
202 * @brief Specialization for volatile lvalue reference noexcept member function pointers.
203 *
204 * @tparam R The return type of the member function.
205 * @tparam C The class type.
206 * @tparam Args The argument types of the member function.
207 */
208template<typename R, typename C, typename... Args>
209struct function_traits<R (C::*)(Args...) volatile & noexcept> : function_traits<R (C::*)(Args...)> {};
210
211/**
212 * @brief Specialization for const volatile lvalue reference member function pointers.
213 *
214 * @tparam R The return type of the member function.
215 * @tparam C The class type.
216 * @tparam Args The argument types of the member function.
217 */
218template<typename R, typename C, typename... Args>
219struct function_traits<R (C::*)(Args...) const volatile&> : function_traits<R (C::*)(Args...)> {};
220
221/**
222 * @brief Specialization for const volatile lvalue reference noexcept member function pointers.
223 *
224 * @tparam R The return type of the member function.
225 * @tparam C The class type.
226 * @tparam Args The argument types of the member function.
227 */
228template<typename R, typename C, typename... Args>
229struct function_traits<R (C::*)(Args...) const volatile & noexcept> : function_traits<R (C::*)(Args...)> {};
230
231/**
232 * @brief Specialization for rvalue reference member function pointers.
233 *
234 * @tparam R The return type of the member function.
235 * @tparam C The class type.
236 * @tparam Args The argument types of the member function.
237 */
238template<typename R, typename C, typename... Args>
239struct function_traits<R (C::*)(Args...) &&> : function_traits<R (C::*)(Args...)> {};
240
241/**
242 * @brief Specialization for rvalue reference noexcept member function pointers.
243 *
244 * @tparam R The return type of the member function.
245 * @tparam C The class type.
246 * @tparam Args The argument types of the member function.
247 */
248template<typename R, typename C, typename... Args>
249struct function_traits<R (C::*)(Args...) && noexcept> : function_traits<R (C::*)(Args...)> {};
250
251/**
252 * @brief Specialization for const rvalue reference member function pointers.
253 *
254 * @tparam R The return type of the member function.
255 * @tparam C The class type.
256 * @tparam Args The argument types of the member function.
257 */
258template<typename R, typename C, typename... Args>
259struct function_traits<R (C::*)(Args...) const&&> : function_traits<R (C::*)(Args...)> {};
260
261/**
262 * @brief Specialization for const rvalue reference noexcept member function pointers.
263 *
264 * @tparam R The return type of the member function.
265 * @tparam C The class type.
266 * @tparam Args The argument types of the member function.
267 */
268template<typename R, typename C, typename... Args>
269struct function_traits<R (C::*)(Args...) const && noexcept> : function_traits<R (C::*)(Args...)> {};
270
271/**
272 * @brief Specialization for volatile rvalue reference member function pointers.
273 *
274 * @tparam R The return type of the member function.
275 * @tparam C The class type.
276 * @tparam Args The argument types of the member function.
277 */
278template<typename R, typename C, typename... Args>
279struct function_traits<R (C::*)(Args...) volatile&&> : function_traits<R (C::*)(Args...)> {};
280
281/**
282 * @brief Specialization for volatile rvalue reference noexcept member function pointers.
283 *
284 * @tparam R The return type of the member function.
285 * @tparam C The class type.
286 * @tparam Args The argument types of the member function.
287 */
288template<typename R, typename C, typename... Args>
289struct function_traits<R (C::*)(Args...) volatile && noexcept> : function_traits<R (C::*)(Args...)> {};
290
291/**
292 * @brief Specialization for const volatile rvalue reference member function pointers.
293 *
294 * @tparam R The return type of the member function.
295 * @tparam C The class type.
296 * @tparam Args The argument types of the member function.
297 */
298template<typename R, typename C, typename... Args>
299struct function_traits<R (C::*)(Args...) const volatile&&> : function_traits<R (C::*)(Args...)> {};
300
301/**
302 * @brief Specialization for const volatile rvalue reference noexcept member function pointers.
303 *
304 * @tparam R The return type of the member function.
305 * @tparam C The class type.
306 * @tparam Args The argument types of the member function.
307 */
308template<typename R, typename C, typename... Args>
309struct function_traits<R (C::*)(Args...) const volatile && noexcept> : function_traits<R (C::*)(Args...)> {};
310
311/**
312 * @brief Specialization for `std::function`.
313 *
314 * @tparam S The type of the function, which includes the return type and argument types.
315 */
316template<typename S>
317struct function_traits<std::function<S>> : function_traits<std::decay_t<S>> {};
318
319/**
320 * @brief Specialization for functors (objects with `operator()`).
321 *
322 * @tparam T The functor type.
323 */
324template<typename T>
325struct function_traits : function_traits<decltype(&T::operator())> {};
326/** @} */
327
328/**
329 * @defgroup offset_sequence Offset Sequence
330 * @brief Utilities for creating offset sequences.
331 * @see https://devblogs.microsoft.com/oldnewthing/20200625-00/?p=103903
332 * @internal
333 * @{
334 */
335
336/**
337 * @brief Template for creating an offset sequence.
338 *
339 * @tparam N The offset value.
340 * @tparam Seq The sequence type.
341 */
342template<std::size_t N, typename Seq>
344
345/**
346 * @brief Specialization for creating an offset sequence.
347 *
348 * @tparam N The offset value.
349 * @tparam Ints The integer sequence.
350 */
351template<std::size_t N, std::size_t... Ints>
353 using type = std::index_sequence<Ints + N...>; ///< The resulting offset sequence.
354};
355
356/**
357 * @brief Alias template for creating an offset sequence.
358 *
359 * @tparam N The offset value.
360 * @tparam Seq The sequence type.
361 */
362template<std::size_t N, typename Seq>
363using offset_sequence_t = typename offset_sequence<N, Seq>::type;
364
365/** @} */
366
367/**
368 * @defgroup param_helpers Parameter Helpers
369 * @brief Utilities for handling handler parameters.
370 * @internal
371 * @{
372 */
373
374/**
375 * @brief Creates a tuple containing the instance if it is a class pointer, or an empty tuple if it is a null pointer.
376 *
377 * @tparam C The type of the instance, which should be a class pointer or a null pointer.
378 * @param inst The instance to be included in the tuple.
379 * @return A tuple containing the instance if it is a class pointer, or an empty tuple if it is a null pointer.
380 *
381 * @note This function uses `constexpr` and `if constexpr` to ensure that the tuple is created at compile time if possible.
382 * @note The function requires that the type C is either a class pointer or a null pointer.
383 */
384template<typename C>
385constexpr auto make_inst_tuple(C inst)
387{
388 if constexpr (std::is_null_pointer_v<C>) {
389 return std::make_tuple();
390 }
391 else {
392 return std::make_tuple(inst);
393 }
394}
395
396/**
397 * @brief Creates a tuple from the provided context object based on the type of @a Context.
398 *
399 * @tparam Context The type of the context.
400 * @param ctx The context object from which the tuple is created.
401 * @return A tuple containing the context object.
402 *
403 * @throws wwa::json_rpc::exception If the extraction of @a Extra from the JSON object @a extra fails.
404 */
405template<typename Context>
407{
408 if constexpr (std::is_void_v<Context>) {
409 return std::make_tuple();
410 }
411 else {
412 return std::make_tuple(ctx);
413 }
414}
415
416/**
417 * @brief Invokes a function with the provided arguments handling `void` return type.
418 *
419 * @tparam F The type of the function.
420 * @tparam Tuple The type of the arguments tuple.
421 * @param f The function.
422 * @param tuple The arguments as a tuple.
423 * @return The result of the function converted to a JSON value.
424 * @retval nlohmann::json::null_t If the function returns void.
425 *
426 * @details This helper invokes the function with the arguments passed as a tuple.
427 * It uses the `if constexpr` construct to handle the case when the handler function returns void.
428 *
429 * The `if constexpr` construct allows for determinining at compile time whether @a f returns `void`.
430 * If the return type is `void`, `invoke_function` calls @a f and returns a JSON `null` value.
431 * If the return type is not `void`, `invoke_function` calls @a f and returns the result converted to a JSON value.
432 */
433template<typename F, typename Tuple>
435{
437
438 if constexpr (std::is_void_v<ReturnType>) {
440 return nullptr;
441 }
442 else {
443 return std::apply(std::forward<F>(f), std::forward<Tuple>(tuple));
444 }
445}
446
447/**
448 * @brief Type alias for a tuple element with decay applied.
449 *
450 * This template alias retrieves the type of the @a I-th element in the tuple type @a A,
451 * and then applies `std::decay_t` to remove any references and cv-qualifiers.
452 *
453 * @tparam I The index of the element in the tuple.
454 * @tparam A The tuple type.
455 */
456template<std::size_t I, typename A>
458
459/**
460 * @brief Converts JSON parameters to a tuple of arguments based on the specified types.
461 *
462 * @tparam Extra An additional type that may be included in the conversion. If Extra is void, it is ignored.
463 * @tparam Args A tuple of argument types to which the JSON parameters will be converted.
464 * @tparam Indices A parameter pack representing the indices of the arguments.
465 * @param params The JSON object containing the parameters to be converted.
466 * @return A tuple containing the converted arguments.
467 *
468 * @throws wwa::json_rpc::exception If the conversion of any parameter from the JSON object fails.
469 *
470 * @details The function attempts to convert each parameter in the JSON object @a params to the corresponding type in @a Args and returns them as a tuple.
471 * It uses `std::index_sequence` to unpack the indices and access the corresponding parameters in @a params.
472 *
473 * We support two types of handler functions:
474 * 1. `ReturnType handler(const Extra& extra, Arguments... args);` (@a Extra is not `void`, @a Indices are [1..`sizeof...(Args)-1`])
475 * 2. `ReturnType handler(Arguments... args);` (@a Extra is `void`, @a Indices are [0..`sizeof...(Args)-1`])
476 *
477 * Because @a Args correspond to the function arguments, @a Args contains both @a Extra and @a Arguments for the first type of handler; therefore, `Args[i]` will be the type of the `params[i-1]`.
478 * For the second type of handler, @a Args contains only @a Arguments, and `Args[i]` will be the type of the `params[i]`.
479 */
480template<typename Extra, typename Args, std::size_t... Indices>
481constexpr auto convert_args(const nlohmann::json& params, std::index_sequence<Indices...>)
482{
483 constexpr std::size_t offset = std::is_void_v<Extra> ? 0 : 1;
484 try {
485 return std::make_tuple(params[Indices - offset].template get<tuple_element<Indices, Args>>()...);
486 }
487 catch (const nlohmann::json::exception& e) {
489 }
490}
491
492/** @} */
493
494} // namespace wwa::json_rpc::details
495
496#endif /* DE443A53_EEA9_4918_BCFB_AE76A19FB197 */
Private implementation of the JSON RPC dispatcher class.
static std::uint64_t get_and_increment_counter() noexcept
Generates a unique request ID.
A class that manages JSON RPC method handlers and processes JSON RPC requests.
Definition dispatcher.h:77
virtual nlohmann::json do_process_request(const nlohmann::json &request, const std::any &data, bool is_batch, std::uint64_t unique_id)
Processes a single, non-batch JSON RPC request.
dispatcher & operator=(dispatcher &&rhs)=default
Move assignment operator.
dispatcher(dispatcher &&rhs)=default
Move constructor.
void add_ex(std::string_view method, F &&f, C instance)
Adds a method handler with a context parameter and a class instance.
Definition dispatcher.h:286
constexpr auto create_closure(C inst, F &&f) const
Creates a closure for invoking a member function with JSON parameters.
Definition dispatcher.h:453
virtual void request_parsed(const jsonrpc_request &request, const std::any &data, std::uint64_t unique_id)
Invoked after the request has been parsed.
void add_internal_method(std::string_view method, handler_t &&handler)
Adds a method handler for the specified method.
nlohmann::json process_request(const nlohmann::json &request, const std::any &data={})
Processes a JSON RPC request.
virtual void request_failed(const nlohmann::json &request_id, const std::exception *e, bool is_batch, std::uint64_t unique_id)
Invoked when a request fails.
virtual nlohmann::json invoke(const std::string &method, const nlohmann::json &params, const dispatcher::context_t &ctx, std::uint64_t unique_id)
Invokes a method handler.
void add(std::string_view method, F &&f)
Adds a method handler f for the method method.
Definition dispatcher.h:203
void add(std::string_view method, F &&f, C instance)
Adds a method to the dispatcher with the specified instance and function.
Definition dispatcher.h:221
virtual nlohmann::json process_batch_request(const nlohmann::json &request, const std::any &data, std::uint64_t unique_id)
Processes a batch request.
dispatcher()
Class constructor.
dispatcher(const dispatcher &)=delete
dispatcher & operator=(const dispatcher &)=delete
virtual ~dispatcher()
Class destructor.
void add_ex(std::string_view method, F &&f)
Adds a method handler with a context parameter.
Definition dispatcher.h:263
std::unique_ptr< dispatcher_private > d_ptr
Pointer to the implementation (Pimpl idiom).
Definition dispatcher.h:411
JSON RPC Exception class.
Definition exception.h:86
Exception thrown when the method is not found.
Definition exception.h:238
#define WWA_JSONRPC_EXPORT
Macro for exporting symbols when building the library dynamically or importing symbols when using the...
Definition export.h:42
static constexpr int INVALID_PARAMS
Invalid method parameter(s).
Definition exception.h:115
static constexpr int INTERNAL_ERROR
Internal JSON-RPC error.
Definition exception.h:120
static constexpr int INVALID_REQUEST
The JSON sent is not a valid Request object.
Definition exception.h:105
typename offset_sequence< N, Seq >::type offset_sequence_t
Alias template for creating an offset sequence.
Definition details.h:363
constexpr auto convert_args(const nlohmann::json &params, std::index_sequence< Indices... >)
Converts JSON parameters to a tuple of arguments based on the specified types.
Definition details.h:481
Contains the implementation details of the JSON RPC library.
Definition details.h:31
Specialization for member function pointers.
Definition details.h:79
Specialization for function pointers.
Definition details.h:57
std::tuple< Args... > args_tuple
A tuple of the argument types.
Definition details.h:59
R return_type
The return type of the function.
Definition details.h:58
Primary template for function traits.
Definition details.h:325
Template for creating an offset sequence.
Definition details.h:343
Represents a JSON RPC request.
Definition request.h:22