1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114
|
// This file is part of CAF, the C++ Actor Framework. See the file LICENSE in
// the main distribution directory for license terms and copyright or visit
// https://github.com/actor-framework/actor-framework/blob/master/LICENSE.
#pragma once
#include <list>
#include <memory>
#include <type_traits>
#include <utility>
#include <vector>
#include "caf/behavior.hpp"
#include "caf/detail/behavior_impl.hpp"
#include "caf/detail/core_export.hpp"
#include "caf/fwd.hpp"
#include "caf/intrusive_ptr.hpp"
#include "caf/may_have_timeout.hpp"
#include "caf/message.hpp"
#include "caf/none.hpp"
#include "caf/ref_counted.hpp"
#include "caf/timeout_definition.hpp"
namespace caf {
/// A partial function implementation used to process a `message`.
class CAF_CORE_EXPORT message_handler {
public:
friend class behavior;
message_handler() = default;
message_handler(message_handler&&) = default;
message_handler(const message_handler&) = default;
message_handler& operator=(message_handler&&) = default;
message_handler& operator=(const message_handler&) = default;
/// A pointer to the underlying implementation.
using impl_ptr = intrusive_ptr<detail::behavior_impl>;
/// Returns a pointer to the implementation.
const impl_ptr& as_behavior_impl() const {
return impl_;
}
/// Creates a message handler from @p ptr.
message_handler(impl_ptr ptr);
/// Checks whether the message handler is not empty.
operator bool() const {
return static_cast<bool>(impl_);
}
/// Create a message handler a list of match expressions,
/// functors, or other message handlers.
template <class T, class... Ts>
message_handler(const T& v, Ts&&... xs) {
assign(v, std::forward<Ts>(xs)...);
}
/// Assigns new message handlers.
template <class... Ts>
void assign(Ts... xs) {
static_assert(sizeof...(Ts) > 0, "assign without arguments called");
static_assert(
!detail::disjunction<
may_have_timeout<typename std::decay<Ts>::type>::value...>::value,
"Timeouts are only allowed in behaviors");
impl_ = detail::make_behavior(xs...);
}
/// Equal to `*this = other`.
void assign(message_handler what);
/// Runs this handler and returns its (optional) result.
optional<message> operator()(message& arg) {
return (impl_) ? impl_->invoke(arg) : none;
}
/// Runs this handler with callback.
bool operator()(detail::invoke_result_visitor& f, message& xs) {
return impl_ ? impl_->invoke(f, xs) : false;
}
/// Returns a new handler that concatenates this handler
/// with a new handler from `xs...`.
template <class... Ts>
typename std::conditional<detail::disjunction<may_have_timeout<
typename std::decay<Ts>::type>::value...>::value,
behavior, message_handler>::type
or_else(Ts&&... xs) const {
// using a behavior is safe here, because we "cast"
// it back to a message_handler when appropriate
behavior tmp{std::forward<Ts>(xs)...};
if (!tmp) {
return *this;
}
if (impl_)
return impl_->or_else(tmp.as_behavior_impl());
return tmp.as_behavior_impl();
}
/// @cond PRIVATE
message_handler& unbox() {
return *this;
}
/// @endcond
private:
impl_ptr impl_;
};
} // namespace caf
|