[#cobalt_operation]
== cobalt/op.hpp

An operation in `cobalt` is an <<awaitable, awaitable>> wrapping an `asio` operation.

[#use_op]
=== use_op

The `use_op` token is the direct way to create an op,
i.e. using `cobalt::use_op` as the completion token will create the required awaitable.

[source,cpp]
----
auto tim = cobalt::use_op.as_default_on(asio::steady_timer{co_await cobalt::this_coro::executor});
co_await tim.async_wait();
----

Depending on the completion signature the `co_await` expression may throw.

[cols="1,1,1"]
|===
| Signature | Return type | Exception

| `void()`                         | `void`             | `noexcept`
| `void(T)`                        | `T`                | `noexcept`
| `void(T...)`                     | `std::tuple<T...>` | `noexcept`
| `void(system::error_code, T)`    | `T`                | `system::system_error`
| `void(system::error_code, T...)` | `std::tuple<T...>` | `system::system_error`
| `void(std::exception_ptr, T)`    | `T`                | _any exception_
| `void(std::exception_ptr, T...)` | `std::tuple<T...>` | _any exception_
|===

NOTE:  `use_op` will never complete immediately, i.e. `await_ready` will always return false, but always suspend the coroutine.



[#op]
=== Hand coded Operations

Operations are a more advanced implementation of the <<cobalt_operation>> feature.

This library makes it easy to create asynchronous operations with an early completion condition,
i.e. a condition that avoids suspension of coroutines altogether.

We can for example create a `wait_op` that does nothing if the timer is already expired.

[source,cpp]
----
struct wait_op : cobalt::op<system::error_code> // <1>
{
  asio::steady_timer & tim;

  wait_op(asio::steady_timer & tim) : tim(tim) {}

  bool ready(cobalt::handler<system::error_code> ) // <2>
  {
    if (tim.expiry() < std::chrono::steady_clock::now())
        h(system::error_code{});
  }
  void initiate(cobalt::completion_handler<system::error_code> complete) // <3>
  {
    tim.async_wait(std::move(complete));
  }
};
----
<1> Inherit `op` with the matching signature `await_transform` picks it up
<2> Check if the operation is ready - called from `await_ready`
<3> Initiate the operation if its not ready.

