Clio  develop
The XRP Ledger API server.
Loading...
Searching...
No Matches
ErasedOperation.hpp
1#pragma once
2
3#include "util/Assert.hpp"
4#include "util/async/Concepts.hpp"
5#include "util/async/Error.hpp"
6
7#include <any>
8#include <expected>
9#include <memory>
10#include <type_traits>
11#include <utility>
12
13namespace util::async::impl {
14
15class ErasedOperation {
16public:
17 template <SomeOperation OpType>
18 requires(not std::is_same_v<std::decay_t<OpType>, ErasedOperation>)
19 /* implicit */ ErasedOperation(OpType&& operation)
20 : pimpl_{std::make_unique<Model<OpType>>(std::forward<OpType>(operation))}
21 {
22 }
23
24 ~ErasedOperation() = default;
25
26 ErasedOperation(ErasedOperation const&) = delete;
27 ErasedOperation(ErasedOperation&&) = default;
28
29 ErasedOperation&
30 operator=(ErasedOperation const&) = delete;
31 ErasedOperation&
32 operator=(ErasedOperation&&) = default;
33
34 void
35 wait() noexcept
36 {
37 pimpl_->wait();
38 }
39
40 std::expected<std::any, ExecutionError>
41 get()
42 {
43 return pimpl_->get();
44 }
45
49 void
51 {
52 pimpl_->abort();
53 }
54
55 void
56 invoke()
57 {
58 pimpl_->invoke();
59 }
60
61private:
62 struct Concept {
63 virtual ~Concept() = default;
64
65 virtual void
66 wait() noexcept = 0;
67 virtual std::expected<std::any, ExecutionError>
68 get() = 0;
69 virtual void
70 abort() = 0;
71 virtual void
72 invoke() = 0;
73 };
74
75 template <SomeOperation OpType>
76 struct Model : Concept {
77 OpType operation;
78
79 template <typename OType>
80 requires std::is_same_v<OType, OpType>
81 Model(OType&& operation) : operation{std::forward<OType>(operation)}
82 {
83 }
84
85 void
86 wait() noexcept override
87 {
88 if constexpr (not SomeAwaitable<OpType>) {
89 ASSERT(false, "Called wait() on an operation that does not support it");
90 std::unreachable();
91 } else {
92 operation.wait();
93 }
94 }
95
96 std::expected<std::any, ExecutionError>
97 get() override
98 {
99 if constexpr (not SomeOperationWithData<OpType>) {
100 ASSERT(false, "Called get() on an operation that does not support it");
101 std::unreachable();
102 } else {
103 // Note: return type of the operation was already wrapped to std::any by
104 // AnyExecutionContext
105 return operation.get();
106 }
107 }
108
109 void
110 abort() override
111 {
112 if constexpr (
113 not SomeCancellableOperation<OpType> and not SomeStoppableOperation<OpType> and
114 not SomeAbortable<OpType>
115 ) {
116 ASSERT(
117 false,
118 "Called abort() on an operation that can't be aborted, cancelled nor stopped"
119 );
120 } else {
121 if constexpr (SomeAbortable<OpType>) {
122 operation.abort();
123 } else {
124 if constexpr (SomeCancellableOperation<OpType>)
125 operation.cancel();
126 if constexpr (SomeStoppableOperation<OpType>)
127 operation.requestStop();
128 }
129 }
130 }
131
132 void
133 invoke() override
134 {
135 if constexpr (not SomeForceInvocableOperation<OpType>) {
136 ASSERT(false, "Called invoke() on an operation that can't be force-invoked");
137 } else {
138 operation.invoke();
139 }
140 }
141 };
142
143private:
144 std::unique_ptr<Concept> pimpl_;
145};
146
147} // namespace util::async::impl
void abort()
Cancel if needed and request stop as soon as possible.
Definition ErasedOperation.hpp:50
Specifies the interface for an operation.
Definition Concepts.hpp:71
Error channel type for async operation of any ExecutionContext.
Definition Error.hpp:19