#include <optional>
#include <utility>
#include <coroutine>

template <typename T>
struct [[nodiscard]] task {
    struct promise_type  {
        std::suspend_always initial_suspend() {
            return {};
        }
        auto final_suspend() noexcept {
            struct awaiter {
#if 1
                std::false_type await_ready() noexcept {
                    return {};
                }
#else
                bool await_ready() noexcept {
                    return false;
                }
#endif
                std::coroutine_handle<> await_suspend(std::coroutine_handle<>) noexcept {
                    return next;
                }
                void await_resume() noexcept {
                }
                std::coroutine_handle<> next;
            };
            return awaiter{next};
        }

        void unhandled_exception() noexcept {
            std::terminate();
        }
        auto get_return_object() {
            return task(this);
        }
        auto coro() {
            return std::coroutine_handle<promise_type>::from_promise(*this);
        }
        void return_value(T val) {
            result.emplace(std::move(val));
        }

        std::coroutine_handle<> next;
        std::optional<T> result;
    };

    task(task&& source) : p(std::exchange(source.p, nullptr)) {}
    explicit task(promise_type* p) : p(p) {}
    ~task() {
        if (p)
            p->coro().destroy();
    }

    bool await_ready() noexcept {
        return p->coro().done();
    }
    std::coroutine_handle<> await_suspend(std::coroutine_handle<> next) noexcept {
        p->next = next;
        return p->coro();
    }
    const T& await_resume() const& noexcept {
        return *p->result;
    }

    promise_type* p;
};

task<int> five() {
    co_return 5;
}

task<int> six() {
    co_return co_await five() + 1;
}


int main() {
    auto task = six();
    task.p->next = std::noop_coroutine();
    task.p->coro().resume();
    return *task.p->result;
}
