|
18 | 18 | #pragma once |
19 | 19 |
|
20 | 20 | #include <any> |
| 21 | +#include <stdexcept> |
| 22 | +#include <type_traits> |
21 | 23 |
|
22 | 24 | #include "scl/coro/task.h" |
23 | 25 | #include "scl/net/network.h" |
@@ -63,18 +65,22 @@ struct Result; |
63 | 65 | * |
64 | 66 | * The following simple example illustrates this idea. |
65 | 67 | * @code |
| 68 | + * #include <scl/protocol.h> |
| 69 | + * |
66 | 70 | * class CountdownProtocol final : public Protocol { |
67 | 71 | * public: |
68 | 72 | * CountdownProtocol(int current) : m_current(current) {} |
| 73 | +
|
69 | 74 | * Task<Result> run(Env& ignored) const override { |
70 | | - * std::cout << "countdown: " << m_current << "\n"; |
71 | 75 | * if (m_current == 0) { |
72 | 76 | * co_return Result::done(); |
73 | 77 | * } else { |
74 | | - * co_return Result::next( |
75 | | - * std::make_unique<CountdownProtocol>(m_current - 1)); |
| 78 | + * co_return Result::nextStep( |
| 79 | + * std::make_unique<CountdownProtocol>(m_current - 1), |
| 80 | + * m_current); |
76 | 81 | * } |
77 | 82 | * } |
| 83 | +
|
78 | 84 | * private: |
79 | 85 | * int m_current; |
80 | 86 | * }; |
@@ -138,21 +144,41 @@ struct Result { |
138 | 144 | std::any output; |
139 | 145 | }; |
140 | 146 |
|
| 147 | +/** |
| 148 | + * @brief Run a protocol. |
| 149 | + */ |
141 | 150 | template <typename CALLBACK> |
142 | 151 | Task<void> runProtocol(std::unique_ptr<Protocol> protocol, |
143 | 152 | Env& env, |
144 | 153 | CALLBACK output_cb) { |
145 | 154 | while (protocol) { |
146 | 155 | Result result = co_await protocol->run(env); |
147 | 156 |
|
148 | | - if (result.next) { |
149 | | - protocol = std::move(result.next); |
150 | | - } |
| 157 | + protocol = std::move(result.next); |
151 | 158 |
|
152 | 159 | if (result.output.has_value()) { |
153 | 160 | output_cb(result.output); |
154 | 161 | } |
155 | 162 | } |
156 | 163 | } |
157 | 164 |
|
| 165 | +template <typename R> |
| 166 | +Task<R> runProtocol(std::unique_ptr<Protocol> protocol, Env& env) { |
| 167 | + Result result; |
| 168 | + |
| 169 | + while (protocol) { |
| 170 | + result = co_await protocol->run(env); |
| 171 | + |
| 172 | + protocol = std::move(result.next); |
| 173 | + } |
| 174 | + |
| 175 | + if constexpr (!std::is_void_v<R>) { |
| 176 | + if (result.output.has_value()) { |
| 177 | + co_return std::any_cast<R>(result.output); |
| 178 | + } else { |
| 179 | + throw std::runtime_error("protocol never gave output"); |
| 180 | + } |
| 181 | + } |
| 182 | +} |
| 183 | + |
158 | 184 | } // namespace scl |
0 commit comments