1 // Copyright 2019 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #ifndef MOJO_PUBLIC_CPP_BINDINGS_PENDING_RECEIVER_H_
6 #define MOJO_PUBLIC_CPP_BINDINGS_PENDING_RECEIVER_H_
7
8 #include <type_traits>
9 #include <utility>
10
11 #include "base/macros.h"
12 #include "build/build_config.h"
13 #include "mojo/public/cpp/bindings/connection_group.h"
14 #include "mojo/public/cpp/bindings/interface_request.h"
15 #include "mojo/public/cpp/bindings/lib/bindings_internal.h"
16 #include "mojo/public/cpp/bindings/lib/pending_receiver_state.h"
17 #include "mojo/public/cpp/bindings/lib/serialization_context.h"
18 #include "mojo/public/cpp/system/message_pipe.h"
19
20 namespace mojo {
21
22 template <typename T>
23 struct PendingReceiverConverter;
24
25 // A PendingReceiver receives and accumulates a queue of incoming Interface
26 // method calls made by a single corresponding Remote. PendingReceiver instances
27 // may be freely moved to another thread/sequence, or even transferred to
28 // another process via a Mojo interface call (see pending_receiver<T> syntax in
29 // mojom IDL).
30 //
31 // This object should eventually be consumed to bind a Receiver, which will then
32 // begin dispatching any queued and future incoming method calls to a local
33 // implementation of Interface. See Receiver documentation for more details.
34 //
35 // NOTE: This object is essentially semantic sugar wrapping a message pipe
36 // handle that is expected to receive Interface messages from a Remote. As such,
37 // consumers who know what they're doing (i.e. who are confident about what lies
38 // on the other end of a pipe) may freely convert between a PendingReceiver and
39 // a raw message pipe handle.
40 template <typename Interface>
41 class PendingReceiver {
42 public:
43 // Constructs an invalid PendingReceiver. This object is not entangled with
44 // any Remote and cannot be used to bind a Receiver.
45 //
46 // A valid PendingReceiver is commonly obtained by calling
47 // |Remote::BindNewPipeAndPassReceiver()| on an existing unbound Remote
48 // instance or less commonly by calling calling
49 // |PendingRemote::InitWithNewPipeAndPassReceiver()| on an existing but
50 // invalid PendingRemote instance.
51 PendingReceiver() = default;
52 PendingReceiver(PendingReceiver&&) noexcept = default;
53
54 // Temporary implicit move constructor to aid in converting from use of
55 // InterfaceRequest<Interface> to PendingReceiver.
PendingReceiver(InterfaceRequest<Interface> && request)56 PendingReceiver(InterfaceRequest<Interface>&& request)
57 : PendingReceiver(request.PassMessagePipe()) {
58 set_connection_group(request.PassConnectionGroupRef());
59 }
60
61 // Constructs a valid PendingReceiver from a valid raw message pipe handle.
PendingReceiver(ScopedMessagePipeHandle pipe)62 explicit PendingReceiver(ScopedMessagePipeHandle pipe)
63 : state_(std::move(pipe)) {}
64
65 // Disabled on NaCl since it crashes old version of clang.
66 #if !defined(OS_NACL)
67 // Move conversion operator for custom receiver types. Only participates in
68 // overload resolution if a typesafe conversion is supported.
69 template <
70 typename T,
71 std::enable_if_t<std::is_same<
72 PendingReceiver<Interface>,
73 std::result_of_t<decltype (&PendingReceiverConverter<T>::template To<
74 Interface>)(T&&)>>::value>* = nullptr>
PendingReceiver(T && other)75 PendingReceiver(T&& other)
76 : PendingReceiver(PendingReceiverConverter<T>::template To<Interface>(
77 std::forward<T>(other))) {}
78 #endif // !defined(OS_NACL)
79
80 ~PendingReceiver() = default;
81
82 PendingReceiver& operator=(PendingReceiver&&) noexcept = default;
83
84 // Temporary implicit conversion operator to InterfaceRequest<Interface> to
85 // aid in converting usage to PendingReceiver.
86 operator InterfaceRequest<Interface>() && {
87 InterfaceRequest<Interface> request(PassPipe());
88 request.set_connection_group(PassConnectionGroupRef());
89 return request;
90 }
91
92 // Indicates whether the PendingReceiver is valid, meaning it can ne used to
93 // bind a Receiver that wants to begin dispatching method calls made by the
94 // entangled Remote.
is_valid()95 bool is_valid() const { return state_.pipe.is_valid(); }
96 explicit operator bool() const { return is_valid(); }
97
98 // Resets this PendingReceiver to an invalid state. If it was entangled with a
99 // Remote or PendingRemote, that object remains in a valid state and will
100 // eventually detect that its receiver is gone. Any calls it makes will
101 // effectively be dropped.
reset()102 void reset() { state_.reset(); }
103
104 // Like above but provides a reason for the disconnection.
ResetWithReason(uint32_t reason,const std::string & description)105 void ResetWithReason(uint32_t reason, const std::string& description) {
106 InterfaceRequest<Interface>(PassPipe())
107 .ResetWithReason(reason, description);
108 }
109
110 // Passes ownership of this PendingReceiver's message pipe handle. After this
111 // call, the PendingReceiver is no longer in a valid state and can no longer
112 // be used to bind a Receiver.
PassPipe()113 ScopedMessagePipeHandle PassPipe() WARN_UNUSED_RESULT {
114 return std::move(state_.pipe);
115 }
116
117 // Assigns this PendingReceiver to the ConnectionGroup referenced by |ref|.
118 // Any Receiver which binds this PendingReceiver will inherit the Ref.
set_connection_group(ConnectionGroup::Ref ref)119 void set_connection_group(ConnectionGroup::Ref ref) {
120 state_.connection_group = std::move(ref);
121 }
122
connection_group()123 const ConnectionGroup::Ref& connection_group() const {
124 return state_.connection_group;
125 }
126
127 // Passes ownership of this PendingReceiver's ConnectionGroup Ref, removing it
128 // from its group.
PassConnectionGroupRef()129 ConnectionGroup::Ref PassConnectionGroupRef() {
130 return std::move(state_.connection_group);
131 }
132
133 // For internal Mojo use only.
internal_state()134 internal::PendingReceiverState* internal_state() { return &state_; }
135
136 private:
137 internal::PendingReceiverState state_;
138
139 DISALLOW_COPY_AND_ASSIGN(PendingReceiver);
140 };
141
COMPONENT_EXPORT(MOJO_CPP_BINDINGS)142 class COMPONENT_EXPORT(MOJO_CPP_BINDINGS) NullReceiver {
143 public:
144 template <typename Interface>
145 operator PendingReceiver<Interface>() const {
146 return PendingReceiver<Interface>();
147 }
148 };
149
150 } // namespace mojo
151
152 #endif // MOJO_PUBLIC_CPP_BINDINGS_PENDING_RECEIVER_H_
153