# Implementing Custom ASIO Completion Tokens: Extending Beyond use_future and use_awaitable

> Learn to implement custom ASIO completion tokens beyond use_future and use_awaitable. Define your own token types and specialize async_result for flexible asynchronous operations.

- Repository: [chriskohlhoff/asio](https://github.com/chriskohlhoff/asio)
- Tags: deep-dive
- Published: 2026-07-11

---

**You can create custom ASIO completion tokens by defining a token type that implements `operator()(CompletionHandler)` and specializing the `async_result` trait to map the token and operation signature to a concrete handler type.**

ASIO's extensibility hinges on the **completion token** abstraction, which decouples asynchronous operation initiation from result delivery semantics. While the library ships with built-in tokens such as `use_future` and `use_awaitable`, implementing custom ASIO completion tokens allows integration with callbacks, custom futures, or proprietary async frameworks. This guide examines the exact pattern used in the [chriskohlhoff/asio](https://github.com/chriskohlhoff/asio) repository to extend the library's async model.

## How ASIO Discovers Completion Tokens

When you invoke an async operation like `socket.async_read_some(buf, token)`, the library transforms your token into a concrete handler through the **`async_result`** trait defined in [`include/asio/async_result.hpp`](https://github.com/chriskohlhoff/asio/blob/main/include/asio/async_result.hpp). The resolution process follows three distinct steps:

1. **Deduce the handler type** using `typename asio::async_result<decay_t<CompletionToken>, Signature>::completion_handler_type`
2. **Construct the handler** by invoking the token's `operator()(CompletionHandler)`, allowing the token to adapt or wrap the handler
3. **Execute the initiation function** with the constructed handler, which eventually gets invoked when the operation completes

The default specializations for built-in tokens reside in the implementation directory. For example, [`include/asio/impl/use_future.hpp`](https://github.com/chriskohlhoff/asio/blob/main/include/asio/impl/use_future.hpp) defines `async_result<use_future_t<Allocator>, R(Args...)>` and its associated `promise_handler`, while [`include/asio/impl/use_awaitable.hpp`](https://github.com/chriskohlhoff/asio/blob/main/include/asio/impl/use_awaitable.hpp) handles coroutine-based tokens. These files serve as the canonical reference for custom implementations.

## Building a Custom Token Structure

A production-ready custom token requires two coordinated components: the public token type and the `async_result` specialization.

### The Token Type

The token itself is a lightweight struct that stores user-defined state and acts as a callable factory for the concrete handler. It must implement a templated `operator()` that accepts a completion handler and returns the adapted handler object.

### The async_result Specialization

You must specialize `async_result<YourTokenType, Signature>` to tell ASIO how to:
- Determine the `completion_handler_type` (the return type of your token's `operator()`)
- Retrieve the operation's final result through the `get()` method

Specializations typically live in `include/asio/impl/` following the library's convention, or adjacent to your token definition in [`include/asio/async_result.hpp`](https://github.com/chriskohlhoff/asio/blob/main/include/asio/async_result.hpp).

## Complete Implementation Example

Below is a minimal working implementation of a **`use_callback`** token that forwards operation results to a `std::function<void(error_code, std::size_t)>`.

### Defining the Token

Create [`include/asio/use_callback.hpp`](https://github.com/chriskohlhoff/asio/blob/main/include/asio/use_callback.hpp) with the token definition:

```cpp
struct use_callback_t
{
    explicit use_callback_t(std::function<void(asio::error_code, std::size_t)> cb)
      : cb_(std::move(cb)) {}

    template <typename CompletionHandler>
    auto operator()(CompletionHandler&& h) const
    {
        struct wrapper
        {
            CompletionHandler inner;
            std::function<void(asio::error_code, std::size_t)> cb;

            void operator()(asio::error_code ec, std::size_t n) const
            {
                inner(ec, n);
                cb(ec, n);
            }
        };
        return wrapper{ std::forward<CompletionHandler>(h), cb_ };
    }

    std::function<void(asio::error_code, std::size_t)> cb_;
};

inline constexpr use_callback_t use_callback{ nullptr };

```

### Specializing async_result

Create [`include/asio/impl/use_callback.hpp`](https://github.com/chriskohlhoff/asio/blob/main/include/asio/impl/use_callback.hpp) with the trait specialization:

```cpp
#include <asio/async_result.hpp>
#include <asio/use_callback.hpp>

namespace asio {

template <typename Signature>
class async_result<use_callback_t, Signature>
{
public:
    using completion_handler_type = decltype(
        std::declval<use_callback_t>()(std::declval<std::function<void()>>())
    );

    void get() const noexcept {}
};

} // namespace asio

```

### Usage in Practice

Invoke the custom token exactly like built-in alternatives:

```cpp
#include <asio.hpp>
#include <asio/use_callback.hpp>

void echo_server(asio::ip::tcp::acceptor& acceptor)
{
    acceptor.async_accept(
        [&](asio::error_code ec, asio::ip::tcp::socket sock)
        {
            if (!ec)
            {
                std::array<char, 1024> buf;
                sock.async_read_some(
                    asio::buffer(buf),
                    asio::use_callback(
                        [](asio::error_code ec, std::size_t n)
                        {
                            std::cout << "Read " << n << " bytes\n";
                        }));
            }
        });
}

```

## Advanced Token Patterns

The ASIO repository demonstrates several sophisticated patterns you can adapt for custom tokens.

### Adapter Tokens

**Adapter tokens** wrap and transform other tokens rather than creating handlers directly. The `redirect_error` token in [`include/asio/redirect_error.hpp`](https://github.com/chriskohlhoff/asio/blob/main/include/asio/redirect_error.hpp) exemplifies this pattern: it inherits from `detail::partial_redirect_error`, intercepts the completion signature to strip error codes, and forwards the modified handler to the underlying token. This approach lets you compose token behavior without rewriting handler logic.

### Executor-Bound Tokens

Tokens requiring specific execution contexts, such as `use_awaitable`, expose a nested **`executor_type`** and a `rebind` member that returns a token bound to a different executor. Examine [`include/asio/impl/use_awaitable.hpp`](https://github.com/chriskohlhoff/asio/blob/main/include/asio/impl/use_awaitable.hpp) to see how the token stores an executor reference and constructs `awaitable<R>` objects that resume on the correct execution context.

### Custom Allocators

The `use_future` implementation in [`include/asio/impl/use_future.hpp`](https://github.com/chriskohlhoff/asio/blob/main/include/asio/impl/use_future.hpp) supports custom allocators through `use_future_t<Allocator>`. The allocator is stored within the token and forwarded to the handler's constructor via the `rebind` method. For memory-sensitive applications, follow this pattern by templating your token on an allocator type and propagating it during handler construction.

## Key Source Files in the Repository

When implementing custom ASIO completion tokens, reference these authoritative implementations in the chriskohlhoff/asio repository:

- **[`include/asio/async_result.hpp`](https://github.com/chriskohlhoff/asio/blob/main/include/asio/async_result.hpp)** — Core trait that drives token resolution and handler type deduction
- **[`include/asio/impl/use_future.hpp`](https://github.com/chriskohlhoff/asio/blob/main/include/asio/impl/use_future.hpp)** — Full-featured token specialization demonstrating allocator support and promise-based results
- **[`include/asio/impl/use_awaitable.hpp`](https://github.com/chriskohlhoff/asio/blob/main/include/asio/impl/use_awaitable.hpp)** — Executor-bound token creating coroutine awaitables
- **[`include/asio/redirect_error.hpp`](https://github.com/chriskohlhoff/asio/blob/main/include/asio/redirect_error.hpp)** — Adapter token pattern for modifying completion signatures
- **[`include/asio/experimental/use_promise.hpp`](https://github.com/chriskohlhoff/asio/blob/main/include/asio/experimental/use_promise.hpp)** — Alternative promise/future pair implementation showing advanced memory handling

## Summary

- **Custom ASIO completion tokens** require a token type implementing `operator()(CompletionHandler)` and an `async_result` specialization defining `completion_handler_type` and `get()`.
- The token acts as a factory that wraps or adapts the library's internal handler before the operation initiates.
- Reference implementations in [`include/asio/impl/use_future.hpp`](https://github.com/chriskohlhoff/asio/blob/main/include/asio/impl/use_future.hpp) and [`include/asio/impl/use_awaitable.hpp`](https://github.com/chriskohlhoff/asio/blob/main/include/asio/impl/use_awaitable.hpp) provide production-ready patterns for handler construction.
- Advanced patterns include adapter tokens (composing behavior), executor-bound tokens (controlling execution context), and allocator-aware tokens (custom memory management).
- Place token definitions in `include/asio/` and specializations in `include/asio/impl/` to maintain consistency with the library's architecture.

## Frequently Asked Questions

### What is the minimum requirement for a custom completion token?

A valid custom token must provide a callable `operator()` that accepts a completion handler and returns a handler-compatible object, plus a specialization of `async_result<Token, Signature>` that defines `completion_handler_type` and implements `get()`. The specialization tells ASIO which concrete handler type to construct and how to retrieve the final result.

### How does ASIO determine which handler type to use for a custom token?

ASIO queries the **`completion_handler_type`** nested type alias within your `async_result` specialization. According to [`include/asio/async_result.hpp`](https://github.com/chriskohlhoff/asio/blob/main/include/asio/async_result.hpp), the library uses `decltype(std::declval<Token>()(std::declval<Handler>()))` or an equivalent deduction to determine the exact handler type before constructing it.

### Can custom tokens wrap other tokens like the built-in redirect_error?

Yes. You can implement **adapter tokens** that store an underlying token and transform the completion signature or handler invocation. Study [`include/asio/redirect_error.hpp`](https://github.com/chriskohlhoff/asio/blob/main/include/asio/redirect_error.hpp) to see how it wraps another token, modifies the handler's signature to remove error codes, and forwards to the wrapped token's handler factory.

### Where should I place my custom token implementation files?

Follow the repository convention used by `use_future` and `use_awaitable`: place the public token definition in [`include/asio/your_token.hpp`](https://github.com/chriskohlhoff/asio/blob/main/include/asio/your_token.hpp) and the `async_result` specialization in [`include/asio/impl/your_token.hpp`](https://github.com/chriskohlhoff/asio/blob/main/include/asio/impl/your_token.hpp). This separation keeps interface and implementation distinct while ensuring the specialization is available when including the main async result header.