Commit eecbf4ec authored by ufownl's avatar ufownl

Forwarding to and from typed actors

Relates #319.
parent 7ede7f2a
......@@ -24,6 +24,7 @@
#include "caf/typed_response_promise.hpp"
#include "caf/detail/type_list.hpp"
#include "caf/detail/delegate_helper.hpp"
#include "caf/detail/typed_actor_util.hpp"
namespace caf {
......@@ -75,6 +76,16 @@ struct ctm_cmp<typed_mpi<In, L, R>,
typed_mpi<In, type_list<typed_response_promise<either_or_t<L, R>>>, empty_type_list>>
: std::true_type { };
template <class In, class Out>
struct ctm_cmp<typed_mpi<In, Out, empty_type_list>,
typed_mpi<In, type_list<delegate_helper<>>, empty_type_list>>
: std::true_type { };
template <class In, class L, class R>
struct ctm_cmp<typed_mpi<In, L, R>,
typed_mpi<In, type_list<delegate_helper<either_or_t<L, R>>>, empty_type_list>>
: std::true_type { };
/*
template <class In, class L, class R>
struct ctm_cmp<typed_mpi<In, L, R>,
......
/******************************************************************************
* ____ _ _____ *
* / ___| / \ | ___| C++ *
* | | / _ \ | |_ Actor *
* | |___ / ___ \| _| Framework *
* \____/_/ \_|_| *
* *
* Copyright (C) 2011 - 2015 *
* Dominik Charousset <dominik.charousset (at) haw-hamburg.de> *
* *
* Distributed under the terms and conditions of the BSD 3-Clause License or *
* (at your option) under the terms and conditions of the Boost Software *
* License 1.0. See accompanying files LICENSE and LICENSE_ALTERNATIVE. *
* *
* If you did not receive a copy of the license files, see *
* http://opensource.org/licenses/BSD-3-Clause and *
* http://www.boost.org/LICENSE_1_0.txt. *
******************************************************************************/
#ifndef CAF_DETAIL_DELEGATE_HELPER_HPP
#define CAF_DETAIL_DELEGATE_HELPER_HPP
namespace caf {
namespace detail {
/// Helper class to indicate that this has been
/// properly forwarded in typed actors.
template <class... Ts>
struct delegate_helper {
// nop
};
} // namespace detail
} // namespace caf
#endif // CAF_DETAIL_DELEGATE_HELPER_HPP
......@@ -53,6 +53,7 @@
#include "caf/detail/logging.hpp"
#include "caf/detail/disposer.hpp"
#include "caf/detail/behavior_stack.hpp"
#include "caf/detail/delegate_helper.hpp"
#include "caf/detail/typed_actor_util.hpp"
#include "caf/detail/single_reader_queue.hpp"
#include "caf/detail/memory_cache_flag_type.hpp"
......@@ -459,6 +460,80 @@ public:
void forward_message(const actor& dest, message_priority mp);
template <class... Ts>
detail::delegate_helper<>
delegate(message_priority mp, const actor& dest, Ts&&... xs) {
static_assert(sizeof...(Ts) > 0, "no message to send");
if (! dest) {
return {};
}
auto mid = current_element_->mid;
current_element_->mid = mp == message_priority::high
? mid.with_high_priority()
: mid.with_normal_priority();
current_element_->msg = make_message(std::forward<Ts>(xs)...);
dest->enqueue(std::move(current_element_), host());
return {};
}
template <class... Ts>
detail::delegate_helper<> delegate(const actor& dest, Ts&&... xs) {
return delegate(message_priority::normal,
dest, std::forward<Ts>(xs)...);
}
template <class... DestSigs, class... Ts>
detail::delegate_helper<
either_or_t<
typename detail::deduce_output_type<
detail::type_list<DestSigs...>,
detail::type_list<
typename detail::implicit_conversions<
typename std::decay<Ts>::type
>::type...
>
>::type::first,
typename detail::deduce_output_type<
detail::type_list<DestSigs...>,
detail::type_list<
typename detail::implicit_conversions<
typename std::decay<Ts>::type
>::type...
>
>::type::second
>
> delegate(message_priority mp,
const typed_actor<DestSigs...>& dest,
Ts&&... xs) {
static_assert(sizeof...(Ts) > 0, "no message to send");
using token =
detail::type_list<
typename detail::implicit_conversions<
typename std::decay<Ts>::type
>::type...>;
token tk;
check_typed_input(dest, tk);
if (! dest) {
return {};
}
auto mid = current_element_->mid;
current_element_->mid = mp == message_priority::high
? mid.with_high_priority()
: mid.with_normal_priority();
current_element_->msg = make_message(std::forward<Ts>(xs)...);
dest->enqueue(std::move(current_element_), host());
return {};
}
template <class... DestSigs, class... Ts>
auto delegate(const typed_actor<DestSigs...>& dest,
Ts&&... xs) -> decltype(delegate(message_priority::normal,
dest,
std::forward<Ts>(xs)...)) {
return delegate(message_priority::normal,
dest, std::forward<Ts>(xs)...);
}
inline uint32_t planned_exit_reason() const {
return planned_exit_reason_;
}
......@@ -594,7 +669,7 @@ private:
host());
}
void send_impl(message_id mp, abstract_channel* dest, message what) const;
void send_impl(message_id mid, abstract_channel* dest, message what) const;
void delayed_send_impl(message_id mid, const channel& whom,
const duration& rtime, message data);
......
......@@ -203,6 +203,33 @@ void simple_relay(string_actor::pointer self, string_actor master, bool leaf) {
});
}
void simple_relay_delegate(string_actor::pointer self, string_actor master, bool leaf) {
string_actor next =
leaf ? spawn_typed(simple_relay_delegate, master, false) : master;
self->link_to(next);
self->become(
[=](const string& str) {
return self->delegate(next, str);
});
}
void dynamic_relay_delegate(string_actor::pointer self, actor master, bool leaf) {
if (leaf) {
auto next = spawn_typed(dynamic_relay_delegate, master, false);
self->link_to(next);
self->become(
[=](const string& str) {
return self->delegate(next, str);
});
} else {
self->link_to(master);
self->become(
[=](const string& str) {
return self->delegate(master, str);
});
}
}
string_actor::behavior_type simple_string_reverter() {
return {
[](const string& str) {
......@@ -211,6 +238,14 @@ string_actor::behavior_type simple_string_reverter() {
};
}
behavior dynamic_string_reverter() {
return {
[](const string& str) {
return string{str.rbegin(), str.rend()};
}
};
}
/******************************************************************************
* sending typed actor handles *
******************************************************************************/
......@@ -356,6 +391,36 @@ CAF_TEST(test_simple_string_reverter) {
anon_send_exit(aut, exit_reason::user_shutdown);
}
CAF_TEST(test_simple_string_reverter_delegate) {
// run test series with string reverter
scoped_actor self;
// actor-under-test
auto aut = self->spawn_typed<monitored>(simple_relay_delegate,
spawn_typed(simple_string_reverter),
true);
set<string> iface{"caf::replies_to<@str>::with<@str>"};
CAF_CHECK(aut->message_types() == iface);
self->sync_send(aut, "Hello World!").await([](const string& answer) {
CAF_CHECK_EQUAL(answer, "!dlroW olleH");
});
anon_send_exit(aut, exit_reason::user_shutdown);
}
CAF_TEST(test_dynamic_string_reverter_delegate) {
// run test series with string reverter
scoped_actor self;
// actor-under-test
auto aut = self->spawn_typed<monitored>(dynamic_relay_delegate,
spawn(dynamic_string_reverter),
true);
set<string> iface{"caf::replies_to<@str>::with<@str>"};
CAF_CHECK(aut->message_types() == iface);
self->sync_send(aut, "Hello World!").await([](const string& answer) {
CAF_CHECK_EQUAL(answer, "!dlroW olleH");
});
anon_send_exit(aut, exit_reason::user_shutdown);
}
CAF_TEST(test_sending_typed_actors) {
scoped_actor self;
auto aut = spawn_typed(int_fun);
......
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