1
1
mirror of https://github.com/trafi/maybe-result-cpp synced 2024-11-22 02:32:02 +01:00
Maybe Result implementation for C++
Go to file
2016-07-10 17:30:15 +03:00
dev Update travis build script. 2016-07-10 01:49:02 +03:00
src Add documentation generation. 2016-07-10 17:11:04 +03:00
tests Use two optional values as backing storage. 2016-07-10 01:37:56 +03:00
.clang-format Move accessors, additional tests and docs. 2016-07-08 13:32:08 +03:00
.gitignore Add documentation generation. 2016-07-10 17:11:04 +03:00
.travis.yml Another way to install doxygen. 2016-07-10 17:30:15 +03:00
CMakeLists.txt Reduxe CMake required version to 3.0. 2016-07-08 15:26:55 +03:00
Doxyfile Add documentation generation. 2016-07-10 17:11:04 +03:00
export_doc.sh Another way to install doxygen. 2016-07-10 17:30:15 +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 Use two optional values as backing storage. 2016-07-10 01:37:56 +03:00

Maybe Result

Build Status

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 (4.9) or CLANG (3.7).

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

Running tests

Library requires std::experimental::optional implementation, location of which can be specified with -DEXPERIMENTAL_OPTIONAL_INCLUDE flag:

cmake -DEXPERIMENTAL_OPTIONAL_INCLUDE=../path/to/optional .
make tests && ./tests/tests

There is a script that does this automatically:

./dev/run-tests.sh

In addition to this, you can run tests on all supported compilers using docker:

./dev/docker-run-tests.sh

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.