File: message_handler.hpp

package info (click to toggle)
actor-framework 0.18.7-1~exp1
  • links: PTS
  • area: main
  • in suites: experimental
  • size: 8,740 kB
  • sloc: cpp: 85,162; sh: 491; python: 187; makefile: 11
file content (114 lines) | stat: -rw-r--r-- 3,291 bytes parent folder | download
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