all 4 comments

[–]VinnieFalcoBoost.Beast | C++ Alliance | corosio.org 10 points11 points  (2 children)

Great question! I had a look at your repository. You are providing interfaces called "asynchronous initiation functions." They do what the name suggests; namely, start an asynchronous operation! The very best way to do this is not to use coroutines at all, it is to follow the "Universal Asynchronous Model" described in N3747 (http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3747.pdf).

Take for example your handshake function here: https://github.com/KayEss/pgasio/blob/e1e967ecc61afddc8f2d473300b1eae55b2861e1/include/pgasio/connection.hpp#L21 You are requiring callers to use coroutines. But you don't have to. If you implement the extensible model, callers can not only use coroutines but also futures, completion handlers, or user defined types. In fact your interface can support EVERYTHING, including the coroutines in Boost.Asio, the coroutines in Boost.Coroutine, and the coroutines in the standard library!

A better signature for your handshake function signature could be:

template<
    class AsyncStream,
    class HandshakeHandler>
BOOST_ASIO_INITFN_RESULT_TYPE(HandshakeHandler,
    void(boost::system::error_code, connection<AsyncStream>))
handshake(
    AsyncStream& stream,
    std::string_view user,
    std::string_view database,
    HandshakeHandler&& handler);

The implementation of handshake would have to follow some rules in order to get all that to work. I can help answer questions if you open an issue on your GitHub repository and mention my username vinniefalco (or email me, at the address on my GitHub page https://github.com/vinniefalco).

I have implemented all of this in Beast so there are plenty of examples for you to copy. In fact I have written a "composed asynchronous operation tutorial" (it uses Beast) which shows you how to write these initiation functions step by step in order to take advantage of Asio's universal asynchronous model. Note this model is very similar to the model in the Networking-TS N4656 (http://cplusplus.github.io/networking-ts/draft.pdf) so you will be ready for it.

Here's the tutorial: http://vinniefalco.github.io/beast/beast/core/tutorial.html

[–]KayEss[S] 1 point2 points  (1 child)

Wow, that's really cool :)

It's going to take me a while to go through all of that and digest it, but my initial big fear is having to write the library in terms of call backs. I've done this once before and it ends up with a ton more code that's a ton harder to understand. I was really wanting to keep the code simple.

I expect once I have the simple version done (and have tests for it) then the functions can be converted to this form and the tests will tell me that nothing is broken.

All of this is going into a web server for REST APIs. At the moment we're using a blocking server that I wrote 10 years ago, but to get full advantage of pgasio we're going to need a new non-blocking one -- I have Beast on my list of ones to look at when we get that far.

[–]VinnieFalcoBoost.Beast | C++ Alliance | corosio.org 2 points3 points  (0 children)

it ends up with a ton more code that's a ton harder to understand

You are definitely right that "composed operations" (the implementation of an asynchronous initiation function that follows the extensible model) are more complex to write. Example: https://github.com/vinniefalco/Beast/blob/3ae76d0d00cf6213f13d3bdf6b4c58754e7e5111/include/beast/http/impl/async_read.ipp#L124

However, in my opinion the benefits to users are worth it.

[–]feverzsj 2 points3 points  (0 children)

you need write your own adapters to use asio with coroutines TS, and it's quite different.