Commit 13ac1a41 authored by Dominik Charousset's avatar Dominik Charousset

Remove flattening of tuple, optional, and expected

Closes #1048 and fixes #1041
parent e44c8110
...@@ -84,6 +84,10 @@ is based on [Keep a Changelog](https://keepachangelog.com). ...@@ -84,6 +84,10 @@ is based on [Keep a Changelog](https://keepachangelog.com).
+ `illegal_escape_sequence` => `invalid_escape_sequence` + `illegal_escape_sequence` => `invalid_escape_sequence`
+ `illegal_argument` => `invalid_argument` + `illegal_argument` => `invalid_argument`
+ `illegal_category` => `invalid_category` + `illegal_category` => `invalid_category`
- CAF no longer automagically flattens `tuple`, `optional`, or `expected` when
returning these types from message handlers. Users can simply replace
`std::tuple<A, B, C>` with `caf::result<A, B, C>` for returning more than one
value from a message handler.
### Removed ### Removed
......
...@@ -43,9 +43,9 @@ chopstick::behavior_type taken_chopstick(chopstick::pointer, ...@@ -43,9 +43,9 @@ chopstick::behavior_type taken_chopstick(chopstick::pointer,
// either taken by a philosopher or available // either taken by a philosopher or available
chopstick::behavior_type available_chopstick(chopstick::pointer self) { chopstick::behavior_type available_chopstick(chopstick::pointer self) {
return { return {
[=](take_atom) -> std::tuple<taken_atom, bool> { [=](take_atom) -> result<taken_atom, bool> {
self->become(taken_chopstick(self, self->current_sender())); self->become(taken_chopstick(self, self->current_sender()));
return std::make_tuple(taken_atom_v, true); return {taken_atom_v, true};
}, },
[](put_atom) { cerr << "chopstick received unexpected 'put'" << endl; }, [](put_atom) { cerr << "chopstick received unexpected 'put'" << endl; },
}; };
...@@ -54,8 +54,8 @@ chopstick::behavior_type available_chopstick(chopstick::pointer self) { ...@@ -54,8 +54,8 @@ chopstick::behavior_type available_chopstick(chopstick::pointer self) {
chopstick::behavior_type taken_chopstick(chopstick::pointer self, chopstick::behavior_type taken_chopstick(chopstick::pointer self,
const strong_actor_ptr& user) { const strong_actor_ptr& user) {
return { return {
[](take_atom) -> std::tuple<taken_atom, bool> { [](take_atom) -> result<taken_atom, bool> {
return std::make_tuple(taken_atom_v, false); return {taken_atom_v, false};
}, },
[=](put_atom) { [=](put_atom) {
if (self->current_sender() == user) if (self->current_sender() == user)
......
...@@ -23,7 +23,7 @@ behavior ping(event_based_actor* self, actor pong_actor, int n) { ...@@ -23,7 +23,7 @@ behavior ping(event_based_actor* self, actor pong_actor, int n) {
behavior pong() { behavior pong() {
return { return {
[=](ping_atom, int x) { return std::make_tuple(pong_atom_v, x); }, [=](ping_atom, int x) { return make_result(pong_atom_v, x); },
}; };
} }
......
...@@ -35,10 +35,6 @@ public: ...@@ -35,10 +35,6 @@ public:
// nop // nop
} }
void operator()() override {
// nop
}
void operator()(error& x) override { void operator()(error& x) override {
CAF_LOG_TRACE(CAF_ARG(x)); CAF_LOG_TRACE(CAF_ARG(x));
delegate(x); delegate(x);
...@@ -49,11 +45,6 @@ public: ...@@ -49,11 +45,6 @@ public:
delegate(x); delegate(x);
} }
void operator()(const none_t& x) override {
CAF_LOG_TRACE(CAF_ARG(x));
delegate(x);
}
private: private:
void deliver(response_promise& rp, error& x) { void deliver(response_promise& rp, error& x) {
CAF_LOG_DEBUG("report error back to requesting actor"); CAF_LOG_DEBUG("report error back to requesting actor");
...@@ -68,11 +59,6 @@ private: ...@@ -68,11 +59,6 @@ private:
rp.deliver(std::move(x)); rp.deliver(std::move(x));
} }
void deliver(response_promise& rp, const none_t&) {
error err = sec::unexpected_response;
deliver(rp, err);
}
template <class T> template <class T>
void delegate(T& x) { void delegate(T& x) {
auto rp = self_->make_response_promise(); auto rp = self_->make_response_promise();
......
...@@ -25,7 +25,6 @@ ...@@ -25,7 +25,6 @@
#include "caf/detail/int_list.hpp" #include "caf/detail/int_list.hpp"
#include "caf/detail/overload.hpp" #include "caf/detail/overload.hpp"
#include "caf/detail/type_traits.hpp" #include "caf/detail/type_traits.hpp"
#include "caf/expected.hpp"
#include "caf/fwd.hpp" #include "caf/fwd.hpp"
#include "caf/make_sink_result.hpp" #include "caf/make_sink_result.hpp"
#include "caf/make_source_result.hpp" #include "caf/make_source_result.hpp"
...@@ -51,48 +50,14 @@ public: ...@@ -51,48 +50,14 @@ public:
// -- virtual handlers ------------------------------------------------------- // -- virtual handlers -------------------------------------------------------
/// Called whenever no result messages gets produced, e.g., when returning a
/// `response_promise`.
virtual void operator()() = 0;
/// Called if the message handler returned an error. /// Called if the message handler returned an error.
virtual void operator()(error&) = 0; virtual void operator()(error&) = 0;
/// Called if the message handler returned any "ordinary" value. /// Called if the message handler returned any "ordinary" value.
virtual void operator()(message&) = 0; virtual void operator()(message&) = 0;
/// Called if the message handler returns "nothing", for example a
/// default-constructed `optional<T>`.
virtual void operator()(const none_t&) = 0;
// -- on-the-fly type conversions -------------------------------------------- // -- on-the-fly type conversions --------------------------------------------
/// Called if the message handler returns `void` or `unit_t`.
inline void operator()(const unit_t&) {
message empty_msg;
(*this)(empty_msg);
}
/// Unwraps an `optional<T>` by recursively calling the visitor with either
/// `none_t` or `T`.
template <class T>
void operator()(optional<T>& x) {
if (x)
(*this)(*x);
else
(*this)(none);
}
/// Unwraps an `expected<T>` by recursively calling the visitor with either
/// `error` or `T`.
template <class T>
void operator()(expected<T>& x) {
if (x)
(*this)(*x);
else
(*this)(x.error());
}
/// Wraps arbitrary values into a `message` and calls the visitor recursively. /// Wraps arbitrary values into a `message` and calls the visitor recursively.
template <class... Ts> template <class... Ts>
void operator()(Ts&... xs) { void operator()(Ts&... xs) {
...@@ -103,70 +68,56 @@ public: ...@@ -103,70 +68,56 @@ public:
(*this)(tmp); (*this)(tmp);
} }
/// Wraps the tuple into a `message` and calls the visitor recursively with /// Called if the message handler returns `void` or `unit_t`.
/// its contents. void operator()(const unit_t&) {
template <class... Ts> message empty_msg;
void operator()(std::tuple<Ts...>& xs) { (*this)(empty_msg);
apply_args(*this, get_indices(xs), xs);
}
/// Disambiguates the variadic `operator<Ts...>()`.
inline void operator()(none_t& x) {
(*this)(const_cast<const none_t&>(x));
} }
/// Disambiguates the variadic `operator<Ts...>()`. /// Disambiguates the variadic `operator<Ts...>()`.
inline void operator()(unit_t& x) { void operator()(unit_t& x) {
(*this)(const_cast<const unit_t&>(x)); (*this)(const_cast<const unit_t&>(x));
} }
// -- special-purpose handlers that don't produce results -------------------- // -- special-purpose handlers that don't produce results --------------------
/// Calls `(*this)()`. void operator()(response_promise&) {
inline void operator()(response_promise&) { // nop
(*this)();
} }
/// Calls `(*this)()`.
template <class... Ts> template <class... Ts>
void operator()(typed_response_promise<Ts...>&) { void operator()(typed_response_promise<Ts...>&) {
(*this)(); // nop
} }
/// Calls `(*this)()`.
template <class... Ts> template <class... Ts>
void operator()(delegated<Ts...>&) { void operator()(delegated<Ts...>&) {
(*this)(); // nop
} }
/// Calls `(*this)()`.
template <class Out, class... Ts> template <class Out, class... Ts>
void operator()(outbound_stream_slot<Out, Ts...>&) { void operator()(outbound_stream_slot<Out, Ts...>&) {
(*this)(); // nop
} }
/// Calls `(*this)()`.
template <class In> template <class In>
void operator()(inbound_stream_slot<In>&) { void operator()(inbound_stream_slot<In>&) {
(*this)(); // nop
} }
/// Calls `(*this)()`.
template <class In> template <class In>
void operator()(make_sink_result<In>&) { void operator()(make_sink_result<In>&) {
(*this)(); // nop
} }
/// Calls `(*this)()`.
template <class DownstreamManager, class... Ts> template <class DownstreamManager, class... Ts>
void operator()(make_source_result<DownstreamManager, Ts...>&) { void operator()(make_source_result<DownstreamManager, Ts...>&) {
(*this)(); // nop
} }
/// Calls `(*this)()`.
template <class In, class DownstreamManager, class... Ts> template <class In, class DownstreamManager, class... Ts>
void operator()(make_stage_result<In, DownstreamManager, Ts...>&) { void operator()(make_stage_result<In, DownstreamManager, Ts...>&) {
(*this)(); // nop
} }
// -- visit API: return true if T was visited, false if T was skipped -------- // -- visit API: return true if T was visited, false if T was skipped --------
...@@ -179,22 +130,19 @@ public: ...@@ -179,22 +130,19 @@ public:
} }
/// Returns `false`. /// Returns `false`.
inline bool visit(skip_t&) { bool visit(skip_t&) {
return false; return false;
} }
/// Returns `false`. /// Returns `false`.
inline bool visit(const skip_t&) { bool visit(const skip_t&) {
return false; return false;
} }
/// Returns `false` if `x != none`, otherwise calls the void handler and /// Returns `false` if `x != none`, otherwise calls the void handler and
/// returns `true`.. /// returns `true`..
inline bool visit(optional<skip_t>& x) { bool visit(optional<skip_t>& x) {
if (x) return static_cast<bool>(x);
return false;
(*this)();
return true;
} }
/// Dispatches on the runtime-type of `x`. /// Dispatches on the runtime-type of `x`.
...@@ -206,7 +154,6 @@ public: ...@@ -206,7 +154,6 @@ public:
return true; return true;
}, },
[this](delegated<Ts...>&) { [this](delegated<Ts...>&) {
(*this)();
return true; return true;
}, },
[this](skip_t&) { return false; }); [this](skip_t&) { return false; });
......
...@@ -236,6 +236,15 @@ public: ...@@ -236,6 +236,15 @@ public:
} }
}; };
// -- free functions -----------------------------------------------------------
/// Convenience function for wrapping the parameter pack `xs...` into a
/// `result`.
template <class... Ts>
auto make_result(Ts&&... xs) {
return result<std::decay_t<Ts>...>(std::forward<Ts>(xs)...);
}
// -- sum type access to result<Ts...> ----------------------------------------- // -- sum type access to result<Ts...> -----------------------------------------
template <class... Ts> template <class... Ts>
......
...@@ -158,7 +158,7 @@ behavior spawn_serv_impl(stateful_actor<spawn_serv_state>* self) { ...@@ -158,7 +158,7 @@ behavior spawn_serv_impl(stateful_actor<spawn_serv_state>* self) {
CAF_LOG_TRACE(""); CAF_LOG_TRACE("");
return { return {
[=](spawn_atom, const std::string& name, message& args, [=](spawn_atom, const std::string& name, message& args,
actor_system::mpi& xs) -> expected<strong_actor_ptr> { actor_system::mpi& xs) -> result<strong_actor_ptr> {
CAF_LOG_TRACE(CAF_ARG(name) << CAF_ARG(args)); CAF_LOG_TRACE(CAF_ARG(name) << CAF_ARG(args));
return self->system().spawn<strong_actor_ptr>(name, std::move(args), return self->system().spawn<strong_actor_ptr>(name, std::move(args),
self->context(), true, &xs); self->context(), true, &xs);
......
...@@ -53,10 +53,6 @@ class maybe_message_visitor : public detail::invoke_result_visitor { ...@@ -53,10 +53,6 @@ class maybe_message_visitor : public detail::invoke_result_visitor {
public: public:
optional<message> value; optional<message> value;
void operator()() override {
value = message{};
}
void operator()(error& x) override { void operator()(error& x) override {
value = make_message(std::move(x)); value = make_message(std::move(x));
} }
...@@ -64,10 +60,6 @@ public: ...@@ -64,10 +60,6 @@ public:
void operator()(message& x) override { void operator()(message& x) override {
value = std::move(x); value = std::move(x);
} }
void operator()(const none_t&) override {
(*this)();
}
}; };
} // namespace } // namespace
......
...@@ -1100,10 +1100,6 @@ scheduled_actor::handle_open_stream_msg(mailbox_element& x) { ...@@ -1100,10 +1100,6 @@ scheduled_actor::handle_open_stream_msg(mailbox_element& x) {
CAF_LOG_TRACE(CAF_ARG(x)); CAF_LOG_TRACE(CAF_ARG(x));
// Fetches a stream manager from a behavior. // Fetches a stream manager from a behavior.
struct visitor : detail::invoke_result_visitor { struct visitor : detail::invoke_result_visitor {
void operator()() override {
// nop
}
void operator()(error&) override { void operator()(error&) override {
// nop // nop
} }
...@@ -1111,10 +1107,6 @@ scheduled_actor::handle_open_stream_msg(mailbox_element& x) { ...@@ -1111,10 +1107,6 @@ scheduled_actor::handle_open_stream_msg(mailbox_element& x) {
void operator()(message&) override { void operator()(message&) override {
// nop // nop
} }
void operator()(const none_t&) override {
// nop
}
}; };
// Extract the handshake part of the message. // Extract the handshake part of the message.
CAF_ASSERT(x.content().match_elements<open_stream_msg>()); CAF_ASSERT(x.content().match_elements<open_stream_msg>());
......
...@@ -42,7 +42,9 @@ using second_stage = typed_actor<replies_to<double, double>::with<double>>; ...@@ -42,7 +42,9 @@ using second_stage = typed_actor<replies_to<double, double>::with<double>>;
first_stage::behavior_type typed_first_stage() { first_stage::behavior_type typed_first_stage() {
return { return {
[](int i) { return std::make_tuple(i * 2.0, i * 4.0); }, [](int i) -> result<double, double> {
return {i * 2.0, i * 4.0};
},
}; };
} }
......
...@@ -370,7 +370,7 @@ CAF_TEST(spawn_event_testee2_test) { ...@@ -370,7 +370,7 @@ CAF_TEST(spawn_event_testee2_test) {
CAF_TEST(function_spawn) { CAF_TEST(function_spawn) {
scoped_actor self{system}; scoped_actor self{system};
auto f = [](const std::string& name) -> behavior { auto f = [](const std::string& name) -> behavior {
return ([name](get_atom) { return std::make_tuple(name_atom_v, name); }); return ([name](get_atom) { return make_result(name_atom_v, name); });
}; };
auto a1 = system.spawn(f, "alice"); auto a1 = system.spawn(f, "alice");
auto a2 = system.spawn(f, "bob"); auto a2 = system.spawn(f, "bob");
......
...@@ -45,9 +45,9 @@ calculator::behavior_type multiplier() { ...@@ -45,9 +45,9 @@ calculator::behavior_type multiplier() {
calculator::behavior_type divider() { calculator::behavior_type divider() {
return { return {
[](int x, int y) -> optional<int> { [](int x, int y) -> result<int> {
if (y == 0) if (y == 0)
return none; return make_error(sec::runtime_error, "division by zero");
return x / y; return x / y;
}, },
}; };
...@@ -57,7 +57,9 @@ using doubler = typed_actor<replies_to<int>::with<int, int>>; ...@@ -57,7 +57,9 @@ using doubler = typed_actor<replies_to<int>::with<int, int>>;
doubler::behavior_type simple_doubler() { doubler::behavior_type simple_doubler() {
return { return {
[](int x) { return std::make_tuple(x, x); }, [](int x) -> result<int, int> {
return {x, x};
},
}; };
} }
......
...@@ -365,7 +365,7 @@ CAF_TEST(sending_typed_actors_and_down_msg) { ...@@ -365,7 +365,7 @@ CAF_TEST(sending_typed_actors_and_down_msg) {
CAF_TEST(check_signature) { CAF_TEST(check_signature) {
using foo_type = typed_actor<replies_to<put_atom>::with<ok_atom>>; using foo_type = typed_actor<replies_to<put_atom>::with<ok_atom>>;
using foo_result_type = optional<ok_atom>; using foo_result_type = result<ok_atom>;
using bar_type = typed_actor<reacts_to<ok_atom>>; using bar_type = typed_actor<reacts_to<ok_atom>>;
auto foo_action = [](foo_type::pointer ptr) -> foo_type::behavior_type { auto foo_action = [](foo_type::pointer ptr) -> foo_type::behavior_type {
return { return {
......
...@@ -366,8 +366,7 @@ behavior basp_broker::make_behavior() { ...@@ -366,8 +366,7 @@ behavior basp_broker::make_behavior() {
return unit; return unit;
return sec::cannot_close_invalid_port; return sec::cannot_close_invalid_port;
}, },
[=](get_atom, [=](get_atom, const node_id& x) -> result<node_id, std::string, uint16_t> {
const node_id& x) -> std::tuple<node_id, std::string, uint16_t> {
std::string addr; std::string addr;
uint16_t port = 0; uint16_t port = 0;
auto hdl = instance.tbl().lookup_direct(x); auto hdl = instance.tbl().lookup_direct(x);
...@@ -375,7 +374,7 @@ behavior basp_broker::make_behavior() { ...@@ -375,7 +374,7 @@ behavior basp_broker::make_behavior() {
addr = remote_addr(*hdl); addr = remote_addr(*hdl);
port = remote_port(*hdl); port = remote_port(*hdl);
} }
return std::make_tuple(x, std::move(addr), port); return {x, std::move(addr), port};
}, },
[=](tick_atom, size_t interval) { [=](tick_atom, size_t interval) {
instance.handle_heartbeat(context()); instance.handle_heartbeat(context());
......
...@@ -126,11 +126,11 @@ behavior peer_acceptor_fun(broker* self, const actor& buddy) { ...@@ -126,11 +126,11 @@ behavior peer_acceptor_fun(broker* self, const actor& buddy) {
self->fork(peer_fun, msg.handle, buddy); self->fork(peer_fun, msg.handle, buddy);
self->quit(); self->quit();
}, },
[=](publish_atom) -> expected<uint16_t> { [=](publish_atom) -> result<uint16_t> {
auto res = self->add_tcp_doorman(8080); if (auto res = self->add_tcp_doorman(8080))
if (!res)
return std::move(res.error());
return res->second; return res->second;
else
return std::move(res.error());
}, },
}; };
} }
......
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