295 lines
30 KiB
HTML
295 lines
30 KiB
HTML
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
|
|
<html><meta http-equiv="Content-Type" content="text/html; charset=utf-8">
|
|
<title>ASIO/Networking TS: Boost >= 1.70 - Boost.Outcome documentation</title>
|
|
<link rel="stylesheet" href="../css/boost.css" type="text/css">
|
|
<meta name="generator" content="Hugo 0.52 with Boostdoc theme">
|
|
<meta name="viewport" content="width=device-width,initial-scale=1.0"/>
|
|
|
|
<link rel="icon" href="../images/favicon.ico" type="image/ico"/>
|
|
<body><div class="spirit-nav">
|
|
<a accesskey="p" href="../recipes/asio-integration.html"><img src="../images/prev.png" alt="Prev"></a>
|
|
<a accesskey="u" href="../recipes.html"><img src="../images/up.png" alt="Up"></a>
|
|
<a accesskey="h" href="../index.html"><img src="../images/home.png" alt="Home"></a><a accesskey="n" href="../recipes/foreign-try.html"><img src="../images/next.png" alt="Next"></a></div><div id="content">
|
|
<div class="titlepage"><div><div><h1 style="clear: both">ASIO/Networking TS: Boost >= 1.70</h1></div></div></div>
|
|
<div class="toc"><dl class="toc">
|
|
<dt>
|
|
<dd><dl>
|
|
<dt>
|
|
<dd><dl>
|
|
<dt><a href="#compatibility-note">Compatibility note</a></dt>
|
|
<dt><a href="#use-case">Use case</a></dt>
|
|
<dt><a href="#implementation">Implementation</a></dt>
|
|
</dl></dd></dt>
|
|
</dl></dd></dt>
|
|
</dl>
|
|
</div>
|
|
|
|
|
|
<p><em>Thanks to <a href="https://github.com/cstratopoulos">Christos Stratopoulos</a> for this Outcome recipe.</em></p>
|
|
|
|
<hr />
|
|
|
|
<h3 id="compatibility-note">Compatibility note</h3>
|
|
|
|
<p>This recipe targets Boost versions including and after 1.70, where coroutine support is
|
|
based around the <code>asio::use_awaitable</code> completion token. For integration with Boost versions
|
|
before 1.70, see <a href="asio-integration">this recipe</a>.</p>
|
|
|
|
<hr />
|
|
|
|
<h3 id="use-case">Use case</h3>
|
|
|
|
<p><a href="https://www.boost.org/doc/libs/develop/doc/html/boost_asio.html">Boost.ASIO</a>
|
|
and <a href="https://think-async.com/Asio/">standalone ASIO</a> provide the
|
|
<a href="https://www.boost.org/doc/libs/develop/doc/html/boost_asio/reference/async_result.html"><code>async_result</code></a>
|
|
customisation point for adapting arbitrary third party libraries, such as Outcome, into ASIO.</p>
|
|
|
|
<p>Historically in ASIO you need to pass completion handler instances
|
|
to the ASIO asynchronous i/o initiation functions. These get executed when the i/o
|
|
completes.</p>
|
|
|
|
<div class="code-snippet"><div class="highlight"><pre class="chroma"><code class="language-c++" data-lang="c++"> <span class="c1">// Dynamically allocate a buffer to read into. This must be move-only
|
|
</span><span class="c1"></span> <span class="c1">// so it can be attached to the completion handler, hence the unique_ptr.
|
|
</span><span class="c1"></span> <span class="k">auto</span> <span class="n">buffer</span> <span class="o">=</span> <span class="n">std</span><span class="o">::</span><span class="n">make_unique</span><span class="o"><</span><span class="n">std</span><span class="o">::</span><span class="n">vector</span><span class="o"><</span><span class="n">byte</span><span class="o">>></span><span class="p">(</span><span class="mi">1024</span><span class="p">);</span>
|
|
|
|
<span class="c1">// Begin an asynchronous socket read, upon completion invoke
|
|
</span><span class="c1"></span> <span class="c1">// the lambda function specified
|
|
</span><span class="c1"></span> <span class="n">skt</span><span class="p">.</span><span class="n">async_read_some</span><span class="p">(</span><span class="n">asio</span><span class="o">::</span><span class="n">buffer</span><span class="p">(</span><span class="n">buffer</span><span class="o">-></span><span class="n">data</span><span class="p">(),</span> <span class="n">buffer</span><span class="o">-></span><span class="n">size</span><span class="p">()),</span>
|
|
|
|
<span class="c1">// Retain lifetime of the i/o buffer until completion
|
|
</span><span class="c1"></span> <span class="p">[</span><span class="n">buffer</span> <span class="o">=</span> <span class="n">std</span><span class="o">::</span><span class="n">move</span><span class="p">(</span><span class="n">buffer</span><span class="p">)](</span><span class="k">const</span> <span class="n">error_code</span> <span class="o">&</span><span class="n">ec</span><span class="p">,</span> <span class="n">size_t</span> <span class="n">bytes</span><span class="p">)</span> <span class="p">{</span>
|
|
<span class="c1">// Handle the buffer read
|
|
</span><span class="c1"></span> <span class="k">if</span><span class="p">(</span><span class="n">ec</span><span class="p">)</span>
|
|
<span class="p">{</span>
|
|
<span class="n">std</span><span class="o">::</span><span class="n">cerr</span> <span class="o"><<</span> <span class="s">"Buffer read failed with "</span> <span class="o"><<</span> <span class="n">ec</span> <span class="o"><<</span> <span class="n">std</span><span class="o">::</span><span class="n">endl</span><span class="p">;</span>
|
|
<span class="k">return</span><span class="p">;</span>
|
|
<span class="p">}</span>
|
|
<span class="n">std</span><span class="o">::</span><span class="n">cout</span> <span class="o"><<</span> <span class="s">"Read "</span> <span class="o"><<</span> <span class="n">bytes</span> <span class="o"><<</span> <span class="s">" bytes into buffer"</span> <span class="o"><<</span> <span class="n">std</span><span class="o">::</span><span class="n">endl</span><span class="p">;</span>
|
|
|
|
<span class="c1">// buffer will be dynamically freed now
|
|
</span><span class="c1"></span> <span class="p">});</span>
|
|
</code></pre></div><a href="https://github.com/boostorg/outcome/tree/master/doc/src/snippets/boost-only/asio_integration_1_70.cpp#L48" class="code-snippet-url" target="_blank">View this code on Github</a></div>
|
|
|
|
|
|
<p>One of the big value adds of the Coroutines TS is the ability to not have to write
|
|
so much boilerplate if you have a Coroutines supporting compiler:</p>
|
|
|
|
<div class="code-snippet"><div class="highlight"><pre class="chroma"><code class="language-c++" data-lang="c++"> <span class="c1">// As coroutines suspend the calling thread whilst an asynchronous
|
|
</span><span class="c1"></span> <span class="c1">// operation executes, we can use stack allocation instead of dynamic
|
|
</span><span class="c1"></span> <span class="c1">// allocation
|
|
</span><span class="c1"></span> <span class="kt">char</span> <span class="n">buffer</span><span class="p">[</span><span class="mi">1024</span><span class="p">];</span>
|
|
|
|
<span class="c1">// Asynchronously read data, suspending this coroutine until completion,
|
|
</span><span class="c1"></span> <span class="c1">// returning the bytes of the data read into the result.
|
|
</span><span class="c1"></span> <span class="k">try</span>
|
|
<span class="p">{</span>
|
|
<span class="c1">// The use_awaitable completion token represents the current coroutine
|
|
</span><span class="c1"></span> <span class="c1">// (requires Coroutines TS)
|
|
</span><span class="c1"></span> <span class="n">size_t</span> <span class="n">bytesread</span> <span class="o">=</span> <span class="c1">//
|
|
</span><span class="c1"></span> <span class="n">co_await</span> <span class="n">skt</span><span class="p">.</span><span class="n">async_read_some</span><span class="p">(</span><span class="n">asio</span><span class="o">::</span><span class="n">buffer</span><span class="p">(</span><span class="n">buffer</span><span class="p">),</span> <span class="n">asio</span><span class="o">::</span><span class="n">use_awaitable</span><span class="p">);</span>
|
|
<span class="n">std</span><span class="o">::</span><span class="n">cout</span> <span class="o"><<</span> <span class="s">"Read "</span> <span class="o"><<</span> <span class="n">bytesread</span> <span class="o"><<</span> <span class="s">" bytes into buffer"</span> <span class="o"><<</span> <span class="n">std</span><span class="o">::</span><span class="n">endl</span><span class="p">;</span>
|
|
<span class="p">}</span>
|
|
<span class="k">catch</span><span class="p">(</span><span class="k">const</span> <span class="n">std</span><span class="o">::</span><span class="n">system_error</span> <span class="o">&</span><span class="n">e</span><span class="p">)</span>
|
|
<span class="p">{</span>
|
|
<span class="n">std</span><span class="o">::</span><span class="n">cerr</span> <span class="o"><<</span> <span class="s">"Buffer read failed with "</span> <span class="o"><<</span> <span class="n">e</span><span class="p">.</span><span class="n">what</span><span class="p">()</span> <span class="o"><<</span> <span class="n">std</span><span class="o">::</span><span class="n">endl</span><span class="p">;</span>
|
|
<span class="p">}</span>
|
|
</code></pre></div><a href="https://github.com/boostorg/outcome/tree/master/doc/src/snippets/boost-only/asio_integration_1_70.cpp#L74" class="code-snippet-url" target="_blank">View this code on Github</a></div>
|
|
|
|
|
|
<p>The default ASIO implementation always throws exceptions on failure through
|
|
its coroutine token transformation. The <a href="https://www.boost.org/doc/libs/develop/doc/html/boost_asio/reference/experimental__redirect_error.html"><code>redirect_error</code></a>
|
|
token transformation recovers the option to use the <code>error_code</code> interface,
|
|
but it suffers from the <a href="../motivation/error_codes.html">same drawbacks</a>
|
|
that make pure error codes unappealing in the synchronous case.</p>
|
|
|
|
<p>This recipe fixes that by making it possible for coroutinised
|
|
i/o in ASIO to return a <code>result<T></code>:</p>
|
|
|
|
<div class="code-snippet"><div class="highlight"><pre class="chroma"><code class="language-c++" data-lang="c++"> <span class="c1">// Asynchronously read data, suspending this coroutine until completion,
|
|
</span><span class="c1"></span> <span class="c1">// returning the bytes of the data read into the result, or any failure.
|
|
</span><span class="c1"></span> <span class="n">outcome</span><span class="o">::</span><span class="n">result</span><span class="o"><</span><span class="n">size_t</span><span class="p">,</span> <span class="n">error_code</span><span class="o">></span> <span class="n">bytesread</span> <span class="o">=</span> <span class="c1">//
|
|
</span><span class="c1"></span> <span class="n">co_await</span> <span class="n">skt</span><span class="p">.</span><span class="n">async_read_some</span><span class="p">(</span><span class="n">asio</span><span class="o">::</span><span class="n">buffer</span><span class="p">(</span><span class="n">buffer</span><span class="p">),</span> <span class="n">as_result</span><span class="p">(</span><span class="n">asio</span><span class="o">::</span><span class="n">use_awaitable</span><span class="p">));</span>
|
|
|
|
<span class="c1">// Usage is exactly like ordinary Outcome. Note the lack of exception throw!
|
|
</span><span class="c1"></span> <span class="k">if</span><span class="p">(</span><span class="n">bytesread</span><span class="p">.</span><span class="n">has_error</span><span class="p">())</span>
|
|
<span class="p">{</span>
|
|
<span class="n">std</span><span class="o">::</span><span class="n">cerr</span> <span class="o"><<</span> <span class="s">"Buffer read failed with "</span> <span class="o"><<</span> <span class="n">bytesread</span><span class="p">.</span><span class="n">error</span><span class="p">()</span> <span class="o"><<</span> <span class="n">std</span><span class="o">::</span><span class="n">endl</span><span class="p">;</span>
|
|
<span class="k">return</span><span class="p">;</span>
|
|
<span class="p">}</span>
|
|
<span class="n">std</span><span class="o">::</span><span class="n">cout</span> <span class="o"><<</span> <span class="s">"Read "</span> <span class="o"><<</span> <span class="n">bytesread</span><span class="p">.</span><span class="n">value</span><span class="p">()</span> <span class="o"><<</span> <span class="s">" bytes into buffer"</span> <span class="o"><<</span> <span class="n">std</span><span class="o">::</span><span class="n">endl</span><span class="p">;</span>
|
|
</code></pre></div><a href="https://github.com/boostorg/outcome/tree/master/doc/src/snippets/boost-only/asio_integration_1_70.cpp#L208" class="code-snippet-url" target="_blank">View this code on Github</a></div>
|
|
|
|
|
|
<hr />
|
|
|
|
<h3 id="implementation">Implementation</h3>
|
|
|
|
<div class="notices warning" style="background: url('../images/warning.png') top left no-repeat padding-box padding-box;">
|
|
<div class="notices heading">warning</div>
|
|
<div class="notices message"><p>The below involves a lot of ASIO voodoo. <strong>NO SUPPORT WILL BE GIVEN HERE FOR THE ASIO
|
|
CODE BELOW</strong>. Please raise any questions or problems that you have with how to implement
|
|
this sort of stuff in ASIO
|
|
on <a href="https://stackoverflow.com/questions/tagged/boost-asio">Stackoverflow #boost-asio</a>.</p>
|
|
</div>
|
|
</div>
|
|
|
|
|
|
<p>The real world, production-level recipe can be found at the bottom of this page.
|
|
You ought to use that in any real world use case.</p>
|
|
|
|
<p>It is however worth providing a walkthrough of a simplified edition of the real world
|
|
recipe, as a lot of barely documented ASIO voodoo is involved. You should not
|
|
use the code presented next in your own code, it is too simplified. But it should
|
|
help you understand how the real implementation works.</p>
|
|
|
|
<p>Firstly we need to define some helper type sugar and a factory function for wrapping
|
|
any arbitrary third party completion token with that type sugar:</p>
|
|
|
|
<div class="code-snippet"><div class="highlight"><pre class="chroma"><code class="language-c++" data-lang="c++"><span class="k">namespace</span> <span class="n">detail</span>
|
|
<span class="p">{</span>
|
|
<span class="c1">// Type sugar for wrapping an external completion token
|
|
</span><span class="c1"></span> <span class="k">template</span> <span class="o"><</span><span class="k">class</span><span class="err"> </span><span class="nc">CompletionToken</span><span class="o">></span> <span class="k">struct</span> <span class="n">as_result_t</span>
|
|
<span class="p">{</span>
|
|
<span class="n">CompletionToken</span> <span class="n">token</span><span class="p">;</span>
|
|
<span class="p">};</span>
|
|
<span class="p">}</span> <span class="c1">// namespace detail
|
|
</span><span class="c1"></span>
|
|
<span class="c1">// Factory function for wrapping a third party completion token with
|
|
</span><span class="c1">// our type sugar
|
|
</span><span class="c1"></span><span class="k">template</span> <span class="o"><</span><span class="k">class</span><span class="err"> </span><span class="nc">CompletionToken</span><span class="o">></span> <span class="c1">//
|
|
</span><span class="c1"></span><span class="kr">inline</span> <span class="k">auto</span> <span class="n">as_result</span><span class="p">(</span><span class="n">CompletionToken</span> <span class="o">&&</span><span class="n">token</span><span class="p">)</span>
|
|
<span class="p">{</span>
|
|
<span class="k">return</span> <span class="n">detail</span><span class="o">::</span><span class="n">as_result_t</span><span class="o"><</span><span class="n">std</span><span class="o">::</span><span class="n">decay_t</span><span class="o"><</span><span class="n">CompletionToken</span><span class="o">>></span><span class="p">{</span><span class="n">std</span><span class="o">::</span><span class="n">forward</span><span class="o"><</span><span class="n">CompletionToken</span><span class="o">></span><span class="p">(</span><span class="n">token</span><span class="p">)};</span>
|
|
<span class="p">};</span>
|
|
</code></pre></div><a href="https://github.com/boostorg/outcome/tree/master/doc/src/snippets/boost-only/asio_integration_1_70.cpp#L97" class="code-snippet-url" target="_blank">View this code on Github</a></div>
|
|
|
|
|
|
<p>Next we tell ASIO about a new completion token it ought to recognise by specialising
|
|
<a href="https://www.boost.org/doc/libs/develop/doc/html/boost_asio/reference/async_result.html"><code>async_result</code></a>:</p>
|
|
|
|
<div class="code-snippet"><div class="highlight"><pre class="chroma"><code class="language-c++" data-lang="c++"><span class="c1">// Tell ASIO about a new kind of completion token, the kind returned
|
|
</span><span class="c1">// from our as_result() factory function. This implementation is
|
|
</span><span class="c1">// for functions with handlers void(error_code, T) only.
|
|
</span><span class="c1"></span><span class="k">template</span> <span class="o"><</span><span class="k">class</span><span class="err"> </span><span class="nc">CompletionToken</span><span class="p">,</span> <span class="k">class</span><span class="err"> </span><span class="nc">T</span><span class="o">></span> <span class="c1">//
|
|
</span><span class="c1"></span><span class="k">struct</span> <span class="n">asio</span><span class="o">::</span><span class="n">async_result</span><span class="o"><</span><span class="n">detail</span><span class="o">::</span><span class="n">as_result_t</span><span class="o"><</span><span class="n">CompletionToken</span><span class="o">></span><span class="p">,</span> <span class="c1">//
|
|
</span><span class="c1"></span> <span class="kt">void</span><span class="p">(</span><span class="n">error_code</span><span class="p">,</span> <span class="n">T</span><span class="p">)</span><span class="o">></span> <span class="c1">//
|
|
</span><span class="c1"></span>
|
|
<span class="p">{</span>
|
|
<span class="c1">// The result type we shall return
|
|
</span><span class="c1"></span> <span class="k">using</span> <span class="n">result_type</span> <span class="o">=</span> <span class="n">outcome</span><span class="o">::</span><span class="n">result</span><span class="o"><</span><span class="n">T</span><span class="p">,</span> <span class="n">error_code</span><span class="o">></span><span class="p">;</span>
|
|
<span class="c1">// The awaitable type to be returned by the initiating function,
|
|
</span><span class="c1"></span> <span class="c1">// the co_await of which will yield a result_type
|
|
</span><span class="c1"></span> <span class="k">using</span> <span class="n">return_type</span> <span class="o">=</span> <span class="c1">//
|
|
</span><span class="c1"></span> <span class="k">typename</span> <span class="n">asio</span><span class="o">::</span><span class="n">async_result</span><span class="o"><</span><span class="n">CompletionToken</span><span class="p">,</span> <span class="kt">void</span><span class="p">(</span><span class="n">result_type</span><span class="p">)</span><span class="o">></span> <span class="c1">//
|
|
</span><span class="c1"></span> <span class="o">::</span><span class="n">return_type</span><span class="p">;</span>
|
|
</code></pre></div><a href="https://github.com/boostorg/outcome/tree/master/doc/src/snippets/boost-only/asio_integration_1_70.cpp#L116" class="code-snippet-url" target="_blank">View this code on Github</a></div>
|
|
|
|
|
|
<p>There are a couple tricky parts to understand. First of all, we want our
|
|
<code>async_result</code> specialization to work, in particular, with the <code>async_result</code> for
|
|
ASIO’s
|
|
<a href="https://www.boost.org/doc/libs/develop/doc/html/boost_asio/reference/use_awaitable_t.html"><code>use_awaitable_t</code> completion token</a>.
|
|
With this token, the <code>async_result</code> specialization takes the form with a static
|
|
<code>initiate</code> method which defers initiation of the asynchronous operation until,
|
|
for example,
|
|
<code>co_await</code> is called on the returned <code>awaitable</code>. Thus, our <code>async_result</code>
|
|
specialization will take the same form. With this in mind, we need only
|
|
understand how our specialization will implement its <code>initiate</code> method. The trick
|
|
is that it will pass the initiation work off to an <code>async_result</code> for the
|
|
supplied completion token type with a completion handler which consumes <code>result<T></code>.
|
|
Our <code>async_result</code> is thus just a simple wrapper over this underlying
|
|
<code>async_result</code>, but we inject a completion handler with the
|
|
<code>void(error_code, size_t)</code> signature which constructs from that a <code>result</code>:</p>
|
|
|
|
<div class="code-snippet"><div class="highlight"><pre class="chroma"><code class="language-c++" data-lang="c++"> <span class="c1">// Wrap a completion handler with void(error_code, T) converting
|
|
</span><span class="c1"></span> <span class="c1">// handler
|
|
</span><span class="c1"></span> <span class="k">template</span> <span class="o"><</span><span class="k">class</span><span class="err"> </span><span class="nc">Handler</span><span class="o">></span>
|
|
<span class="k">struct</span> <span class="n">completion_handler</span> <span class="p">{</span>
|
|
<span class="c1">// Our completion handler spec
|
|
</span><span class="c1"></span> <span class="kt">void</span> <span class="k">operator</span><span class="p">()(</span><span class="n">error_code</span> <span class="n">ec</span><span class="p">,</span> <span class="n">T</span> <span class="n">v</span><span class="p">)</span>
|
|
<span class="p">{</span>
|
|
<span class="c1">// Call the underlying completion handler, whose
|
|
</span><span class="c1"></span> <span class="c1">// completion function is void(result_type)
|
|
</span><span class="c1"></span> <span class="k">if</span><span class="p">(</span><span class="n">ec</span><span class="p">)</span>
|
|
<span class="p">{</span>
|
|
<span class="c1">// Complete with a failed result
|
|
</span><span class="c1"></span> <span class="n">_handler</span><span class="p">(</span><span class="n">result_type</span><span class="p">(</span><span class="n">outcome</span><span class="o">::</span><span class="n">failure</span><span class="p">(</span><span class="n">ec</span><span class="p">)));</span>
|
|
<span class="k">return</span><span class="p">;</span>
|
|
<span class="p">}</span>
|
|
<span class="c1">// Complete with a successful result
|
|
</span><span class="c1"></span> <span class="n">_handler</span><span class="p">(</span><span class="n">result_type</span><span class="p">(</span><span class="n">outcome</span><span class="o">::</span><span class="n">success</span><span class="p">(</span><span class="n">v</span><span class="p">)));</span>
|
|
<span class="p">}</span>
|
|
|
|
<span class="n">Handler</span> <span class="n">_handler</span><span class="p">;</span>
|
|
<span class="p">};</span>
|
|
|
|
<span class="c1">// NOTE the initiate member function initiates the async operation,
|
|
</span><span class="c1"></span> <span class="c1">// and we want to defer to what would be the initiation of the
|
|
</span><span class="c1"></span> <span class="c1">// async_result whose handler signature is void(result_type).
|
|
</span><span class="c1"></span> <span class="k">template</span> <span class="o"><</span><span class="k">class</span><span class="err"> </span><span class="nc">Initiation</span><span class="p">,</span> <span class="k">class</span><span class="err">... </span><span class="nc">Args</span><span class="o">></span>
|
|
<span class="k">static</span> <span class="n">return_type</span>
|
|
<span class="n">initiate</span><span class="p">(</span>
|
|
<span class="n">Initiation</span><span class="o">&&</span> <span class="n">init</span><span class="p">,</span>
|
|
<span class="n">detail</span><span class="o">::</span><span class="n">as_result_t</span><span class="o"><</span><span class="n">CompletionToken</span><span class="o">>&&</span> <span class="n">token</span><span class="p">,</span>
|
|
<span class="n">Args</span><span class="o">&&</span><span class="p">...</span> <span class="n">args</span><span class="p">)</span>
|
|
<span class="p">{</span>
|
|
<span class="c1">// The async_initiate<CompletionToken, void(result_type)> helper
|
|
</span><span class="c1"></span> <span class="c1">// function will invoke the async initiation method of the
|
|
</span><span class="c1"></span> <span class="c1">// async_result<CompletionToken, void(result_type)>, as desired.
|
|
</span><span class="c1"></span> <span class="c1">// Instead of CompletionToken and void(result_type) we start with
|
|
</span><span class="c1"></span> <span class="c1">// detail::as_result_t<CompletionToken> and void(ec, T), so
|
|
</span><span class="c1"></span> <span class="c1">// the inputs need to be massaged then passed along.
|
|
</span><span class="c1"></span> <span class="k">return</span> <span class="n">asio</span><span class="o">::</span><span class="n">async_initiate</span><span class="o"><</span><span class="n">CompletionToken</span><span class="p">,</span> <span class="kt">void</span><span class="p">(</span><span class="n">result_type</span><span class="p">)</span><span class="o">></span><span class="p">(</span>
|
|
<span class="c1">// create a new initiation which wraps the provided init
|
|
</span><span class="c1"></span> <span class="p">[</span><span class="n">init</span> <span class="o">=</span> <span class="n">std</span><span class="o">::</span><span class="n">forward</span><span class="o"><</span><span class="n">Initiation</span><span class="o">></span><span class="p">(</span><span class="n">init</span><span class="p">)](</span>
|
|
<span class="k">auto</span><span class="o">&&</span> <span class="n">handler</span><span class="p">,</span> <span class="k">auto</span><span class="o">&&</span><span class="p">...</span> <span class="n">initArgs</span><span class="p">)</span> <span class="k">mutable</span> <span class="p">{</span>
|
|
<span class="n">std</span><span class="o">::</span><span class="n">move</span><span class="p">(</span><span class="n">init</span><span class="p">)(</span>
|
|
<span class="c1">// we wrap the handler in the converting completion_handler from
|
|
</span><span class="c1"></span> <span class="c1">// above, and pass along the args
|
|
</span><span class="c1"></span> <span class="n">completion_handler</span><span class="o"><</span><span class="n">std</span><span class="o">::</span><span class="n">decay_t</span><span class="o"><</span><span class="k">decltype</span><span class="p">(</span><span class="n">handler</span><span class="p">)</span><span class="o">>></span><span class="p">{</span>
|
|
<span class="n">std</span><span class="o">::</span><span class="n">forward</span><span class="o"><</span><span class="k">decltype</span><span class="p">(</span><span class="n">handler</span><span class="p">)</span><span class="o">></span><span class="p">(</span><span class="n">handler</span><span class="p">)},</span>
|
|
<span class="n">std</span><span class="o">::</span><span class="n">forward</span><span class="o"><</span><span class="k">decltype</span><span class="p">(</span><span class="n">initArgs</span><span class="p">)</span><span class="o">></span><span class="p">(</span><span class="n">initArgs</span><span class="p">)...);</span>
|
|
<span class="p">},</span>
|
|
<span class="c1">// the new initiation is called with the handler unwrapped from
|
|
</span><span class="c1"></span> <span class="c1">// the token, and the original initiation arguments.
|
|
</span><span class="c1"></span> <span class="n">token</span><span class="p">.</span><span class="n">token</span><span class="p">,</span>
|
|
<span class="n">std</span><span class="o">::</span><span class="n">forward</span><span class="o"><</span><span class="n">Args</span><span class="o">></span><span class="p">(</span><span class="n">args</span><span class="p">)...);</span>
|
|
<span class="p">}</span>
|
|
<span class="p">};</span>
|
|
</code></pre></div><a href="https://github.com/boostorg/outcome/tree/master/doc/src/snippets/boost-only/asio_integration_1_70.cpp#L134" class="code-snippet-url" target="_blank">View this code on Github</a></div>
|
|
|
|
|
|
<p>To use, simply wrap the third party completion token with <code>as_result</code> to cause
|
|
ASIO to return from <code>co_await</code> a <code>result</code> instead of throwing exceptions on
|
|
failure:</p>
|
|
<div class="highlight"><pre class="chroma"><code class="language-c++" data-lang="c++"><span class="kt">char</span> <span class="n">buffer</span><span class="p">[</span><span class="mi">1024</span><span class="p">];</span>
|
|
|
|
<span class="n">outcome</span><span class="o">::</span><span class="n">result</span><span class="o"><</span><span class="n">size_t</span><span class="p">,</span> <span class="n">error_code</span><span class="o">></span> <span class="n">bytesread</span> <span class="o">=</span>
|
|
<span class="n">co_await</span> <span class="n">skt</span><span class="p">.</span><span class="n">async_read_some</span><span class="p">(</span><span class="n">asio</span><span class="o">::</span><span class="n">buffer</span><span class="p">(</span><span class="n">buffer</span><span class="p">),</span> <span class="n">as_result</span><span class="p">(</span><span class="n">asio</span><span class="o">::</span><span class="n">use_awaitable</span><span class="p">));</span>
|
|
</code></pre></div>
|
|
<p>The real world production-level implementation below is a lot more complex than the
|
|
above which has been deliberately simplified to aid exposition. The above
|
|
should help you get up and running with the below, eventually.</p>
|
|
|
|
<p>One again I would like to remind you that Outcome is not the appropriate place
|
|
to seek help with ASIO voodoo. Please ask on
|
|
<a href="https://stackoverflow.com/questions/tagged/boost-asio">Stackoverflow #boost-asio</a>.</p>
|
|
|
|
<hr />
|
|
|
|
<p>Here follows the real world, production-level adapation of Outcome into
|
|
ASIO, written and maintained by <a href="https://github.com/cstratopoulos">Christos Stratopoulos</a>.
|
|
If the following does not load due to Javascript being disabled, you can visit the gist at
|
|
<a href="https://gist.github.com/cstratopoulos/901b5cdd41d07c6ce6d83798b09ecf9b/863c1dbf3b063a5ff9ff2bdd834242ead556e74e">https://gist.github.com/cstratopoulos/901b5cdd41d07c6ce6d83798b09ecf9b/863c1dbf3b063a5ff9ff2bdd834242ead556e74e</a>.</p>
|
|
|
|
<script type="application/javascript" src="//gist.github.com/cstratopoulos/901b5cdd41d07c6ce6d83798b09ecf9b/863c1dbf3b063a5ff9ff2bdd834242ead556e74e.js"></script>
|
|
|
|
|
|
</div><p><small>Last revised: August 06, 2019 at 10:42:06 +0100</small></p>
|
|
<hr>
|
|
<div class="spirit-nav">
|
|
<a accesskey="p" href="../recipes/asio-integration.html"><img src="../images/prev.png" alt="Prev"></a>
|
|
<a accesskey="u" href="../recipes.html"><img src="../images/up.png" alt="Up"></a>
|
|
<a accesskey="h" href="../index.html"><img src="../images/home.png" alt="Home"></a><a accesskey="n" href="../recipes/foreign-try.html"><img src="../images/next.png" alt="Next"></a></div></body>
|
|
</html>
|