On Wed, Feb 4, 2026 at 2:26 PM Ruben Perez <rubenperez038@gmail.com> wrote:
Can I implement an Asio universal async operation using Capy?
We had a conversation today in the Official C++ Language Slack Workspace and this clarified my understanding of what you are asking for. You want: asynchronous initiating functions which have Asio's Universal Asynchronous Model [1] which drive Capy's type-erased streams. This allows you to implement business logic (for example, a PostgresSQL client implementation) as "sans-I/O." That is, agnostic to the model of asynchrony. While allowing existing users who are already Asio-based, to interact with your algorithms - this provides a clear migration path. Otherwise known as "brownfield development." Yes this is possible. The example that I provided previously, offers Capy's execution model wrapped around an invisible Asio socket. I have added a new example which wraps Asio's universal asynchronous model around a type-erased Capy stream: * `uni_stream` models Asio's AsyncReadStream and AsyncWriteStream and uses completion tokens: https://github.com/cppalliance/capy/blob/4c4fa32cb96865eda059d1cb559f928624c... * `make_uni_pair` returns two connected `uni_stream` which type-erase an underlying `asio::ip::tcp::socket`: https://github.com/cppalliance/capy/blob/4c4fa32cb96865eda059d1cb559f928624c... * The asio_callbacks.cpp demo shows how asio-style completion handlers can drive the `uni_stream`: https://github.com/cppalliance/capy/blob/4c4fa32cb96865eda059d1cb559f928624c... https://github.com/cppalliance/capy/blob/4c4fa32cb96865eda059d1cb559f928624c... Note how the demo uses `asio::read` and `asio::write` free functions, which are composed operations built on top of `uni_stream` - this demonstrates that it works as expected. On the other side of the `uni_stream` (the thing erased by the `any_stream`) sits an asio::ip::tcp::socket. For your use_case, you might have something like this: // Postgres client with Asio interface class uni_postgres_client { postgres_client cli_; public: template< class CompletionToken > auto f( CompletionToken&& ); } // Postgress client with Capy interface, implemented sans-I/O class postgres_client { capy::any_stream stream_; public: capy::task f(); }; postgres_client::f is an ordinary coroutine function (goes in the cpp file) which implements an algorithm in terms of capy::any_stream. In the first iteration of your library, users will interact with uni_postgres_client. In future versions new users or migrating users would interact with postgres_client directly (both work). This allows them to upgrade little by little. Most of your algorithms can be expressed in terms of capy::any_stream, but there are some things which cannot. Resolving DNS names, establishing outgoing connections, or accepting incoming connections are not operations reflected by Capy concepts. Your uni_postgres_client would need to have some pure virtual member functions to do these things (they can be capy::task coroutines of course), and a derived class would have to implement some I/O specific things. If your underlying stream is asio socket then you would write asio code to connect or resolve names. If your underlying stream is Corosio, then you would use Corosio's APIs to do those things. Happy to elaborate further if there are specific questions. Thanks