Clio develop
The XRP Ledger API server.
Loading...
Searching...
No Matches
Factories.hpp
1//------------------------------------------------------------------------------
2/*
3 This file is part of clio: https://github.com/XRPLF/clio
4 Copyright (c) 2023, the clio developers.
5
6 Permission to use, copy, modify, and 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#pragma once
21
22#include "rpc/Errors.hpp"
23#include "rpc/common/Checkers.hpp"
24#include "rpc/common/Concepts.hpp"
25#include "rpc/common/Types.hpp"
26#include "util/UnsupportedType.hpp"
27
28#include <boost/json/array.hpp>
29#include <boost/json/value.hpp>
30
31#include <expected>
32#include <functional>
33#include <optional>
34#include <string>
35#include <utility>
36#include <vector>
37
38namespace rpc::impl {
39
40using FieldSpecProcessor = std::function<MaybeError(boost::json::value&)>;
41
42static FieldSpecProcessor const kEMPTY_FIELD_PROCESSOR = [](boost::json::value&) -> MaybeError { return {}; };
43
44template <SomeProcessor... Processors>
45[[nodiscard]] FieldSpecProcessor
46makeFieldProcessor(std::string const& key, Processors&&... procs)
47{
48 return [key, ... proc = std::forward<Processors>(procs)](boost::json::value& j) -> MaybeError {
49 std::optional<Status> firstFailure = std::nullopt;
50
51 // This expands in order of Requirements and stops evaluating after first failure which is stored in
52 // `firstFailure` and can be checked later on to see whether the verification failed as a whole or not.
53 (
54 [&j, &key, &firstFailure, req = &proc]() {
55 if (firstFailure)
56 return; // already failed earlier - skip
57
58 if constexpr (SomeRequirement<decltype(*req)>) {
59 if (auto const res = req->verify(j, key); not res)
60 firstFailure = res.error();
61 } else if constexpr (SomeModifier<decltype(*req)>) {
62 if (auto const res = req->modify(j, key); not res)
63 firstFailure = res.error();
64 } else {
65 static_assert(util::Unsupported<decltype(*req)>);
66 }
67 }(),
68 ...
69 );
70
71 if (firstFailure)
72 return std::unexpected{std::move(firstFailure).value()};
73
74 return {};
75 };
76}
77
78using FieldChecker = std::function<check::Warnings(boost::json::value const&)>;
79
80static FieldChecker const kEMPTY_FIELD_CHECKER = [](boost::json::value const&) -> check::Warnings { return {}; };
81
82template <SomeCheck... Checks>
83[[nodiscard]] FieldChecker
84makeFieldChecker(std::string const& key, Checks&&... checks)
85{
86 return [key, ... checks = std::forward<Checks>(checks)](boost::json::value const& j) -> check::Warnings {
87 check::Warnings warnings;
88 // This expands in order of Checks and collects all warnings into a WarningsCollection
89 (
90 [&j, &key, &warnings, req = &checks]() {
91 if (auto res = req->check(j, key); res)
92 warnings.push_back(std::move(res).value());
93 }(),
94 ...
95 );
96 return warnings;
97 };
98}
99
100} // namespace rpc::impl
std::expected< void, Status > MaybeError
Return type used for Validators that can return error but don't have specific value to return.
Definition Types.hpp:55
static constexpr bool Unsupported
used for compile time checking of unsupported types
Definition UnsupportedType.hpp:26