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