emlabcpp
modern opinionated embedded C++ library
coroutine.h
Go to the documentation of this file.
1 
24 #pragma once
25 
26 #include "../coro/data_promise.h"
27 #include "../coro/memory_promise.h"
28 #include "../coro/owning_coroutine_handle.h"
29 
30 #include <coroutine>
31 
32 namespace emlabcpp::testing
33 {
34 
35 enum class coro_state : uint8_t
36 {
37  WAITING = 0x1,
38  ERRORED = 0x3,
39  SKIPPED = 0x4,
40  FAILED = 0x5,
41  DONE = 0x6
42 };
43 
45 {
46  [[nodiscard]] virtual coro_state get_state() const = 0;
47  virtual void tick() {};
48  virtual ~wait_interface() = default;
49 };
50 
51 template < typename T >
52 class coroutine : public wait_interface
53 {
54 public:
55  struct promise_type : coro::data_promise< T >, coro::memory_promise< promise_type >
56  {
58  {
60  }
61 
62  [[nodiscard]] coroutine get_return_object()
63  {
64  return coroutine{ handle::from_promise( *this ) };
65  }
66 
67  [[nodiscard]] std::suspend_always initial_suspend() const
68  {
69  return {};
70  }
71 
72  [[nodiscard]] std::suspend_always final_suspend() const noexcept
73  {
74  return {};
75  }
76 
77  void unhandled_exception() const
78  {
79  }
80 
81  wait_interface* iface = nullptr;
82  };
83 
84  using handle = std::coroutine_handle< promise_type >;
86 
87  explicit coroutine() = default;
88 
89  explicit coroutine( handle const& cor )
90  : state_( cor ? coro_state::WAITING : coro_state::ERRORED )
91  , h_( cor )
92  {
93  }
94 
95  explicit coroutine( coro_state s )
96  : state_( s )
97  {
98  }
99 
100  [[nodiscard]] bool done() const
101  {
102  if ( h_ )
103  return h_.done();
104  return true;
105  }
106 
107  [[nodiscard]] coro_state get_state() const override
108  {
109  return state_;
110  }
111 
112  [[nodiscard]] bool await_ready() const
113  {
114  return false;
115  }
116 
117  void await_suspend( auto const& h )
118  {
119  h.promise().iface = this;
120  }
121 
123  {
124  if constexpr ( !std::is_void_v< T > )
125  return h_.promise().value;
126  }
127 
128  auto run()
129  {
130  while ( !done() )
131  tick();
132 
133  if constexpr ( !std::is_void_v< T > )
134  return h_.promise().value;
135  }
136 
137  void tick() override
138  {
139  if ( state_ != coro_state::WAITING )
140  return;
141 
142  if ( done() ) {
143  state_ = coro_state::ERRORED;
144  return;
145  }
146 
147  wait_interface* iface = h_.promise().iface;
148 
149  if ( iface != nullptr ) {
150  coro_state const s = iface->get_state();
151  switch ( s ) {
152  case coro_state::WAITING:
153  iface->tick();
154  return;
155  case coro_state::ERRORED:
156  case coro_state::SKIPPED:
157  case coro_state::FAILED:
158  h_ = owning_handle();
159  state_ = s;
160  return;
161  case coro_state::DONE:
162  break;
163  }
164  }
165  h_();
166 
167  if ( done() )
168  state_ = coro_state::DONE;
169  }
170 
171 private:
172  coro_state state_ = coro_state::DONE;
173  owning_handle h_;
174 };
175 
177 {
179 
181  : state( s )
182  {
183  }
184 
185  [[nodiscard]] coro_state get_state() const override
186  {
187  return state;
188  }
189 
190  void tick() override
191  {
192  }
193 
194  [[nodiscard]] bool await_ready() const
195  {
196  return state == coro_state::DONE;
197  }
198 
199  template < typename T >
200  void await_suspend( std::coroutine_handle< T > h )
201  {
202  h.promise().iface = this;
203  }
204 
205  void await_resume() const
206  {
207  }
208 };
209 
210 inline status_awaiter expect( bool expr )
211 {
212  return { expr ? coro_state::DONE : coro_state::FAILED };
213 }
214 
216 {
217  return { coro_state::FAILED };
218 }
219 
221 {
222  return { coro_state::SKIPPED };
223 }
224 
225 } // namespace emlabcpp::testing
constexpr bool done() const
Definition: owning_coroutine_handle.h:70
constexpr promise_type & promise()
Definition: owning_coroutine_handle.h:80
Definition: coroutine.h:53
void tick() override
Definition: coroutine.h:137
std::coroutine_handle< promise_type > handle
Definition: coroutine.h:84
coro::owning_coroutine_handle< promise_type > owning_handle
Definition: coroutine.h:85
coro_state get_state() const override
Definition: coroutine.h:107
bool await_ready() const
Definition: coroutine.h:112
bool done() const
Definition: coroutine.h:100
void await_suspend(auto const &h)
Definition: coroutine.h:117
coroutine(handle const &cor)
Definition: coroutine.h:89
coroutine(coro_state s)
Definition: coroutine.h:95
auto await_resume()
Definition: coroutine.h:122
auto run()
Definition: coroutine.h:128
MIT License.
Definition: base.h:37
status_awaiter fail()
Definition: coroutine.h:215
coro_state
Definition: coroutine.h:36
status_awaiter skip()
Definition: coroutine.h:220
status_awaiter expect(collector &c, bool expr, std::source_location loc=std::source_location::current())
Definition: collect.h:167
Definition: data_promise.h:31
T value
Definition: data_promise.h:38
Definition: memory_promise.h:34
wait_interface * iface
Definition: coroutine.h:81
std::suspend_always final_suspend() const noexcept
Definition: coroutine.h:72
coroutine get_return_object()
Definition: coroutine.h:62
void unhandled_exception() const
Definition: coroutine.h:77
std::suspend_always initial_suspend() const
Definition: coroutine.h:67
static coroutine get_return_object_on_allocation_failure()
Definition: coroutine.h:57
Definition: coroutine.h:177
void await_resume() const
Definition: coroutine.h:205
coro_state get_state() const override
Definition: coroutine.h:185
coro_state state
Definition: coroutine.h:178
void await_suspend(std::coroutine_handle< T > h)
Definition: coroutine.h:200
status_awaiter(coro_state s)
Definition: coroutine.h:180
bool await_ready() const
Definition: coroutine.h:194
void tick() override
Definition: coroutine.h:190
Definition: coroutine.h:45
virtual void tick()
Definition: coroutine.h:47
virtual coro_state get_state() const =0