-
-
Notifications
You must be signed in to change notification settings - Fork 64
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Outcome.Experimental has had C representation support since the beg…
…inning, however it had been mainly intended that C++ would originate Results, they would pass through C, and back into C++. It hadn't really been expected that C would want to do much with Results other than inspect them for happy or sad path. It turns out there is more demand than expected for a more functional Result from within C, so this release adds the power to create Results in success and two types of failure, semantic comparison of Results, and printing of Result messages. You can also wrap a C enum into a quick status code from enum, allowing easy custom C error coding from 100% within C. [The documentation for the C support]({{% relref "../experimental/c-api" %}}) has been updated to reflect the new facilities.
- Loading branch information
Showing
37 changed files
with
1,320 additions
and
345 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,50 @@ | ||
+++ | ||
title = "C Results" | ||
description = "Outcome's C Result support" | ||
weight = 30 | ||
+++ | ||
|
||
The C macro API header `<outcome/experimental/result.h>` has some macros for working with any kind of Result: | ||
|
||
<dl> | ||
<dt><code>CXX_DECLARE_RESULT(ident, T, E)</code> | ||
<dd>Declares to C a <code>basic_result<T, E></code> type uniquely | ||
identified by <code>ident</code>. <code>T</code> is available at the | ||
member variable <code>.value</code>, and <code>E</code> is available | ||
at the member variable <code>.error</code>. | ||
|
||
<dt><code>CXX_RESULT(ident)</code> | ||
<dd>A reference to a previously declared <code>result</code> type with | ||
unique <code>ident</code>. | ||
|
||
<dt><code>CXX_RESULT_HAS_VALUE(r)</code> | ||
<dd>Evaluates to 1 (true) if the input <code>result</code> has a value. | ||
|
||
<dt><code>CXX_RESULT_HAS_ERROR(r)</code> | ||
<dd>Evaluates to 1 (true) if the input <code>result</code> has an error. | ||
|
||
<dt><code>CXX_RESULT_ERROR_IS_ERRNO(r)</code> | ||
<dd>Evaluates to 1 (true) if the input <code>result</code>'s error value | ||
is a code in the POSIX <code>errno</code> domain. | ||
</dl> | ||
|
||
The above let you work, somewhat awkwardly, with any C-compatible | ||
`basic_result<T, E>`. `basic_result<T, E>` is trivially copyable and | ||
standard layout if its `T` and `E` are both so, and it has the C layout: | ||
|
||
```c++ | ||
struct cxx_result_##ident | ||
{ | ||
union | ||
{ | ||
T value; | ||
E error; | ||
}; | ||
unsigned flags; | ||
}; | ||
``` | ||
|
||
Note that this layout is different to that of [`CXX_DECLARE_STATUS_CODE`]({{% relref "../from-c" %}}) | ||
as the C++ `result` has a different layout if `E` is a status code. | ||
|
||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
+++ | ||
title = "Declare a Result" | ||
description = "Declaring a C Result" | ||
weight = 20 | ||
+++ | ||
|
||
{{% snippet "c_api2.cpp" "preamble" %}} | ||
|
||
The key to making C programming easy is to alias the long complex things | ||
into short easy thing. Obviously `SUCCESS(expr)` and `FAILURE(expr)` is too | ||
generic, but for the purposes of this documentation it makes thing easier. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,86 @@ | ||
+++ | ||
title = "C system error results" | ||
description = "Status code's `std::error` in C" | ||
weight = 10 | ||
+++ | ||
|
||
In v2.2.11, C Result support went from second tier to first tier status, and | ||
now you can create, query and manipulate a subset of Result types entirely from | ||
within C by including `<outcome/experimental/result.h>`. | ||
|
||
The subset supported are those `result<T, E>` which are [a `status_result<T>`]({{% relref "../../status_result" %}}) | ||
i.e. the `E` is hardcoded to `experimental::error` which is the type erased runtime | ||
polymorphic holder for any errored `status_code` whose payload is not bigger | ||
than an `intptr_t`. This is the most useful subset of Outcome Experimental's | ||
possible Result types, allowing arbitrary custom error coding schemes from | ||
any unknown source to work seamlessly with all others, including errors from | ||
the system or third party libraries. | ||
|
||
The operations available to C are: | ||
|
||
<dl> | ||
<dt><code>CXX_DECLARE_RESULT_SYSTEM(ident, T)</code> | ||
<dd>Declares to C a <code>status_result<T></code> type uniquely | ||
identified by <code>ident</code>. <code>T</code> is available at the | ||
member variable <code>.value</code>, and <code>struct cxx_status_code_system</code> | ||
is available at the member variable <code>.error</code>. If in C++, | ||
implements C extern functions for making successful and failure results | ||
of this type. | ||
|
||
<dt><code>CXX_RESULT_SYSTEM(ident)</code> | ||
<dd>A reference to a previously declared <code>status_result</code> type with | ||
unique <code>ident</code>. | ||
|
||
<dt><code>CXX_MAKE_RESULT_SYSTEM_SUCCESS(ident, expr)</code> (needs C++ counterpart linked into final binary) | ||
<dd>This invokes the aforementioned extern function which creates a <code>status_result</code> | ||
with a successful value of type <code>T</code>. | ||
<dt><code>CXX_MAKE_RESULT_SYSTEM_FAILURE_POSIX(ident, expr)</code> (needs C++ counterpart linked into final binary) | ||
<dd>This invokes the aforementioned extern function which creates a <code>status_result</code> | ||
with a failure of type <code>posix_code</code> representing a POSIX <code>errno</code>. | ||
<dt><code>CXX_MAKE_RESULT_SYSTEM_FAILURE_SYSTEM(ident, expr)</code> (needs C++ counterpart linked into final binary) | ||
<dd>This invokes the aforementioned extern function which creates a <code>status_result</code> | ||
with a failure of type <code>posix_code</code> representing a POSIX <code>errno</code> | ||
if on POSIX; if on Windows then a failure of type <code>win32_code</code> | ||
representing a Win32 error code from a Windows API. | ||
|
||
<br><br> | ||
<dt><code>CXX_RESULT_HAS_VALUE(r)</code> | ||
<dd>Evaluates to 1 (true) if the input <code>result</code> has a value. | ||
|
||
<dt><code>CXX_RESULT_HAS_ERROR(r)</code> | ||
<dd>Evaluates to 1 (true) if the input <code>result</code> has an error. | ||
|
||
<dt><code>CXX_RESULT_ERROR_IS_ERRNO(r)</code> | ||
<dd>Evaluates to 1 (true) if the input <code>result</code>'s error value | ||
is a code in the POSIX <code>errno</code> domain. | ||
<br><br> | ||
<dt><code>CXX_RESULT_SYSTEM_TRY(expr)</code> | ||
<dd>If the <code>status_result</code> returned by <code>expr</code> is | ||
errored, exit the current function returning the result. This obviously | ||
requires that the return type of the current function matches that of <code> | ||
expr</code>. | ||
|
||
<dt><code>CXX_RESULT_SYSTEM_TRY(cleanup, expr)</code> | ||
<dd>Same as the above, but execute <code>cleanup</code> just before exiting the function | ||
if returning failure. | ||
|
||
<dt><code>CXX_RESULT_SYSTEM_TRY(var, cleanup, expr)</code> | ||
<dd>Same as the above, but set <code>var</code> equal to the result's <code>.value</code> on success. | ||
|
||
<dt><code>CXX_RESULT_SYSTEM_TRY(var, ident, cleanup, expr)</code> | ||
<dd>Same as the above, but use <code>ident</code> as the return type instead. This allows | ||
the return type of the calling function to differ from that of <code>expr</code>. | ||
<br><br> | ||
<dt><code>CXX_DECLARE_RESULT_SYSTEM_FROM_ENUM(ident, enum_name, uuid, {enum mapping-sequence, ...})</code> | ||
<dd>This declares to C an extern function which creates a <code>status_result</code> | ||
from a C enum. If in C++, it implements a <code>quick_status_code_from_enum</code> for | ||
the C enum and the associated extern function, and you will need to supply <code>uuid</code> | ||
and the appropriate enum value mapping sequence <a href="{{% relref "../../worked-example" %}}"> | ||
as per the <code>quick_status_code_from_enum</code> documentation</a>. | ||
<dt><code>CXX_MAKE_RESULT_SYSTEM_FROM_ENUM(ident, enum_name, expr)</code> (needs C++ counterpart linked into final binary) | ||
<dd>This invokes the aforementioned extern function which creates a <code>status_result</code> | ||
from a C enum. | ||
</dl> | ||
|
||
Using the above you can write C code using Outcome.Experimental's Result type | ||
quite effectively. Let's look at an example of use next. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
+++ | ||
title = "TRY a C Result" | ||
description = "Operation TRY on a C Result" | ||
weight = 40 | ||
+++ | ||
|
||
Thanks to much of the magic of {{< api "OUTCOME_TRY(var, expr)" >}} being implemented | ||
using C preprocessor metaprogramming, we can offer a very similar experience for the | ||
C try operation and without needing anything compiled in C++ as support functions: | ||
|
||
{{% snippet "c_api2.cpp" "try" %}} | ||
|
||
The principle difference is that you can specify a cleanup routine to perform if | ||
failure is encountered. This is especially useful in C, which has no stack unwinding. | ||
|
||
Also due to lack of type sugaring and user defined implicit conversions, if your | ||
callers result type isn't your callee's, you may need to specify what your caller's | ||
result type is so the error state can be correctly propagated. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
+++ | ||
title = "Using a Result" | ||
description = "Using a C Result" | ||
weight = 30 | ||
+++ | ||
|
||
This models [the earlier C++ example of use]({{% relref "/experimental/worked-example/implicit-construction" %}}), | ||
and its C equivalent isn't much more verbose thanks to our helper typedefs and macros: | ||
|
||
{{% snippet "c_api2.cpp" "using" %}} | ||
|
||
For this to link, the `CXX_DECLARE_RESULT_SYSTEM_FROM_ENUM` macro needs to be | ||
compiled at least once within C++ within the final binary to emit the extern | ||
functions needed by C. |
4 changes: 2 additions & 2 deletions
4
...content/experimental/c-api/limitations.md → ...ent/experimental/c-api/from-cxx/_index.md
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
File renamed without changes.
File renamed without changes.
This file was deleted.
Oops, something went wrong.
Oops, something went wrong.