1 // Copyright 2014 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_INTERFACE_REQUEST_H_
6 #define MOJO_PUBLIC_CPP_BINDINGS_INTERFACE_REQUEST_H_
7
8 #include <utility>
9
10 #include "base/macros.h"
11 #include "base/single_thread_task_runner.h"
12 #include "base/threading/thread_task_runner_handle.h"
13 #include "mojo/public/cpp/bindings/interface_ptr.h"
14
15 namespace mojo {
16
17 // Represents a request from a remote client for an implementation of Interface
18 // over a specified message pipe. The implementor of the interface should
19 // remove the message pipe by calling PassMessagePipe() and bind it to the
20 // implementation. If this is not done, the InterfaceRequest will automatically
21 // close the pipe on destruction. Can also represent the absence of a request
22 // if the client did not provide a message pipe.
23 template <typename Interface>
24 class InterfaceRequest {
25 public:
26 // Constructs an empty InterfaceRequest, representing that the client is not
27 // requesting an implementation of Interface.
InterfaceRequest()28 InterfaceRequest() {}
InterfaceRequest(decltype (nullptr))29 InterfaceRequest(decltype(nullptr)) {}
30
31 // Takes the message pipe from another InterfaceRequest.
InterfaceRequest(InterfaceRequest && other)32 InterfaceRequest(InterfaceRequest&& other) {
33 handle_ = std::move(other.handle_);
34 }
35 InterfaceRequest& operator=(InterfaceRequest&& other) {
36 handle_ = std::move(other.handle_);
37 return *this;
38 }
39
40 // Assigning to nullptr resets the InterfaceRequest to an empty state,
41 // closing the message pipe currently bound to it (if any).
decltype(nullptr)42 InterfaceRequest& operator=(decltype(nullptr)) {
43 handle_.reset();
44 return *this;
45 }
46
47 // Binds the request to a message pipe over which Interface is to be
48 // requested. If the request is already bound to a message pipe, the current
49 // message pipe will be closed.
Bind(ScopedMessagePipeHandle handle)50 void Bind(ScopedMessagePipeHandle handle) { handle_ = std::move(handle); }
51
52 // Indicates whether the request currently contains a valid message pipe.
is_pending()53 bool is_pending() const { return handle_.is_valid(); }
54
55 // Removes the message pipe from the request and returns it.
PassMessagePipe()56 ScopedMessagePipeHandle PassMessagePipe() { return std::move(handle_); }
57
Equals(const InterfaceRequest & other)58 bool Equals(const InterfaceRequest& other) const {
59 if (this == &other)
60 return true;
61
62 // Now that the two refer to different objects, they are equivalent if
63 // and only if they are both invalid.
64 return !is_pending() && !other.is_pending();
65 }
66
67 private:
68 ScopedMessagePipeHandle handle_;
69
70 DISALLOW_COPY_AND_ASSIGN(InterfaceRequest);
71 };
72
73 // Makes an InterfaceRequest bound to the specified message pipe. If |handle|
74 // is empty or invalid, the resulting InterfaceRequest will represent the
75 // absence of a request.
76 template <typename Interface>
MakeRequest(ScopedMessagePipeHandle handle)77 InterfaceRequest<Interface> MakeRequest(ScopedMessagePipeHandle handle) {
78 InterfaceRequest<Interface> request;
79 request.Bind(std::move(handle));
80 return std::move(request);
81 }
82
83 // Creates a new message pipe over which Interface is to be served. Binds the
84 // specified InterfacePtr to one end of the message pipe, and returns an
85 // InterfaceRequest bound to the other. The InterfacePtr should be passed to
86 // the client, and the InterfaceRequest should be passed to whatever will
87 // provide the implementation. The implementation should typically be bound to
88 // the InterfaceRequest using the Binding or StrongBinding classes. The client
89 // may begin to issue calls even before an implementation has been bound, since
90 // messages sent over the pipe will just queue up until they are consumed by
91 // the implementation.
92 //
93 // Example #1: Requesting a remote implementation of an interface.
94 // ===============================================================
95 //
96 // Given the following interface:
97 //
98 // interface Database {
99 // OpenTable(Table& table);
100 // }
101 //
102 // The client would have code similar to the following:
103 //
104 // DatabasePtr database = ...; // Connect to database.
105 // TablePtr table;
106 // database->OpenTable(GetProxy(&table));
107 //
108 // Upon return from GetProxy, |table| is ready to have methods called on it.
109 //
110 // Example #2: Registering a local implementation with a remote service.
111 // =====================================================================
112 //
113 // Given the following interface
114 // interface Collector {
115 // RegisterSource(Source source);
116 // }
117 //
118 // The client would have code similar to the following:
119 //
120 // CollectorPtr collector = ...; // Connect to Collector.
121 // SourcePtr source;
122 // InterfaceRequest<Source> source_request = GetProxy(&source);
123 // collector->RegisterSource(std::move(source));
124 // CreateSource(std::move(source_request)); // Create implementation locally.
125 //
126 template <typename Interface>
127 InterfaceRequest<Interface> GetProxy(
128 InterfacePtr<Interface>* ptr,
129 scoped_refptr<base::SingleThreadTaskRunner> runner =
130 base::ThreadTaskRunnerHandle::Get()) {
131 MessagePipe pipe;
132 ptr->Bind(InterfacePtrInfo<Interface>(std::move(pipe.handle0), 0u),
133 std::move(runner));
134 return MakeRequest<Interface>(std::move(pipe.handle1));
135 }
136
137 // Fuses an InterfaceRequest<T> endpoint with an InterfacePtrInfo<T> endpoint.
138 // Returns |true| on success or |false| on failure.
139 template <typename Interface>
FuseInterface(InterfaceRequest<Interface> request,InterfacePtrInfo<Interface> proxy_info)140 bool FuseInterface(InterfaceRequest<Interface> request,
141 InterfacePtrInfo<Interface> proxy_info) {
142 MojoResult result = FuseMessagePipes(request.PassMessagePipe(),
143 proxy_info.PassHandle());
144 return result == MOJO_RESULT_OK;
145 }
146
147 } // namespace mojo
148
149 #endif // MOJO_PUBLIC_CPP_BINDINGS_INTERFACE_REQUEST_H_
150