From: James Sedgwick Date: Wed, 15 Apr 2015 17:11:47 +0000 (-0700) Subject: onError(exception_wrapper) X-Git-Tag: v0.36.0~39 X-Git-Url: http://demsky.eecs.uci.edu/git/?a=commitdiff_plain;h=d3ceb2322e5e08df5150b531f550d54d650ab47c;p=folly.git onError(exception_wrapper) Summary: title Test Plan: unit Reviewed By: hans@fb.com Subscribers: folly-diffs@, jsedgwick, yfeldblum, chalfant, hannesr, vloh FB internal diff: D1984864 Tasks: 6045789 Signature: t1:1984864:1429116418:b4a9cdbb88f605a09b5753eea41dd970c96b9d4e --- diff --git a/folly/futures/Future-inl.h b/folly/futures/Future-inl.h index dc842741..ffa22ad6 100644 --- a/folly/futures/Future-inl.h +++ b/folly/futures/Future-inl.h @@ -244,6 +244,7 @@ Future Future::then() { template template typename std::enable_if< + !detail::callableWith::value && !detail::Extract::ReturnsFuture::value, Future>::type Future::onError(F&& func) { @@ -273,6 +274,7 @@ Future::onError(F&& func) { template template typename std::enable_if< + !detail::callableWith::value && detail::Extract::ReturnsFuture::value, Future>::type Future::onError(F&& func) { @@ -323,6 +325,70 @@ Future Future::onTimeout(Duration dur, F&& func, Timekeeper* tk) { .onError([funcw](TimedOut const&) { return (*funcw)(); }); } +template +template +typename std::enable_if< + detail::callableWith::value && + detail::Extract::ReturnsFuture::value, + Future>::type +Future::onError(F&& func) { + static_assert( + std::is_same::Return, Future>::value, + "Return type of onError callback must be T or Future"); + + Promise p; + auto f = p.getFuture(); + auto pm = folly::makeMoveWrapper(std::move(p)); + auto funcm = folly::makeMoveWrapper(std::move(func)); + setCallback_([pm, funcm](Try t) mutable { + if (t.hasException()) { + try { + auto f2 = (*funcm)(std::move(t.exception())); + f2.setCallback_([pm](Try t2) mutable { + pm->fulfilTry(std::move(t2)); + }); + } catch (const std::exception& e2) { + pm->setException(exception_wrapper(std::current_exception(), e2)); + } catch (...) { + pm->setException(exception_wrapper(std::current_exception())); + } + } else { + pm->fulfilTry(std::move(t)); + } + }); + + return f; +} + +// onError(exception_wrapper) that returns T +template +template +typename std::enable_if< + detail::callableWith::value && + !detail::Extract::ReturnsFuture::value, + Future>::type +Future::onError(F&& func) { + static_assert( + std::is_same::Return, Future>::value, + "Return type of onError callback must be T or Future"); + + Promise p; + auto f = p.getFuture(); + auto pm = folly::makeMoveWrapper(std::move(p)); + auto funcm = folly::makeMoveWrapper(std::move(func)); + setCallback_([pm, funcm](Try t) mutable { + if (t.hasException()) { + pm->fulfil([&]{ + return (*funcm)(std::move(t.exception())); + }); + } else { + pm->fulfilTry(std::move(t)); + } + }); + + return f; +} + template typename std::add_lvalue_reference::type Future::value() { throwIfInvalid(); diff --git a/folly/futures/Future.h b/folly/futures/Future.h index 18649726..6919fd4e 100644 --- a/folly/futures/Future.h +++ b/folly/futures/Future.h @@ -344,6 +344,7 @@ class Future { /// }); template typename std::enable_if< + !detail::callableWith::value && !detail::Extract::ReturnsFuture::value, Future>::type onError(F&& func); @@ -351,10 +352,27 @@ class Future { /// Overload of onError where the error callback returns a Future template typename std::enable_if< + !detail::callableWith::value && detail::Extract::ReturnsFuture::value, Future>::type onError(F&& func); + /// Overload of onError that takes exception_wrapper and returns Future + template + typename std::enable_if< + detail::callableWith::value && + detail::Extract::ReturnsFuture::value, + Future>::type + onError(F&& func); + + /// Overload of onError that takes exception_wrapper and returns T + template + typename std::enable_if< + detail::callableWith::value && + !detail::Extract::ReturnsFuture::value, + Future>::type + onError(F&& func); + /// func is like std::function and is executed unconditionally, and /// the value/exception is passed through to the resulting Future. /// func shouldn't throw, but if it does it will be captured and propagated, diff --git a/folly/futures/test/FutureTest.cpp b/folly/futures/test/FutureTest.cpp index 5a38c18b..01e63769 100644 --- a/folly/futures/test/FutureTest.cpp +++ b/folly/futures/test/FutureTest.cpp @@ -260,6 +260,66 @@ TEST(Future, onError) { .onError([&] (eggs_t& e) { throw e; return makeFuture(-1); }); EXPECT_THROW(f.value(), eggs_t); } + + // exception_wrapper, return Future + { + auto f = makeFuture() + .then([] { throw eggs; }) + .onError([&] (exception_wrapper e) { flag(); return makeFuture(); }); + EXPECT_FLAG(); + EXPECT_NO_THROW(f.value()); + } + + // exception_wrapper, return Future but throw + { + auto f = makeFuture() + .then([]{ throw eggs; return 0; }) + .onError([&] (exception_wrapper e) { + flag(); + throw eggs; + return makeFuture(-1); + }); + EXPECT_FLAG(); + EXPECT_THROW(f.value(), eggs_t); + } + + // exception_wrapper, return T + { + auto f = makeFuture() + .then([]{ throw eggs; return 0; }) + .onError([&] (exception_wrapper e) { + flag(); + return -1; + }); + EXPECT_FLAG(); + EXPECT_EQ(-1, f.value()); + } + + // exception_wrapper, return T but throw + { + auto f = makeFuture() + .then([]{ throw eggs; return 0; }) + .onError([&] (exception_wrapper e) { + flag(); + throw eggs; + return -1; + }); + EXPECT_FLAG(); + EXPECT_THROW(f.value(), eggs_t); + } + + // const exception_wrapper& + { + auto f = makeFuture() + .then([] { throw eggs; }) + .onError([&] (const exception_wrapper& e) { + flag(); + return makeFuture(); + }); + EXPECT_FLAG(); + EXPECT_NO_THROW(f.value()); + } + } TEST(Future, try) {