From 90f8c0f91e1de14685477a98b14a29e7b0781ec9 Mon Sep 17 00:00:00 2001 From: BlackMATov Date: Sun, 9 Dec 2018 09:40:36 +0700 Subject: [PATCH] is_promise, is_promise_r, make_resolved_promise, make_rejected_promise --- promise.hpp | 113 ++++++++++++++++++++++++++++++++++++++++++---------- tests.cpp | 112 +++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 203 insertions(+), 22 deletions(-) diff --git a/promise.hpp b/promise.hpp index 7370c39..d20348f 100644 --- a/promise.hpp +++ b/promise.hpp @@ -25,33 +25,43 @@ namespace promise_hpp class promise; // - // make_promise + // is_promise // - template < typename R, typename F > - promise make_promise(F&& f) { - promise result; + namespace impl + { + template < typename T > + struct is_promise_impl + : std::false_type {}; - auto resolver = std::bind([](promise& p, auto&& v){ - p.resolve(std::forward(v)); - }, result, std::placeholders::_1); - - auto rejector = std::bind([](promise& p, auto&& e){ - p.reject(std::forward(e)); - }, result, std::placeholders::_1); - - try { - invoke_hpp::invoke( - std::forward(f), - std::move(resolver), - std::move(rejector)); - } catch (...) { - result.reject(std::current_exception()); - } - - return result; + template < typename R > + struct is_promise_impl> + : std::true_type {}; } + template < typename T > + struct is_promise + : impl::is_promise_impl> {}; + + // + // is_promise_r + // + + namespace impl + { + template < typename R, typename T > + struct is_promise_r_impl + : std::false_type {}; + + template < typename R, typename PR > + struct is_promise_r_impl> + : std::is_convertible {}; + } + + template < typename R, typename T > + struct is_promise_r + : impl::is_promise_r_impl> {}; + // // promise // @@ -59,6 +69,8 @@ namespace promise_hpp template < typename T > class promise final { public: + using value_type = T; + enum class status : std::uint8_t { pending, resolved, @@ -298,6 +310,8 @@ namespace promise_hpp template <> class promise final { public: + using value_type = void; + enum class status : std::uint8_t { pending, resolved, @@ -487,4 +501,59 @@ namespace promise_hpp std::vector handlers_; }; }; + + // + // make_promise + // + + template < typename R, typename F > + promise make_promise(F&& f) { + promise result; + + auto resolver = std::bind([](promise& p, auto&& v){ + p.resolve(std::forward(v)); + }, result, std::placeholders::_1); + + auto rejector = std::bind([](promise& p, auto&& e){ + p.reject(std::forward(e)); + }, result, std::placeholders::_1); + + try { + invoke_hpp::invoke( + std::forward(f), + std::move(resolver), + std::move(rejector)); + } catch (...) { + result.reject(std::current_exception()); + } + + return result; + } + + inline promise make_resolved_promise() { + promise result; + result.resolve(); + return result; + } + + template < typename R > + promise> make_resolved_promise(R&& v) { + promise> result; + result.resolve(std::forward(v)); + return result; + } + + template < typename E > + promise make_rejected_promise(E&& e) { + promise result; + result.reject(std::forward(e)); + return result; + } + + template < typename R, typename E > + promise make_rejected_promise(E&& e) { + promise result; + result.reject(std::forward(e)); + return result; + } } diff --git a/tests.cpp b/tests.cpp index cf705e6..216a5ca 100644 --- a/tests.cpp +++ b/tests.cpp @@ -6,6 +6,9 @@ namespace pr = promise_hpp; namespace { + struct obj_t { + }; + bool check_hello_fail_exception(std::exception_ptr e) { try { std::rethrow_exception(e); @@ -17,6 +20,79 @@ namespace } } +TEST_CASE("is_promise") { + SECTION("positive") { + static_assert( + pr::is_promise>::value, + "unit test fail"); + static_assert( + pr::is_promise>::value, + "unit test fail"); + static_assert( + pr::is_promise>::value, + "unit test fail"); + + static_assert( + pr::is_promise>::value, + "unit test fail"); + static_assert( + pr::is_promise>::value, + "unit test fail"); + static_assert( + pr::is_promise>::value, + "unit test fail"); + } + SECTION("negative") { + static_assert( + !pr::is_promise&>::value, + "unit test fail"); + static_assert( + !pr::is_promise*>::value, + "unit test fail"); + static_assert( + !pr::is_promise&>::value, + "unit test fail"); + + static_assert( + !pr::is_promise::value, + "unit test fail"); + static_assert( + !pr::is_promise::value, + "unit test fail"); + static_assert( + !pr::is_promise::value, + "unit test fail"); + } +} + +TEST_CASE("is_promise_r") { + SECTION("positive") { + static_assert( + pr::is_promise_r>::value, + "unit test fail"); + static_assert( + pr::is_promise_r>::value, + "unit test fail"); + static_assert( + pr::is_promise_r>::value, + "unit test fail"); + } + SECTION("negative") { + static_assert( + !pr::is_promise_r>::value, + "unit test fail"); + static_assert( + !pr::is_promise_r>::value, + "unit test fail"); + static_assert( + !pr::is_promise_r>::value, + "unit test fail"); + static_assert( + !pr::is_promise_r::value, + "unit test fail"); + } +} + TEST_CASE("promise") { SECTION("resolved") { { @@ -191,6 +267,42 @@ TEST_CASE("promise") { REQUIRE(call_fail_with_logic_error); } } + SECTION("make_resolved_promise") { + { + bool call_check = false; + pr::make_resolved_promise() + .then([&call_check]{ + call_check = true; + }); + REQUIRE(call_check); + } + { + int check_42_int = 0; + pr::make_resolved_promise(42) + .then([&check_42_int](int value){ + check_42_int = value; + }); + REQUIRE(check_42_int == 42); + } + } + SECTION("make_rejected_promise") { + { + bool call_fail_with_logic_error = false; + pr::make_rejected_promise(std::logic_error("hello fail")) + .fail([&call_fail_with_logic_error](std::exception_ptr e){ + call_fail_with_logic_error = check_hello_fail_exception(e); + }); + REQUIRE(call_fail_with_logic_error); + } + { + bool call_fail_with_logic_error = 0; + pr::make_rejected_promise(std::logic_error("hello fail")) + .fail([&call_fail_with_logic_error](std::exception_ptr e){ + call_fail_with_logic_error = check_hello_fail_exception(e); + }); + REQUIRE(call_fail_with_logic_error); + } + } SECTION("exceptions") { { bool not_call_then_on_reject = true;