Hi all, As you might know, I'm currently using Capy and Corosio in 3 projects: * Boost.Redis [1]: I've implemented a Corosio API matching what we had for Asio. Currently in a PR that will be merged if the libraries are accepted. * A fork of Boost.MySQL [2]. It is functional, but unclear if I will propose it as a new library, or add it to the existing one. * A PostgreSQL library that I'm writing [3]. I'm in general happy. Coroutines make everything much simpler. I don't have this "everything wants to eat me" feeling that writing Asio universal async operations transmits. Benchmarks are also quite promising, well above what we were able to get with Asio. Marcelo did the benchmarks, so I'll leave him to tell the whole story here. I've got some real questions that need answers before emitting a review. 1) What's the status of the interoperability with Asio, and what can we expect? Asio currently has many users who won't migrate their existing code from one day to another. There is a pull request in Capy [4] addressing this. I'd like to know what to expect. Especially, how seamless would the interaction with Corosio (rather than Capy) be? Would the following work? // Code using capy/corosio that creates I/O objects capy::task<> my_capy_task() { corosio::tcp_socket sock {co_await capy::this_coro::executor}; co_await sock.connect(/* whatever */); } // Represents the main application, still using Asio. // At some point, it needs to call out to code using capy/corosio asio::awaitable<void> co_main() { auto exec = capy::wrap_asio_executor(co_await asio::this_coro::executor); co_await capy::asio_spawn(my_capy_task(), compute()); } int main() { asio::io_context ctx; asio::co_spawn(ctx, co_main(), asio::detached); ctx.run(); } In real use cases, it'd be libraries (like Boost.Redis) that may create I/O objects on behalf of the user. 2) What's the rationale for having tls_context::set_hostname but no tls_stream::set_hostname? Say I have a tls_stream I want to re-use for connecting to different hosts (e.g. HTTP redirection, or Redis Sentinel). Different hosts should have different SNIs. But IIUC tls_context is supposed to be set up beforehand and not modified after the stream is created. How do I do this with Corosio? Note that I raised [5] some time ago - this may be a good time to discuss it (I understand everyone has been busy, don't take this as a criticism). 3) Asio has the concept of error dispositions [6]. In a nutshell, these are a generalization of error codes, so custom error types can be used in error code-aware functionality, like when_any. This is useful in code using specialized types. Future candidate Boost.Http uses this in its router [8], and I intended to use it as a way to attach error messages in my database libraries. I discuss my use case in more detail in this issue [9]. Have you considered the feature? 4) Does capy::cond::canceled add anything vs. just using std::errc::operation_canceled? 5) I initially found the when_any semantics confusing. It uses the equivalent to Asio's wait_for_one_success semantics [10]. Asio has also wait_for_one, and it turns out it's the one I tend to need more. Docs [11] propose a workaround - but io_task<std::error_code> doesn't look that good. Is there a chance of adding first-class support for this? What is the rationale behind making wait_for_one_success semantics the default? 6) Can I write types that satisfy ConstBufferSequence or DynamicBuffer without explicitly depending on Capy? This would be useful for low-level protocol libraries that want to take as few dependencies as possible. Setting the concrete const_buffer and mutable_buffer types apart, the usual way of representing "raw bytes" would be span<const unsigned char>/span<std::byte>. For instance, std::as_bytes [12] uses std::byte. If I got the reasoning behind ConstBufferSequence right [13], the purpose is to avoid allocations with vectored I/O. I'd say it's reasonable to allow std::array<std::span<const unsigned char>> to satisfy ConstBufferSequence. Note that I have read The Span Reflex [14]. I agree with the need of ConstBufferSequence. While I personally don't agree with the need of the concrete const_buffer and mutable_buffer types, I understand the rationale of avoiding std::byte. I'm not challenging these types, only asking for better compatibility with std::span. I'll probably get more questions as I explore the parts of the library that I don't have implementation experience with. Congratulations on the work, it's really great. Regards, Ruben. [1] https://github.com/boostorg/redis/pull/417 [2] https://github.com/anarthal/mycosql [3] https://github.com/anarthal/nativepg [4] https://github.com/cppalliance/capy/pull/246 [5] https://github.com/cppalliance/corosio/issues/239 [6] https://www.boost.org/doc/libs/latest/doc/html/boost_asio/reference/Disposit... [7] https://github.com/cppalliance/capy/issues/298 [8] https://github.com/cppalliance/http/blob/1ab0b6fe1763618215d72baaca4859b9a47... [9] https://github.com/cppalliance/capy/issues/298 [10] https://www.boost.org/doc/libs/latest/doc/html/boost_asio/overview/compositi... [11] https://master.capy.cpp.al/capy/4.coroutines/4f.composition.html#_errors_do_... [12] https://en.cppreference.com/cpp/container/span/as_bytes [13] https://master.capy.cpp.al/capy/5.buffers/5a.overview.html#_the_concept_driv... [14] https://www.vinniefalco.com/p/the-span-reflex-when-concrete-thinking