This is a small template library aiming to make composing coroutine types much simpler. Implementing future semantics without implementing a
promise_type or touching std::coroutine_traits. It is still very not production worthy and no tests exist yet but there are a
few examples to showcase basic functionality.
Implementation begins with your standard CRTP pattern
#include <basic_coroutine.hpp>
struct my_coro_type : tmf::basic_coroutine<my_coro_type>
...to create a valid type you need to implement 2 member callables on_invoke which is called when you create a coroutine instance and
an on_return function whose parameter type is the coroutine return type.
tmf::co_control on_invoke()
{
return tmf::co_control::suspend;
}the return type here co_control is an enum which tells the coroutine to either resume or suspend,
an other return type co_resumer is possible but is not referenced directly
auto on_invoke()
{
return tmf::co_control::suspend >> []() { return; };
}this does the same as before but invokes a lambda on the next resume
void on_return(int value)
{
do_something(value);
}the coroutine returns an int and my_coro_type does something with it
member callables are optional to implement but required to support yielding from coroutines
tmf::co_control on_yield(int value)
{
do_something(value);
return tmf::co_control::suspend;
}you can return a co_resumer as we did with on_invoke
tmf::co_control on_yield(tmf::co_expect<int, int> ce)
{
do_something(ce.from);
return tmf::co_control::suspend >> []() { return 42; };
}auto on_yield(tmf::co_expect<int> ce)
{
return tmf::co_control::suspend >> []() { return 42; };
}tmf::co_control on_yield()
{
return tmf::co_control::suspend;
}intercepts a co_await and can transform the result (type included) before giving it to the coroutine
you can use 2 types of resumers and co_expect is required in the signature
auto on_await(tmf::co_expect<int>)
{
return tmf::co_control::surrender >> []() { /*no return value and no parameters*/};
}the resumer can just be side effects, the resumer can be omitted if not needed
auto on_await(tmf::co_expect<int>)
{
return tmf::co_control::surrender >> [](int n) { return n + 1; };
}resumers can also be a transform
note: when awaiting and tmf::co_control::surrender is part of the return value, the coroutine does whatever the awaited object is doing
to customize how a coroutine is executed you will use the executor callable member
template<typename F>
void executor(F&& f)
{
f();
}this is the default behaviour, just done manually.
anything can be used, like threads or a thread pool. making my_coro_type an awaiter type
by implementing await_ready, await_suspend and await_resume and coordinating with the executor can give you context dependent executors
such that only co_await suspend/resume operations run synchronously. or coordinate with other handlers to affect execution. sky's the limit