1 // Copyright 2015 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #ifndef IPC_IPC_MESSAGE_TEMPLATES_H_
6 #define IPC_IPC_MESSAGE_TEMPLATES_H_
11 #include <type_traits>
14 #include "base/check.h"
15 #include "base/notreached.h"
16 #include "base/trace_event/trace_event.h"
17 #include "base/tuple.h"
18 #include "build/build_config.h"
19 #include "ipc/ipc_message.h"
20 #include "ipc/ipc_message_utils.h"
21 #include "ipc/ipc_sync_message.h"
25 template <typename Tuple, size_t... Ns>
26 auto TupleForwardImpl(Tuple&& tuple, std::index_sequence<Ns...>) -> decltype(
27 std::forward_as_tuple(std::get<Ns>(std::forward<Tuple>(tuple))...)) {
28 return std::forward_as_tuple(std::get<Ns>(std::forward<Tuple>(tuple))...);
31 // Transforms std::tuple contents to the forwarding form.
33 // std::tuple<int, int&, const int&, int&&>&&
34 // -> std::tuple<int&&, int&, const int&, int&&>.
35 // const std::tuple<int, const int&, int&&>&
36 // -> std::tuple<const int&, int&, const int&, int&>.
38 // TupleForward(std::make_tuple(a, b, c)) is equivalent to
39 // std::forward_as_tuple(a, b, c).
40 template <typename Tuple>
41 auto TupleForward(Tuple&& tuple) -> decltype(TupleForwardImpl(
42 std::forward<Tuple>(tuple),
43 std::make_index_sequence<std::tuple_size<std::decay_t<Tuple>>::value>())) {
44 return TupleForwardImpl(
45 std::forward<Tuple>(tuple),
46 std::make_index_sequence<std::tuple_size<std::decay_t<Tuple>>::value>());
49 // This function is for all the async IPCs that don't pass an extra parameter
50 // using IPC_BEGIN_MESSAGE_MAP_WITH_PARAM.
51 template <typename ObjT, typename Method, typename P, typename Tuple>
52 void DispatchToMethod(ObjT* obj, Method method, P*, Tuple&& tuple) {
53 base::DispatchToMethod(obj, method, std::forward<Tuple>(tuple));
56 template <typename ObjT,
61 void DispatchToMethodImpl(ObjT* obj,
65 std::index_sequence<Ns...>) {
66 (obj->*method)(parameter, std::get<Ns>(std::forward<Tuple>(tuple))...);
69 // The following function is for async IPCs which have a dispatcher with an
70 // extra parameter specified using IPC_BEGIN_MESSAGE_MAP_WITH_PARAM.
71 template <typename ObjT, typename P, typename... Args, typename Tuple>
72 std::enable_if_t<sizeof...(Args) == std::tuple_size<std::decay_t<Tuple>>::value>
73 DispatchToMethod(ObjT* obj,
74 void (ObjT::*method)(P*, Args...),
77 constexpr size_t size = std::tuple_size<std::decay_t<Tuple>>::value;
78 DispatchToMethodImpl(obj, method, parameter, std::forward<Tuple>(tuple),
79 std::make_index_sequence<size>());
82 enum class MessageKind {
87 // Routing is a helper struct so MessageT's private common constructor has a
88 // different type signature than the public "int32_t routing_id" one.
90 explicit Routing(int32_t id) : id(id) {}
94 // We want to restrict MessageT's constructors so that a routing_id is always
95 // provided for ROUTED messages and never provided for CONTROL messages, so
96 // use the SFINAE technique from N4387's "Implementation Hint" section.
97 #define IPC_MESSAGET_SFINAE(x) \
98 template <bool X = (x), typename std::enable_if<X, bool>::type = false>
100 // MessageT is the common template used for all user-defined message types.
101 // It's intended to be used via the macros defined in ipc_message_macros.h.
102 template <typename Meta,
103 typename InTuple = typename Meta::InTuple,
104 typename OutTuple = typename Meta::OutTuple>
107 // Asynchronous message partial specialization.
108 template <typename Meta, typename... Ins>
109 class MessageT<Meta, std::tuple<Ins...>, void> : public Message {
111 using Param = std::tuple<Ins...>;
112 enum { ID = Meta::ID };
114 // TODO(mdempsky): Remove. Uses of MyMessage::Schema::Param can be replaced
115 // with just MyMessage::Param.
116 using Schema = MessageT;
118 IPC_MESSAGET_SFINAE(Meta::kKind == MessageKind::CONTROL)
119 MessageT(const Ins&... ins) : MessageT(Routing(MSG_ROUTING_CONTROL), ins...) {
120 DCHECK(Meta::kKind == MessageKind::CONTROL) << Meta::kName;
123 IPC_MESSAGET_SFINAE(Meta::kKind == MessageKind::ROUTED)
124 MessageT(int32_t routing_id, const Ins&... ins)
125 : MessageT(Routing(routing_id), ins...) {
126 DCHECK(Meta::kKind == MessageKind::ROUTED) << Meta::kName;
129 static bool Read(const Message* msg, Param* p);
130 static void Log(std::string* name, const Message* msg, std::string* l);
132 template <class T, class S, class P, class Method>
133 static bool Dispatch(const Message* msg,
138 TRACE_EVENT0("ipc", Meta::kName);
141 DispatchToMethod(obj, func, parameter, std::move(p));
148 MessageT(Routing routing, const Ins&... ins);
151 // Synchronous message partial specialization.
152 template <typename Meta, typename... Ins, typename... Outs>
153 class MessageT<Meta, std::tuple<Ins...>, std::tuple<Outs...>>
154 : public SyncMessage {
156 using SendParam = std::tuple<Ins...>;
157 using ReplyParam = std::tuple<Outs...>;
158 enum { ID = Meta::ID };
160 // TODO(mdempsky): Remove. Uses of MyMessage::Schema::{Send,Reply}Param can
161 // be replaced with just MyMessage::{Send,Reply}Param.
162 using Schema = MessageT;
164 IPC_MESSAGET_SFINAE(Meta::kKind == MessageKind::CONTROL)
165 MessageT(const Ins&... ins, Outs*... outs)
166 : MessageT(Routing(MSG_ROUTING_CONTROL), ins..., outs...) {
167 DCHECK(Meta::kKind == MessageKind::CONTROL) << Meta::kName;
170 IPC_MESSAGET_SFINAE(Meta::kKind == MessageKind::ROUTED)
171 MessageT(int32_t routing_id, const Ins&... ins, Outs*... outs)
172 : MessageT(Routing(routing_id), ins..., outs...) {
173 DCHECK(Meta::kKind == MessageKind::ROUTED) << Meta::kName;
176 static bool ReadSendParam(const Message* msg, SendParam* p);
177 static bool ReadReplyParam(const Message* msg, ReplyParam* p);
178 static void WriteReplyParams(Message* reply, const Outs&... outs);
179 static void Log(std::string* name, const Message* msg, std::string* l);
181 template <class T, class S, class P, class Method>
182 static bool Dispatch(const Message* msg,
187 TRACE_EVENT0("ipc", Meta::kName);
188 SendParam send_params;
189 bool ok = ReadSendParam(msg, &send_params);
190 Message* reply = SyncMessage::GenerateReply(msg);
192 NOTREACHED() << "Error deserializing message " << msg->type();
193 reply->set_reply_error();
198 ReplyParam reply_params;
199 base::DispatchToMethod(obj, func, std::move(send_params), &reply_params);
200 WriteParam(reply, reply_params);
201 LogReplyParamsToMessage(reply_params, msg);
206 template <class T, class P, class Method>
207 static bool DispatchDelayReply(const Message* msg,
211 TRACE_EVENT0("ipc", Meta::kName);
212 SendParam send_params;
213 bool ok = ReadSendParam(msg, &send_params);
214 Message* reply = SyncMessage::GenerateReply(msg);
216 NOTREACHED() << "Error deserializing message " << msg->type();
217 reply->set_reply_error();
222 std::tuple<Message&> t = std::tie(*reply);
223 ConnectMessageAndReply(msg, reply);
224 base::DispatchToMethod(obj, func, std::move(send_params), &t);
228 template <class T, class P, class Method>
229 static bool DispatchWithParamDelayReply(const Message* msg,
233 TRACE_EVENT0("ipc", Meta::kName);
234 SendParam send_params;
235 bool ok = ReadSendParam(msg, &send_params);
236 Message* reply = SyncMessage::GenerateReply(msg);
238 NOTREACHED() << "Error deserializing message " << msg->type();
239 reply->set_reply_error();
244 std::tuple<Message&> t = std::tie(*reply);
245 ConnectMessageAndReply(msg, reply);
246 std::tuple<P*> parameter_tuple(parameter);
247 base::DispatchToMethod(
249 std::tuple_cat(std::move(parameter_tuple), TupleForward(send_params)),
255 MessageT(Routing routing, const Ins&... ins, Outs*... outs);
260 #if defined(IPC_MESSAGE_IMPL)
261 #include "ipc/ipc_message_templates_impl.h"
264 #endif // IPC_IPC_MESSAGE_TEMPLATES_H_