1
1
mirror of https://github.com/trafi/maybe-result-cpp synced 2024-11-22 02:32:02 +01:00

Implement and_then and use simpler magic.

This commit is contained in:
Nerijus Arlauskas 2016-07-07 01:10:45 +03:00
parent 9b2c4842ae
commit 52c783731e
6 changed files with 104 additions and 32 deletions

@ -50,6 +50,8 @@ namespace maybe {
template <typename T, typename E>
class result final {
public:
typedef T ok_type;
result() : tag(internal::Value::NONE)
{
}
@ -194,7 +196,10 @@ namespace maybe {
}
template <typename F>
constexpr auto map(F f) noexcept -> maybe::result<decltype(f(std::declval<T>())), E>;
constexpr auto map(F f) noexcept -> maybe::result<typename std::result_of<F(T)>::type, E>;
template <typename F>
constexpr auto and_then(F f) noexcept -> typename std::result_of<F(T)>::type;
private:
constexpr void copy_from(const result<T, E>& other) noexcept;

@ -99,12 +99,24 @@ constexpr void maybe::result<T, E>::clear() noexcept
template <typename T, typename E>
template <typename F>
constexpr auto maybe::result<T, E>::map(F f) noexcept
-> maybe::result<decltype(f(std::declval<T>())), E>
-> maybe::result<typename std::result_of<F(T)>::type, E>
{
typedef maybe::result<decltype(f(std::declval<T>())), E> return_result_t;
typedef maybe::result<typename std::result_of<F(T)>::type, E> return_result_t;
if (is_err()) {
return return_result_t::err(std::forward<E>(err_value()));
}
return return_result_t::ok(f(std::forward<T>(ok_value())));
};
template <typename T, typename E>
template <typename F>
constexpr auto maybe::result<T, E>::and_then(F f) noexcept -> typename std::result_of<F(T)>::type
{
typedef typename std::result_of<F(T)>::type result_t;
if (is_err()) {
return maybe::result<typename result_t::ok_type, E>::err(std::forward<E>(err_value()));
}
return f(std::forward<T>(ok_value()));
};

@ -5,7 +5,9 @@ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++14")
add_executable(${TARGET}
main.cpp
result_tests.cpp
result_chaining_tests.cpp)
result_map_tests.cpp
result_and_then_tests.cpp
)
target_include_directories(${TARGET}
PUBLIC $<TARGET_PROPERTY:maybe_result,INTERFACE_INCLUDE_DIRECTORIES>

@ -0,0 +1,41 @@
#include "catch.hpp"
#include <maybe/result.hpp>
class A final {
public:
A(std::string value) : value(value)
{
}
std::string value;
};
class B final {
public:
B(std::string value) : value(value)
{
}
std::string value;
};
using maybe::result;
TEST_CASE("result_and_then")
{
SECTION("chains another function returning different result if previous one was successful")
{
auto a = result<A, int>::ok(A("hello"));
auto b = a.and_then([](A v) { return result<B, int>::ok(B(v.value + " world")); });
REQUIRE(b);
REQUIRE(b.ok_value().value == "hello world");
}
SECTION(
"should not run another function returning different result if previous one returned error")
{
auto a = result<A, int>::err(43);
auto b = a.and_then([](A v) { return result<B, int>::ok(B(v.value + " world")); });
REQUIRE(!b);
REQUIRE(b.err_value() == 43);
}
}

@ -1,28 +0,0 @@
#include "catch.hpp"
#include <maybe/result.hpp>
class A final {
public:
A(std::string value) : value(value) {}
std::string value;
};
class B final {
public:
B(std::string value) : value(value) {}
std::string value;
};
using maybe::result;
TEST_CASE("result_chaining")
{
SECTION("converts result A to result B")
{
auto a = result<A, int>::ok(A("hello"));
auto b = a.map([](A v) { return B(v.value); });
REQUIRE(b);
REQUIRE(b.ok_value().value == "hello");
}
}

@ -0,0 +1,40 @@
#include "catch.hpp"
#include <maybe/result.hpp>
class A final {
public:
A(std::string value) : value(value)
{
}
std::string value;
};
class B final {
public:
B(std::string value) : value(value)
{
}
std::string value;
};
using maybe::result;
TEST_CASE("result_map")
{
SECTION("converts result A to result B")
{
auto a = result<A, int>::ok(A("hello"));
auto b = a.map([](A v) { return B(v.value + " world"); });
REQUIRE(b);
REQUIRE(b.ok_value().value == "hello world");
}
SECTION("does not convert result A to result B if value was error")
{
auto a = result<A, int>::err(43);
auto b = a.map([](A v) { return B(v.value = " world"); });
REQUIRE(!b);
REQUIRE(b.err_value() == 43);
}
}