Unverified Commit 99212ecc authored by Dominik Charousset's avatar Dominik Charousset Committed by GitHub

Merge pull request #1072

Fix several issues with typed actor views
parents 13d75ffe 90ce18a1
......@@ -89,6 +89,11 @@ is based on [Keep a Changelog](https://keepachangelog.com).
could monitor typed actors but not demonitoring it again. This member function
is now a template that accepts any actor handle in the same way `monitor`
already did.
- The `typed_actor_view` decorator lacked several member functions such as
`link_to`, `send_exit`, etc. These are now available.
- Constructing a `typed_actor` handle from a pointer view failed du to a missing
constructor overload. This (explicit) overload now exists and the conversion
should work as expected.
## [0.17.5] - Unreleased
......
......@@ -322,6 +322,10 @@ if(CMAKE_CXX_COMPILER_ID MATCHES "Clang"
add_compile_options("-ftemplate-depth=512"
"-ftemplate-backtrace-limit=0")
endif()
# enable useful warnings by default
if(CMAKE_CXX_COMPILER_ID MATCHES "Clang")
add_compile_options(-Wdocumentation)
endif()
# explicitly disable obnoxious GCC warnings
if(CMAKE_CXX_COMPILER_ID MATCHES "GNU")
build_string("EXTRA_FLAGS" "-Wno-missing-field-initializers")
......
......@@ -44,7 +44,7 @@ public:
= 0;
/// Called before the actor system calls the destructor for `self`.
/// @param ptr Points to an actor that is about to get destroyed.
/// @param self Points to an actor that is about to get destroyed.
/// @thread-safe
virtual void remove_actor(const local_actor& self) = 0;
......
......@@ -33,10 +33,7 @@ namespace caf {
/// implementation with `Driver`. The returned manager is not connected to any
/// slot and thus not stored by the actor automatically.
/// @param self Points to the hosting actor.
/// @param init Function object for initializing the state of the source.
/// @param pull Generator function object for producing downstream messages.
/// @param done Predicate returning `true` when generator is done.
/// @param fin Cleanup handler.
/// @param xs Parameter pack for constructing the driver.
/// @returns The new `stream_manager`.
template <class Driver, class... Ts>
typename Driver::source_ptr_type
......
......@@ -40,10 +40,7 @@ namespace caf {
/// manager with `Driver`.
/// @param self Points to the hosting actor.
/// @param xs User-defined arguments for the stream handshake.
/// @param init Function object for initializing the state of the source.
/// @param pull Function object for generating downstream messages.
/// @param done Predicate returning `true` when generator is done.
/// @param fin Optional cleanup handler.
/// @param ctor_args Parameter pack for constructing the driver.
/// @returns The allocated `stream_manager` and the output slot.
template <class Driver, class... Ts, class... CtorArgs>
make_source_result_t<typename Driver::downstream_manager_type, Ts...>
......@@ -104,10 +101,10 @@ template <class Init, class Pull, class Done, class Finalize = unit_t,
detail::enable_if_t<!is_actor_handle<Init>::value && Trait::valid,
make_source_result_t<DownstreamManager>>
attach_stream_source(scheduled_actor* self, Init init, Pull pull, Done done,
Finalize finalize = {},
Finalize fin = {},
policy::arg<DownstreamManager> token = {}) {
return attach_stream_source(self, std::make_tuple(), init, pull, done,
finalize, token);
return attach_stream_source(self, std::make_tuple(), init, pull, done, fin,
token);
}
/// Attaches a new stream source to `self` by creating a default stream source
......
......@@ -167,16 +167,17 @@ public:
// -- sending asynchronous messages ------------------------------------------
/// Sends an exit message to `dest`.
/// Sends an exit message to `whom`.
void send_exit(const actor_addr& whom, error reason);
void send_exit(const strong_actor_ptr& dest, error reason);
/// Sends an exit message to `whom`.
void send_exit(const strong_actor_ptr& whom, error reason);
/// Sends an exit message to `dest`.
/// Sends an exit message to `whom`.
template <class ActorHandle>
void send_exit(const ActorHandle& dest, error reason) {
if (dest)
dest->eq_impl(make_message_id(), ctrl(), context(),
void send_exit(const ActorHandle& whom, error reason) {
if (whom)
whom->eq_impl(make_message_id(), ctrl(), context(),
exit_msg{address(), std::move(reason)});
}
......@@ -294,7 +295,7 @@ public:
/// Adds a unidirectional `monitor` to `whom`.
/// @note Each call to `monitor` creates a new, independent monitor.
template <message_priority P = message_priority::normal, class Handle = actor>
template <message_priority P = message_priority::normal, class Handle>
void monitor(const Handle& whom) {
monitor(actor_cast<abstract_actor*>(whom), P);
}
......
......@@ -300,23 +300,16 @@ public:
// -- state modifiers --------------------------------------------------------
/// Finishes execution of this actor after any currently running
/// message handler is done.
/// This member function clears the behavior stack of the running actor
/// and invokes `on_exit()`. The actors does not finish execution
/// if the implementation of `on_exit()` sets a new behavior.
/// When setting a new behavior in `on_exit()`, one has to make sure
/// to not produce an infinite recursion.
/// Finishes execution of this actor after any currently running message
/// handler is done. This member function clears the behavior stack of the
/// running actor and invokes `on_exit()`. The actors does not finish
/// execution if the implementation of `on_exit()` sets a new behavior. When
/// setting a new behavior in `on_exit()`, one has to make sure to not produce
/// an infinite recursion.
///
/// If `on_exit()` did not set a new behavior, the actor sends an
/// exit message to all of its linked actors, sets its state to exited
/// and finishes execution.
///
/// In case this actor uses the blocking API, this member function unwinds
/// the stack by throwing an `actor_exited` exception.
/// @warning This member function throws immediately in thread-based actors
/// that do not use the behavior stack, i.e., actors that use
/// blocking API calls such as {@link receive()}.
/// If `on_exit()` did not set a new behavior, the actor sends an exit message
/// to all of its linked actors, sets its state to exited and finishes
/// execution.
void quit(error x = error{});
// -- properties -------------------------------------------------------------
......@@ -436,10 +429,10 @@ public:
// -- stream management ------------------------------------------------------
/// @deprecated Please use `attach_stream_source` instead.
template <class Driver, class... Ts, class Init, class Pull, class Done,
class Finalize = unit_t>
make_source_result_t<typename Driver::downstream_manager_type, Ts...>
[[deprecated("use attach_stream_source instead")]] make_source_result_t<
typename Driver::downstream_manager_type, Ts...>
make_source(std::tuple<Ts...> xs, Init init, Pull pull, Done done,
Finalize fin = {}) {
using detail::make_stream_source;
......@@ -449,12 +442,12 @@ public:
return {slot, std::move(mgr)};
}
/// @deprecated Please use `attach_stream_source` instead.
template <class... Ts, class Init, class Pull, class Done,
class Finalize = unit_t,
class DownstreamManager = broadcast_downstream_manager<
typename stream_source_trait_t<Pull>::output>>
make_source_result_t<DownstreamManager, Ts...>
[[deprecated("use attach_stream_source instead")]] make_source_result_t<
DownstreamManager, Ts...>
make_source(std::tuple<Ts...> xs, Init init, Pull pull, Done done,
Finalize fin = {}, policy::arg<DownstreamManager> = {}) {
using driver = detail::stream_source_driver_impl<DownstreamManager, Pull,
......@@ -463,23 +456,23 @@ public:
std::move(done), std::move(fin));
}
/// @deprecated Please use `attach_stream_source` instead.
template <class Init, class Pull, class Done, class Finalize = unit_t,
class DownstreamManager = default_downstream_manager_t<Pull>,
class Trait = stream_source_trait_t<Pull>>
detail::enable_if_t<!is_actor_handle<Init>::value && Trait::valid,
[[deprecated("use attach_stream_source instead")]] detail::enable_if_t<
!is_actor_handle<Init>::value && Trait::valid,
make_source_result_t<DownstreamManager>>
make_source(Init init, Pull pull, Done done, Finalize finalize = {},
policy::arg<DownstreamManager> token = {}) {
return make_source(std::make_tuple(), init, pull, done, finalize, token);
}
/// @deprecated Please use `attach_stream_source` instead.
template <class ActorHandle, class... Ts, class Init, class Pull, class Done,
class Finalize = unit_t,
class DownstreamManager = default_downstream_manager_t<Pull>,
class Trait = stream_source_trait_t<Pull>>
detail::enable_if_t<is_actor_handle<ActorHandle>::value,
[[deprecated("use attach_stream_source instead")]] detail::enable_if_t<
is_actor_handle<ActorHandle>::value,
make_source_result_t<DownstreamManager>>
make_source(const ActorHandle& dest, std::tuple<Ts...> xs, Init init,
Pull pull, Done done, Finalize fin = {},
......@@ -493,12 +486,12 @@ public:
return {slot, std::move(mgr)};
}
/// @deprecated Please use `attach_stream_source` instead.
template <class ActorHandle, class Init, class Pull, class Done,
class Finalize = unit_t,
class DownstreamManager = default_downstream_manager_t<Pull>,
class Trait = stream_source_trait_t<Pull>>
detail::enable_if_t<is_actor_handle<ActorHandle>::value && Trait::valid,
[[deprecated("use attach_stream_source instead")]] detail::enable_if_t<
is_actor_handle<ActorHandle>::value && Trait::valid,
make_source_result_t<DownstreamManager>>
make_source(const ActorHandle& dest, Init init, Pull pull, Done done,
Finalize fin = {}, policy::arg<DownstreamManager> token = {}) {
......@@ -506,10 +499,9 @@ public:
std::move(pull), std::move(done), std::move(fin), token);
}
/// @deprecated Please use `attach_continuous_stream_source` instead.
template <class Driver, class Init, class Pull, class Done,
class Finalize = unit_t>
typename Driver::source_ptr_type
[[deprecated("use attach_continuous_stream_source instead")]] auto
make_continuous_source(Init init, Pull pull, Done done, Finalize fin = {}) {
using detail::make_stream_source;
auto mgr = make_stream_source<Driver>(
......@@ -518,11 +510,10 @@ public:
return mgr;
}
/// @deprecated Please use `attach_continuous_stream_source` instead.
template <class Init, class Pull, class Done, class Finalize = unit_t,
class DownstreamManager = broadcast_downstream_manager<
typename stream_source_trait_t<Pull>::output>>
stream_source_ptr<DownstreamManager>
[[deprecated("use attach_continuous_stream_source instead")]] auto
make_continuous_source(Init init, Pull pull, Done done, Finalize fin = {},
policy::arg<DownstreamManager> = {}) {
using driver = detail::stream_source_driver_impl<DownstreamManager, Pull,
......@@ -531,28 +522,27 @@ public:
std::move(done), std::move(fin));
}
/// @deprecated Please use `attach_stream_sink` instead.
template <class Driver, class... Ts>
make_sink_result<typename Driver::input_type>
[[deprecated("use attach_stream_sink instead")]] make_sink_result<
typename Driver::input_type>
make_sink(const stream<typename Driver::input_type>& src, Ts&&... xs) {
auto mgr = detail::make_stream_sink<Driver>(this, std::forward<Ts>(xs)...);
auto slot = mgr->add_inbound_path(src);
return {slot, std::move(mgr)};
}
/// @deprecated Please use `attach_stream_sink` instead.
template <class In, class Init, class Fun, class Finalize = unit_t,
class Trait = stream_sink_trait_t<Fun>>
make_sink_result<In>
[[deprecated("use attach_stream_sink instead")]] make_sink_result<In>
make_sink(const stream<In>& in, Init init, Fun fun, Finalize fin = {}) {
using driver = detail::stream_sink_driver_impl<In, Fun, Finalize>;
return make_sink<driver>(in, std::move(init), std::move(fun),
std::move(fin));
}
/// @deprecated Please use `attach_stream_stage` instead.
template <class Driver, class In, class... Ts, class... Us>
make_stage_result_t<In, typename Driver::downstream_manager_type, Ts...>
[[deprecated("use attach_stream_stage instead")]] make_stage_result_t<
In, typename Driver::downstream_manager_type, Ts...>
make_stage(const stream<In>& src, std::tuple<Ts...> xs, Us&&... ys) {
using detail::make_stream_stage;
auto mgr = make_stream_stage<Driver>(this, std::forward<Us>(ys)...);
......@@ -561,12 +551,12 @@ public:
return {in, out, std::move(mgr)};
}
/// @deprecated Please use `attach_stream_stage` instead.
template <class In, class... Ts, class Init, class Fun,
class Finalize = unit_t,
class DownstreamManager = default_downstream_manager_t<Fun>,
class Trait = stream_stage_trait_t<Fun>>
make_stage_result_t<In, DownstreamManager, Ts...>
[[deprecated("use attach_stream_stage instead")]] make_stage_result_t<
In, DownstreamManager, Ts...>
make_stage(const stream<In>& in, std::tuple<Ts...> xs, Init init, Fun fun,
Finalize fin = {}, policy::arg<DownstreamManager> token = {}) {
CAF_IGNORE_UNUSED(token);
......@@ -591,30 +581,29 @@ public:
std::move(fun), std::move(fin));
}
/// @deprecated Please use `attach_stream_stage` instead.
template <class In, class Init, class Fun, class Finalize = unit_t,
class DownstreamManager = default_downstream_manager_t<Fun>,
class Trait = stream_stage_trait_t<Fun>>
make_stage_result_t<In, DownstreamManager>
[[deprecated("use attach_stream_stage instead")]] make_stage_result_t<
In, DownstreamManager>
make_stage(const stream<In>& in, Init init, Fun fun, Finalize fin = {},
policy::arg<DownstreamManager> token = {}) {
return make_stage(in, std::make_tuple(), std::move(init), std::move(fun),
std::move(fin), token);
}
/// @deprecated Please use `attach_continuous_stream_stage` instead.
template <class Driver, class... Ts>
typename Driver::stage_ptr_type make_continuous_stage(Ts&&... xs) {
[[deprecated("use attach_continuous_stream_stage instead")]] auto
make_continuous_stage(Ts&&... xs) {
auto ptr = detail::make_stream_stage<Driver>(this, std::forward<Ts>(xs)...);
ptr->continuous(true);
return ptr;
}
/// @deprecated Please use `attach_continuous_stream_stage` instead.
template <class Init, class Fun, class Cleanup,
class DownstreamManager = default_downstream_manager_t<Fun>,
class Trait = stream_stage_trait_t<Fun>>
stream_stage_ptr<typename Trait::input, DownstreamManager>
[[deprecated("use attach_continuous_stream_stage instead")]] auto
make_continuous_stage(Init init, Fun fun, Cleanup cleanup,
policy::arg<DownstreamManager> token = {}) {
CAF_IGNORE_UNUSED(token);
......
......@@ -31,6 +31,7 @@
#include "caf/make_actor.hpp"
#include "caf/replies_to.hpp"
#include "caf/stateful_actor.hpp"
#include "caf/typed_actor_view_base.hpp"
#include "caf/typed_behavior.hpp"
#include "caf/typed_response_promise.hpp"
......@@ -148,6 +149,15 @@ public:
CAF_ASSERT(ptr != nullptr);
}
// Enable `handle_type{self}` for typed actor views.
template <class T, class = std::enable_if_t<
std::is_base_of<typed_actor_view_base, T>::value>>
explicit typed_actor(T ptr) : ptr_(ptr.internal_ptr()) {
static_assert(
detail::tl_subset_of<signatures, typename T::signatures>::value,
"Cannot assign T to incompatible handle type");
}
template <class... Ts>
typed_actor& operator=(const typed_actor<Ts...>& other) {
static_assert(
......
......@@ -24,7 +24,7 @@
namespace caf {
template <class... Sigs>
class typed_actor_pointer {
class typed_actor_pointer : public typed_actor_view_base {
public:
/// Stores the template parameter pack.
using signatures = detail::type_list<Sigs...>;
......@@ -45,6 +45,10 @@ public:
// nop
}
typed_actor_pointer(const typed_actor_pointer&) = default;
typed_actor_pointer& operator=(const typed_actor_pointer&) = default;
typed_actor_view<Sigs...>* operator->() {
return &view_;
}
......
......@@ -19,6 +19,7 @@
#pragma once
#include "caf/actor_traits.hpp"
#include "caf/config.hpp"
#include "caf/mixin/requester.hpp"
#include "caf/mixin/sender.hpp"
#include "caf/scheduled_actor.hpp"
......@@ -27,6 +28,8 @@
namespace caf {
/// Decorates a pointer to a @ref scheduled_actor with a statically typed actor
/// interface.
template <class... Sigs>
class typed_actor_view : public extend<typed_actor_view_base,
typed_actor_view<Sigs...>>::template
......@@ -46,30 +49,129 @@ public:
return *this;
}
/****************************************************************************
* spawn actors *
****************************************************************************/
// -- spawn functions --------------------------------------------------------
/// @copydoc local_actor::spawn
template <class T, spawn_options Os = no_spawn_options, class... Ts>
typename infer_handle_from_class<T>::type
spawn(Ts&&... xs) {
return self_->spawn<T, Os>(std::forward<Ts>(xs)...);
}
/// @copydoc local_actor::spawn
template <class T, spawn_options Os = no_spawn_options>
infer_handle_from_state_t<T> spawn() {
return self_->spawn<T, Os>();
}
/// @copydoc local_actor::spawn
template <spawn_options Os = no_spawn_options, class F, class... Ts>
typename infer_handle_from_fun<F>::type
spawn(F fun, Ts&&... xs) {
return self_->spawn<Os>(std::move(fun), std::forward<Ts>(xs)...);
}
/****************************************************************************
* miscellaneous actor operations *
****************************************************************************/
// -- state modifiers --------------------------------------------------------
/// @copydoc scheduled_actor::quit
void quit(error x = error{}) {
self_->quit(std::move(x));
}
// -- properties -------------------------------------------------------------
/// @copydoc scheduled_actor::mailbox
auto& mailbox() noexcept {
return self_->mailbox();
}
// -- event handlers ---------------------------------------------------------
/// @copydoc scheduled_actor::set_default_handler
template <class Fun>
void set_default_handler(Fun&& fun) {
self_->set_default_handler(std::forward<Fun>(fun));
}
/// @copydoc scheduled_actor::set_error_handler
template <class Fun>
void set_error_handler(Fun&& fun) {
self_->set_error_handler(std::forward<Fun>(fun));
}
/// @copydoc scheduled_actor::set_down_handler
template <class Fun>
void set_down_handler(Fun&& fun) {
self_->set_down_handler(std::forward<Fun>(fun));
}
/// @copydoc scheduled_actor::set_node_down_handler
template <class Fun>
void set_node_down_handler(Fun&& fun) {
self_->set_node_down_handler(std::forward<Fun>(fun));
}
/// @copydoc scheduled_actor::set_exit_handler
template <class Fun>
void set_exit_handler(Fun&& fun) {
self_->set_exit_handler(std::forward<Fun>(fun));
}
#ifndef CAF_NO_EXCEPTIONS
/// @copydoc scheduled_actor::set_exception_handler
template <class Fun>
void set_exception_handler(Fun&& fun) {
self_->set_exception_handler(std::forward<Fun>(fun));
}
#endif // CAF_NO_EXCEPTIONS
// -- linking and monitoring -------------------------------------------------
/// @copydoc monitorable_actor::link_to
template <class ActorHandle>
void link_to(const ActorHandle& x) {
self_->link_to(x);
}
/// @copydoc monitorable_actor::unlink_from
template <class ActorHandle>
void unlink_from(const ActorHandle& x) {
self_->unlink_from(x);
}
/// @copydoc local_actor::monitor
void monitor(const node_id& node) {
self_->monitor(node);
}
/// @copydoc local_actor::monitor
template <message_priority P = message_priority::normal, class Handle>
void monitor(const Handle& whom) {
self_->monitor(whom);
}
/// @copydoc local_actor::demonitor
void demonitor(const node_id& node) {
self_->demonitor(node);
}
/// @copydoc local_actor::demonitor
template <class Handle>
void demonitor(const Handle& whom) {
self_->demonitor(whom);
}
// -- sending asynchronous messages ------------------------------------------
/// @copydoc local_actor::send_exit
template <class ActorHandle>
void send_exit(const ActorHandle& whom, error reason) {
self_->send_exit(whom, std::move(reason));
}
// -- miscellaneous actor operations -----------------------------------------
execution_unit* context() const {
return self_->context();
......@@ -93,16 +195,6 @@ public:
return self_->make_response_promise<Ts...>();
}
template <message_priority P = message_priority::normal, class Handle = actor>
void monitor(const Handle& x) {
self_->monitor<P>(x);
}
template <class T>
void demonitor(const T& x) {
self_->demonitor(x);
}
message_id new_request_id(message_priority mp) {
return self_->new_request_id(mp);
}
......
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