OLD | NEW |
---|---|
(Empty) | |
1 // Copyright 2015 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 IPC_IPC_MESSAGE_TEMPLATES_H_ | |
6 #define IPC_IPC_MESSAGE_TEMPLATES_H_ | |
7 | |
8 #include <stdint.h> | |
9 | |
10 #include <type_traits> | |
11 | |
12 #include "base/logging.h" | |
13 #include "base/tuple.h" | |
14 #include "build/build_config.h" | |
15 #include "ipc/ipc_message.h" | |
16 #include "ipc/ipc_message_utils.h" | |
17 | |
18 namespace IPC { | |
19 | |
20 // This function is for all the async IPCs that don't pass an extra parameter | |
21 // using IPC_BEGIN_MESSAGE_MAP_WITH_PARAM. | |
22 template <typename ObjT, typename Method, typename P, typename Tuple> | |
23 void DispatchToMethod(ObjT* obj, Method method, P*, const Tuple& tuple) { | |
24 base::DispatchToMethod(obj, method, tuple); | |
25 } | |
26 | |
27 template <typename ObjT, | |
28 typename Method, | |
29 typename P, | |
30 typename Tuple, | |
31 size_t... Ns> | |
32 void DispatchToMethodImpl(ObjT* obj, | |
33 Method method, | |
34 P* parameter, | |
35 const Tuple& tuple, | |
36 base::IndexSequence<Ns...>) { | |
37 // TODO(mdempsky): Apply UnwrapTraits like base::DispatchToMethod? | |
dcheng
2016/02/05 21:31:41
Do we need that here though? I don't think we'd ne
mdempsky
2016/02/05 22:36:06
I don't know, hence the question mark. :)
IPC is
| |
38 (obj->*method)(parameter, base::get<Ns>(tuple)...); | |
39 } | |
40 | |
41 // The following function is for async IPCs which have a dispatcher with an | |
42 // extra parameter specified using IPC_BEGIN_MESSAGE_MAP_WITH_PARAM. | |
43 template <typename ObjT, typename P, typename... Args, typename... Ts> | |
44 typename std::enable_if<sizeof...(Args) == sizeof...(Ts)>::type | |
45 DispatchToMethod(ObjT* obj, | |
46 void (ObjT::*method)(P*, Args...), | |
47 P* parameter, | |
48 const base::Tuple<Ts...>& tuple) { | |
49 DispatchToMethodImpl(obj, method, parameter, tuple, | |
50 base::MakeIndexSequence<sizeof...(Ts)>()); | |
51 } | |
52 | |
53 enum class MessageKind { | |
54 CONTROL, | |
55 ROUTED, | |
56 }; | |
57 | |
58 // Routing is a helper struct so MessageT's private common constructor has a | |
59 // different type signature than the public "int32_t routing_id" one. | |
60 struct Routing { | |
61 explicit Routing(int32_t id) : id(id) {} | |
62 int32_t id; | |
63 }; | |
64 | |
65 // We want to restrict MessageT's constructors so that a routing_id is always | |
66 // provided for ROUTED messages and never provided for CONTROL messages, so | |
67 // use the SFINAE technique from N4387's "Implementation Hint" section. | |
68 #if defined(COMPILER_MSVC) | |
69 // MSVC 2013 doesn't support default arguments for template member functions | |
70 // of templated classes, so there we have to rely on the DCHECKs instead. | |
71 // TODO(mdempsky): Reevaluate once MSVC 2015. | |
72 #define IPC_MESSAGET_SFINAE(x) | |
73 #else | |
74 #define IPC_MESSAGET_SFINAE(x) \ | |
75 template <bool X = (x), typename std::enable_if<X, bool>::type = false> | |
76 #endif | |
77 | |
78 // MessageT is the common template used for all user-defined message types. | |
79 // It's intended to be used via the macros defined in ipc_message_macros.h. | |
80 template <typename Meta, | |
81 typename InTuple = typename Meta::InTuple, | |
82 typename OutTuple = typename Meta::OutTuple> | |
83 class MessageT; | |
84 | |
85 // Asynchronous message partial specialization. | |
86 template <typename Meta, typename... Ins> | |
87 class MessageT<Meta, base::Tuple<Ins...>, void> : public Message { | |
88 public: | |
89 using Param = base::Tuple<Ins...>; | |
90 enum { ID = Meta::ID }; | |
91 | |
92 // TODO(mdempsky): Remove. Uses of MyMessage::Schema::Param can be replaced | |
93 // with just MyMessage::Param. | |
94 using Schema = MessageT; | |
95 | |
96 IPC_MESSAGET_SFINAE(Meta::kKind == MessageKind::CONTROL) | |
97 MessageT(const Ins&... ins) : MessageT(Routing(MSG_ROUTING_CONTROL), ins...) { | |
98 DCHECK(Meta::kKind == MessageKind::CONTROL) << Meta::kName; | |
99 } | |
100 | |
101 IPC_MESSAGET_SFINAE(Meta::kKind == MessageKind::ROUTED) | |
102 MessageT(int32_t routing_id, const Ins&... ins) | |
103 : MessageT(Routing(routing_id), ins...) { | |
104 DCHECK(Meta::kKind == MessageKind::ROUTED) << Meta::kName; | |
105 } | |
106 | |
107 static bool Read(const Message* msg, Param* p); | |
108 static void Log(std::string* name, const Message* msg, std::string* l); | |
109 | |
110 template <class T, class S, class P, class Method> | |
111 static bool Dispatch(const Message* msg, | |
112 T* obj, | |
113 S* sender, | |
114 P* parameter, | |
115 Method func) { | |
116 Param p; | |
117 if (Read(msg, &p)) { | |
118 DispatchToMethod(obj, func, parameter, p); | |
119 return true; | |
120 } | |
121 return false; | |
122 } | |
123 | |
124 private: | |
125 MessageT(Routing routing, const Ins&... ins); | |
126 }; | |
127 | |
128 // Synchronous message partial specialization. | |
129 template <typename Meta, typename... Ins, typename... Outs> | |
130 class MessageT<Meta, base::Tuple<Ins...>, base::Tuple<Outs...>> | |
131 : public SyncMessage { | |
132 public: | |
133 using SendParam = base::Tuple<Ins...>; | |
134 using ReplyParam = base::Tuple<Outs...>; | |
135 enum { ID = Meta::ID }; | |
136 | |
137 // TODO(mdempsky): Remove. Uses of MyMessage::Schema::{Send,Reply}Param can | |
138 // be replaced with just MyMessage::{Send,Reply}Param. | |
139 using Schema = MessageT; | |
140 | |
141 IPC_MESSAGET_SFINAE(Meta::kKind == MessageKind::CONTROL) | |
142 MessageT(const Ins&... ins, Outs*... outs) | |
143 : MessageT(Routing(MSG_ROUTING_CONTROL), ins..., outs...) { | |
144 DCHECK(Meta::kKind == MessageKind::CONTROL) << Meta::kName; | |
145 } | |
146 | |
147 IPC_MESSAGET_SFINAE(Meta::kKind == MessageKind::ROUTED) | |
148 MessageT(int32_t routing_id, const Ins&... ins, Outs*... outs) | |
149 : MessageT(Routing(routing_id), ins..., outs...) { | |
150 DCHECK(Meta::kKind == MessageKind::ROUTED) << Meta::kName; | |
151 } | |
152 | |
153 static bool ReadSendParam(const Message* msg, SendParam* p); | |
154 static bool ReadReplyParam(const Message* msg, ReplyParam* p); | |
155 static void WriteReplyParams(Message* reply, const Outs&... outs); | |
156 static void Log(std::string* name, const Message* msg, std::string* l); | |
157 | |
158 template <class T, class S, class P, class Method> | |
159 static bool Dispatch(const Message* msg, | |
160 T* obj, | |
161 S* sender, | |
162 P* parameter, | |
163 Method func) { | |
164 SendParam send_params; | |
165 bool ok = ReadSendParam(msg, &send_params); | |
166 Message* reply = SyncMessage::GenerateReply(msg); | |
167 if (ok) { | |
168 ReplyParam reply_params; | |
169 base::DispatchToMethod(obj, func, send_params, &reply_params); | |
170 WriteParam(reply, reply_params); | |
171 LogReplyParamsToMessage(reply_params, msg); | |
172 } else { | |
173 NOTREACHED() << "Error deserializing message " << msg->type(); | |
174 reply->set_reply_error(); | |
175 } | |
176 sender->Send(reply); | |
177 return ok; | |
178 } | |
179 | |
180 template <class T, class P, class Method> | |
181 static bool DispatchDelayReply(const Message* msg, | |
182 T* obj, | |
183 P* parameter, | |
184 Method func) { | |
185 SendParam send_params; | |
186 bool ok = ReadSendParam(msg, &send_params); | |
187 Message* reply = SyncMessage::GenerateReply(msg); | |
188 if (ok) { | |
189 base::Tuple<Message&> t = base::MakeRefTuple(*reply); | |
190 ConnectMessageAndReply(msg, reply); | |
191 base::DispatchToMethod(obj, func, send_params, &t); | |
192 } else { | |
193 NOTREACHED() << "Error deserializing message " << msg->type(); | |
194 reply->set_reply_error(); | |
195 obj->Send(reply); | |
196 } | |
197 return ok; | |
198 } | |
199 | |
200 private: | |
201 MessageT(Routing routing, const Ins&... ins, Outs*... outs); | |
202 }; | |
203 | |
204 } // namespace IPC | |
205 | |
206 #if defined(IPC_MESSAGE_IMPL) | |
207 #include "ipc/ipc_message_templates_impl.h" | |
208 #endif | |
209 | |
210 #endif // IPC_IPC_MESSAGE_TEMPLATES_H_ | |
OLD | NEW |