• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1+++
2title = "ASIO/Networking TS : Boost < 1.70"
3description = "How to teach ASIO/Networking TS about Outcome."
4tags = [ "asio", "networking-ts" ]
5+++
6
7*Thanks to [Christos Stratopoulos](https://github.com/cstratopoulos) for this Outcome recipe.*
8
9---
10
11### Compatibility note
12
13This recipe targets Boost versions before 1.70, where coroutine support is based around
14the `asio::experimental::this_coro::token` completion token. For integration with Boost
15versions 1.70 and onward, see [this recipe](asio-integration-1-70).
16
17
18---
19
20### Use case
21
22[Boost.ASIO](https://www.boost.org/doc/libs/develop/doc/html/boost_asio.html)
23and [standalone ASIO](https://think-async.com/Asio/) provide the
24[`async_result`](https://www.boost.org/doc/libs/develop/doc/html/boost_asio/reference/async_result.html)
25customisation point for adapting arbitrary third party libraries, such as Outcome, into ASIO.
26
27Historically in ASIO you need to pass completion handler instances
28to the ASIO asynchronous i/o initiation functions. These get executed when the i/o
29completes.
30
31{{% snippet "boost-only/asio_integration.cpp" "old-use-case" %}}
32
33One of the big value adds of the Coroutines TS is the ability to not have to write
34so much boilerplate if you have a Coroutines supporting compiler:
35
36{{% snippet "boost-only/asio_integration.cpp" "new-use-case" %}}
37
38The default ASIO implementation always throws exceptions on failure through
39its coroutine token transformation. The [`redirect_error`](https://www.boost.org/doc/libs/develop/doc/html/boost_asio/reference/experimental__redirect_error.html)
40token transformation recovers the option to use the `error_code` interface,
41but it suffers from the [same drawbacks]({{< relref "/motivation/error_codes" >}})
42that make pure error codes unappealing in the synchronous case.
43
44This recipe fixes that by making it possible for coroutinised
45i/o in ASIO to return a `result<T>`:
46
47{{% snippet "boost-only/asio_integration.cpp" "outcome-use-case" %}}
48
49---
50
51### Implementation
52
53{{% notice warning %}}
54The below involves a lot of ASIO voodoo. **NO SUPPORT WILL BE GIVEN HERE FOR THE ASIO
55CODE BELOW**. Please raise any questions or problems that you have with how to implement
56this sort of stuff in ASIO
57on [Stackoverflow #boost-asio](https://stackoverflow.com/questions/tagged/boost-asio).
58{{% /notice %}}
59
60The real world, production-level recipe can be found at the bottom of this page.
61You ought to use that in any real world use case.
62
63It is however worth providing a walkthrough of a simplified edition of the real world
64recipe, as a lot of barely documented ASIO voodoo is involved. You should not
65use the code presented next in your own code, it is too simplified. But it should
66help you understand how the real implementation works.
67
68Firstly we need to define some helper type sugar and a factory function for wrapping
69any arbitrary third party completion token with that type sugar:
70
71{{% snippet "boost-only/asio_integration.cpp" "as_result" %}}
72
73Next we tell ASIO about a new completion token it ought to recognise by specialising
74[`async_result`](https://www.boost.org/doc/libs/develop/doc/html/boost_asio/reference/async_result.html):
75
76{{% snippet "boost-only/asio_integration.cpp" "async_result1" %}}
77
78The tricky part to understand is that our `async_result` specialisation inherits
79from an `async_result` for the supplied completion token type with a completion
80handler which consumes a `result<T>`. Our `async_result` is actually therefore
81the base `async_result`, but we layer on top a `completion_handler_type` with
82the `void(error_code, size_t)` signature which constructs from that a `result`:
83
84{{% snippet "boost-only/asio_integration.cpp" "async_result2" %}}
85
86To use, simply wrap the third party completion token with `as_result` to cause
87ASIO to return from `co_await` a `result` instead of throwing exceptions on
88failure:
89
90```c++
91char buffer[1024];
92asio::experimental::await_token token =
93  co_await asio::experimental::this_coro::token();
94
95outcome::result<size_t, error_code> bytesread =
96  co_await skt.async_read_some(asio::buffer(buffer), as_result(token));
97```
98
99The real world production-level implementation below is a lot more complex than the
100above which has been deliberately simplified to aid exposition. The above
101should help you get up and running with the below, eventually.
102
103One again I would like to remind you that Outcome is not the appropriate place
104to seek help with ASIO voodoo. Please ask on
105[Stackoverflow #boost-asio](https://stackoverflow.com/questions/tagged/boost-asio).
106
107---
108
109Here follows the real world, production-level adapation of Outcome into
110ASIO, written and maintained by [Christos Stratopoulos](https://github.com/cstratopoulos).
111If the following does not load due to Javascript being disabled, you can visit the gist at
112https://gist.github.com/cstratopoulos/901b5cdd41d07c6ce6d83798b09ecf9b/da584844f58353915dc2600fba959813f793b456.
113
114{{% gist "cstratopoulos" "901b5cdd41d07c6ce6d83798b09ecf9b/da584844f58353915dc2600fba959813f793b456" %}}
115