Index: ipc/ipc_message_templates.h |
diff --git a/ipc/ipc_message_templates.h b/ipc/ipc_message_templates.h |
new file mode 100644 |
index 0000000000000000000000000000000000000000..17dfc1b9ff221169167c2f3103089a219e14fa5e |
--- /dev/null |
+++ b/ipc/ipc_message_templates.h |
@@ -0,0 +1,210 @@ |
+// Copyright 2015 The Chromium Authors. All rights reserved. |
+// Use of this source code is governed by a BSD-style license that can be |
+// found in the LICENSE file. |
+ |
+#ifndef IPC_IPC_MESSAGE_TEMPLATES_H_ |
+#define IPC_IPC_MESSAGE_TEMPLATES_H_ |
+ |
+#include <stdint.h> |
+ |
+#include <type_traits> |
+ |
+#include "base/logging.h" |
+#include "base/tuple.h" |
+#include "build/build_config.h" |
+#include "ipc/ipc_message.h" |
+#include "ipc/ipc_message_utils.h" |
+ |
+namespace IPC { |
+ |
+// This function is for all the async IPCs that don't pass an extra parameter |
+// using IPC_BEGIN_MESSAGE_MAP_WITH_PARAM. |
+template <typename ObjT, typename Method, typename P, typename Tuple> |
+void DispatchToMethod(ObjT* obj, Method method, P*, const Tuple& tuple) { |
+ base::DispatchToMethod(obj, method, tuple); |
+} |
+ |
+template <typename ObjT, |
+ typename Method, |
+ typename P, |
+ typename Tuple, |
+ size_t... Ns> |
+void DispatchToMethodImpl(ObjT* obj, |
+ Method method, |
+ P* parameter, |
+ const Tuple& tuple, |
+ base::IndexSequence<Ns...>) { |
+ // TODO(mdempsky): Apply UnwrapTraits like base::DispatchToMethod? |
+ (obj->*method)(parameter, base::get<Ns>(tuple)...); |
+} |
+ |
+// The following function is for async IPCs which have a dispatcher with an |
+// extra parameter specified using IPC_BEGIN_MESSAGE_MAP_WITH_PARAM. |
+template <typename ObjT, typename P, typename... Args, typename... Ts> |
+typename std::enable_if<sizeof...(Args) == sizeof...(Ts)>::type |
+DispatchToMethod(ObjT* obj, |
+ void (ObjT::*method)(P*, Args...), |
+ P* parameter, |
+ const base::Tuple<Ts...>& tuple) { |
+ DispatchToMethodImpl(obj, method, parameter, tuple, |
+ base::MakeIndexSequence<sizeof...(Ts)>()); |
+} |
+ |
+enum class MessageKind { |
+ CONTROL, |
+ ROUTED, |
+}; |
+ |
+// Routing is a helper struct so MessageT's private common constructor has a |
+// different type signature than the public "int32_t routing_id" one. |
+struct Routing { |
+ explicit Routing(int32_t id) : id(id) {} |
+ int32_t id; |
+}; |
+ |
+// We want to restrict MessageT's constructors so that a routing_id is always |
+// provided for ROUTED messages and never provided for CONTROL messages, so |
+// use the SFINAE technique from N4387's "Implementation Hint" section. |
+#if defined(COMPILER_MSVC) |
+// MSVC 2013 doesn't support default arguments for template member functions |
+// of templated classes, so there we have to rely on the DCHECKs instead. |
+// TODO(mdempsky): Reevaluate once MSVC 2015. |
+#define IPC_MESSAGET_SFINAE(x) |
+#else |
+#define IPC_MESSAGET_SFINAE(x) \ |
+ template <bool X = (x), typename std::enable_if<X, bool>::type = false> |
+#endif |
+ |
+// MessageT is the common template used for all user-defined message types. |
+// It's intended to be used via the macros defined in ipc_message_macros.h. |
+template <typename Meta, |
+ typename InTuple = typename Meta::InTuple, |
+ typename OutTuple = typename Meta::OutTuple> |
+class MessageT; |
+ |
+// Asynchronous message partial specialization. |
+template <typename Meta, typename... Ins> |
+class MessageT<Meta, base::Tuple<Ins...>, void> : public Message { |
+ public: |
+ using Param = base::Tuple<Ins...>; |
+ enum { ID = Meta::ID }; |
+ |
+ // TODO(mdempsky): Remove. Uses of MyMessage::Schema::Param can be replaced |
+ // with just MyMessage::Param. |
+ using Schema = MessageT; |
+ |
+ IPC_MESSAGET_SFINAE(Meta::kKind == MessageKind::CONTROL) |
+ MessageT(const Ins&... ins) : MessageT(Routing(MSG_ROUTING_CONTROL), ins...) { |
+ DCHECK(Meta::kKind == MessageKind::CONTROL) << Meta::kName; |
+ } |
+ |
+ IPC_MESSAGET_SFINAE(Meta::kKind == MessageKind::ROUTED) |
+ MessageT(int32_t routing_id, const Ins&... ins) |
+ : MessageT(Routing(routing_id), ins...) { |
+ DCHECK(Meta::kKind == MessageKind::ROUTED) << Meta::kName; |
+ } |
+ |
+ static bool Read(const Message* msg, Param* p); |
+ static void Log(std::string* name, const Message* msg, std::string* l); |
+ |
+ template <class T, class S, class P, class Method> |
+ static bool Dispatch(const Message* msg, |
+ T* obj, |
+ S* sender, |
+ P* parameter, |
+ Method func) { |
+ Param p; |
+ if (Read(msg, &p)) { |
+ DispatchToMethod(obj, func, parameter, p); |
+ return true; |
+ } |
+ return false; |
+ } |
+ |
+ private: |
+ MessageT(Routing routing, const Ins&... ins); |
+}; |
+ |
+// Synchronous message partial specialization. |
+template <typename Meta, typename... Ins, typename... Outs> |
+class MessageT<Meta, base::Tuple<Ins...>, base::Tuple<Outs...>> |
+ : public SyncMessage { |
+ public: |
+ using SendParam = base::Tuple<Ins...>; |
+ using ReplyParam = base::Tuple<Outs...>; |
+ enum { ID = Meta::ID }; |
+ |
+ // TODO(mdempsky): Remove. Uses of MyMessage::Schema::{Send,Reply}Param can |
+ // be replaced with just MyMessage::{Send,Reply}Param. |
+ using Schema = MessageT; |
+ |
+ IPC_MESSAGET_SFINAE(Meta::kKind == MessageKind::CONTROL) |
+ MessageT(const Ins&... ins, Outs*... outs) |
+ : MessageT(Routing(MSG_ROUTING_CONTROL), ins..., outs...) { |
+ DCHECK(Meta::kKind == MessageKind::CONTROL) << Meta::kName; |
+ } |
+ |
+ IPC_MESSAGET_SFINAE(Meta::kKind == MessageKind::ROUTED) |
+ MessageT(int32_t routing_id, const Ins&... ins, Outs*... outs) |
+ : MessageT(Routing(routing_id), ins..., outs...) { |
+ DCHECK(Meta::kKind == MessageKind::ROUTED) << Meta::kName; |
+ } |
+ |
+ static bool ReadSendParam(const Message* msg, SendParam* p); |
+ static bool ReadReplyParam(const Message* msg, ReplyParam* p); |
+ static void WriteReplyParams(Message* reply, const Outs&... outs); |
+ static void Log(std::string* name, const Message* msg, std::string* l); |
+ |
+ template <class T, class S, class P, class Method> |
+ static bool Dispatch(const Message* msg, |
+ T* obj, |
+ S* sender, |
+ P* parameter, |
+ Method func) { |
+ SendParam send_params; |
+ bool ok = ReadSendParam(msg, &send_params); |
+ Message* reply = SyncMessage::GenerateReply(msg); |
+ if (ok) { |
+ ReplyParam reply_params; |
+ base::DispatchToMethod(obj, func, send_params, &reply_params); |
+ WriteParam(reply, reply_params); |
+ LogReplyParamsToMessage(reply_params, msg); |
+ } else { |
+ NOTREACHED() << "Error deserializing message " << msg->type(); |
+ reply->set_reply_error(); |
+ } |
+ sender->Send(reply); |
+ return ok; |
+ } |
+ |
+ template <class T, class P, class Method> |
+ static bool DispatchDelayReply(const Message* msg, |
+ T* obj, |
+ P* parameter, |
+ Method func) { |
+ SendParam send_params; |
+ bool ok = ReadSendParam(msg, &send_params); |
+ Message* reply = SyncMessage::GenerateReply(msg); |
+ if (ok) { |
+ base::Tuple<Message&> t = base::MakeRefTuple(*reply); |
+ ConnectMessageAndReply(msg, reply); |
+ base::DispatchToMethod(obj, func, send_params, &t); |
+ } else { |
+ NOTREACHED() << "Error deserializing message " << msg->type(); |
+ reply->set_reply_error(); |
+ obj->Send(reply); |
+ } |
+ return ok; |
+ } |
+ |
+ private: |
+ MessageT(Routing routing, const Ins&... ins, Outs*... outs); |
+}; |
+ |
+} // namespace IPC |
+ |
+#if defined(IPC_MESSAGE_IMPL) |
+#include "ipc/ipc_message_templates_impl.h" |
+#endif |
+ |
+#endif // IPC_IPC_MESSAGE_TEMPLATES_H_ |