Commit 0f1831cd authored by Dominik Charousset's avatar Dominik Charousset

Improve error reporting on function-based actors

parent 0b9b191e
......@@ -40,5 +40,11 @@ struct actor_marker<behavior> {
using type = dynamically_typed_actor_base;
};
template <class T>
using is_statically_typed = std::is_base_of<statically_typed_actor_base, T>;
template <class T>
using is_dynamically_typed = std::is_base_of<dynamically_typed_actor_base, T>;
} // namespace caf
......@@ -32,10 +32,12 @@
#include "caf/actor_cast.hpp"
#include "caf/actor_clock.hpp"
#include "caf/actor_config.hpp"
#include "caf/actor_marker.hpp"
#include "caf/actor_registry.hpp"
#include "caf/composable_behavior_based_actor.hpp"
#include "caf/detail/init_fun_factory.hpp"
#include "caf/detail/spawn_fwd.hpp"
#include "caf/detail/spawnable.hpp"
#include "caf/fwd.hpp"
#include "caf/group_manager.hpp"
#include "caf/infer_handle.hpp"
......@@ -328,30 +330,27 @@ public:
return spawn<composable_behavior_based_actor<S>, Os>();
}
/// Called by `spawn_functor` to apply static assertions and
/// store an initialization function in `cfg` before calling `spawn_class`.
/// Called by `spawn` when used to create a functor-based actor to select a
/// proper implementation and then delegates to `spawn_impl`.
/// @param cfg To-be-filled config for the actor.
/// @param fun Function object for the actor's behavior; will be moved.
/// @param xs Arguments for `fun`.
template <spawn_options Os, class C, class F, class... Ts>
infer_handle_from_class_t<C>
spawn_functor_impl(actor_config& cfg, F& fun, Ts&&... xs) {
detail::init_fun_factory<C, F> fac;
/// @private
template <spawn_options Os = no_spawn_options, class F, class... Ts>
infer_handle_from_fun_t<F> spawn_functor(std::true_type, actor_config& cfg,
F& fun, Ts&&... xs) {
using impl = infer_impl_from_fun_t<F>;
detail::init_fun_factory<impl, F> fac;
cfg.init_fun = fac(std::move(fun), std::forward<Ts>(xs)...);
return spawn_impl<C, Os>(cfg);
return spawn_impl<impl, Os>(cfg);
}
/// Called by `spawn` when used to create a functor-based actor to select
/// a proper implementation and then delegates to `spawn_functor_impl`.
/// Should not be called by users of the library directly.
/// @param cfg To-be-filled config for the actor.
/// @param fun Function object for the actor's behavior; will be moved.
/// @param xs Arguments for `fun`.
/// Fallback no-op overload.
/// @private
template <spawn_options Os = no_spawn_options, class F, class... Ts>
infer_handle_from_fun_t<F>
spawn_functor(actor_config& cfg, F& fun, Ts&&... xs) {
using impl = infer_impl_from_fun_t<F>;
return spawn_functor_impl<Os, impl>(cfg, fun, std::forward<Ts>(xs)...);
infer_handle_from_fun_t<F> spawn_functor(std::false_type, actor_config&, F&,
Ts&&...) {
return {};
}
/// Returns a new functor-based actor. The first argument must be the functor,
......@@ -361,9 +360,14 @@ public:
template <spawn_options Os = no_spawn_options, class F, class... Ts>
infer_handle_from_fun_t<F>
spawn(F fun, Ts&&... xs) {
check_invariants<infer_impl_from_fun_t<F>>();
using impl = infer_impl_from_fun_t<F>;
check_invariants<impl>();
static constexpr bool spawnable = detail::spawnable<F, impl, Ts...>();
static_assert(spawnable,
"cannot spawn function-based actor with given arguments");
actor_config cfg;
return spawn_functor<Os>(cfg, fun, std::forward<Ts>(xs)...);
return spawn_functor<Os>(detail::bool_token<spawnable>{}, cfg, fun,
std::forward<Ts>(xs)...);
}
/// Returns a new actor with run-time type `name`, constructed
......@@ -393,7 +397,7 @@ public:
infer_handle_from_class_t<T>
spawn_class_in_groups(actor_config& cfg, Iter first, Iter last, Ts&&... xs) {
static_assert(std::is_same<infer_handle_from_class_t<T>, actor>::value,
"Only dynamically typed actors can be spawned in a group.");
"only dynamically-typed actors can be spawned in a group");
check_invariants<T>();
auto irange = make_input_range(first, last);
cfg.groups = &irange;
......@@ -407,12 +411,19 @@ public:
infer_handle_from_fun_t<F>
spawn_fun_in_groups(actor_config& cfg, Iter first, Iter second,
F& fun, Ts&&... xs) {
static_assert(std::is_same<infer_handle_from_fun_t<F>, actor>::value,
"Only dynamically actors can be spawned in a group.");
check_invariants<infer_impl_from_fun_t<F>>();
using impl = infer_impl_from_fun_t<F>;
check_invariants<impl>();
static constexpr bool dynamically_typed = is_dynamically_typed<impl>::value;
static_assert(dynamically_typed,
"only dynamically-typed actors can join groups");
static constexpr bool spawnable = detail::spawnable<F, impl, Ts...>();
static_assert(spawnable,
"cannot spawn function-based actor with given arguments");
static constexpr bool enabled = dynamically_typed && spawnable;
auto irange = make_input_range(first, second);
cfg.groups = &irange;
return spawn_functor<Os>(cfg, fun, std::forward<Ts>(xs)...);
return spawn_functor<Os>(detail::bool_token<enabled>{}, cfg, fun,
std::forward<Ts>(xs)...);
}
/// Returns a new functor-based actor subscribed to all groups in `gs`.
......
/******************************************************************************
* ____ _ _____ *
* / ___| / \ | ___| C++ *
* | | / _ \ | |_ Actor *
* | |___ / ___ \| _| Framework *
* \____/_/ \_|_| *
* *
* Copyright 2011-2018 Dominik Charousset *
* *
* Distributed under the terms and conditions of the BSD 3-Clause License or *
* (at your option) under the terms and conditions of the Boost Software *
* License 1.0. See accompanying files LICENSE and LICENSE_ALTERNATIVE. *
* *
* If you did not receive a copy of the license files, see *
* http://opensource.org/licenses/BSD-3-Clause and *
* http://www.boost.org/LICENSE_1_0.txt. *
******************************************************************************/
#pragma once
#include <type_traits>
#include "caf/detail/type_traits.hpp"
#include "caf/infer_handle.hpp"
namespace caf {
namespace detail {
/// Returns whether the function object `F` is spawnable from the actor
/// implementation `Impl` with arguments of type `Ts...`.
template <class F, class Impl, class... Ts>
constexpr bool spawnable() {
return is_callable_with<F, Ts...>::value
|| is_callable_with<F, Impl*, Ts...>::value;
}
} // namespace detail
} // namespace caf
......@@ -694,6 +694,10 @@ struct is_same_ish
is_equal_int_type<T, U>
>::type { };
/// Utility for fallbacks calling `static_assert`.
template <class>
struct always_false : std::false_type {};
} // namespace detail
} // namespace caf
......@@ -114,8 +114,8 @@ struct infer_handle_from_fun {
};
/// @relates infer_handle_from_fun
template <class T>
using infer_handle_from_fun_t = typename infer_handle_from_fun<T>::type;
template <class F>
using infer_handle_from_fun_t = typename infer_handle_from_fun<F>::type;
/// @relates infer_handle_from_fun
template <class T>
......
......@@ -34,6 +34,8 @@
#include "caf/behavior.hpp"
#include "caf/check_typed_input.hpp"
#include "caf/delegated.hpp"
#include "caf/detail/type_traits.hpp"
#include "caf/detail/typed_actor_util.hpp"
#include "caf/duration.hpp"
#include "caf/error.hpp"
#include "caf/fwd.hpp"
......@@ -49,8 +51,6 @@
#include "caf/typed_actor.hpp"
#include "caf/typed_response_promise.hpp"
#include "caf/detail/typed_actor_util.hpp"
namespace caf {
/// Base class for actors running on this node, either
......@@ -109,9 +109,16 @@ public:
template <spawn_options Os = no_spawn_options, class F, class... Ts>
infer_handle_from_fun_t<F> spawn(F fun, Ts&&... xs) {
using impl = infer_impl_from_fun_t<F>;
static constexpr bool spawnable = detail::spawnable<F, impl, Ts...>();
static_assert(spawnable,
"cannot spawn function-based actor with given arguments");
actor_config cfg{context()};
return eval_opts(Os, system().spawn_functor<make_unbound(Os)>(
cfg, fun, std::forward<Ts>(xs)...));
static constexpr spawn_options unbound = make_unbound(Os);
detail::bool_token<spawnable> enabled;
return eval_opts(Os,
system().spawn_functor<unbound>(enabled, cfg, fun,
std::forward<Ts>(xs)...));
}
template <class T, spawn_options Os = no_spawn_options, class Groups,
......
......@@ -255,8 +255,14 @@ public:
class F = std::function<void(broker*)>, class... Ts>
typename infer_handle_from_fun<F>::type
spawn_broker(F fun, Ts&&... xs) {
using impl = infer_impl_from_fun_t<F>;
static constexpr bool spawnable = detail::spawnable<F, impl, Ts...>();
static_assert(spawnable,
"cannot spawn function-based broker with given arguments");
actor_config cfg{&backend()};
return system().spawn_functor<Os>(cfg, fun, std::forward<Ts>(xs)...);
detail::bool_token<spawnable> enabled;
return system().spawn_functor<Os>(enabled, cfg, fun,
std::forward<Ts>(xs)...);
}
/// Returns a new functor-based broker connected
......
......@@ -119,7 +119,14 @@ public:
actor_config cfg{this->context()};
detail::init_fun_factory<impl, F> fac;
cfg.init_fun = fac(std::move(fun), hdl, std::forward<Ts>(xs)...);
auto res = this->system().spawn_functor(cfg, fun, hdl, std::forward<Ts>(xs)...);
using impl = infer_impl_from_fun_t<F>;
static constexpr bool spawnable = detail::spawnable<F, impl, decltype(hdl),
Ts...>();
static_assert(spawnable,
"cannot spawn function-based broker with given arguments");
detail::bool_token<spawnable> enabled;
auto res = this->system().spawn_functor(enabled, cfg, fun, hdl,
std::forward<Ts>(xs)...);
auto forked = static_cast<impl*>(actor_cast<abstract_actor*>(res));
forked->move_scribe(std::move(sptr));
return res;
......
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