Commit 5e5ccb08 authored by Dominik Charousset's avatar Dominik Charousset

implemented send to typed actors

parent fe9fa2ce
...@@ -152,6 +152,7 @@ set(LIBCPPA_SRC ...@@ -152,6 +152,7 @@ set(LIBCPPA_SRC
src/channel.cpp src/channel.cpp
src/context_switching_resume.cpp src/context_switching_resume.cpp
src/continuable.cpp src/continuable.cpp
src/continue_helper.cpp
src/decorated_tuple.cpp src/decorated_tuple.cpp
src/actor_proxy.cpp src/actor_proxy.cpp
src/peer.cpp src/peer.cpp
......
...@@ -20,6 +20,7 @@ cppa/binary_serializer.hpp ...@@ -20,6 +20,7 @@ cppa/binary_serializer.hpp
cppa/blocking_actor.hpp cppa/blocking_actor.hpp
cppa/channel.hpp cppa/channel.hpp
cppa/config.hpp cppa/config.hpp
cppa/continue_helper.hpp
cppa/cow_ptr.hpp cppa/cow_ptr.hpp
cppa/cow_tuple.hpp cppa/cow_tuple.hpp
cppa/cppa.hpp cppa/cppa.hpp
...@@ -155,6 +156,7 @@ cppa/primitive_variant.hpp ...@@ -155,6 +156,7 @@ cppa/primitive_variant.hpp
cppa/qtsupport/actor_widget_mixin.hpp cppa/qtsupport/actor_widget_mixin.hpp
cppa/ref_counted.hpp cppa/ref_counted.hpp
cppa/replies_to.hpp cppa/replies_to.hpp
cppa/response_handle.hpp
cppa/response_promise.hpp cppa/response_promise.hpp
cppa/resumable.hpp cppa/resumable.hpp
cppa/sb_actor.hpp cppa/sb_actor.hpp
...@@ -256,6 +258,7 @@ src/buffer.cpp ...@@ -256,6 +258,7 @@ src/buffer.cpp
src/channel.cpp src/channel.cpp
src/context_switching_resume.cpp src/context_switching_resume.cpp
src/continuable.cpp src/continuable.cpp
src/continue_helper.cpp
src/decorated_tuple.cpp src/decorated_tuple.cpp
src/demangle.cpp src/demangle.cpp
src/deserializer.cpp src/deserializer.cpp
......
...@@ -92,7 +92,7 @@ class behavior_stack_based : public single_timeout<Base, Subtype> { ...@@ -92,7 +92,7 @@ class behavior_stack_based : public single_timeout<Base, Subtype> {
return m_bhvr_stack; return m_bhvr_stack;
} }
inline optional<behavior&> sync_handler(message_id msg_id) { optional<behavior&> sync_handler(message_id msg_id) override {
return m_bhvr_stack.sync_handler(msg_id); return m_bhvr_stack.sync_handler(msg_id);
} }
......
...@@ -34,87 +34,32 @@ ...@@ -34,87 +34,32 @@
#include "cppa/on.hpp" #include "cppa/on.hpp"
#include "cppa/extend.hpp" #include "cppa/extend.hpp"
#include "cppa/behavior.hpp" #include "cppa/behavior.hpp"
#include "cppa/typed_actor.hpp"
#include "cppa/local_actor.hpp" #include "cppa/local_actor.hpp"
#include "cppa/mailbox_based.hpp" #include "cppa/mailbox_based.hpp"
#include "cppa/mailbox_element.hpp" #include "cppa/mailbox_element.hpp"
#include "cppa/response_handle.hpp"
#include "cppa/detail/response_handle_util.hpp" #include "cppa/detail/response_handle_util.hpp"
namespace cppa { namespace cppa {
/** /**
* @brief A thread-mapped or context-switching actor using a blocking
* receive rather than a behavior-stack based message processing.
* @extends local_actor * @extends local_actor
*/ */
class blocking_actor : public extend<local_actor>::with<mailbox_based> { class blocking_actor : public extend<local_actor>::with<mailbox_based> {
public: public:
class response_handle { typedef blocking_response_handle_tag response_handle_tag;
public: typedef response_handle<blocking_actor> response_handle_type;
response_handle() = delete;
void await(behavior&);
inline void await(behavior&& bhvr) {
behavior arg{std::move(bhvr)};
await(arg);
}
/**
* @brief Blocks until the response arrives and then executes @p mexpr.
*/
template<typename... Cs, typename... Ts>
void await(const match_expr<Cs...>& arg, const Ts&... args) {
await(match_expr_convert(arg, args...));
}
/**
* @brief Blocks until the response arrives and then executes @p @p fun,
* calls <tt>self->handle_sync_failure()</tt> if the response
* message is an 'EXITED' or 'VOID' message.
*/
template<typename... Fs>
typename std::enable_if<util::all_callable<Fs...>::value>::type
await(Fs... fs) {
await(detail::fs2bhvr(m_self, fs...));
}
/**
* @brief Returns the awaited response ID.
*/
inline const message_id& id() const { return m_mid; }
response_handle(const response_handle&) = default;
response_handle& operator=(const response_handle&) = default;
inline response_handle(const message_id& from, blocking_actor* self)
: m_mid(from), m_self(self) { }
private:
message_id m_mid;
blocking_actor* m_self;
};
class sync_receive_helper {
public:
inline sync_receive_helper(const response_handle& mf) : m_mf(mf) { }
template<typename... Ts>
inline void operator()(Ts&&... args) {
m_mf.await(std::forward<Ts>(args)...);
}
private:
response_handle m_mf;
}; /**************************************************************************
* sync_send[_tuple](actor, ...) *
**************************************************************************/
/** /**
* @brief Sends @p what as a synchronous message to @p whom. * @brief Sends @p what as a synchronous message to @p whom.
...@@ -125,11 +70,15 @@ class blocking_actor : public extend<local_actor>::with<mailbox_based> { ...@@ -125,11 +70,15 @@ class blocking_actor : public extend<local_actor>::with<mailbox_based> {
* sent message cannot be received by another actor. * sent message cannot be received by another actor.
* @throws std::invalid_argument if <tt>whom == nullptr</tt> * @throws std::invalid_argument if <tt>whom == nullptr</tt>
*/ */
response_handle sync_send_tuple(const actor& dest, any_tuple what); inline response_handle_type sync_send_tuple(message_priority prio,
response_handle timed_sync_send_tuple(const util::duration& rtime,
const actor& dest, const actor& dest,
any_tuple what); any_tuple what) {
return {sync_send_tuple_impl(prio, dest, std::move(what)), this};
}
inline response_handle_type sync_send_tuple(const actor& dest, any_tuple what) {
return sync_send_tuple(message_priority::normal, dest, std::move(what));
}
/** /**
* @brief Sends <tt>{what...}</tt> as a synchronous message to @p whom. * @brief Sends <tt>{what...}</tt> as a synchronous message to @p whom.
...@@ -142,13 +91,35 @@ class blocking_actor : public extend<local_actor>::with<mailbox_based> { ...@@ -142,13 +91,35 @@ class blocking_actor : public extend<local_actor>::with<mailbox_based> {
* @throws std::invalid_argument if <tt>whom == nullptr</tt> * @throws std::invalid_argument if <tt>whom == nullptr</tt>
*/ */
template<typename... Ts> template<typename... Ts>
inline response_handle sync_send(const actor& dest, Ts&&... what) { inline response_handle_type sync_send(message_priority prio,
const actor& dest, Ts&&... what) {
static_assert(sizeof...(Ts) > 0, "no message to send"); static_assert(sizeof...(Ts) > 0, "no message to send");
return sync_send_tuple(dest, make_any_tuple(std::forward<Ts>(what)...)); return sync_send_tuple(prio, dest,
make_any_tuple(std::forward<Ts>(what)...));
} }
template<typename... Ts> template<typename... Ts>
response_handle timed_sync_send(const actor& dest, inline response_handle_type sync_send(const actor& dest, Ts&&... what) {
static_assert(sizeof...(Ts) > 0, "no message to send");
return sync_send_tuple(message_priority::normal,
dest, make_any_tuple(std::forward<Ts>(what)...));
}
/**************************************************************************
* timed_sync_send[_tuple](actor, ...) *
**************************************************************************/
inline response_handle_type timed_sync_send_tuple(const util::duration& rtime,
const actor& dest,
any_tuple what) {
return {timed_sync_send_tuple_impl(message_priority::normal,
dest, rtime, std::move(what)),
this};
}
template<typename... Ts>
response_handle_type timed_sync_send(const actor& dest,
const util::duration& rtime, const util::duration& rtime,
Ts&&... what) { Ts&&... what) {
static_assert(sizeof...(Ts) > 0, "no message to send"); static_assert(sizeof...(Ts) > 0, "no message to send");
...@@ -156,6 +127,27 @@ class blocking_actor : public extend<local_actor>::with<mailbox_based> { ...@@ -156,6 +127,27 @@ class blocking_actor : public extend<local_actor>::with<mailbox_based> {
make_any_tuple(std::forward<Ts>(what)...)); make_any_tuple(std::forward<Ts>(what)...));
} }
/**************************************************************************
* sync_send[_tuple](typed_actor<...>, ...) *
**************************************************************************/
template<typename... Rs, typename... Ts>
inline response_handle_type sync_send_tuple(message_priority prio,
const typed_actor<Rs...>& dest,
cow_tuple<Ts...> what) {
return {sync_send_tuple_impl(prio, dest, std::move(what)), this};
}
template<typename... Rs, typename... Ts>
inline response_handle_type sync_send_tuple(const typed_actor<Rs...>& dest,
cow_tuple<Ts...> what) {
return sync_send_tuple(message_priority::normal, dest, std::move(what));
}
/**************************************************************************
* utility stuff and receive() member function family *
**************************************************************************/
typedef std::chrono::high_resolution_clock::time_point timeout_type; typedef std::chrono::high_resolution_clock::time_point timeout_type;
struct receive_while_helper { struct receive_while_helper {
...@@ -267,18 +259,6 @@ class blocking_actor : public extend<local_actor>::with<mailbox_based> { ...@@ -267,18 +259,6 @@ class blocking_actor : public extend<local_actor>::with<mailbox_based> {
return {make_dequeue_callback(), stmt}; return {make_dequeue_callback(), stmt};
} }
/**
* @brief Handles a synchronous response message in an event-based way.
* @param handle A future for a synchronous response.
* @throws std::logic_error if @p handle is not valid or if the actor
* already received the response for @p handle
* @relates response_handle
*/
inline sync_receive_helper receive_response(const response_handle& f) {
return {f};
}
/** /**
* @brief Receives messages until @p stmt returns true. * @brief Receives messages until @p stmt returns true.
* *
...@@ -304,44 +284,58 @@ class blocking_actor : public extend<local_actor>::with<mailbox_based> { ...@@ -304,44 +284,58 @@ class blocking_actor : public extend<local_actor>::with<mailbox_based> {
, match_expr_convert(std::forward<Ts>(args)...)}; , match_expr_convert(std::forward<Ts>(args)...)};
} }
inline optional<behavior&> sync_handler(message_id msg_id) { optional<behavior&> sync_handler(message_id msg_id) override {
auto i = m_sync_handler.find(msg_id); auto i = m_sync_handler.find(msg_id);
if (i != m_sync_handler.end()) return i->second; if (i != m_sync_handler.end()) return i->second;
return none; return none;
} }
// unused in blocking actors /**
* @brief Blocks this actor until all other actors are done.
*/
void await_all_other_actors_done();
/**
* @brief Implements the actor's behavior.
*/
virtual void act() = 0;
/**
* @brief Unwinds the stack by throwing an actor_exited exception.
* @throws actor_exited
*/
virtual void quit(std::uint32_t reason = exit_reason::normal);
/** @cond PRIVATE */
// required from invoke_policy; unused in blocking actors
inline void remove_handler(message_id) { } inline void remove_handler(message_id) { }
// required by receive() member function family
inline void dequeue(behavior&& bhvr) { inline void dequeue(behavior&& bhvr) {
behavior tmp{std::move(bhvr)}; behavior tmp{std::move(bhvr)};
dequeue(tmp); dequeue(tmp);
} }
// required by receive() member function family
inline void dequeue(behavior& bhvr) { inline void dequeue(behavior& bhvr) {
dequeue_response(bhvr, message_id::invalid); dequeue_response(bhvr, message_id::invalid);
} }
// implemented by detail::proper_actor
virtual void dequeue_response(behavior& bhvr, message_id mid) = 0; virtual void dequeue_response(behavior& bhvr, message_id mid) = 0;
void await_all_other_actors_done(); /** @endcond */
virtual void act() = 0;
/**
* @brief Unwinds the stack by throwing an actor_exited exception.
* @throws actor_exited
*/
virtual void quit(std::uint32_t reason = exit_reason::normal);
private: private:
std::map<message_id, behavior> m_sync_handler; // helper function to implement receive_(for|while) and do_receive
std::function<void(behavior&)> make_dequeue_callback() { std::function<void(behavior&)> make_dequeue_callback() {
return [=](behavior& bhvr) { dequeue(bhvr); }; return [=](behavior& bhvr) { dequeue(bhvr); };
} }
std::map<message_id, behavior> m_sync_handler;
}; };
} // namespace cppa } // namespace cppa
......
/******************************************************************************\
* ___ __ *
* /\_ \ __/\ \ *
* \//\ \ /\_\ \ \____ ___ _____ _____ __ *
* \ \ \ \/\ \ \ '__`\ /'___\/\ '__`\/\ '__`\ /'__`\ *
* \_\ \_\ \ \ \ \L\ \/\ \__/\ \ \L\ \ \ \L\ \/\ \L\.\_ *
* /\____\\ \_\ \_,__/\ \____\\ \ ,__/\ \ ,__/\ \__/.\_\ *
* \/____/ \/_/\/___/ \/____/ \ \ \/ \ \ \/ \/__/\/_/ *
* \ \_\ \ \_\ *
* \/_/ \/_/ *
* *
* Copyright (C) 2011-2013 *
* Dominik Charousset <dominik.charousset@haw-hamburg.de> *
* *
* This file is part of libcppa. *
* libcppa is free software: you can redistribute it and/or modify it under *
* the terms of the GNU Lesser General Public License as published by the *
* Free Software Foundation; either version 2.1 of the License, *
* or (at your option) any later version. *
* *
* libcppa is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. *
* See the GNU Lesser General Public License for more details. *
* *
* You should have received a copy of the GNU Lesser General Public License *
* along with libcppa. If not, see <http://www.gnu.org/licenses/>. *
\******************************************************************************/
#ifndef CONTINUE_HELPER_HPP
#define CONTINUE_HELPER_HPP
#include <functional>
#include "cppa/on.hpp"
#include "cppa/behavior.hpp"
#include "cppa/message_id.hpp"
namespace cppa {
class local_actor;
/**
* @brief Helper class to enable users to add continuations
* when dealing with synchronous sends.
*/
class continue_helper {
public:
typedef int message_id_wrapper_tag;
continue_helper(message_id mid, local_actor* self);
/**
* @brief Adds a continuation to the synchronous message handler
* that is invoked if the response handler successfully returned.
* @param fun The continuation as functor object.
*/
template<typename F>
continue_helper& continue_with(F fun) {
return continue_with(behavior::continuation_fun{partial_function{
on(any_vals, arg_match) >> fun
}});
}
/**
* @brief Adds a continuation to the synchronous message handler
* that is invoked if the response handler successfully returned.
* @param fun The continuation as functor object.
*/
continue_helper& continue_with(behavior::continuation_fun fun);
/**
* @brief Returns the ID of the expected response message.
*/
message_id get_message_id() const {
return m_mid;
}
private:
message_id m_mid;
local_actor* m_self;
};
} // namespace cppa
#endif // CONTINUE_HELPER_HPP
...@@ -33,6 +33,8 @@ ...@@ -33,6 +33,8 @@
#include <cstdint> #include <cstdint>
#include "cppa/spawn_options.hpp"
namespace cppa { namespace cppa {
// classes // classes
...@@ -74,6 +76,21 @@ typedef intrusive_ptr<node_id> node_id_ptr; ...@@ -74,6 +76,21 @@ typedef intrusive_ptr<node_id> node_id_ptr;
// weak intrusive pointer typedefs // weak intrusive pointer typedefs
typedef weak_intrusive_ptr<actor_proxy> weak_actor_proxy_ptr; typedef weak_intrusive_ptr<actor_proxy> weak_actor_proxy_ptr;
// prototype definitions of the spawn function famility;
// implemented in spawn.hpp (this header is included there)
template<class Impl, spawn_options Options = no_spawn_options, typename... Ts>
actor spawn(Ts&&... args);
template<spawn_options Options = no_spawn_options, typename... Ts>
actor spawn(Ts&&... args);
template<class Impl, spawn_options Options = no_spawn_options, typename... Ts>
actor spawn_in_group(const group&, Ts&&... args);
template<spawn_options Options = no_spawn_options, typename... Ts>
actor spawn_in_group(const group&, Ts&&... args);
} // namespace cppa } // namespace cppa
#endif // CPPA_FWD_HPP #endif // CPPA_FWD_HPP
...@@ -48,8 +48,8 @@ behavior fs2bhvr(Actor* self, Fs... fs) { ...@@ -48,8 +48,8 @@ behavior fs2bhvr(Actor* self, Fs... fs) {
}; };
return behavior{ return behavior{
on<sync_timeout_msg>() >> handle_sync_timeout, on<sync_timeout_msg>() >> handle_sync_timeout,
on(atom("VOID")) >> skip_message, on<unit_t>() >> skip_message,
on(atom("EXITED")) >> skip_message, on<sync_exited_msg>() >> skip_message,
(on(any_vals, arg_match) >> std::move(fs))... (on(any_vals, arg_match) >> std::move(fs))...
}; };
} }
......
...@@ -73,6 +73,7 @@ using mapped_type_list = util::type_list< ...@@ -73,6 +73,7 @@ using mapped_type_list = util::type_list<
io::accept_handle, io::accept_handle,
io::connection_handle, io::connection_handle,
message_header, message_header,
sync_exited_msg,
sync_timeout_msg, sync_timeout_msg,
timeout_msg, timeout_msg,
unit_t, unit_t,
......
...@@ -36,6 +36,7 @@ ...@@ -36,6 +36,7 @@
#include "cppa/logging.hpp" #include "cppa/logging.hpp"
#include "cppa/local_actor.hpp" #include "cppa/local_actor.hpp"
#include "cppa/mailbox_based.hpp" #include "cppa/mailbox_based.hpp"
#include "cppa/response_handle.hpp"
#include "cppa/behavior_stack_based.hpp" #include "cppa/behavior_stack_based.hpp"
#include "cppa/detail/response_handle_util.hpp" #include "cppa/detail/response_handle_util.hpp"
...@@ -44,52 +45,6 @@ namespace cppa { ...@@ -44,52 +45,6 @@ namespace cppa {
class event_based_actor; class event_based_actor;
/**
* @brief Helper class to enable users to add continuations when dealing
* with synchronous sends.
*/
class continue_helper {
public:
typedef int message_id_wrapper_tag;
inline continue_helper(message_id mid, event_based_actor* self)
: m_mid(mid), m_self(self) { }
/**
* @brief Adds a continuation to the synchronous message handler
* that is invoked if the response handler successfully returned.
* @param fun The continuation as functor object.
*/
template<typename F>
continue_helper& continue_with(F fun) {
return continue_with(behavior::continuation_fun{partial_function{
on(any_vals, arg_match) >> fun
}});
}
/**
* @brief Adds a continuation to the synchronous message handler
* that is invoked if the response handler successfully returned.
* @param fun The continuation as functor object.
*/
continue_helper& continue_with(behavior::continuation_fun fun);
/**
* @brief Returns the ID of the expected response message.
*/
message_id get_message_id() const {
return m_mid;
}
private:
message_id m_mid;
event_based_actor* m_self;
};
/** /**
* @brief A cooperatively scheduled, event-based actor implementation. * @brief A cooperatively scheduled, event-based actor implementation.
* *
...@@ -116,60 +71,9 @@ class event_based_actor : public extend<local_actor>:: ...@@ -116,60 +71,9 @@ class event_based_actor : public extend<local_actor>::
public: public:
/** typedef nonblocking_response_handle_tag response_handle_tag;
* @brief This helper class identifies an expected response message
* enables <tt>sync_send(...).then(...)</tt>.
*/
class response_handle {
friend class event_based_actor;
public:
response_handle() = delete;
response_handle(const response_handle&) = default;
response_handle& operator=(const response_handle&) = default;
/**
* @brief Sets @p bhvr as event-handler for the response message.
*/
inline continue_helper then(behavior bhvr) {
m_self->bhvr_stack().push_back(std::move(bhvr), m_mid);
return {m_mid, m_self};
}
/**
* @brief Sets @p mexpr as event-handler for the response message.
*/
template<typename... Cs, typename... Ts>
continue_helper then(const match_expr<Cs...>& arg, const Ts&... args) {
return then(match_expr_convert(arg, args...));
}
/**
* @brief Sets @p fun as event-handler for the response message, calls
* <tt>self->handle_sync_failure()</tt> if the response message
* is an 'EXITED' or 'VOID' message.
*/
template<typename... Fs>
typename std::enable_if<
util::all_callable<Fs...>::value,
continue_helper
>::type
then(Fs... fs) {
return then(detail::fs2bhvr(m_self, fs...));
}
private:
response_handle(const message_id& from, event_based_actor* self);
message_id m_mid;
event_based_actor* m_self;
}; typedef response_handle<event_based_actor> untyped_response_handle;
/** /**
* @brief Sends @p what as a synchronous message to @p whom. * @brief Sends @p what as a synchronous message to @p whom.
...@@ -180,8 +84,12 @@ class event_based_actor : public extend<local_actor>:: ...@@ -180,8 +84,12 @@ class event_based_actor : public extend<local_actor>::
* sent message cannot be received by another actor. * sent message cannot be received by another actor.
* @throws std::invalid_argument if <tt>whom == nullptr</tt> * @throws std::invalid_argument if <tt>whom == nullptr</tt>
*/ */
response_handle sync_send_tuple(const actor& whom, any_tuple what); inline untyped_response_handle sync_send_tuple(const actor& whom,
any_tuple what) {
return {sync_send_tuple_impl(message_priority::normal,
whom, std::move(what)),
this};
}
/** /**
* @brief Sends <tt>{what...}</tt> as a synchronous message to @p whom. * @brief Sends <tt>{what...}</tt> as a synchronous message to @p whom.
...@@ -194,7 +102,7 @@ class event_based_actor : public extend<local_actor>:: ...@@ -194,7 +102,7 @@ class event_based_actor : public extend<local_actor>::
* @throws std::invalid_argument if <tt>whom == nullptr</tt> * @throws std::invalid_argument if <tt>whom == nullptr</tt>
*/ */
template<typename... Ts> template<typename... Ts>
inline response_handle sync_send(const actor& whom, Ts&&... what) { inline untyped_response_handle sync_send(const actor& whom, Ts&&... what) {
static_assert(sizeof...(Ts) > 0, "no message to send"); static_assert(sizeof...(Ts) > 0, "no message to send");
return sync_send_tuple(whom, make_any_tuple(std::forward<Ts>(what)...)); return sync_send_tuple(whom, make_any_tuple(std::forward<Ts>(what)...));
} }
...@@ -205,9 +113,13 @@ class event_based_actor : public extend<local_actor>:: ...@@ -205,9 +113,13 @@ class event_based_actor : public extend<local_actor>::
* @param rtime Relative time until this messages times out. * @param rtime Relative time until this messages times out.
* @param what Message content as tuple. * @param what Message content as tuple.
*/ */
response_handle timed_sync_send_tuple(const util::duration& rtime, untyped_response_handle timed_sync_send_tuple(const util::duration& rtime,
const actor& whom, const actor& whom,
any_tuple what); any_tuple what) {
return {timed_sync_send_tuple_impl(message_priority::normal, whom,
rtime, std::move(what)),
this};
}
/** /**
* @brief Sends a synchronous message with timeout @p rtime to @p whom. * @brief Sends a synchronous message with timeout @p rtime to @p whom.
...@@ -217,7 +129,7 @@ class event_based_actor : public extend<local_actor>:: ...@@ -217,7 +129,7 @@ class event_based_actor : public extend<local_actor>::
* @pre <tt>sizeof...(Ts) > 0</tt> * @pre <tt>sizeof...(Ts) > 0</tt>
*/ */
template<typename... Ts> template<typename... Ts>
response_handle timed_sync_send(const actor& whom, untyped_response_handle timed_sync_send(const actor& whom,
const util::duration& rtime, const util::duration& rtime,
Ts&&... what) { Ts&&... what) {
static_assert(sizeof...(Ts) > 0, "no message to send"); static_assert(sizeof...(Ts) > 0, "no message to send");
......
This diff is collapsed.
...@@ -221,7 +221,7 @@ class invoke_policy { ...@@ -221,7 +221,7 @@ class invoke_policy {
<< " did not reply to a " << " did not reply to a "
"synchronous request message"); "synchronous request message");
auto fhdl = fetch_response_promise(self, hdl); auto fhdl = fetch_response_promise(self, hdl);
if (fhdl) fhdl.deliver(make_any_tuple(atom("VOID"))); if (fhdl) fhdl.deliver(make_any_tuple(unit));
} }
} else { } else {
if ( detail::matches<atom_value, std::uint64_t>(*res) if ( detail::matches<atom_value, std::uint64_t>(*res)
......
/******************************************************************************\
* ___ __ *
* /\_ \ __/\ \ *
* \//\ \ /\_\ \ \____ ___ _____ _____ __ *
* \ \ \ \/\ \ \ '__`\ /'___\/\ '__`\/\ '__`\ /'__`\ *
* \_\ \_\ \ \ \ \L\ \/\ \__/\ \ \L\ \ \ \L\ \/\ \L\.\_ *
* /\____\\ \_\ \_,__/\ \____\\ \ ,__/\ \ ,__/\ \__/.\_\ *
* \/____/ \/_/\/___/ \/____/ \ \ \/ \ \ \/ \/__/\/_/ *
* \ \_\ \ \_\ *
* \/_/ \/_/ *
* *
* Copyright (C) 2011-2013 *
* Dominik Charousset <dominik.charousset@haw-hamburg.de> *
* *
* This file is part of libcppa. *
* libcppa is free software: you can redistribute it and/or modify it under *
* the terms of the GNU Lesser General Public License as published by the *
* Free Software Foundation; either version 2.1 of the License, *
* or (at your option) any later version. *
* *
* libcppa is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. *
* See the GNU Lesser General Public License for more details. *
* *
* You should have received a copy of the GNU Lesser General Public License *
* along with libcppa. If not, see <http://www.gnu.org/licenses/>. *
\******************************************************************************/
#ifndef CPPA_RESPONSE_HANDLE_HPP
#define CPPA_RESPONSE_HANDLE_HPP
#include <type_traits>
#include "cppa/message_id.hpp"
#include "cppa/typed_behavior.hpp"
#include "cppa/continue_helper.hpp"
#include "cppa/util/type_list.hpp"
#include "cppa/detail/response_handle_util.hpp"
namespace cppa {
/**
* @brief This tag identifies response handles featuring a
* nonblocking API by providing a @p then member function.
*/
struct nonblocking_response_handle_tag { };
/**
* @brief This tag identifies response handles featuring a
* blocking API by providing an @p await member function.
*/
struct blocking_response_handle_tag { };
/**
* @brief This helper class identifies an expected response message
* and enables <tt>sync_send(...).then(...)</tt>.
*
* @tparam Self The type of the actor this handle belongs to.
* @tparam Result Either any_tuple or type_list<R1, R2, ... Rn>.
* @tparam Tag Either {@link nonblocking_response_handle_tag} or
* {@link blocking_response_handle_tag}.
*/
template<class Self,
class Result = any_tuple,
class Tag = typename Self::response_handle_tag>
class response_handle { // default impl for nonblocking_response_handle_tag
friend Self;
public:
response_handle() = delete;
response_handle(const response_handle&) = default;
response_handle& operator=(const response_handle&) = default;
/**
* @brief Sets @p bhvr as event-handler for the response message.
*/
inline continue_helper then(behavior bhvr) {
return then_impl<Result>(std::move(bhvr));
}
/**
* @brief Sets @p mexpr as event-handler for the response message.
*/
template<typename... Cs, typename... Ts>
continue_helper then(const match_expr<Cs...>& arg, const Ts&... args) {
return then_impl<Result>({arg, args...});
}
/**
* @brief Sets @p fun as event-handler for the response message, calls
* <tt>self->handle_sync_failure()</tt> if the response message
* is an 'EXITED' or 'VOID' message.
*/
template<typename... Fs>
typename std::enable_if<
util::all_callable<Fs...>::value,
continue_helper
>::type
then(Fs... fs) {
return then_impl<Result>(detail::fs2bhvr(m_self, fs...));
}
private:
template<typename R>
typename std::enable_if<
std::is_same<R, any_tuple>::value,
continue_helper
>::type
then_impl(behavior&& bhvr) {
m_self->bhvr_stack().push_back(std::move(bhvr), m_mid);
return {m_mid, m_self};
}
template<typename R>
typename std::enable_if<
util::is_type_list<R>::value,
continue_helper
>::type
then_impl(behavior&& bhvr) {
m_self->bhvr_stack().push_back(std::move(bhvr), m_mid);
return {m_mid, m_self};
}
response_handle(const message_id& mid, Self* self)
: m_mid(mid), m_self(self) { }
message_id m_mid;
Self* m_self;
};
template<class Self, typename Result>
class response_handle<Self, Result, blocking_response_handle_tag> {
friend Self;
public:
response_handle() = delete;
response_handle(const response_handle&) = default;
response_handle& operator=(const response_handle&) = default;
/**
* @brief Blocks until the response arrives and then executes @p pfun.
*/
void await(behavior& pfun) {
m_self->dequeue_response(pfun, m_mid);
}
/**
* @copydoc await(behavior&)
*/
inline void await(behavior&& pfun) {
behavior arg{std::move(pfun)};
await(arg);
}
/**
* @brief Blocks until the response arrives and then executes
* the corresponding handler.
*/
template<typename... Cs, typename... Ts>
void await(const match_expr<Cs...>& arg, const Ts&... args) {
await(match_expr_convert(arg, args...));
}
/**
* @brief Blocks until the response arrives and then executes
* the corresponding handler.
* @note Calls <tt>self->handle_sync_failure()</tt> if the response
* message is an 'EXITED' or 'VOID' message.
*/
template<typename... Fs>
typename std::enable_if<util::all_callable<Fs...>::value>::type
await(Fs... fs) {
await(detail::fs2bhvr(m_self, fs...));
}
private:
response_handle(const message_id& mid, Self* self)
: m_mid(mid), m_self(self) { }
message_id m_mid;
Self* m_self;
};
} // namespace cppa
#endif // CPPA_RESPONSE_HANDLE_HPP
...@@ -28,8 +28,8 @@ ...@@ -28,8 +28,8 @@
\******************************************************************************/ \******************************************************************************/
#ifndef CPPA_RESPONSE_HANDLE_HPP #ifndef CPPA_RESPONSE_PROMISE_HPP
#define CPPA_RESPONSE_HANDLE_HPP #define CPPA_RESPONSE_PROMISE_HPP
#include "cppa/actor.hpp" #include "cppa/actor.hpp"
#include "cppa/any_tuple.hpp" #include "cppa/any_tuple.hpp"
...@@ -78,4 +78,4 @@ class response_promise { ...@@ -78,4 +78,4 @@ class response_promise {
} // namespace cppa } // namespace cppa
#endif // CPPA_RESPONSE_HANDLE_HPP #endif // CPPA_RESPONSE_PROMISE_HPP
...@@ -35,8 +35,8 @@ ...@@ -35,8 +35,8 @@
#include "cppa/policy.hpp" #include "cppa/policy.hpp"
#include "cppa/logging.hpp" #include "cppa/logging.hpp"
#include "cppa/cppa_fwd.hpp"
#include "cppa/scheduler.hpp" #include "cppa/scheduler.hpp"
#include "cppa/local_actor.hpp"
#include "cppa/typed_actor.hpp" #include "cppa/typed_actor.hpp"
#include "cppa/spawn_options.hpp" #include "cppa/spawn_options.hpp"
#include "cppa/typed_event_based_actor.hpp" #include "cppa/typed_event_based_actor.hpp"
...@@ -157,7 +157,7 @@ intrusive_ptr<Impl> spawn_fwd_args(BeforeLaunch before_launch_fun, Ts&&... args) ...@@ -157,7 +157,7 @@ intrusive_ptr<Impl> spawn_fwd_args(BeforeLaunch before_launch_fun, Ts&&... args)
template<class Impl, spawn_options Opts, typename... Ts> template<class Impl, spawn_options Opts, typename... Ts>
actor spawn(Ts&&... args) { actor spawn(Ts&&... args) {
return detail::spawn_fwd_args<Impl, Opts>( return detail::spawn_fwd_args<Impl, Opts>(
[](local_actor*) { /* no-op as BeforeLaunch callback */ }, [](Impl*) { /* no-op as BeforeLaunch callback */ },
std::forward<Ts>(args)...); std::forward<Ts>(args)...);
} }
...@@ -196,7 +196,7 @@ actor spawn_in_group(const group& grp, Ts&&... args) { ...@@ -196,7 +196,7 @@ actor spawn_in_group(const group& grp, Ts&&... args) {
detail::functor_based_actor detail::functor_based_actor
>::type; >::type;
return detail::spawn_fwd_args<base_class, Opts>( return detail::spawn_fwd_args<base_class, Opts>(
[&](local_actor* ptr) { ptr->join(grp); }, [&](base_class* ptr) { ptr->join(grp); },
std::forward<Ts>(args)...); std::forward<Ts>(args)...);
} }
...@@ -211,7 +211,7 @@ actor spawn_in_group(const group& grp, Ts&&... args) { ...@@ -211,7 +211,7 @@ actor spawn_in_group(const group& grp, Ts&&... args) {
template<class Impl, spawn_options Opts, typename... Ts> template<class Impl, spawn_options Opts, typename... Ts>
actor spawn_in_group(const group& grp, Ts&&... args) { actor spawn_in_group(const group& grp, Ts&&... args) {
return detail::spawn_fwd_args<Impl, Opts>( return detail::spawn_fwd_args<Impl, Opts>(
[&](local_actor* ptr) { ptr->join(grp); }, [&](Impl* ptr) { ptr->join(grp); },
std::forward<Ts>(args)...); std::forward<Ts>(args)...);
} }
......
...@@ -65,10 +65,6 @@ constexpr spawn_options operator+(const spawn_options& lhs, ...@@ -65,10 +65,6 @@ constexpr spawn_options operator+(const spawn_options& lhs,
| static_cast<int>(rhs)); | static_cast<int>(rhs));
} }
#ifndef CPPA_DOCUMENTATION
namespace {
#endif
/** /**
* @brief Denotes default settings. * @brief Denotes default settings.
*/ */
...@@ -111,10 +107,6 @@ constexpr spawn_options blocking_api = spawn_options::blocking_api_flag; ...@@ -111,10 +107,6 @@ constexpr spawn_options blocking_api = spawn_options::blocking_api_flag;
constexpr spawn_options priority_aware = spawn_options::priority_aware_flag constexpr spawn_options priority_aware = spawn_options::priority_aware_flag
+ spawn_options::detach_flag; + spawn_options::detach_flag;
#ifndef CPPA_DOCUMENTATION
} // namespace <anonymous>
#endif
/** /**
* @brief Checks wheter @p haystack contains @p needle. * @brief Checks wheter @p haystack contains @p needle.
* @relates spawn_options * @relates spawn_options
...@@ -182,8 +174,7 @@ constexpr bool is_unbound(spawn_options opts) { ...@@ -182,8 +174,7 @@ constexpr bool is_unbound(spawn_options opts) {
constexpr spawn_options make_unbound(spawn_options opts) { constexpr spawn_options make_unbound(spawn_options opts) {
return static_cast<spawn_options>( return static_cast<spawn_options>(
(static_cast<int>(opts) (static_cast<int>(opts)
& ~static_cast<int>(spawn_options::link_flag)) & ~(static_cast<int>(linked) | static_cast<int>(monitored))));
& ~static_cast<int>(spawn_options::monitor_flag));
} }
/** @endcond */ /** @endcond */
......
...@@ -76,6 +76,20 @@ struct down_msg { ...@@ -76,6 +76,20 @@ struct down_msg {
*/ */
struct sync_timeout_msg { }; struct sync_timeout_msg { };
/**
* @brief Sent whenever a terminated actor receives a synchronous request.
*/
struct sync_exited_msg {
/**
* @brief The source of this message, i.e., the terminated actor.
*/
actor_addr source;
/**
* @brief The exit reason of the terminated actor.
*/
std::uint32_t reason;
};
/** /**
* @brief Signalizes a timeout event. * @brief Signalizes a timeout event.
* @note This message is handled implicitly by the runtime system. * @note This message is handled implicitly by the runtime system.
......
...@@ -31,19 +31,26 @@ ...@@ -31,19 +31,26 @@
#ifndef CPPA_TYPED_ACTOR_HPP #ifndef CPPA_TYPED_ACTOR_HPP
#define CPPA_TYPED_ACTOR_HPP #define CPPA_TYPED_ACTOR_HPP
#include "cppa/actor_addr.hpp"
#include "cppa/replies_to.hpp" #include "cppa/replies_to.hpp"
#include "cppa/intrusive_ptr.hpp" #include "cppa/intrusive_ptr.hpp"
#include "cppa/abstract_actor.hpp" #include "cppa/abstract_actor.hpp"
#include "cppa/typed_event_based_actor.hpp"
namespace cppa { namespace cppa {
class actor_addr;
class local_actor;
struct invalid_actor_addr_t;
template<typename... Signatures> template<typename... Signatures>
class typed_actor { class typed_actor : util::comparable<typed_actor<Signatures...>>
, util::comparable<typed_actor<Signatures...>, actor_addr>
, util::comparable<typed_actor<Signatures...>, invalid_actor_addr_t> {
public: friend class local_actor;
typedef typed_event_based_actor<Signatures...> actor_type; public:
typedef util::type_list<Signatures...> signatures; typedef util::type_list<Signatures...> signatures;
...@@ -69,6 +76,21 @@ class typed_actor { ...@@ -69,6 +76,21 @@ class typed_actor {
set(other); set(other);
} }
/**
* @brief Queries the address of the stored actor.
*/
actor_addr address() const {
return m_ptr ? m_ptr->address() : actor_addr{};
}
inline intptr_t compare(const actor_addr& rhs) const {
return address().compare(rhs);
}
inline intptr_t compare(const invalid_actor_addr_t&) const {
return m_ptr ? 1 : 0;
}
private: private:
template<class ListA, class ListB> template<class ListA, class ListB>
......
...@@ -102,7 +102,7 @@ class typed_behavior_stack_based : public extend<Base>::template ...@@ -102,7 +102,7 @@ class typed_behavior_stack_based : public extend<Base>::template
return m_bhvr_stack; return m_bhvr_stack;
} }
inline optional<behavior&> sync_handler(message_id msg_id) { optional<behavior&> sync_handler(message_id msg_id) override {
return m_bhvr_stack.sync_handler(msg_id); return m_bhvr_stack.sync_handler(msg_id);
} }
......
...@@ -37,31 +37,10 @@ ...@@ -37,31 +37,10 @@
namespace cppa { namespace cppa {
void blocking_actor::response_handle::await(behavior& bhvr) {
m_self->dequeue_response(bhvr, m_mid);
}
void blocking_actor::await_all_other_actors_done() { void blocking_actor::await_all_other_actors_done() {
get_actor_registry()->await_running_count_equal(1); get_actor_registry()->await_running_count_equal(1);
} }
blocking_actor::response_handle
blocking_actor::sync_send_tuple(const actor& dest, any_tuple what) {
auto nri = new_request_id();
dest->enqueue({address(), dest, nri}, std::move(what));
return {nri.response_id(), this};
}
blocking_actor::response_handle
blocking_actor::timed_sync_send_tuple(const util::duration& rtime,
const actor& dest,
any_tuple what) {
return {timed_sync_send_tuple_impl(message_priority::normal, dest, rtime,
std::move(what)),
this};
}
void blocking_actor::quit(std::uint32_t reason) { void blocking_actor::quit(std::uint32_t reason) {
planned_exit_reason(reason); planned_exit_reason(reason);
throw actor_exited(reason); throw actor_exited(reason);
......
/******************************************************************************\
* ___ __ *
* /\_ \ __/\ \ *
* \//\ \ /\_\ \ \____ ___ _____ _____ __ *
* \ \ \ \/\ \ \ '__`\ /'___\/\ '__`\/\ '__`\ /'__`\ *
* \_\ \_\ \ \ \ \L\ \/\ \__/\ \ \L\ \ \ \L\ \/\ \L\.\_ *
* /\____\\ \_\ \_,__/\ \____\\ \ ,__/\ \ ,__/\ \__/.\_\ *
* \/____/ \/_/\/___/ \/____/ \ \ \/ \ \ \/ \/__/\/_/ *
* \ \_\ \ \_\ *
* \/_/ \/_/ *
* *
* Copyright (C) 2011-2013 *
* Dominik Charousset <dominik.charousset@haw-hamburg.de> *
* *
* This file is part of libcppa. *
* libcppa is free software: you can redistribute it and/or modify it under *
* the terms of the GNU Lesser General Public License as published by the *
* Free Software Foundation; either version 2.1 of the License, *
* or (at your option) any later version. *
* *
* libcppa is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. *
* See the GNU Lesser General Public License for more details. *
* *
* You should have received a copy of the GNU Lesser General Public License *
* along with libcppa. If not, see <http://www.gnu.org/licenses/>. *
\******************************************************************************/
#include "cppa/continue_helper.hpp"
#include "cppa/event_based_actor.hpp"
namespace cppa {
continue_helper::continue_helper(message_id mid, local_actor* self)
: m_mid(mid), m_self(self) { }
continue_helper& continue_helper::continue_with(behavior::continuation_fun f) {
auto ref_opt = m_self->sync_handler(m_mid);
if (ref_opt) {
behavior cpy = *ref_opt;
*ref_opt = cpy.add_continuation(std::move(f));
}
else { CPPA_LOG_ERROR("failed to add continuation"); }
return *this;
}
} // namespace cppa
...@@ -35,39 +35,8 @@ ...@@ -35,39 +35,8 @@
namespace cppa { namespace cppa {
continue_helper&
continue_helper::continue_with(behavior::continuation_fun fun) {
auto ref_opt = m_self->bhvr_stack().sync_handler(m_mid);
if (ref_opt) {
behavior cpy = *ref_opt;
*ref_opt = cpy.add_continuation(std::move(fun));
}
else { CPPA_LOG_ERROR("failed to add continuation"); }
return *this;
}
event_based_actor::response_handle::response_handle(const message_id& from,
event_based_actor* self)
: m_mid(from), m_self(self) { }
void event_based_actor::forward_to(const actor& whom) { void event_based_actor::forward_to(const actor& whom) {
forward_message(whom, message_priority::normal); forward_message(whom, message_priority::normal);
} }
event_based_actor::response_handle
event_based_actor::sync_send_tuple(const actor& dest, any_tuple what) {
auto nri = new_request_id();
dest->enqueue({address(), dest, nri}, std::move(what));
return {nri.response_id(), this};
}
event_based_actor::response_handle
event_based_actor::timed_sync_send_tuple(const util::duration& rtime,
const actor& dest,
any_tuple what) {
return {timed_sync_send_tuple_impl(message_priority::normal, dest, rtime,
std::move(what)),
this};
}
} // namespace cppa } // namespace cppa
...@@ -147,18 +147,18 @@ void local_actor::send_tuple(message_priority prio, const channel& dest, any_tup ...@@ -147,18 +147,18 @@ void local_actor::send_tuple(message_priority prio, const channel& dest, any_tup
dest.enqueue({address(), dest, id}, std::move(what)); dest.enqueue({address(), dest, id}, std::move(what));
} }
void local_actor::send_tuple(const channel& dest, any_tuple what) {
send_tuple(message_priority::normal, dest, std::move(what));
}
void local_actor::send_exit(const actor_addr& whom, std::uint32_t reason) { void local_actor::send_exit(const actor_addr& whom, std::uint32_t reason) {
send(detail::raw_access::get(whom), exit_msg{address(), reason}); send(detail::raw_access::get(whom), exit_msg{address(), reason});
} }
void local_actor::delayed_send_tuple(const channel& dest, void local_actor::delayed_send_tuple(message_priority prio,
const channel& dest,
const util::duration& rel_time, const util::duration& rel_time,
cppa::any_tuple msg) { cppa::any_tuple msg) {
get_scheduler()->delayed_send({address(), dest}, rel_time, std::move(msg)); message_id mid;
if (prio == message_priority::high) mid = mid.with_high_priority();
get_scheduler()->delayed_send({address(), dest, mid},
rel_time, std::move(msg));
} }
response_promise local_actor::make_response_promise() { response_promise local_actor::make_response_promise() {
...@@ -205,6 +205,15 @@ message_id local_actor::timed_sync_send_tuple_impl(message_priority mp, ...@@ -205,6 +205,15 @@ message_id local_actor::timed_sync_send_tuple_impl(message_priority mp,
return rri; return rri;
} }
message_id local_actor::sync_send_tuple_impl(message_priority mp,
const actor& dest,
any_tuple&& what) {
auto nri = new_request_id();
if (mp == message_priority::high) nri = nri.with_high_priority();
dest->enqueue({address(), dest, nri}, std::move(what));
return nri.response_id();
}
void anon_send_exit(const actor_addr& whom, std::uint32_t reason) { void anon_send_exit(const actor_addr& whom, std::uint32_t reason) {
auto ptr = detail::raw_access::get(whom); auto ptr = detail::raw_access::get(whom);
ptr->enqueue({invalid_actor_addr, ptr, message_id{}.with_high_priority()}, ptr->enqueue({invalid_actor_addr, ptr, message_id{}.with_high_priority()},
......
...@@ -33,6 +33,7 @@ ...@@ -33,6 +33,7 @@
#include "cppa/message_id.hpp" #include "cppa/message_id.hpp"
#include "cppa/exit_reason.hpp" #include "cppa/exit_reason.hpp"
#include "cppa/mailbox_element.hpp" #include "cppa/mailbox_element.hpp"
#include "cppa/system_messages.hpp"
#include "cppa/detail/raw_access.hpp" #include "cppa/detail/raw_access.hpp"
#include "cppa/detail/sync_request_bouncer.hpp" #include "cppa/detail/sync_request_bouncer.hpp"
...@@ -48,7 +49,7 @@ void sync_request_bouncer::operator()(const actor_addr& sender, ...@@ -48,7 +49,7 @@ void sync_request_bouncer::operator()(const actor_addr& sender,
if (sender && mid.is_request()) { if (sender && mid.is_request()) {
auto ptr = detail::raw_access::get(sender); auto ptr = detail::raw_access::get(sender);
ptr->enqueue({invalid_actor_addr, ptr, mid.response_id()}, ptr->enqueue({invalid_actor_addr, ptr, mid.response_id()},
make_any_tuple(atom("EXITED"), rsn)); make_any_tuple(sync_exited_msg{sender, rsn}));
} }
} }
......
...@@ -73,6 +73,7 @@ namespace cppa { namespace detail { ...@@ -73,6 +73,7 @@ namespace cppa { namespace detail {
{ "cppa::io::accept_handle", "@ac_hdl" }, { "cppa::io::accept_handle", "@ac_hdl" },
{ "cppa::io::connection_handle", "@cn_hdl" }, { "cppa::io::connection_handle", "@cn_hdl" },
{ "cppa::message_header", "@header" }, { "cppa::message_header", "@header" },
{ "cppa::sync_exited_msg", "@sync_exited" },
{ "cppa::sync_timeout_msg", "@sync_timeout" }, { "cppa::sync_timeout_msg", "@sync_timeout" },
{ "cppa::timeout_msg", "@timeout" }, { "cppa::timeout_msg", "@timeout" },
{ "cppa::unit_t", "@0" }, { "cppa::unit_t", "@0" },
...@@ -391,7 +392,9 @@ inline void deserialize_impl(bool& val, deserializer* source) { ...@@ -391,7 +392,9 @@ inline void deserialize_impl(bool& val, deserializer* source) {
// exit_msg & down_msg have the same fields // exit_msg & down_msg have the same fields
template<typename T> template<typename T>
typename std::enable_if< typename std::enable_if<
std::is_same<T, down_msg>::value || std::is_same<T, exit_msg>::value std::is_same<T, down_msg>::value
|| std::is_same<T, exit_msg>::value
|| std::is_same<T, sync_exited_msg>::value
>::type >::type
serialize_impl(const T& dm, serializer* sink) { serialize_impl(const T& dm, serializer* sink) {
serialize_impl(dm.source, sink); serialize_impl(dm.source, sink);
...@@ -401,7 +404,9 @@ serialize_impl(const T& dm, serializer* sink) { ...@@ -401,7 +404,9 @@ serialize_impl(const T& dm, serializer* sink) {
// exit_msg & down_msg have the same fields // exit_msg & down_msg have the same fields
template<typename T> template<typename T>
typename std::enable_if< typename std::enable_if<
std::is_same<T, down_msg>::value || std::is_same<T, exit_msg>::value std::is_same<T, down_msg>::value
|| std::is_same<T, exit_msg>::value
|| std::is_same<T, sync_exited_msg>::value
>::type >::type
deserialize_impl(T& dm, deserializer* source) { deserialize_impl(T& dm, deserializer* source) {
deserialize_impl(dm.source, source); deserialize_impl(dm.source, source);
...@@ -782,6 +787,7 @@ class utim_impl : public uniform_type_info_map { ...@@ -782,6 +787,7 @@ class utim_impl : public uniform_type_info_map {
*i++ = &m_type_proc; // @proc *i++ = &m_type_proc; // @proc
*i++ = &m_type_str; // @str *i++ = &m_type_str; // @str
*i++ = &m_type_strmap; // @strmap *i++ = &m_type_strmap; // @strmap
*i++ = &m_type_sync_exited; // @sync_exited
*i++ = &m_type_sync_timeout; // @sync_timeout *i++ = &m_type_sync_timeout; // @sync_timeout
*i++ = &m_type_timeout; // @timeout *i++ = &m_type_timeout; // @timeout
*i++ = &m_type_tuple; // @tuple *i++ = &m_type_tuple; // @tuple
...@@ -903,6 +909,7 @@ class utim_impl : public uniform_type_info_map { ...@@ -903,6 +909,7 @@ class utim_impl : public uniform_type_info_map {
// 10-19 // 10-19
uti_impl<any_tuple> m_type_tuple; uti_impl<any_tuple> m_type_tuple;
uti_impl<util::duration> m_type_duration; uti_impl<util::duration> m_type_duration;
uti_impl<sync_exited_msg> m_type_sync_exited;
uti_impl<sync_timeout_msg> m_type_sync_timeout; uti_impl<sync_timeout_msg> m_type_sync_timeout;
uti_impl<timeout_msg> m_type_timeout; uti_impl<timeout_msg> m_type_timeout;
uti_impl<message_header> m_type_header; uti_impl<message_header> m_type_header;
...@@ -910,9 +917,9 @@ class utim_impl : public uniform_type_info_map { ...@@ -910,9 +917,9 @@ class utim_impl : public uniform_type_info_map {
uti_impl<atom_value> m_type_atom; uti_impl<atom_value> m_type_atom;
uti_impl<std::string> m_type_str; uti_impl<std::string> m_type_str;
uti_impl<std::u16string> m_type_u16str; uti_impl<std::u16string> m_type_u16str;
uti_impl<std::u32string> m_type_u32str;
// 20-29 // 20-29
uti_impl<std::u32string> m_type_u32str;
default_uniform_type_info_impl<strmap> m_type_strmap; default_uniform_type_info_impl<strmap> m_type_strmap;
uti_impl<bool> m_type_bool; uti_impl<bool> m_type_bool;
uti_impl<float> m_type_float; uti_impl<float> m_type_float;
...@@ -922,15 +929,15 @@ class utim_impl : public uniform_type_info_map { ...@@ -922,15 +929,15 @@ class utim_impl : public uniform_type_info_map {
int_tinfo<std::uint8_t> m_type_u8; int_tinfo<std::uint8_t> m_type_u8;
int_tinfo<std::int16_t> m_type_i16; int_tinfo<std::int16_t> m_type_i16;
int_tinfo<std::uint16_t> m_type_u16; int_tinfo<std::uint16_t> m_type_u16;
int_tinfo<std::int32_t> m_type_i32;
// 30-32 // 30-33
int_tinfo<std::int32_t> m_type_i32;
int_tinfo<std::uint32_t> m_type_u32; int_tinfo<std::uint32_t> m_type_u32;
int_tinfo<std::int64_t> m_type_i64; int_tinfo<std::int64_t> m_type_i64;
int_tinfo<std::uint64_t> m_type_u64; int_tinfo<std::uint64_t> m_type_u64;
// both containers are sorted by uniform name // both containers are sorted by uniform name
std::array<pointer, 33> m_builtin_types; std::array<pointer, 34> m_builtin_types;
std::vector<uniform_type_info*> m_user_types; std::vector<uniform_type_info*> m_user_types;
mutable util::shared_spinlock m_lock; mutable util::shared_spinlock m_lock;
......
...@@ -675,7 +675,7 @@ void test_spawn() { ...@@ -675,7 +675,7 @@ void test_spawn() {
} }
); );
// must skip remaining async message // must skip remaining async message
self->receive_response (handle) ( handle.await(
on_arg_match >> [&](int a, int b) { on_arg_match >> [&](int a, int b) {
CPPA_CHECK_EQUAL(a, 42); CPPA_CHECK_EQUAL(a, 42);
CPPA_CHECK_EQUAL(b, 2); CPPA_CHECK_EQUAL(b, 2);
...@@ -738,7 +738,7 @@ void test_spawn() { ...@@ -738,7 +738,7 @@ void test_spawn() {
CPPA_CHECKPOINT(); CPPA_CHECKPOINT();
self->sync_send(sync_testee, "!?").await( self->sync_send(sync_testee, "!?").await(
on(atom("EXITED"), any_vals) >> CPPA_CHECKPOINT_CB(), on<sync_exited_msg>() >> CPPA_CHECKPOINT_CB(),
others() >> CPPA_UNEXPECTED_MSG_CB(), others() >> CPPA_UNEXPECTED_MSG_CB(),
after(chrono::milliseconds(5)) >> CPPA_UNEXPECTED_TOUT_CB() after(chrono::milliseconds(5)) >> CPPA_UNEXPECTED_TOUT_CB()
); );
......
...@@ -300,7 +300,7 @@ void test_sync_send() { ...@@ -300,7 +300,7 @@ void test_sync_send() {
// first 'request', then 'idle' // first 'request', then 'idle'
auto handle = self->sync_send(s, atom("request")); auto handle = self->sync_send(s, atom("request"));
send_as(w, s, atom("idle")); send_as(w, s, atom("idle"));
self->receive_response(handle) ( handle.await(
on(atom("response")) >> [=] { on(atom("response")) >> [=] {
CPPA_CHECKPOINT(); CPPA_CHECKPOINT();
CPPA_CHECK_EQUAL(self->last_sender(), w); CPPA_CHECK_EQUAL(self->last_sender(), w);
......
...@@ -41,6 +41,14 @@ bool operator==(const my_request& lhs, const my_request& rhs) { ...@@ -41,6 +41,14 @@ bool operator==(const my_request& lhs, const my_request& rhs) {
return lhs.a == rhs.a && lhs.b == rhs.b; return lhs.a == rhs.a && lhs.b == rhs.b;
} }
typed_behavior<replies_to<my_request>::with<bool>> typed_server() {
return {
on_arg_match >> [](const my_request& req) {
return req.a == req.b;
}
};
}
/* /*
typed_actor_ptr<replies_to<my_request>::with<bool>> typed_actor_ptr<replies_to<my_request>::with<bool>>
spawn_typed_server() { spawn_typed_server() {
...@@ -66,10 +74,31 @@ class typed_testee : public typed_actor<replies_to<my_request>::with<bool>> { ...@@ -66,10 +74,31 @@ class typed_testee : public typed_actor<replies_to<my_request>::with<bool>> {
}; };
*/ */
void test_typed_spawn() {
auto ts = spawn_typed(typed_server);
scoped_actor self;
self->send(ts, my_request{1, 2});
self->receive(
on_arg_match >> [](bool value) {
CPPA_CHECK_EQUAL(value, false);
}
);
self->send(ts, my_request{42, 42});
self->receive(
on_arg_match >> [](bool value) {
CPPA_CHECK_EQUAL(value, true);
}
);
self->send_exit(ts, exit_reason::user_shutdown);
}
int main() { int main() {
CPPA_TEST(test_typed_spawn); CPPA_TEST(test_typed_spawn);
/*
announce<my_request>(&my_request::a, &my_request::b); announce<my_request>(&my_request::a, &my_request::b);
test_typed_spawn();
await_all_actors_done();
shutdown();
/*
auto sptr = spawn_typed_server(); auto sptr = spawn_typed_server();
sync_send(sptr, my_request{2, 2}).await( sync_send(sptr, my_request{2, 2}).await(
[](bool value) { [](bool value) {
......
...@@ -96,6 +96,7 @@ int main() { ...@@ -96,6 +96,7 @@ int main() {
"@down", // down_msg "@down", // down_msg
"@exit", // exit_msg "@exit", // exit_msg
"@timeout", // timeout_msg "@timeout", // timeout_msg
"@sync_exited", // sync_exited_msg
"@sync_timeout", // sync_timeout_msg "@sync_timeout", // sync_timeout_msg
// default announced cppa tuples // default announced cppa tuples
"@<>+@atom", // {atom_value} "@<>+@atom", // {atom_value}
......
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