1
1
Fork 0
mirror of https://github.com/trafi/maybe-result-cpp synced 2024-06-01 03:06:15 +02:00
Maybe Result implementation for C++
Go to file
Nerijus Arlauskas b6e242b36c Move accessors, additional tests and docs. 2016-07-08 13:32:08 +03:00
src Move accessors, additional tests and docs. 2016-07-08 13:32:08 +03:00
tests Move accessors, additional tests and docs. 2016-07-08 13:32:08 +03:00
.clang-format Move accessors, additional tests and docs. 2016-07-08 13:32:08 +03:00
.gitignore Initial files. 2016-07-05 22:59:12 +03:00
CMakeLists.txt Initial files. 2016-07-05 22:59:12 +03:00
LICENSE-APACHE Initial files. 2016-07-05 22:59:12 +03:00
LICENSE-MIT Initial files. 2016-07-05 22:59:12 +03:00
README.md Add example. 2016-07-07 10:46:19 +03:00

Maybe Result

Maybe Result is a return value wrapper that can contain either a value T or error E. It borrows ideas heavily from the C++17's std::experimental::optional, Rust's std::result and the std::expected that was proposed but not yet accepted for C++17.

Example

#include <maybe/result.hpp>
#include <vector>

using maybe::result;
using namespace std;

/**
 * Error type.
 */
enum class LoadError {
    FileNotFound,
};

/**
 * Example function that returns a successful result or error depending on param.
 */
result<vector<string>, LoadError> load_names(bool return_successfully)
{
    if (return_successfully) {
        return result<vector<string>, LoadError>::ok({"Bob", "Alice"});
    } else {
        return result<vector<string>, LoadError>::err(LoadError::FileNotFound);
    }
}

/**
 * Chain both functions and merge results into one.
 *
 * If `return_success_from_first` is false, the fist function will fail.
 */
result<size_t, string> run(bool return_success_from_first)
{
    return load_names(success) // function will fail depending on flag
        // run this if previous succeeds
        .and_then([](auto prev_names) {
            // combine results of both
            return load_names(true).map([prev_names](auto more_names) {
                vector<string> all;
                copy(prev_names.begin(), prev_names.end(), back_inserter(all));
                copy(more_names.begin(), more_names.end(), back_inserter(all));
                return all;
            });
        })
        // change error from LoadError to string
        .map_err([](auto err) {
            if (err == LoadError::FileNotFound) {
                return string("file not found");
            }
            return string("other error");
        })
        // map result value to the number of elements in vector
        .map([](vector<string> results) { return results.size(); });
}

auto success_result = run(true);

REQUIRE(success_result);
REQUIRE(success_result.ok_value() == 4);

auto error_result = run(false);

REQUIRE(!error_result);
REQUIRE(error_result.err_value() == "file not found");

How is it different from std::experimental::optional?

Has a value for error instead of nullopt.

How is it different from std::expected?

It does not require the error to be an exception, and does not fall back to exceptions. All values must be checked, similar to std::experimental::optional.

Setting up

This is header-only library. We recommend to add src to included directories, so that the include would be:

#include <maybe/result.hpp>

A C++ compiler shat supports C++14 is required. You can use -std=c++14 flag for sufficiently recent versions of GCC or CLANG.

Warning! Library is highly experimental and is not guaranteed to work.

Running tests

cmake .
make tests && ./tests/tests

License

Licensed under either of

at your option.

Contribution

Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions.