Commit 40511f65 authored by Mathieu Stefani's avatar Mathieu Stefani

Async: added a way to rethrow an exception and then propagate the exception...

Async: added a way to rethrow an exception and then propagate the exception along to an other promise
parent 4684f678
...@@ -119,6 +119,14 @@ namespace Async { ...@@ -119,6 +119,14 @@ namespace Async {
namespace Private { namespace Private {
struct InternalRethrow {
InternalRethrow(std::exception_ptr exc)
: exc(std::move(exc))
{ }
std::exception_ptr exc;
};
struct IgnoreException { struct IgnoreException {
void operator()(std::exception_ptr) const { } void operator()(std::exception_ptr) const { }
}; };
...@@ -127,6 +135,12 @@ namespace Async { ...@@ -127,6 +135,12 @@ namespace Async {
void operator()(std::exception_ptr) const { std::terminate(); } void operator()(std::exception_ptr) const { std::terminate(); }
}; };
struct Throw {
void operator()(std::exception_ptr exc) const {
throw InternalRethrow(std::move(exc));
}
};
class Core; class Core;
class Request { class Request {
...@@ -209,8 +223,9 @@ namespace Async { ...@@ -209,8 +223,9 @@ namespace Async {
template<typename T> template<typename T>
struct Continuable : public Request { struct Continuable : public Request {
Continuable() Continuable(const std::shared_ptr<Core>& chain)
: resolveCount_(0) : chain_(chain)
, resolveCount_(0)
, rejectCount_(0) , rejectCount_(0)
{ } { }
...@@ -226,7 +241,16 @@ namespace Async { ...@@ -226,7 +241,16 @@ namespace Async {
if (rejectCount_ >= 1) if (rejectCount_ >= 1)
throw Error("Reject must not be called more than once"); throw Error("Reject must not be called more than once");
doReject(coreCast(core)); try {
doReject(coreCast(core));
} catch (const InternalRethrow& e) {
chain_->exc = std::move(e.exc);
chain_->state = State::Rejected;
for (const auto& req: chain_->requests) {
req->reject(chain_);
}
}
++rejectCount_; ++rejectCount_;
} }
...@@ -239,13 +263,16 @@ namespace Async { ...@@ -239,13 +263,16 @@ namespace Async {
size_t resolveCount_; size_t resolveCount_;
size_t rejectCount_; size_t rejectCount_;
std::shared_ptr<Core> chain_;
}; };
template<typename T, typename ResolveFunc, typename RejectFunc> template<typename T, typename ResolveFunc, typename RejectFunc>
struct ThenContinuation : public Continuable<T> { struct ThenContinuation : public Continuable<T> {
ThenContinuation( ThenContinuation(
const std::shared_ptr<Core>& chain,
ResolveFunc&& resolveFunc, RejectFunc&& rejectFunc) ResolveFunc&& resolveFunc, RejectFunc&& rejectFunc)
: resolveFunc_(std::forward<ResolveFunc>(resolveFunc)) : Continuable<T>(chain)
, resolveFunc_(std::forward<ResolveFunc>(resolveFunc))
, rejectFunc_(std::forward<RejectFunc>(rejectFunc)) , rejectFunc_(std::forward<RejectFunc>(rejectFunc))
{ {
} }
...@@ -275,7 +302,7 @@ namespace Async { ...@@ -275,7 +302,7 @@ namespace Async {
ThenReturnContinuation( ThenReturnContinuation(
const std::shared_ptr<Core>& chain, const std::shared_ptr<Core>& chain,
ResolveFunc&& resolveFunc, RejectFunc&& rejectFunc) ResolveFunc&& resolveFunc, RejectFunc&& rejectFunc)
: chain_(chain) : Continuable<T>(chain)
, resolveFunc_(std::forward<ResolveFunc>(resolveFunc)) , resolveFunc_(std::forward<ResolveFunc>(resolveFunc))
, rejectFunc_(std::forward<RejectFunc>(rejectFunc)) , rejectFunc_(std::forward<RejectFunc>(rejectFunc))
{ {
...@@ -287,8 +314,8 @@ namespace Async { ...@@ -287,8 +314,8 @@ namespace Async {
void doReject(const std::shared_ptr<CoreT<T>>& core) const { void doReject(const std::shared_ptr<CoreT<T>>& core) const {
rejectFunc_(core->exc); rejectFunc_(core->exc);
for (const auto& req: chain_->requests) { for (const auto& req: this->chain_->requests) {
req->reject(chain_); req->reject(this->chain_);
} }
} }
...@@ -303,13 +330,12 @@ namespace Async { ...@@ -303,13 +330,12 @@ namespace Async {
template<typename Ret> template<typename Ret>
void finishResolve(Ret&& ret) const { void finishResolve(Ret&& ret) const {
typedef typename std::remove_reference<Ret>::type CleanRet; typedef typename std::remove_reference<Ret>::type CleanRet;
chain_->construct<CleanRet>(std::forward<Ret>(ret)); this->chain_->template construct<CleanRet>(std::forward<Ret>(ret));
for (const auto& req: chain_->requests) { for (const auto& req: this->chain_->requests) {
req->resolve(chain_); req->resolve(this->chain_);
} }
} }
std::shared_ptr<Core> chain_;
ResolveFunc resolveFunc_; ResolveFunc resolveFunc_;
RejectFunc rejectFunc_; RejectFunc rejectFunc_;
}; };
...@@ -319,7 +345,7 @@ namespace Async { ...@@ -319,7 +345,7 @@ namespace Async {
ThenChainContinuation( ThenChainContinuation(
const std::shared_ptr<Core>& chain, const std::shared_ptr<Core>& chain,
ResolveFunc&& resolveFunc, RejectFunc&& rejectFunc) ResolveFunc&& resolveFunc, RejectFunc&& rejectFunc)
: chain_(chain) : Continuable<T>(chain)
, resolveFunc_(std::forward<ResolveFunc>(resolveFunc)) , resolveFunc_(std::forward<ResolveFunc>(resolveFunc))
, rejectFunc_(std::forward<RejectFunc>(rejectFunc)) , rejectFunc_(std::forward<RejectFunc>(rejectFunc))
{ {
...@@ -360,7 +386,6 @@ namespace Async { ...@@ -360,7 +386,6 @@ namespace Async {
}); });
} }
std::shared_ptr<Core> chain_;
ResolveFunc resolveFunc_; ResolveFunc resolveFunc_;
RejectFunc rejectFunc_; RejectFunc rejectFunc_;
...@@ -385,7 +410,7 @@ namespace Async { ...@@ -385,7 +410,7 @@ namespace Async {
typename Type = typename detail::RemovePromise<Promise>::Type> typename Type = typename detail::RemovePromise<Promise>::Type>
Chainer<Type> Chainer<Type>
makeChainer(const Promise&) const { makeChainer(const Promise&) const {
return Chainer<Type>(chain_); return Chainer<Type>(this->chain_);
} }
}; };
...@@ -413,6 +438,7 @@ namespace Async { ...@@ -413,6 +438,7 @@ namespace Async {
const std::shared_ptr<Private::Core>& chain, const std::shared_ptr<Private::Core>& chain,
ResolveFunc&& resolveFunc, RejectFunc&& rejectFunc) { ResolveFunc&& resolveFunc, RejectFunc&& rejectFunc) {
return new ThenContinuation<T, ResolveFunc, RejectFunc>( return new ThenContinuation<T, ResolveFunc, RejectFunc>(
chain,
std::forward<ResolveFunc>(resolveFunc), std::forward<ResolveFunc>(resolveFunc),
std::forward<RejectFunc>(rejectFunc)); std::forward<RejectFunc>(rejectFunc));
} }
...@@ -510,6 +536,7 @@ namespace Async { ...@@ -510,6 +536,7 @@ namespace Async {
static constexpr Private::IgnoreException IgnoreException{}; static constexpr Private::IgnoreException IgnoreException{};
static constexpr Private::NoExcept NoExcept{}; static constexpr Private::NoExcept NoExcept{};
static constexpr Private::Throw Throw{};
template<typename T> template<typename T>
class Promise : public PromiseBase class Promise : public PromiseBase
......
...@@ -229,5 +229,15 @@ TEST(async_test, when_all) { ...@@ -229,5 +229,15 @@ TEST(async_test, when_all) {
Async::whenAll(p3, p4).then([](const std::tuple<std::string, void>& results) { Async::whenAll(p3, p4).then([](const std::tuple<std::string, void>& results) {
}, Async::NoExcept); }, Async::NoExcept);
#endif #endif
}
TEST(async_test, rethrow_test) {
auto p1 = Async::Promise<void>([](Async::Resolver& resolve, Async::Rejection& reject) {
reject(std::runtime_error("Because"));
});
auto p2 = p1.then([]() { }, Async::Throw);
ASSERT_TRUE(p2.isRejected());
} }
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment