d275f6423085cd06e9b8c0345cba691ac3351299
[oota-llvm.git] / include / llvm / ExecutionEngine / Orc / RPCUtils.h
1 //===----- RPCUTils.h - Basic tilities for building RPC APIs ----*- C++ -*-===//
2 //
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 //
10 // Basic utilities for building RPC APIs.
11 //
12 //===----------------------------------------------------------------------===//
13
14 #ifndef LLVM_EXECUTIONENGINE_ORC_RPCUTILS_H
15 #define LLVM_EXECUTIONENGINE_ORC_RPCUTILS_H
16
17 #include "llvm/ADT/STLExtras.h"
18
19 namespace llvm {
20 namespace orc {
21 namespace remote {
22
23 /// Contains primitive utilities for defining, calling and handling calls to
24 /// remote procedures. ChannelT is a bidirectional stream conforming to the
25 /// RPCChannel interface (see RPCChannel.h), and ProcedureIdT is a procedure
26 /// identifier type that must be serializable on ChannelT.
27 ///
28 /// These utilities support the construction of very primitive RPC utilities.
29 /// Their intent is to ensure correct serialization and deserialization of
30 /// procedure arguments, and to keep the client and server's view of the API in
31 /// sync.
32 ///
33 /// These utilities do not support return values. These can be handled by
34 /// declaring a corresponding '.*Response' procedure and expecting it after a
35 /// call). They also do not support versioning: the client and server *must* be
36 /// compiled with the same procedure definitions.
37 ///
38 ///
39 ///
40 /// Overview (see comments individual types/methods for details):
41 ///
42 /// Procedure<Id, Args...> :
43 ///
44 ///   associates a unique serializable id with an argument list.
45 ///
46 ///
47 /// call<Proc>(Channel, Args...) :
48 ///
49 ///   Calls the remote procedure 'Proc' by serializing Proc's id followed by its
50 /// arguments and sending the resulting bytes to 'Channel'.
51 ///
52 ///
53 /// handle<Proc>(Channel, <functor matching std::error_code(Args...)> :
54 ///
55 ///   Handles a call to 'Proc' by deserializing its arguments and calling the
56 /// given functor. This assumes that the id for 'Proc' has already been
57 /// deserialized.
58 ///
59 /// expect<Proc>(Channel, <functor matching std::error_code(Args...)> :
60 ///
61 ///   The same as 'handle', except that the procedure id should not have been
62 /// read yet. Expect will deserialize the id and assert that it matches Proc's
63 /// id. If it does not, and unexpected RPC call error is returned.
64
65 template <typename ChannelT, typename ProcedureIdT = uint32_t> class RPC {
66 public:
67   /// Utility class for defining/referring to RPC procedures.
68   ///
69   /// Typedefs of this utility are used when calling/handling remote procedures.
70   ///
71   /// ProcId should be a unique value of ProcedureIdT (i.e. not used with any
72   /// other Procedure typedef in the RPC API being defined.
73   ///
74   /// the template argument Ts... gives the argument list for the remote
75   /// procedure.
76   ///
77   /// E.g.
78   ///
79   ///   typedef Procedure<0, bool> Proc1;
80   ///   typedef Procedure<1, std::string, std::vector<int>> Proc2;
81   ///
82   ///   if (auto EC = call<Proc1>(Channel, true))
83   ///     /* handle EC */;
84   ///
85   ///   if (auto EC = expect<Proc2>(Channel,
86   ///         [](std::string &S, std::vector<int> &V) {
87   ///           // Stuff.
88   ///           return std::error_code();
89   ///         })
90   ///     /* handle EC */;
91   ///
92   template <ProcedureIdT ProcId, typename... Ts> class Procedure {
93   public:
94     static const ProcedureIdT Id = ProcId;
95   };
96
97 private:
98   template <typename Proc> class CallHelper {};
99
100   template <ProcedureIdT ProcId, typename... ArgTs>
101   class CallHelper<Procedure<ProcId, ArgTs...>> {
102   public:
103     static std::error_code call(ChannelT &C, const ArgTs &... Args) {
104       if (auto EC = serialize(C, ProcId))
105         return EC;
106       // If you see a compile-error on this line you're probably calling a
107       // function with the wrong signature.
108       return serialize_seq(C, Args...);
109     }
110   };
111
112   template <typename Proc> class HandlerHelper {};
113
114   template <ProcedureIdT ProcId, typename... ArgTs>
115   class HandlerHelper<Procedure<ProcId, ArgTs...>> {
116   public:
117     template <typename HandlerT>
118     static std::error_code handle(ChannelT &C, HandlerT Handler) {
119       return readAndHandle(C, Handler, llvm::index_sequence_for<ArgTs...>());
120     }
121
122   private:
123     template <typename HandlerT, size_t... Is>
124     static std::error_code readAndHandle(ChannelT &C, HandlerT Handler,
125                                          llvm::index_sequence<Is...> _) {
126       std::tuple<ArgTs...> RPCArgs;
127       if (auto EC = deserialize_seq(C, std::get<Is>(RPCArgs)...))
128         return EC;
129       return Handler(std::get<Is>(RPCArgs)...);
130     }
131   };
132
133   template <typename... ArgTs> class ReadArgs {
134   public:
135     std::error_code operator()() { return std::error_code(); }
136   };
137
138   template <typename ArgT, typename... ArgTs>
139   class ReadArgs<ArgT, ArgTs...> : public ReadArgs<ArgTs...> {
140   public:
141     ReadArgs(ArgT &Arg, ArgTs &... Args)
142         : ReadArgs<ArgTs...>(Args...), Arg(Arg) {}
143
144     std::error_code operator()(ArgT &ArgVal, ArgTs &... ArgVals) {
145       this->Arg = std::move(ArgVal);
146       return ReadArgs<ArgTs...>::operator()(ArgVals...);
147     }
148
149   private:
150     ArgT &Arg;
151   };
152
153 public:
154   /// Serialize Args... to channel C, but do not call C.send().
155   ///
156   /// For buffered channels, this can be used to queue up several calls before
157   /// flushing the channel.
158   template <typename Proc, typename... ArgTs>
159   static std::error_code appendCall(ChannelT &C, const ArgTs &... Args) {
160     return CallHelper<Proc>::call(C, Args...);
161   }
162
163   /// Serialize Args... to channel C and call C.send().
164   template <typename Proc, typename... ArgTs>
165   static std::error_code call(ChannelT &C, const ArgTs &... Args) {
166     if (auto EC = appendCall<Proc>(C, Args...))
167       return EC;
168     return C.send();
169   }
170
171   /// Deserialize and return an enum whose underlying type is ProcedureIdT.
172   static std::error_code getNextProcId(ChannelT &C, ProcedureIdT &Id) {
173     return deserialize(C, Id);
174   }
175
176   /// Deserialize args for Proc from C and call Handler. The signature of
177   /// handler must conform to 'std::error_code(Args...)' where Args... matches
178   /// the arguments used in the Proc typedef.
179   template <typename Proc, typename HandlerT>
180   static std::error_code handle(ChannelT &C, HandlerT Handler) {
181     return HandlerHelper<Proc>::handle(C, Handler);
182   }
183
184   /// Deserialize a ProcedureIdT from C and verify it matches the id for Proc.
185   /// If the id does match, deserialize the arguments and call the handler
186   /// (similarly to handle).
187   /// If the id does not match, return an unexpect RPC call error and do not
188   /// deserialize any further bytes.
189   template <typename Proc, typename HandlerT>
190   static std::error_code expect(ChannelT &C, HandlerT Handler) {
191     ProcedureIdT ProcId;
192     if (auto EC = getNextProcId(C, ProcId))
193       return EC;
194     if (ProcId != Proc::Id)
195       return orcError(OrcErrorCode::UnexpectedRPCCall);
196     return handle<Proc>(C, Handler);
197   }
198
199   /// Helper for handling setter procedures - this method returns a functor that
200   /// sets the variables referred to by Args... to values deserialized from the
201   /// channel.
202   /// E.g.
203   ///
204   ///   typedef Procedure<0, bool, int> Proc1;
205   ///
206   ///   ...
207   ///   bool B;
208   ///   int I;
209   ///   if (auto EC = expect<Proc1>(Channel, readArgs(B, I)))
210   ///     /* Handle Args */ ;
211   ///
212   template <typename... ArgTs>
213   static ReadArgs<ArgTs...> readArgs(ArgTs &... Args) {
214     return ReadArgs<ArgTs...>(Args...);
215   }
216 };
217
218 } // end namespace remote
219 } // end namespace orc
220 } // end namespace llvm
221
222 #endif