File: message_handler.hpp

package info (click to toggle)
actor-framework 0.17.6-3.2
  • links: PTS
  • area: main
  • in suites: forky, sid
  • size: 9,008 kB
  • sloc: cpp: 77,684; sh: 674; python: 309; makefile: 13
file content (147 lines) | stat: -rw-r--r-- 4,941 bytes parent folder | download | duplicates (4)
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
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
/******************************************************************************
 *                       ____    _    _____                                   *
 *                      / ___|  / \  |  ___|    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 <list>
#include <vector>
#include <memory>
#include <utility>
#include <type_traits>

#include "caf/fwd.hpp"
#include "caf/none.hpp"
#include "caf/intrusive_ptr.hpp"

#include "caf/behavior.hpp"
#include "caf/duration.hpp"
#include "caf/match_case.hpp"
#include "caf/may_have_timeout.hpp"
#include "caf/message.hpp"
#include "caf/ref_counted.hpp"
#include "caf/timeout_definition.hpp"

#include "caf/detail/behavior_impl.hpp"

namespace caf {

/// A partial function implementation used to process a `message`.
class 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.
  inline 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.
  inline 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.
  inline optional<message> operator()(message& arg) {
    return (impl_) ? impl_->invoke(arg) : none;
  }

  /// Runs this handler and returns its (optional) result.
  inline optional<message> operator()(type_erased_tuple& xs) {
    return impl_ ? impl_->invoke(xs) : none;
  }

  /// Runs this handler with callback.
  inline match_case::result operator()(detail::invoke_result_visitor& f,
                                       type_erased_tuple& xs) {
    return impl_ ? impl_->invoke(f, xs) : match_case::no_match;
  }

  /// Runs this handler with callback.
  inline match_case::result operator()(detail::invoke_result_visitor& f,
                                       message& xs) {
    return impl_ ? impl_->invoke(f, xs) : match_case::no_match;
  }

  /// 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

  inline message_handler& unbox() {
    return *this;
  }

  /// @endcond

private:
  impl_ptr impl_;
};

} // namespace caf