mirror of
https://github.com/boostorg/outcome.git
synced 2026-02-18 14:22:08 +00:00
133 lines
14 KiB
XML
133 lines
14 KiB
XML
<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
|
|
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
|
|
<channel>
|
|
<title>Interoperation on Boost.Outcome documentation</title>
|
|
<link>https://ned14.github.io/boost-outcome/tutorial/interop/</link>
|
|
<description>Recent content in Interoperation on Boost.Outcome documentation</description>
|
|
<generator>Hugo -- gohugo.io</generator>
|
|
<lastBuildDate>Wed, 05 Dec 2018 14:18:52 +0000</lastBuildDate>
|
|
|
|
<atom:link href="https://ned14.github.io/boost-outcome/tutorial/interop/index.xml" rel="self" type="application/rss+xml" />
|
|
|
|
|
|
<item>
|
|
<title>Incommensurate E types</title>
|
|
<link>https://ned14.github.io/boost-outcome/tutorial/interop/problem/</link>
|
|
<pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
|
|
|
|
<guid>https://ned14.github.io/boost-outcome/tutorial/interop/problem/</guid>
|
|
<description>Back in the tutorial section on Default Actions, we studied a likely very common initial choice of E type: a strongly typed enum. We saw how by marking up strongly typed enums to tell the C++ standard library what they are, they gain implicit convertibility into std::error_code, and we then pointed out that you might as well now set E = std::error_code as that comes with the enormous advantage that you can use the boilerplate saving BOOST_OUTCOME_TRY macro when the E type is always the same.</description>
|
|
</item>
|
|
|
|
<item>
|
|
<title>ValueOrError Concept</title>
|
|
<link>https://ned14.github.io/boost-outcome/tutorial/interop/value-or-error/</link>
|
|
<pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
|
|
|
|
<guid>https://ned14.github.io/boost-outcome/tutorial/interop/value-or-error/</guid>
|
|
<description>Something not really mentioned until now is how Outcome interoperates with the proposed std::expected&lt;T, E&gt;, whose design lands in between outcome::unchecked&lt;T, E&gt; and outcome::checked&lt;T, E&gt;, both of which are simplified aliases for outcome::result&lt;T, E&gt; hard coding the NoValuePolicy to a fixed policy.
|
|
Expected and Outcome are isomorphic to one another in design intent, but interoperation for code using Expected and Outcome ought to be seamless thanks to the proposed ValueOrError concept framework, a subset of which Outcome implements.</description>
|
|
</item>
|
|
|
|
<item>
|
|
<title>The HTTP library</title>
|
|
<link>https://ned14.github.io/boost-outcome/tutorial/interop/httplib/</link>
|
|
<pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
|
|
|
|
<guid>https://ned14.github.io/boost-outcome/tutorial/interop/httplib/</guid>
|
|
<description>Let us imagine a simple application: it fetches a HTTP page using a HTTP library, sends it through HTML tidy via the htmltidy library, and then writes it to disc using a filelib library. So three third party libraries, two using Outcome in incompatible ways, and the third being a C library just for kicks.
|
|
Let us imagine that the HTTP library has the following public interface:
|
|
// This is some standalone library implementing high level HTTP namespace httplib { // These are the error code that this HTTP library can return enum classstatus_code { success = 0, // not the HTTP success code of 200 // A subset of all HTTP status codes for brevity bad_request = 400, access_denied = 401, logon_failed = 402, forbidden = 403, not_found = 404, internal_error = 500 }; // This is the error type that this HTTP library can return struct failure { status_code status{status_code::success}; std::string url{}; // The failing URL }; // Localise a result implementation to this library template &lt;classT&gt; using result = BOOST_OUTCOME_V2_NAMESPACE::result&lt;T, failure&gt;; /* Performs a HTTP GET on the url, returning the body if successful, a failure with status_code if unsuccessful at the HTTP level, or a C++ exception throw if something catastrophic happened e.</description>
|
|
</item>
|
|
|
|
<item>
|
|
<title>The HTMLTidy library</title>
|
|
<link>https://ned14.github.io/boost-outcome/tutorial/interop/tidylib/</link>
|
|
<pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
|
|
|
|
<guid>https://ned14.github.io/boost-outcome/tutorial/interop/tidylib/</guid>
|
|
<description>// There actually is a library for tidying HTML into XHTML called HTMLTidy // See http://www.html-tidy.org/ // HTMLTidy is actually a great tool, I highly recommend it. // This isn&#39;t the API for Tidy, but let&#39;s assume it&#39;s a C library returning // errno domained error codes. out must be freed with free() after use. extern &#34;C&#34; int tidy_html(char **out, size_t *outlen, const char *in, size_t inlen); View this code on Github A C API may not initially appear to be a T|E based API, but if failure returns some domained error code and causes no other effects, and success returns some value, then it is effectively a &ldquo;split&rdquo; T|E API.</description>
|
|
</item>
|
|
|
|
<item>
|
|
<title>The File I/O library</title>
|
|
<link>https://ned14.github.io/boost-outcome/tutorial/interop/filelib/</link>
|
|
<pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
|
|
|
|
<guid>https://ned14.github.io/boost-outcome/tutorial/interop/filelib/</guid>
|
|
<description>The File I/O library we shall be using is very similar to the one we saw earlier in this tutorial:
|
|
// You may remember this from the tutorial section on Custom Payloads namespace filelib { // Error code + paths related to a failure. Also causes ADL discovery to check this namespace. struct failure_info { std::error_code ec; path path1{}, path2{}; }; // Tell Outcome that failure_info is to be treated as a std::error_code inline const std::error_code &amp;make_error_code(const failure_info &amp;fi) { return fi.</description>
|
|
</item>
|
|
|
|
<item>
|
|
<title>The Application</title>
|
|
<link>https://ned14.github.io/boost-outcome/tutorial/interop/app/</link>
|
|
<pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
|
|
|
|
<guid>https://ned14.github.io/boost-outcome/tutorial/interop/app/</guid>
|
|
<description>The application is of course also based on Outcome, and like the HTTP library is also of mixed-failure design in that failure can be returned via error code, type erased exception_ptr or indeed a C++ exception throw.
|
|
// This is the namespace of the application which is connecting together the httplib, // filelib and tidylib libraries into a solution. namespace app { // Create an ADL bridge so copy/move hooks will be searched for in this namespace struct error_code : public std::error_code { // passthrough using std::error_code::error_code; error_code() = default; error_code(std::error_code ec) : std::error_code(ec) { } }; // Localise an outcome implementation for this namespace template &lt;classT&gt; using outcome = BOOST_OUTCOME_V2_NAMESPACE::outcome&lt;T, error_code /*, std::exception_ptr */&gt;; using BOOST_OUTCOME_V2_NAMESPACE::success; } View this code on Github Here we localise a passthrough error_code solely for the purpose of ADL bridging, otherwise the localised outcome configured is the default one which comes with Outcome.</description>
|
|
</item>
|
|
|
|
<item>
|
|
<title>Mapping the HTTP library into the Application 1/2</title>
|
|
<link>https://ned14.github.io/boost-outcome/tutorial/interop/app-map-httplib1/</link>
|
|
<pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
|
|
|
|
<guid>https://ned14.github.io/boost-outcome/tutorial/interop/app-map-httplib1/</guid>
|
|
<description>Firstly we are going to need to wrap up httplib::failure into a custom STL exception type before we can type erase it into an exception_ptr instance. Please note that this code is defined in the app namespace:
|
|
namespace app { // Specialise an exception type for httplib errors struct httplib_error : std::runtime_error { // passthrough using std::runtime_error::runtime_error; httplib_error(httplib::failure _failure, std::string msg) : std::runtime_error(std::move(msg)) , failure(std::move(_failure)) { } // the original failure httplib::failure failure; }; // Type erase httplib::result&lt;U&gt; into a httplib_error exception ptr template &lt;classU&gt; inline std::exception_ptr make_httplib_exception(const httplib::result&lt;U&gt; &amp;src) { std::string str(&#34;httplib failed with error &#34;); switch(src.</description>
|
|
</item>
|
|
|
|
<item>
|
|
<title>Mapping the HTTP library into the Application 2/2</title>
|
|
<link>https://ned14.github.io/boost-outcome/tutorial/interop/app-map-httplib2/</link>
|
|
<pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
|
|
|
|
<guid>https://ned14.github.io/boost-outcome/tutorial/interop/app-map-httplib2/</guid>
|
|
<description>If you remember the tutorial section on the ValueOrError Concept, this is an example of how to implement a custom ValueOrError Concept converter in Outcome:
|
|
// Inject custom ValueOrError conversion BOOST_OUTCOME_V2_NAMESPACE_BEGIN namespace convert { // Provide custom ValueOrError conversion from httplib::result&lt;U&gt; into any app::outcome&lt;T&gt; template &lt;classT, classU&gt; struct value_or_error&lt;app::outcome&lt;T&gt;, httplib::result&lt;U&gt;&gt; { // False to indicate that this converter wants `result`/`outcome` to NOT reject all other `result` static constexpr bool enable_result_inputs = true; // False to indicate that this converter wants `outcome` to NOT reject all other `outcome` static constexpr bool enable_outcome_inputs = true; template &lt;classX, // typename = std::enable_if_t&lt;std::is_same&lt;httplib::result&lt;U&gt;, std::decay_t&lt;X&gt;&gt;::value // &amp;&amp; std::is_constructible&lt;T, U&gt;::value&gt;&gt; // constexpr app::outcome&lt;T&gt; operator()(X &amp;&amp;src) { // Forward any successful value, else synthesise an exception ptr return src.</description>
|
|
</item>
|
|
|
|
<item>
|
|
<title>Mapping the File I/O library into the Application</title>
|
|
<link>https://ned14.github.io/boost-outcome/tutorial/interop/app-map-filelib/</link>
|
|
<pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
|
|
|
|
<guid>https://ned14.github.io/boost-outcome/tutorial/interop/app-map-filelib/</guid>
|
|
<description>To handle the File I/O library, once again we turn to custom ValueOrError converters:
|
|
// Inject custom ValueOrError conversion BOOST_OUTCOME_V2_NAMESPACE_BEGIN namespace convert { // Provide custom ValueOrError conversion from filelib::result&lt;U&gt; into any app::outcome&lt;T&gt; template &lt;classT, classU&gt; struct value_or_error&lt;app::outcome&lt;T&gt;, filelib::result&lt;U&gt;&gt; { // True to indicate that this converter wants `result`/`outcome` to NOT reject all other `result` static constexpr bool enable_result_inputs = true; // False to indicate that this converter wants `outcome` to NOT reject all other `outcome` static constexpr bool enable_outcome_inputs = true; template &lt;classX, // typename = std::enable_if_t&lt;std::is_same&lt;filelib::result&lt;U&gt;, std::decay_t&lt;X&gt;&gt;::value // &amp;&amp; std::is_constructible&lt;T, U&gt;::value&gt;&gt; // constexpr app::outcome&lt;T&gt; operator()(X &amp;&amp;src) { // Forward any successful value if(src.</description>
|
|
</item>
|
|
|
|
<item>
|
|
<title>Mapping the HTMLTidy library into the Application</title>
|
|
<link>https://ned14.github.io/boost-outcome/tutorial/interop/app-map-tidylib/</link>
|
|
<pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
|
|
|
|
<guid>https://ned14.github.io/boost-outcome/tutorial/interop/app-map-tidylib/</guid>
|
|
<description>Once again, we create a custom STL exception type to represent failure from the HTMLTidy library. We also create an app namespace wrapper for the C tidy_html() function which is more C++ friendly.
|
|
namespace app { // Specialise an exception type for tidylib errors struct tidylib_error : std::system_error { // passthrough using std::system_error::system_error; tidylib_error() = default; explicit tidylib_error(int c) : std::system_error(c, std::generic_category()) { } }; // Create a C++ invoking wrapper for the tidylib C API, modifying data with the returned data, // returing a unique_ptr to release storage on scope exit.</description>
|
|
</item>
|
|
|
|
<item>
|
|
<title>In use</title>
|
|
<link>https://ned14.github.io/boost-outcome/tutorial/interop/app-go/</link>
|
|
<pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
|
|
|
|
<guid>https://ned14.github.io/boost-outcome/tutorial/interop/app-go/</guid>
|
|
<description>This is how you might now write application code using these three libraries:
|
|
namespace app { outcome&lt;void&gt; go() // NOT noexcept, this can throw STL exceptions e.g. bad_alloc { // Note that explicit construction is required when converting between differing types // of outcome and result. This makes it explicit what you intend to do as conversion // may be a lot more expensive than moves. // Try to GET this URL.</description>
|
|
</item>
|
|
|
|
<item>
|
|
<title>Conclusion</title>
|
|
<link>https://ned14.github.io/boost-outcome/tutorial/interop/conclusion/</link>
|
|
<pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
|
|
|
|
<guid>https://ned14.github.io/boost-outcome/tutorial/interop/conclusion/</guid>
|
|
<description>This worked example was in fact excessively complex: a quicker route to achieving the same thing would be to add explicit converting constructors to app::error_code for each of the third party library E types. One then could have saved oneself with having to bother injecting custom converters into the BOOST_OUTCOME_V2_NAMESPACE::convert namespace.
|
|
However there are occasions when you don&rsquo;t have control over the implementation of the destination E type e.g. in callbacks.</description>
|
|
</item>
|
|
|
|
</channel>
|
|
</rss> |