22#include < version>
33
44#include " libfork/__impl/assume.hpp"
5+ #include " libfork/__impl/exception.hpp"
56#include " libfork/__impl/utils.hpp"
67export module libfork.core:promise;
78
@@ -10,6 +11,7 @@ import std;
1011import :concepts;
1112import :utility;
1213import :frame;
14+ import :tuple;
1315
1416namespace lf {
1517
@@ -37,7 +39,7 @@ struct promise_type;
3739 * \endrst
3840 */
3941export template <returnable T, alloc_mixin Stack>
40- struct task {
42+ struct task : immovable, std::type_identity<T> {
4143 promise_type<T, Stack> *promise;
4244};
4345
@@ -46,6 +48,8 @@ struct task {
4648[[nodiscard]]
4749constexpr auto final_suspend (frame_type *frame) -> std::coroutine_handle<> {
4850
51+ // TODO: noexcept
52+
4953 LF_ASSUME (frame != nullptr );
5054
5155 frame_type *parent_frame = frame->parent ;
@@ -68,13 +72,15 @@ struct final_awaitable : std::suspend_always {
6872 }
6973};
7074
71- struct just_awaitable : std::suspend_always {
75+ struct call_awaitable : std::suspend_always {
7276
7377 frame_type *child;
7478
7579 template <typename ... Us>
7680 auto await_suspend (std::coroutine_handle<promise_type<Us...>> parent) noexcept -> std::coroutine_handle<> {
7781
82+ // TODO: destroy on child if cannot launch i.e. scheduling failure
83+
7884 LF_ASSUME (child != nullptr );
7985 LF_ASSUME (child->parent == nullptr );
8086
@@ -84,6 +90,36 @@ struct just_awaitable : std::suspend_always {
8490 }
8591};
8692
93+ // clang-format off
94+
95+ template <typename R, typename Fn, typename ... Args>
96+ struct pkg {
97+ R *return_address;
98+ [[no_unique_address]] Fn fn;
99+ [[no_unique_address]] tuple<Args...> args;
100+ };
101+
102+ template <typename Fn, typename ... Args>
103+ struct pkg <void , Fn, Args...> {
104+ [[no_unique_address]] Fn fn;
105+ [[no_unique_address]] tuple<Args...> args;
106+ };
107+
108+ // clang-format on
109+
110+ template <typename R, typename Fn, typename ... Args>
111+ struct [[nodiscard(" You should immediately co_await this!" )]] call_pkg : pkg<R, Fn, Args...>, immovable {};
112+
113+ export template <typename ... Args, async_invocable_to<void , Args...> Fn>
114+ constexpr auto call (Fn &&fn, Args &&...args) noexcept -> call_pkg<void, Fn, Args &&...> {
115+ return {LF_FWD (fn), {LF_FWD (args)...}};
116+ }
117+
118+ export template <typename R, typename ... Args, async_invocable_to<R, Args...> Fn>
119+ constexpr auto call (R *ret, Fn &&fn, Args &&...args) noexcept -> call_pkg<R, Fn, Args &&...> {
120+ return {ret, LF_FWD (fn), {LF_FWD (args)...}};
121+ }
122+
87123struct mixin_frame {
88124
89125 // === For internal use === //
@@ -99,8 +135,15 @@ struct mixin_frame {
99135
100136 // === Called by the compiler === //
101137
102- template <alloc_mixin P>
103- constexpr static auto await_transform(task<void , P> child) noexcept -> just_awaitable {
138+ template <typename R, typename Fn, typename... Args>
139+ constexpr static auto await_transform(call_pkg<R, Fn, Args...> &&pkg) noexcept -> call_awaitable {
140+
141+ task child = std::move (pkg.args ).apply (std::move (pkg.fn ));
142+
143+ if constexpr (!std::is_void_v<R>) {
144+ child.promise ->return_address = pkg.return_address ;
145+ }
146+
104147 return {.child = &child.promise ->frame };
105148 }
106149
@@ -120,9 +163,9 @@ struct promise_type<void, StackPolicy> : StackPolicy, mixin_frame {
120163
121164 frame_type frame;
122165
123- constexpr auto get_return_object () -> task<void, StackPolicy> { return {.promise = this }; }
166+ constexpr auto get_return_object () noexcept -> task<void, StackPolicy> { return {.promise = this }; }
124167
125- constexpr static void return_void () {}
168+ constexpr static void return_void () noexcept {}
126169};
127170
128171struct dummy_alloc {
@@ -142,8 +185,17 @@ static_assert(std::is_standard_layout_v<promise_type<void, dummy_alloc>>);
142185
143186template <typename T, alloc_mixin StackPolicy>
144187struct promise_type : StackPolicy, mixin_frame {
188+
145189 frame_type frame;
146190 T *return_address;
191+
192+ constexpr auto get_return_object () noexcept -> task<T, StackPolicy> { return {.promise = this }; }
193+
194+ template <typename U = T>
195+ requires std::assignable_from<T &, U &&>
196+ constexpr void return_value (U &&value) noexcept (std::is_nothrow_assignable_v<T &, U &&>) {
197+ *return_address = LF_FWD (value);
198+ }
147199};
148200
149201static_assert (alignof (promise_type<int , dummy_alloc>) == alignof (frame_type));
0 commit comments