From dc721316df4c6d12ad37ea49e56a38eca0ffb1ab Mon Sep 17 00:00:00 2001 From: Nerijus Arlauskas Date: Thu, 7 Jul 2016 01:30:56 +0300 Subject: [PATCH] Add map_err and some docs. --- src/maybe/result.hpp | 31 ++++++++++++++++++++++++++++++- src/maybe/result.inline.hpp | 13 +++++++++++++ tests/CMakeLists.txt | 1 + tests/result_map_err_tests.cpp | 32 ++++++++++++++++++++++++++++++++ 4 files changed, 76 insertions(+), 1 deletion(-) create mode 100644 tests/result_map_err_tests.cpp diff --git a/src/maybe/result.hpp b/src/maybe/result.hpp index b2e5e56..bd22178 100644 --- a/src/maybe/result.hpp +++ b/src/maybe/result.hpp @@ -195,11 +195,40 @@ namespace maybe { return std::addressof(err_val); } + /** + * Maps a result to result (where U is return value of F(T)) by applying a function F to a + * contained ok value, leaving an err value untouched. + * + * This function can be used to compose the results of two functions. + * + * @param f F(T) -> U + * @return maybe::result + */ template constexpr auto map(F f) noexcept -> maybe::result::type, E>; + /** + * Maps a result to result (where U is return value of F(E)) by applying a function to a + * contained err value, leaving an ok value untouched. + * + * This function can be used to pass through a successful result while changing an error. + * + * @param f F(E) -> U + * @return maybe::result + */ template - constexpr auto and_then(F f) noexcept -> typename std::result_of::type; + constexpr auto map_err(F f) noexcept -> maybe::result::type>; + + /** + * Calls op if the result is ok, otherwise returns the err value of self. + * + * This function can be used for control flow based on result values. + * + * @param f F(T) -> maybe::result + * @return maybe::result + */ + template + constexpr auto and_then(F op) noexcept -> typename std::result_of::type; private: constexpr void copy_from(const result& other) noexcept; diff --git a/src/maybe/result.inline.hpp b/src/maybe/result.inline.hpp index c7885f6..5ba1b4b 100644 --- a/src/maybe/result.inline.hpp +++ b/src/maybe/result.inline.hpp @@ -109,6 +109,19 @@ constexpr auto maybe::result::map(F f) noexcept return return_result_t::ok(f(std::forward(ok_value()))); }; +template +template +constexpr auto maybe::result::map_err(F f) noexcept + -> maybe::result::type> +{ + typedef maybe::result::type> return_result_t; + + if (is_ok()) { + return return_result_t::ok(std::forward(ok_value())); + } + return return_result_t::err(f(std::forward(err_value()))); +}; + template template constexpr auto maybe::result::and_then(F f) noexcept -> typename std::result_of::type diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index df38a68..f565d23 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -6,6 +6,7 @@ add_executable(${TARGET} main.cpp result_tests.cpp result_map_tests.cpp + result_map_err_tests.cpp result_and_then_tests.cpp ) diff --git a/tests/result_map_err_tests.cpp b/tests/result_map_err_tests.cpp new file mode 100644 index 0000000..8e3279b --- /dev/null +++ b/tests/result_map_err_tests.cpp @@ -0,0 +1,32 @@ +#include "catch.hpp" + +#include + +class A final { +public: + A(std::string value) : value(value) + { + } + std::string value; +}; + +using maybe::result; + +TEST_CASE("result_map_err") +{ + SECTION("converts err bool to err int") + { + auto a = result::err(true); + auto b = a.map_err([](bool v) { return v ? 42 : 43; }); + REQUIRE(!b); + REQUIRE(b.err_value() == 42); + } + + SECTION("does not convert anything and returns ok if not err") + { + auto a = result::ok(A("hi")); + auto b = a.map_err([](bool v) { return v ? 42 : 43; }); + REQUIRE(b); + REQUIRE(b.ok_value().value == "hi"); + } +} \ No newline at end of file