| 37 | // The initiating function for the asynchronous operation. |
| 38 | template <boost::asio::completion_token_for<void(std::string)> CompletionToken> |
| 39 | auto async_read_input(const std::string& prompt, CompletionToken&& token) |
| 40 | { |
| 41 | // Define a function object that contains the code to launch the asynchronous |
| 42 | // operation. This is passed the concrete completion handler, followed by any |
| 43 | // additional arguments that were passed through the call to async_initiate. |
| 44 | auto init = []( |
| 45 | boost::asio::completion_handler_for<void(std::string)> auto handler, |
| 46 | const std::string& prompt) |
| 47 | { |
| 48 | // According to the rules for asynchronous operations, we need to track |
| 49 | // outstanding work against the handler's associated executor until the |
| 50 | // asynchronous operation is complete. |
| 51 | auto work = boost::asio::make_work_guard(handler); |
| 52 | |
| 53 | // Launch the operation with a callback that will receive the result and |
| 54 | // pass it through to the asynchronous operation's completion handler. |
| 55 | read_input(prompt, |
| 56 | [ |
| 57 | handler = std::move(handler), |
| 58 | work = std::move(work) |
| 59 | ](std::string result) mutable |
| 60 | { |
| 61 | // Get the handler's associated allocator. If the handler does not |
| 62 | // specify an allocator, use the recycling allocator as the default. |
| 63 | auto alloc = boost::asio::get_associated_allocator( |
| 64 | handler, boost::asio::recycling_allocator<void>()); |
| 65 | |
| 66 | // Dispatch the completion handler through the handler's associated |
| 67 | // executor, using the handler's associated allocator. |
| 68 | boost::asio::dispatch(work.get_executor(), |
| 69 | boost::asio::bind_allocator(alloc, |
| 70 | [ |
| 71 | handler = std::move(handler), |
| 72 | result = std::string(result) |
| 73 | ]() mutable |
| 74 | { |
| 75 | std::move(handler)(result); |
| 76 | })); |
| 77 | }); |
| 78 | }; |
| 79 | |
| 80 | // The async_initiate function is used to transform the supplied completion |
| 81 | // token to the completion handler. When calling this function we explicitly |
| 82 | // specify the completion signature of the operation. We must also return the |
| 83 | // result of the call since the completion token may produce a return value, |
| 84 | // such as a future. |
| 85 | return boost::asio::async_initiate<CompletionToken, void(std::string)>( |
| 86 | init, // First, pass the function object that launches the operation, |
| 87 | token, // then the completion token that will be transformed to a handler, |
| 88 | prompt); // and, finally, any additional arguments to the function object. |
| 89 | } |
| 90 | |
| 91 | //------------------------------------------------------------------------------ |
| 92 | |