Commit f72ff6a5 authored by Matthias Vallentin's avatar Matthias Vallentin

Streamline response promise delivery and return

A common use case involves creating a response promise, doing some work,
and then finalizing it followed by returning from the function:

        auto rp = make_response_promise();
        // do work
        rp.deliver(..);
        return rp;

The last two statements can now be written more idiomatically:

        return rp.deliver(..);
parent 077e7d46
...@@ -46,16 +46,16 @@ public: ...@@ -46,16 +46,16 @@ public:
/// Satisfies the promise by sending a non-error response message. /// Satisfies the promise by sending a non-error response message.
template <class T, class... Ts> template <class T, class... Ts>
typename std::enable_if< typename std::enable_if<
(sizeof...(Ts) > 0) || (sizeof...(Ts) > 0) || ! std::is_convertible<T, error>::value,
! std::is_convertible<T, error>::value response_promise
>::type >::type
deliver(T&&x, Ts&&... xs) { deliver(T&&x, Ts&&... xs) {
deliver_impl(make_message(std::forward<T>(x), std::forward<Ts>(xs)...)); return deliver_impl(make_message(std::forward<T>(x), std::forward<Ts>(xs)...));
} }
/// Satisfies the promise by sending an error response message. /// Satisfies the promise by sending an error response message.
/// For non-requests, nothing is done. /// For non-requests, nothing is done.
void deliver(error x); response_promise deliver(error x);
/// Returns whether this response promise replies to an asynchronous message. /// Returns whether this response promise replies to an asynchronous message.
bool async() const; bool async() const;
...@@ -76,7 +76,7 @@ public: ...@@ -76,7 +76,7 @@ public:
private: private:
using forwarding_stack = std::vector<strong_actor_ptr>; using forwarding_stack = std::vector<strong_actor_ptr>;
void deliver_impl(message response_message); response_promise deliver_impl(message response_message);
local_actor* self_; local_actor* self_;
strong_actor_ptr source_; strong_actor_ptr source_;
......
...@@ -53,7 +53,8 @@ public: ...@@ -53,7 +53,8 @@ public:
/// Satisfies the promise by sending a non-error response message. /// Satisfies the promise by sending a non-error response message.
template <class U, class... Us> template <class U, class... Us>
typename std::enable_if< typename std::enable_if<
(sizeof...(Us) > 0) || ! std::is_convertible<U, error>::value (sizeof...(Us) > 0) || ! std::is_convertible<U, error>::value,
typed_response_promise
>::type >::type
deliver(U&& x, Us&&... xs) { deliver(U&& x, Us&&... xs) {
static_assert( static_assert(
...@@ -62,12 +63,14 @@ public: ...@@ -62,12 +63,14 @@ public:
typename std::decay<Us>::type...>>::value, typename std::decay<Us>::type...>>::value,
"typed_response_promise: message type mismatched"); "typed_response_promise: message type mismatched");
promise_.deliver(std::forward<U>(x), std::forward<Us>(xs)...); promise_.deliver(std::forward<U>(x), std::forward<Us>(xs)...);
return *this;
} }
/// Satisfies the promise by sending an error response message. /// Satisfies the promise by sending an error response message.
/// For non-requests, nothing is done. /// For non-requests, nothing is done.
inline void deliver(error x) { inline typed_response_promise deliver(error x) {
promise_.deliver(std::move(x)); promise_.deliver(std::move(x));
return *this;
} }
/// Queries whether this promise is a valid promise that is not satisfied yet. /// Queries whether this promise is a valid promise that is not satisfied yet.
......
...@@ -41,34 +41,35 @@ response_promise::response_promise(local_actor* self, mailbox_element& src) ...@@ -41,34 +41,35 @@ response_promise::response_promise(local_actor* self, mailbox_element& src)
} }
} }
void response_promise::deliver(error x) { response_promise response_promise::deliver(error x) {
//if (id_.valid()) //if (id_.valid())
deliver_impl(make_message(std::move(x))); return deliver_impl(make_message(std::move(x)));
} }
bool response_promise::async() const { bool response_promise::async() const {
return id_.is_async(); return id_.is_async();
} }
void response_promise::deliver_impl(message msg) { response_promise response_promise::deliver_impl(message msg) {
if (! stages_.empty()) { if (! stages_.empty()) {
auto next = std::move(stages_.back()); auto next = std::move(stages_.back());
stages_.pop_back(); stages_.pop_back();
next->enqueue(mailbox_element::make(std::move(source_), id_, next->enqueue(mailbox_element::make(std::move(source_), id_,
std::move(stages_), std::move(msg)), std::move(stages_), std::move(msg)),
self_->context()); self_->context());
return; return *this;
} }
if (source_) { if (source_) {
source_->enqueue(self_->ctrl(), id_.response_id(), source_->enqueue(self_->ctrl(), id_.response_id(),
std::move(msg), self_->context()); std::move(msg), self_->context());
source_.reset(); source_.reset();
return; return *this;
} }
if (self_) if (self_)
CAF_LOG_ERROR("response promise already satisfied"); CAF_LOG_ERROR("response promise already satisfied");
else else
CAF_LOG_ERROR("invalid response promise"); CAF_LOG_ERROR("invalid response promise");
return *this;
} }
} // namespace caf } // namespace caf
...@@ -54,8 +54,7 @@ public: ...@@ -54,8 +54,7 @@ public:
[=](int x) -> foo_promise { [=](int x) -> foo_promise {
auto resp = response(x * 2); auto resp = response(x * 2);
CAF_CHECK(! resp.pending()); CAF_CHECK(! resp.pending());
resp.deliver(x * 4); // has no effect return resp.deliver(x * 4); // has no effect
return resp;
}, },
[=](get_atom, int x) -> foo_promise { [=](get_atom, int x) -> foo_promise {
auto calculator = spawn([](event_based_actor* self) -> behavior { auto calculator = spawn([](event_based_actor* self) -> behavior {
...@@ -95,8 +94,7 @@ public: ...@@ -95,8 +94,7 @@ public:
}, },
[=](get_atom, double) -> foo3_promise { [=](get_atom, double) -> foo3_promise {
auto resp = make_response_promise<double>(); auto resp = make_response_promise<double>();
resp.deliver(make_error(sec::unexpected_message)); return resp.deliver(make_error(sec::unexpected_message));
return resp;
}, },
[=](get_atom, double x, double y) { [=](get_atom, double x, double y) {
return response(x * 2, y * 2); return response(x * 2, y * 2);
......
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