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:
parent
9b2c4842ae
commit
52c783731e
@ -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>
|
||||
|
41
tests/result_and_then_tests.cpp
Normal file
41
tests/result_and_then_tests.cpp
Normal file
@ -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");
|
||||
}
|
||||
}
|
40
tests/result_map_tests.cpp
Normal file
40
tests/result_map_tests.cpp
Normal file
@ -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);
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user