Commit ffed360f authored by Dominik Charousset's avatar Dominik Charousset

fixed several issues with typed actors

parent 3b25a510
......@@ -31,9 +31,11 @@
#ifndef CPPA_ABSTRACT_ACTOR_HPP
#define CPPA_ABSTRACT_ACTOR_HPP
#include <set>
#include <mutex>
#include <atomic>
#include <memory>
#include <string>
#include <vector>
#include <cstdint>
#include <type_traits>
......@@ -119,7 +121,10 @@ class abstract_actor : public abstract_channel {
/**
* @copydoc abstract_actor::link_to(const actor_addr&)
*/
void link_to(const actor& whom);
template<typename ActorHandle>
void link_to(const ActorHandle& whom) {
link_to(whom.address());
}
/**
* @brief Unlinks this actor from @p whom.
......@@ -131,7 +136,10 @@ class abstract_actor : public abstract_channel {
/**
* @copydoc abstract_actor::unlink_from(const actor_addr&)
*/
void unlink_from(const actor& whom);
template<class ActorHandle>
void unlink_from(const ActorHandle& whom) {
unlink_from(whom.address());
}
/**
* @brief Establishes a link relation between this actor and @p other.
......@@ -174,6 +182,12 @@ class abstract_actor : public abstract_channel {
*/
inline std::uint32_t exit_reason() const;
/**
* @brief Returns the type interface as set of strings.
* @note The returned set is empty for all untyped actors.
*/
virtual std::set<std::string> interface() const;
protected:
abstract_actor();
......
......@@ -484,7 +484,8 @@ void anon_send_exit(const actor_addr& whom, std::uint32_t reason);
/**
* @brief Anonymously sends @p whom an exit message.
*/
inline void anon_send_exit(const actor& whom, std::uint32_t reason) {
template<typename ActorHandle>
inline void anon_send_exit(const ActorHandle& whom, std::uint32_t reason) {
anon_send_exit(whom.address(), reason);
}
......@@ -548,10 +549,10 @@ actor remote_actor(io::stream_ptr_pair connection);
* @brief Spawns an IO actor of type @p Impl.
* @param args Constructor arguments.
* @tparam Impl Subtype of {@link io::broker}.
* @tparam Options Optional flags to modify <tt>spawn</tt>'s behavior.
* @tparam Os Optional flags to modify <tt>spawn</tt>'s behavior.
* @returns An {@link actor_ptr} to the spawned {@link actor}.
*/
template<class Impl, spawn_options Options = no_spawn_options, typename... Ts>
template<class Impl, spawn_options Os = no_spawn_options, typename... Ts>
actor spawn_io(Ts&&... args) {
auto ptr = make_counted<Impl>(std::forward<Ts>(args)...);
return {io::init_and_launch(std::move(ptr))};
......@@ -563,10 +564,10 @@ actor spawn_io(Ts&&... args) {
* @param in The actor's input stream.
* @param out The actor's output stream.
* @param args Optional arguments for @p fun.
* @tparam Options Optional flags to modify <tt>spawn</tt>'s behavior.
* @tparam Os Optional flags to modify <tt>spawn</tt>'s behavior.
* @returns A {@link actor handle} to the spawned actor.
*/
template<spawn_options Options = no_spawn_options,
template<spawn_options Os = no_spawn_options,
typename F = std::function<void (io::broker*)>,
typename... Ts>
actor spawn_io(F fun,
......@@ -578,7 +579,7 @@ actor spawn_io(F fun,
return {io::init_and_launch(std::move(ptr))};
}
template<spawn_options Options = no_spawn_options,
template<spawn_options Os = no_spawn_options,
typename F = std::function<void (io::broker*)>,
typename... Ts>
actor spawn_io(F fun, const std::string& host, uint16_t port, Ts&&... args) {
......@@ -586,13 +587,13 @@ actor spawn_io(F fun, const std::string& host, uint16_t port, Ts&&... args) {
return spawn_io(std::move(fun), ptr, ptr, std::forward<Ts>(args)...);
}
template<spawn_options Options = no_spawn_options,
template<spawn_options Os = no_spawn_options,
typename F = std::function<void (io::broker*)>,
typename... Ts>
actor spawn_io_server(F fun, uint16_t port, Ts&&... args) {
static_assert(!has_detach_flag(Options),
static_assert(!has_detach_flag(Os),
"brokers cannot be detached");
static_assert(is_unbound(Options),
static_assert(is_unbound(Os),
"top-level spawns cannot have monitor or link flag");
using namespace std;
auto ptr = io::broker::from(move(fun),
......
......@@ -44,8 +44,6 @@
namespace cppa {
class event_based_actor;
/**
* @brief A cooperatively scheduled, event-based actor implementation.
*
......
......@@ -127,13 +127,17 @@ class local_actor : public extend<abstract_actor>::with<memory_cached> {
* spawn typed actors *
**************************************************************************/
template<spawn_options Os = no_spawn_options, typename F>
typename detail::actor_handle_from_typed_behavior<
typename util::get_callable_trait<F>::result_type
template<spawn_options Os = no_spawn_options, typename F, typename... Ts>
typename detail::infer_typed_actor_handle<
typename util::get_callable_trait<F>::result_type,
typename util::tl_head<
typename util::get_callable_trait<F>::arg_types
>::type
spawn_typed(F fun) {
>::type
spawn_typed(F fun, Ts&&... args) {
constexpr auto os = make_unbound(Os);
auto res = cppa::spawn_typed<os>(std::move(fun));
auto res = cppa::spawn_typed<os>(std::move(fun),
std::forward<Ts>(args)...);
return eval_opts(Os, std::move(res));
}
......@@ -195,9 +199,9 @@ class local_actor : public extend<abstract_actor>::with<memory_cached> {
* @param whom Receiver of the message.
* @param what Message content as a tuple.
*/
template<typename... Signatures, typename... Ts>
template<typename... Rs, typename... Ts>
void send_tuple(message_priority prio,
const typed_actor<Signatures...>& whom,
const typed_actor<Rs...>& whom,
cow_tuple<Ts...> what) {
check_typed_input(whom, what);
send_tuple(prio, whom.m_ptr, any_tuple{std::move(what)});
......@@ -208,8 +212,8 @@ class local_actor : public extend<abstract_actor>::with<memory_cached> {
* @param whom Receiver of the message.
* @param what Message content as a tuple.
*/
template<typename... Signatures, typename... Ts>
void send_tuple(const typed_actor<Signatures...>& whom,
template<typename... Rs, typename... Ts>
void send_tuple(const typed_actor<Rs...>& whom,
cow_tuple<Ts...> what) {
check_typed_input(whom, what);
send_tuple_impl(message_priority::normal, whom, std::move(what));
......@@ -222,9 +226,9 @@ class local_actor : public extend<abstract_actor>::with<memory_cached> {
* @param what Message elements.
* @pre <tt>sizeof...(Ts) > 0</tt>.
*/
template<typename... Signatures, typename... Ts>
template<typename... Rs, typename... Ts>
void send(message_priority prio,
const typed_actor<Signatures...>& whom,
const typed_actor<Rs...>& whom,
cow_tuple<Ts...> what) {
send_tuple(prio, whom, make_cow_tuple(std::forward<Ts>(what)...));
}
......@@ -235,8 +239,8 @@ class local_actor : public extend<abstract_actor>::with<memory_cached> {
* @param what Message elements.
* @pre <tt>sizeof...(Ts) > 0</tt>.
*/
template<typename... Signatures, typename... Ts>
void send(const typed_actor<Signatures...>& whom, Ts... what) {
template<typename... Rs, typename... Ts>
void send(const typed_actor<Rs...>& whom, Ts... what) {
send_tuple(message_priority::normal, whom,
make_cow_tuple(std::forward<Ts>(what)...));
}
......@@ -256,8 +260,8 @@ class local_actor : public extend<abstract_actor>::with<memory_cached> {
/**
* @copydoc send_exit(const actor_addr&, std::uint32_t)
*/
template<typename... Signatures>
void send_exit(const typed_actor<Signatures...>& whom,
template<typename... Rs>
void send_exit(const typed_actor<Rs...>& whom,
std::uint32_t reason) {
send_exit(whom.address(), reason);
}
......@@ -516,9 +520,9 @@ class local_actor : public extend<abstract_actor>::with<memory_cached> {
any_tuple&& what);
// returns the response ID
template<typename... Signatures, typename... Ts>
template<typename... Rs, typename... Ts>
message_id sync_send_tuple_impl(message_priority mp,
const typed_actor<Signatures...>& whom,
const typed_actor<Rs...>& whom,
cow_tuple<Ts...>&& what) {
check_typed_input(whom, what);
return sync_send_tuple_impl(mp,
......@@ -601,11 +605,11 @@ class local_actor : public extend<abstract_actor>::with<memory_cached> {
private:
template<typename... Signatures, typename... Ts>
static void check_typed_input(const typed_actor<Signatures...>&,
template<typename... Rs, typename... Ts>
static void check_typed_input(const typed_actor<Rs...>&,
const cow_tuple<Ts...>&) {
static constexpr int input_pos = util::tl_find_if<
util::type_list<Signatures...>,
util::type_list<Rs...>,
detail::input_is<
util::type_list<Ts...>
>::template eval
......
......@@ -217,23 +217,44 @@ actor spawn_in_group(const group& grp, Ts&&... args) {
namespace detail {
template<typename... Sigs>
class functor_based_typed_actor : public typed_event_based_actor<Sigs...> {
template<typename... Rs>
class functor_based_typed_actor : public typed_event_based_actor<Rs...> {
typedef typed_event_based_actor<Sigs...> super;
typedef typed_event_based_actor<Rs...> super;
public:
typedef typed_event_based_actor<Sigs...>* pointer;
typedef typed_event_based_actor<Rs...>* pointer;
typedef typename super::behavior_type behavior_type;
typedef std::function<typed_behavior<Sigs...> ()> no_arg_fun;
typedef std::function<typed_behavior<Sigs...> (pointer)> one_arg_fun;
typedef std::function<behavior_type ()> no_arg_fun;
typedef std::function<behavior_type (pointer)> one_arg_fun1;
typedef std::function<void (pointer)> one_arg_fun2;
functor_based_typed_actor(one_arg_fun fun) : m_fun(std::move(fun)) { }
functor_based_typed_actor(one_arg_fun1 fun) {
set(std::move(fun));
}
functor_based_typed_actor(one_arg_fun2 fun) {
set(std::move(fun));
}
functor_based_typed_actor(no_arg_fun fun) {
m_fun = [fun](pointer) { return fun(); };
set(std::move(fun));
}
template<typename F, typename T, typename... Ts>
functor_based_typed_actor(F fun, T&& arg, Ts&&... args) {
typedef typename util::get_callable_trait<F>::arg_types arg_types;
constexpr bool uses_first_arg = std::is_same<
typename util::tl_head<
arg_types
>::type,
pointer
>::value;
std::integral_constant<bool, uses_first_arg> token;
bind_and_set(token, std::move(fun),
std::forward<T>(arg), std::forward<Ts>(args)...);
}
protected:
......@@ -244,45 +265,93 @@ class functor_based_typed_actor : public typed_event_based_actor<Sigs...> {
private:
one_arg_fun m_fun;
void set(one_arg_fun1 fun) {
m_fun = std::move(fun);
}
};
void set(one_arg_fun2 fun) {
m_fun = [fun](pointer ptr) {
fun(ptr);
return behavior_type{};
};
}
template<typename TypedBehavior>
struct actor_type_from_typed_behavior;
void set(no_arg_fun fun) {
m_fun = [fun](pointer) { return fun(); };
}
template<typename F, typename... Ts>
void bind_and_set(std::true_type, F fun, Ts&&... args) {
set(std::bind(fun, std::placeholders::_1, std::forward<Ts>(args)...));
}
template<typename F, typename... Ts>
void bind_and_set(std::false_type, F fun, Ts&&... args) {
set(std::bind(fun, std::forward<Ts>(args)...));
}
one_arg_fun1 m_fun;
template<typename... Signatures>
struct actor_type_from_typed_behavior<typed_behavior<Signatures...>> {
typedef functor_based_typed_actor<Signatures...> type;
};
} // namespace detail
template<class TypedBehavior, class FirstArg>
struct infer_typed_actor_base;
template<spawn_options Options, typename F>
typename detail::actor_handle_from_typed_behavior<
typename util::get_callable_trait<F>::result_type
>::type
spawn_typed(F fun) {
typedef typename detail::actor_type_from_typed_behavior<
typename util::get_callable_trait<F>::result_type
>::type
impl;
return detail::spawn_fwd_args<impl, Options>(
[&](impl*) { },
std::move(fun));
}
template<typename... Rs, class FirstArg>
struct infer_typed_actor_base<typed_behavior<Rs...>, FirstArg> {
typedef functor_based_typed_actor<Rs...> type;
};
template<typename... Rs>
struct infer_typed_actor_base<void, typed_event_based_actor<Rs...>*> {
typedef functor_based_typed_actor<Rs...> type;
};
} // namespace detail
template<class C, spawn_options Options, typename... Ts>
/**
* @brief Spawns a typed actor of type @p C.
* @param args Constructor arguments.
* @tparam C Subtype of {@link typed_event_based_actor}.
* @tparam Os Optional flags to modify <tt>spawn</tt>'s behavior.
* @returns A {@link typed_actor} handle to the spawned actor.
*/
template<class C, spawn_options Os, typename... Ts>
typename detail::actor_handle_from_signature_list<
typename C::signatures
>::type
spawn_typed(Ts&&... args) {
return detail::spawn_fwd_args<C, Options>(
return detail::spawn_fwd_args<C, Os>(
[&](C*) { },
std::forward<Ts>(args)...);
}
/**
* @brief Spawns a typed actor from a functor.
* @param args A functor followed by its arguments.
* @tparam Os Optional flags to modify <tt>spawn</tt>'s behavior.
* @returns An {@link actor} to the spawned {@link actor}.
*/
template<spawn_options Os, typename F, typename... Ts>
typename detail::infer_typed_actor_handle<
typename util::get_callable_trait<F>::result_type,
typename util::tl_head<
typename util::get_callable_trait<F>::arg_types
>::type
>::type
spawn_typed(F fun, Ts&&... args) {
typedef typename detail::infer_typed_actor_base<
typename util::get_callable_trait<F>::result_type,
typename util::tl_head<
typename util::get_callable_trait<F>::arg_types
>::type
>::type
impl;
return detail::spawn_fwd_args<impl, Os>(
[&](impl*) { },
std::move(fun), std::forward<Ts>(args)...);
}
/** @} */
} // namespace cppa
......
......@@ -45,16 +45,16 @@ namespace cppa {
* untyped actors *
******************************************************************************/
template<class Impl, spawn_options Options = no_spawn_options, typename... Ts>
template<class Impl, spawn_options Os = no_spawn_options, typename... Ts>
actor spawn(Ts&&... args);
template<spawn_options Options = no_spawn_options, typename... Ts>
template<spawn_options Os = no_spawn_options, typename... Ts>
actor spawn(Ts&&... args);
template<class Impl, spawn_options Options = no_spawn_options, typename... Ts>
template<class Impl, spawn_options Os = no_spawn_options, typename... Ts>
actor spawn_in_group(const group&, Ts&&... args);
template<spawn_options Options = no_spawn_options, typename... Ts>
template<spawn_options Os = no_spawn_options, typename... Ts>
actor spawn_in_group(const group&, Ts&&... args);
/******************************************************************************
......@@ -63,36 +63,46 @@ actor spawn_in_group(const group&, Ts&&... args);
namespace detail { // some utility
template<typename TypedBehavior>
struct actor_handle_from_typed_behavior;
template<class TypedBehavior, class FirstArg>
struct infer_typed_actor_handle;
template<typename... Signatures>
struct actor_handle_from_typed_behavior<typed_behavior<Signatures...>> {
typedef typed_actor<Signatures...> type;
// infer actor type from result type if possible
template<typename... Rs, class FirstArg>
struct infer_typed_actor_handle<typed_behavior<Rs...>, FirstArg> {
typedef typed_actor<Rs...> type;
};
// infer actor type from first argument if result type is void
template<typename... Rs>
struct infer_typed_actor_handle<void, typed_event_based_actor<Rs...>*> {
typedef typed_actor<Rs...> type;
};
template<typename SignatureList>
struct actor_handle_from_signature_list;
template<typename... Signatures>
struct actor_handle_from_signature_list<util::type_list<Signatures...>> {
typedef typed_actor<Signatures...> type;
template<typename... Rs>
struct actor_handle_from_signature_list<util::type_list<Rs...>> {
typedef typed_actor<Rs...> type;
};
} // namespace detail
template<spawn_options Options = no_spawn_options, typename F>
typename detail::actor_handle_from_typed_behavior<
typename util::get_callable_trait<F>::result_type
>::type
spawn_typed(F fun);
template<class Impl, spawn_options Options = no_spawn_options, typename... Ts>
template<class Impl, spawn_options Os = no_spawn_options, typename... Ts>
typename detail::actor_handle_from_signature_list<
typename Impl::signatures
>::type
spawn_typed(Ts&&... args);
template<spawn_options Os = no_spawn_options, typename F, typename... Ts>
typename detail::infer_typed_actor_handle<
typename util::get_callable_trait<F>::result_type,
typename util::tl_head<
typename util::get_callable_trait<F>::arg_types
>::type
>::type
spawn_typed(F fun, Ts&&... args);
} // namespace cppa
#endif // CPPA_SPAWN_FWD_HPP
......@@ -44,38 +44,43 @@ class local_actor;
struct invalid_actor_addr_t;
template<typename... Signatures>
template<typename... Rs>
class typed_event_based_actor;
/**
* @brief Identifies a strongly typed actor.
* @tparam Rs Interface as @p replies_to<...>::with<...> parameter pack.
*/
template<typename... Signatures>
class typed_actor : util::comparable<typed_actor<Signatures...>>
, util::comparable<typed_actor<Signatures...>, actor_addr>
, util::comparable<typed_actor<Signatures...>, invalid_actor_addr_t> {
template<typename... Rs>
class typed_actor : util::comparable<typed_actor<Rs...>>
, util::comparable<typed_actor<Rs...>, actor_addr>
, util::comparable<typed_actor<Rs...>, invalid_actor_addr_t> {
friend class local_actor;
// friend with all possible instantiations
template<typename...>
friend class typed_actor;
public:
/**
* @brief Identifies the behavior type actors of this kind use
* for their behavior stack.
*/
typedef typed_behavior<Signatures...> behavior_type;
typedef typed_behavior<Rs...> behavior_type;
/**
* @brief Identifies pointers to instances of this kind of actor.
*/
typedef typed_event_based_actor<Signatures...>* pointer;
typedef typed_event_based_actor<Rs...>* pointer;
/**
* @brief Identifies the base class for this kind of actor.
*/
typedef typed_event_based_actor<Signatures...> base;
typedef typed_event_based_actor<Rs...> base;
typedef util::type_list<Signatures...> signatures;
typedef util::type_list<Rs...> signatures;
typed_actor() = default;
typed_actor(typed_actor&&) = default;
......@@ -83,13 +88,13 @@ class typed_actor : util::comparable<typed_actor<Signatures...>>
typed_actor& operator=(typed_actor&&) = default;
typed_actor& operator=(const typed_actor&) = default;
template<typename... OtherSignatures>
typed_actor(const typed_actor<OtherSignatures...>& other) {
template<typename... OtherRs>
typed_actor(const typed_actor<OtherRs...>& other) {
set(std::move(other));
}
template<typename... OtherSignatures>
typed_actor& operator=(const typed_actor<OtherSignatures...>& other) {
template<typename... OtherRs>
typed_actor& operator=(const typed_actor<OtherRs...>& other) {
set(std::move(other));
return *this;
}
......@@ -99,6 +104,14 @@ class typed_actor : util::comparable<typed_actor<Signatures...>>
set(other);
}
pointer operator->() const {
return static_cast<pointer>(m_ptr.get());
}
base& operator*() const {
return static_cast<base&>(*m_ptr.get());
}
/**
* @brief Queries the address of the stored actor.
*/
......@@ -110,6 +123,10 @@ class typed_actor : util::comparable<typed_actor<Signatures...>>
return address().compare(rhs);
}
inline intptr_t compare(const typed_actor& other) const {
return compare(other.address());
}
inline intptr_t compare(const invalid_actor_addr_t&) const {
return m_ptr ? 1 : 0;
}
......@@ -122,9 +139,9 @@ class typed_actor : util::comparable<typed_actor<Signatures...>>
"'this' must be a strict subset of 'other'");
}
template<typename... OtherSignatures>
inline void set(const typed_actor<OtherSignatures...>& other) {
check_signatures<signatures, util::type_list<OtherSignatures...>>();
template<typename... OtherRs>
inline void set(const typed_actor<OtherRs...>& other) {
check_signatures<signatures, util::type_list<OtherRs...>>();
m_ptr = other.m_ptr;
}
......
......@@ -40,6 +40,9 @@ namespace cppa {
namespace detail {
template<typename... Rs>
class functor_based_typed_actor;
template<typename T>
struct match_hint_to_void {
typedef T type;
......@@ -49,18 +52,40 @@ template<>
struct match_hint_to_void<match_hint> {
typedef void type;
};
template<typename T>
struct infer_result_from_continue_helper {
typedef T type;
};
template<typename R>
struct infer_result_from_continue_helper<typed_continue_helper<R>> {
typedef R type;
};
template<class List>
struct collapse_infered_list {
typedef List type;
};
template<typename... Ts>
struct collapse_infered_list<util::type_list<util::type_list<Ts...>>> {
typedef util::type_list<Ts...> type;
};
template<typename T>
struct all_match_hints_to_void {
struct infer_response_types {
typedef typename T::input_types input_types;
typedef typename util::tl_map<
typename T::output_types,
match_hint_to_void
match_hint_to_void,
infer_result_from_continue_helper
>::type
output_types;
typedef typename replies_to_from_type_list<
input_types,
output_types
// continue_helper stores a type list,
// so we need to collapse the list here
typename collapse_infered_list<output_types>::type
>::type
type;
};
......@@ -81,22 +106,23 @@ void static_check_typed_behavior_input() {
} // namespace detail
template<typename... Signatures>
template<typename... Rs>
class typed_actor;
template<class Base, class Subtype, class BehaviorType>
class behavior_stack_based_impl;
template<typename... Signatures>
template<typename... Rs>
class typed_behavior {
template<typename... OtherSignatures>
template<typename... OtherRs>
friend class typed_actor;
template<class Base, class Subtype, class BehaviorType>
friend class behavior_stack_based_impl;
typed_behavior() = delete;
template<typename...>
friend class detail::functor_based_typed_actor;
public:
......@@ -105,7 +131,7 @@ class typed_behavior {
typed_behavior& operator=(typed_behavior&&) = default;
typed_behavior& operator=(const typed_behavior&) = default;
typedef util::type_list<Signatures...> signatures;
typedef util::type_list<Rs...> signatures;
template<typename... Cs, typename... Ts>
typed_behavior(match_expr<Cs...> expr, Ts&&... args) {
......@@ -139,6 +165,8 @@ class typed_behavior {
private:
typed_behavior() = default;
behavior& unbox() { return m_bhvr; }
template<typename... Cs>
......@@ -148,15 +176,18 @@ class typed_behavior {
detail::match_expr_has_no_guard<Cs>::value...
>::value,
"typed actors are not allowed to use guard expressions");
// returning a match_hint from a message handler does
// not send anything back, so we can consider match_hint to be void
// do some transformation before type-checking the input signatures
typedef typename util::tl_map<
util::type_list<
typename detail::deduce_signature<Cs>::type...
>,
detail::all_match_hints_to_void
// returning a match_hint from a message handler does
// not send anything back, so we can consider
// match_hint to be void
detail::infer_response_types
>::type
input;
// check types
detail::static_check_typed_behavior_input<signatures, input>();
// final (type-erasure) step
m_bhvr = std::move(expr);
......
......@@ -40,12 +40,22 @@
namespace cppa {
template<typename... Signatures>
/**
* @brief A cooperatively scheduled, event-based actor implementation
* with strong type checking.
*
* This is the recommended base class for user-defined actors and is used
* implicitly when spawning typed, functor-based actors without the
* {@link blocking_api} flag.
*
* @extends local_actor
*/
template<typename... Rs>
class typed_event_based_actor
: public extend<local_actor, typed_event_based_actor<Signatures...>>::template
: public extend<local_actor, typed_event_based_actor<Rs...>>::template
with<mailbox_based,
behavior_stack_based<
typed_behavior<Signatures...>
typed_behavior<Rs...>
>::template impl,
sync_sender<
nonblocking_response_handle_tag
......@@ -53,9 +63,13 @@ class typed_event_based_actor
public:
typedef util::type_list<Signatures...> signatures;
typedef util::type_list<Rs...> signatures;
typedef typed_behavior<Signatures...> behavior_type;
typedef typed_behavior<Rs...> behavior_type;
std::set<std::string> interface() const override {
return {detail::to_uniform_name<Rs>()...};
}
protected:
......
......@@ -85,7 +85,7 @@ struct tl_head;
template<template<typename...> class List>
struct tl_head<List<>> {
typedef empty_type_list type;
typedef void type;
};
template<template<typename...> class List, typename T0, typename... Ts>
......
......@@ -66,14 +66,6 @@ abstract_actor::abstract_actor()
: m_id(get_actor_registry()->next_id()), m_is_proxy(false)
, m_exit_reason(exit_reason::not_exited) { }
void abstract_actor::link_to(const actor& whom) {
link_to(whom.address());
}
void abstract_actor::unlink_from(const actor& whom) {
unlink_from(whom.address());
}
bool abstract_actor::link_to_impl(const actor_addr& other) {
if (other && other != this) {
guard_type guard{m_mtx};
......@@ -226,4 +218,9 @@ void abstract_actor::cleanup(std::uint32_t reason) {
}
}
std::set<std::string> abstract_actor::interface() const {
// defaults to untyped
return std::set<std::string>{};
}
} // namespace cppa
......@@ -174,7 +174,7 @@ inline void deserialize_impl(unit_t&, deserializer*) { }
void serialize_impl(const actor_addr& addr, serializer* sink) {
auto ns = sink->get_namespace();
if (ns) ns->write(sink, addr);
else throw std::runtime_error("unable to serialize actor_ptr: "
else throw std::runtime_error("unable to serialize actor_addr: "
"no actor addressing defined");
}
......
......@@ -204,7 +204,13 @@ void test_event_testee() {
self->send(et, .3f);
self->send(et, "hello again event testee!");
self->send(et, "goodbye event testee!");
self->send(et, get_state_msg{});
typed_actor<replies_to<get_state_msg>::with<string>> sub_et = et;
set<string> iface{"cppa::replies_to<get_state_msg>::with<@str>",
"cppa::replies_to<@str>::with<void>",
"cppa::replies_to<float>::with<void>",
"cppa::replies_to<@i32>::with<void>"};
CPPA_CHECK(sub_et->interface() == iface);
self->send(sub_et, get_state_msg{});
self->receive (
on_arg_match >> [&](const string& str) {
result = str;
......@@ -219,6 +225,88 @@ void test_event_testee() {
CPPA_CHECK_EQUAL(result, "wait4int");
}
/******************************************************************************
* simple 'forwarding' chain *
******************************************************************************/
typedef typed_actor<replies_to<string>::with<string>> string_actor;
void simple_relay(string_actor::pointer self, string_actor master, bool leaf) {
string_actor next = leaf ? spawn_typed(simple_relay, master, false) : master;
self->link_to(next);
self->become(
on_arg_match >> [=](const string& str) {
return self->sync_send(next, str).then(
[](const string& answer) -> string {
return answer;
}
);
}
);
}
string_actor::behavior_type simple_string_reverter() {
return {
on_arg_match >> [](const string& str) {
return string{str.rbegin(), str.rend()};
}
};
}
void test_simple_string_reverter() {
scoped_actor self;
// actor-under-test
auto aut = self->spawn_typed<monitored>(simple_relay,
spawn_typed(simple_string_reverter),
true);
set<string> iface{"cppa::replies_to<@str>::with<@str>"};
CPPA_CHECK(aut->interface() == iface);
self->sync_send(aut, "Hello World!").await(
[](const string& answer) {
CPPA_CHECK_EQUAL(answer, "!dlroW olleH");
}
);
anon_send_exit(aut, exit_reason::user_shutdown);
}
/******************************************************************************
* sending typed actor handles *
******************************************************************************/
typedef typed_actor<replies_to<int>::with<int>> int_actor;
int_actor::behavior_type int_fun() {
return {
on_arg_match >> [](int i) {
return i * i;
}
};
}
behavior foo(event_based_actor* self) {
return {
on_arg_match >> [=](int i, int_actor server) {
return self->sync_send(server, i).then(
[=](int result) -> int {
self->quit(exit_reason::normal);
return result;
}
);
}
};
}
void test_sending_typed_actors() {
scoped_actor self;
auto aut = spawn_typed(int_fun);
self->send(spawn(foo), 10, aut);
self->receive(
on_arg_match >> [](int i) {
CPPA_CHECK_EQUAL(i, 100);
}
);
self->send_exit(aut, exit_reason::user_shutdown);
}
/******************************************************************************
* put it all together *
......@@ -229,9 +317,10 @@ int main() {
// announce stuff
announce_tag<get_state_msg>();
announce<int_actor>();
announce<my_request>(&my_request::a, &my_request::b);
// run test series with typed_server*
// run test series with typed_server(1|2)
test_typed_spawn(spawn_typed(typed_server1));
CPPA_CHECKPOINT();
await_all_actors_done();
......@@ -255,117 +344,17 @@ int main() {
CPPA_CHECKPOINT();
await_all_actors_done();
// call it a day
shutdown();
/*
auto sptr = spawn_typed_server();
sync_send(sptr, my_request{2, 2}).await(
[](bool value) {
CPPA_CHECK_EQUAL(value, true);
}
);
send_exit(sptr, exit_reason::user_shutdown);
sptr = spawn_typed<typed_testee>();
sync_send(sptr, my_request{2, 2}).await(
[](bool value) {
CPPA_CHECK_EQUAL(value, true);
}
);
send_exit(sptr, exit_reason::user_shutdown);
auto ptr0 = spawn_typed(
on_arg_match >> [](double d) {
return d * d;
},
on_arg_match >> [](float f) {
return f / 2.0f;
}
);
CPPA_CHECK((std::is_same<
decltype(ptr0),
typed_actor_ptr<
replies_to<double>::with<double>,
replies_to<float>::with<float>
>
>::value));
typed_actor_ptr<replies_to<double>::with<double>> ptr0_double = ptr0;
typed_actor_ptr<replies_to<float>::with<float>> ptr0_float = ptr0;
auto ptr = spawn_typed(
on<int>() >> [] { return "wtf"; },
on<string>() >> [] { return 42; },
on<float>() >> [] { return make_cow_tuple(1, 2, 3); },
on<double>() >> [=](double d) {
return sync_send(ptr0_double, d).then(
[](double res) { return res + res; }
);
}
);
// check async messages
send(ptr0_float, 4.0f);
receive(
on_arg_match >> [](float f) {
CPPA_CHECK_EQUAL(f, 4.0f / 2.0f);
}
);
// check sync messages
sync_send(ptr0_float, 4.0f).await(
[](float f) {
CPPA_CHECK_EQUAL(f, 4.0f / 2.0f);
}
);
sync_send(ptr, 10.0).await(
[](double d) {
CPPA_CHECK_EQUAL(d, 200.0);
}
);
sync_send(ptr, 42).await(
[](const std::string& str) {
CPPA_CHECK_EQUAL(str, "wtf");
}
);
sync_send(ptr, 1.2f).await(
[](int a, int b, int c) {
CPPA_CHECK_EQUAL(a, 1);
CPPA_CHECK_EQUAL(b, 2);
CPPA_CHECK_EQUAL(c, 3);
}
);
sync_send(ptr, 1.2f).await(
[](int b, int c) {
CPPA_CHECK_EQUAL(b, 2);
CPPA_CHECK_EQUAL(c, 3);
}
);
sync_send(ptr, 1.2f).await(
[](int c) {
CPPA_CHECK_EQUAL(c, 3);
}
);
sync_send(ptr, 1.2f).await(
[] { CPPA_CHECKPOINT(); }
);
spawn([=] {
sync_send(ptr, 2.3f).then(
[] (int c) {
CPPA_CHECK_EQUAL(c, 3);
return "hello continuation";
}
).continue_with(
[] (const string& str) {
CPPA_CHECK_EQUAL(str, "hello continuation");
return 4.2;
}
).continue_with(
[=] (double d) {
CPPA_CHECK_EQUAL(d, 4.2);
send_exit(ptr0, exit_reason::user_shutdown);
send_exit(ptr, exit_reason::user_shutdown);
self->quit();
}
);
});
// run test series with string reverter
test_simple_string_reverter();
CPPA_CHECKPOINT();
await_all_actors_done();
// run test series with sending of typed actors
test_sending_typed_actors();
CPPA_CHECKPOINT();
await_all_actors_done();
// call it a day
shutdown();
*/
return CPPA_TEST_RESULT();
}
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