== cobalt/io/ops.hpp Most functionality in this wrapper is implemented with operations. They are type-erase, but not by using `virtual`. This makes devirtualization easier. The `implementation` function must be provided, where as `try_implementation_t` is optional and will be used in the `ready` function. Both will be called with `void *this` as the first parameter. [source,cpp] ---- struct [[nodiscard]] write_op final : op { const_buffer_sequence buffer; using implementation_t = void(void*, const_buffer_sequence, completion_handler); using try_implementation_t = void(void*, const_buffer_sequence, handler); write_op(const_buffer_sequence buffer, void * this_, implementation_t *implementation, try_implementation_t * try_implementation = nullptr); void initiate(completion_handler handler) final; void ready(handler handler) final; }; struct [[nodiscard]] read_op final : op { mutable_buffer_sequence buffer; using implementation_t = void(void*, mutable_buffer_sequence, completion_handler); using try_implementation_t = void(void*, mutable_buffer_sequence, handler); read_op(mutable_buffer_sequence buffer, void * this_, implementation_t *implementation, try_implementation_t * try_implementation = nullptr); void initiate(completion_handler handler) final; void ready(handler handler) final; }; struct [[nodiscard]] write_at_op final : op { std::uint64_t offset; const_buffer_sequence buffer; using implementation_t = void(void*, std::uint64_t, const_buffer_sequence, completion_handler); using try_implementation_t = void(void*, std::uint64_t, const_buffer_sequence, handler); write_at_op(std::uint64_t offset, const_buffer_sequence buffer, void * this_, implementation_t *implementation, try_implementation_t * try_implementation = nullptr); void initiate(completion_handler handler) final; void ready(handler handler) final; }; struct [[nodiscard]] read_at_op final : op { std::uint64_t offset; mutable_buffer_sequence buffer; using implementation_t = void(void*, std::uint64_t, mutable_buffer_sequence, completion_handler); using try_implementation_t = void(void*, std::uint64_t, mutable_buffer_sequence, handler); read_at_op(std::uint64_t offset, mutable_buffer_sequence buffer, void * this_, implementation_t *implementation, try_implementation_t * try_implementation = nullptr); void initiate(completion_handler handler) final; void ready(handler handler) final; }; struct [[nodiscard]] wait_op final : op { using implementation_t = void(void*, completion_handler); using try_implementation_t = void(void*, handler); wait_op(void * this_, implementation_t *implementation, try_implementation_t * try_implementation = nullptr); void initiate(completion_handler handler) final; void ready(handler handler) final; }; ---- The ops can be reused and public members (such as buffer) can be modified when the op is not awaited. E.g. like this: [source,cpp] ---- write_op wo = do_w; auto sz = co_await wo; while (sz > 0) { wo.buffer += sz; sz = co_await wo; } ----