std::experimental::coroutine_handle<> await_suspend(std::experimental::coroutine_handle continuation) noexcept {
return continuation.promise().continuation_;
}
void await_resume() noexcept {
}
};
struct promise_type {
task get_return_object() {
return task{*this};
}
std::experimental::suspend_always initial_suspend() {
return {};
}
final_awaiter final_suspend() {
return final_awaiter{};
}
void return_value(T v) {
value_ = v;
}
T move_value() {
return std::move(value_.value());
}
void unhandled_exception() {
}
optional value_;
std::experimental::coroutine_handle<> continuation_;
};
// awaiter
std::experimental::coroutine_handle coroutine_handle_;
task(task &&other) = default;
task(promise_type &promise)
: coroutine_handle_(std::experimental::coroutine_handle::from_promise(promise)) {
}
bool await_ready() const noexcept {
return !coroutine_handle_ || coroutine_handle_.done();
}
std::experimental::coroutine_handle<> await_suspend(std::experimental::coroutine_handle<> continuation) noexcept {
coroutine_handle_.promise().continuation_ = continuation;
return coroutine_handle_;
}
T await_resume() noexcept {
return coroutine_handle_.promise().move_value();
}
};
task f() {
co_return 1;
}
task g() {
co_return 2;
}
task h() {
auto a = co_await f();
auto b = co_await g();
co_return a + b;
}
struct immediate_task {
struct promise_type {
immediate_task get_return_object() {
return {};
}
std::experimental::suspend_never initial_suspend() {
return {};
}
std::experimental::suspend_never final_suspend() {
return {};
}
void return_void() {
}
void unhandled_exception() {
}
};
};
struct OnActor {
public:
template
OnActor(T &&actor_id) : actor_id_(actor_id.as_actor_ref()) {
}
bool await_ready() const noexcept {
return false;
}
void await_suspend(std::experimental::coroutine_handle<> continuation) noexcept {
//TODO: destroy if lambda is lost
send_lambda(actor_id_, [continuation]() mutable { continuation.resume(); });
}
void await_resume() noexcept {
}
private:
actor::detail::ActorRef actor_id_;
};
immediate_task check_h() {
LOG(ERROR) << "check_h: call h";
auto c = co_await h();
LOG(ERROR) << "check_h: after call h";
ASSERT_EQ(3, c);
}
TEST(ActorCoro, Task) {
check_h();
}
namespace actor {
class AsyncQuery {};
class Printer : public Actor {
public:
void f();
void print_a() {
LOG(ERROR) << "a";
}
void print_b() {
LOG(ERROR) << "b";
}
};
class SampleActor : public Actor {
public:
SampleActor(std::shared_ptr watcher) : watcher_(std::move(watcher)) {
}
private:
std::shared_ptr watcher_;
ActorOwn printer_;
void start_up() override {
printer_ = create_actor("Printer");
run_coroutine();
}
task print_a() {
auto self = actor_id(this);
LOG(ERROR) << "enter print_a";
co_await OnActor(printer_);
detail::current_actor().print_a();
co_await OnActor(self);
LOG(ERROR) << "exit print_a";
co_return{};
}
task print_b() {
auto self = actor_id(this);
LOG(ERROR) << "enter print_b";
co_await OnActor(printer_);
detail::current_actor().print_b();
co_await OnActor(self);
LOG(ERROR) << "exit print_b";
co_return{};
}
immediate_task run_coroutine() {
co_await print_a();
co_await print_b();
stop();
}
};
} // namespace actor
TEST(ActorCoro, Simple) {
using namespace td::actor;
using namespace td;
Scheduler scheduler({1});
auto watcher = td::create_shared_destructor([] {
LOG(ERROR) << "STOP";
SchedulerContext::get()->stop();
});
scheduler.run_in_context([watcher = std::move(watcher)] {
create_actor(ActorOptions().with_name("SampleActor").with_poll(), watcher).release();
});
scheduler.run();
}
} // namespace td
#endif