1+ #pragma once
2+
3+ #include < coroutine>
4+ #include < concepts>
5+ #include < utility>
6+ #include < iostream>
7+
8+ namespace ucoro {
9+
10+ template <typename T>
11+ requires (!std::is_reference_v<T> && !std::is_pointer_v<T>)
12+ class [[nodiscard]] Coro final
13+ {
14+ public:
15+ class FinalAwaitable ;
16+ class Awaitable ;
17+
18+ class promise_type final
19+ {
20+ public:
21+ Coro get_return_object () { return Coro{std::coroutine_handle<promise_type>::from_promise (*this )}; }
22+ std::suspend_always initial_suspend () noexcept { return {}; }
23+
24+ void return_value (T&& new_value) {
25+ std::cerr << " \n PromiseType::return_value" ;
26+ m_value = std::move (new_value);
27+ }
28+
29+ // an exception escapes the body of the coroutine.
30+ void unhandled_exception () {
31+ std::terminate ();
32+ }
33+
34+ FinalAwaitable final_suspend () noexcept { return FinalAwaitable{}; }
35+
36+ void continuation (std::coroutine_handle<> continuation) {
37+ m_continuation = continuation;
38+ }
39+
40+ std::coroutine_handle<> continuation () const {
41+ return m_continuation;
42+ }
43+
44+ T&& value() && {
45+ return std::move (m_value);
46+ }
47+
48+ private:
49+ T m_value{};
50+
51+ std::coroutine_handle<> m_continuation{nullptr };
52+ };
53+
54+ explicit Coro (std::coroutine_handle<promise_type> handle)
55+ : m_handle{handle} {}
56+
57+ ~Coro () {
58+ if (m_handle)
59+ m_handle.destroy ();
60+ }
61+
62+ Coro (const Coro&) = delete ;
63+ Coro& operator =(const Coro&) = delete ;
64+
65+ Coro (Coro&& rhs) noexcept
66+ : m_handle (std::move (rhs.m_handle )) {
67+ rhs.m_handle = nullptr ;
68+ }
69+
70+ Coro& operator =(Coro&& rhs) noexcept {
71+ if (&rhs != this ) {
72+ if (m_handle) {
73+ m_handle.destroy ();
74+ }
75+ m_handle = std::exchange (rhs.m_handle , nullptr );
76+ }
77+ return *this ;
78+ }
79+
80+ Awaitable operator co_await () && noexcept ;
81+
82+ private:
83+ std::coroutine_handle<promise_type> m_handle;
84+ };
85+
86+ template <typename T>
87+ class Coro <T>::FinalAwaitable final {
88+ public:
89+ bool await_ready () const noexcept { return false ; }
90+
91+ std::coroutine_handle<> await_suspend (std::coroutine_handle<typename Coro<T>::promise_type> coroutine) noexcept
92+ {
93+ std::cerr << " \n FinalAwaitable::await_suspend done? " << coroutine.done ()
94+ << " continuation nullptr? " << (coroutine.promise ().continuation () == nullptr );
95+ // If there is a continuation call it, otherwise this is the end of the line.
96+ // auto& promise = coroutine.promise();
97+ // if (promise.continuation() != nullptr)
98+ // {
99+ // return promise.continuation();
100+ // }
101+ // else
102+ // {
103+ // return std::noop_coroutine();
104+ // }
105+ return coroutine.promise ().continuation ();
106+ }
107+
108+ void await_resume () noexcept {
109+ std::cerr << " \n FinalAwaitable::await_resume" ;
110+ }
111+ };
112+
113+ template <typename T>
114+ class Coro <T>::Awaitable final
115+ {
116+ using promise_type = typename Coro<T>::promise_type;
117+ public:
118+ explicit Awaitable (std::coroutine_handle<promise_type> handler) noexcept
119+ : m_handler{std::move (handler)} {}
120+
121+ bool await_ready () const {
122+ return !m_handler || m_handler.done ();
123+ }
124+
125+ std::coroutine_handle<> await_suspend (std::coroutine_handle<promise_type> continuation) {
126+ std::cerr << " \n AwaitableBase::await_suspend" ;
127+ // Store the continuation in the task's promise so that the final_suspend()
128+ // knows to resume this coroutine when the task completes.
129+
130+ m_handler.promise ().continuation (continuation);
131+
132+ // Then we resume the task's coroutine, which is currently suspended
133+ // at the initial-suspend-point (ie. at the open curly brace).
134+ return m_handler;
135+ }
136+
137+ T&& await_resume() const {
138+ std::cerr << " \n ResponseAwaitable::await_resume" ;
139+ return std::move (m_handler.promise ()).value ();
140+ }
141+
142+ protected:
143+ std::coroutine_handle<promise_type> m_handler;
144+ };
145+
146+
147+ template <typename T>
148+ typename Coro<T>::Awaitable Coro<T>::operator co_await () && noexcept {
149+ return typename Coro<T>::Awaitable{m_handle};
150+ }
151+
152+
153+ } // < namespace ucoro
0 commit comments