Clean-ups to types.
[invirt/third/libt4.git] / rpc / marshall.h
1 #ifndef marshall_h
2 #define marshall_h
3
4 #include "types.h"
5 #include "rpc_protocol.h"
6
7 // for structs or classes containing a MEMBERS declaration
8 class marshall;
9 class unmarshall;
10 #define FORWARD_MARSHALLABLE(_c_) \
11 extern unmarshall & operator>>(unmarshall &u, typename remove_reference<_c_>::type &a); \
12 extern marshall & operator<<(marshall &m, const _c_ a);
13 #define MARSHALLABLE(_c_) \
14 inline unmarshall & operator>>(unmarshall &u, _c_ &a) { return u >> a._tuple_(); } \
15 inline marshall & operator<<(marshall &m, const _c_ a) { return m << a._tuple_(); }
16
17 // for plain old data
18 #define MARSHALL_RAW_NETWORK_ORDER_AS(_c_, _d_) \
19 marshall & operator<<(marshall &m, _c_ x) { _d_ y = hton((_d_)x); m.rawbytes(&y, sizeof(_d_)); return m; } \
20 unmarshall & operator>>(unmarshall &u, _c_ &x) { _d_ y; u.rawbytes(&y, sizeof(_d_)); x = (_c_)ntoh(y); return u; }
21
22 #define MARSHALL_RAW_NETWORK_ORDER(_c_) MARSHALL_RAW_NETWORK_ORDER_AS(_c_, _c_)
23
24 FORWARD_MARSHALLABLE(request_header)
25 ENDIAN_SWAPPABLE(request_header)
26
27 FORWARD_MARSHALLABLE(reply_header)
28 ENDIAN_SWAPPABLE(reply_header)
29
30 // Template parameter pack expansion is not allowed in certain contexts, but
31 // brace initializers (for instance, calls to constructors of empty structs)
32 // are fair game.  
33 struct pass { template <typename... Args> inline pass(Args&&...) {} };
34
35 class marshall {
36     private:
37         string buf_ = string(DEFAULT_RPC_SZ, 0); // Raw bytes buffer
38         size_t index_ = RPC_HEADER_SZ; // Read/write head position
39
40         inline void reserve(size_t n) {
41             if (index_+n > buf_.size())
42                 buf_.resize(index_+n);
43         }
44     public:
45         template <typename... Args>
46         marshall(const Args&... args) {
47             (void)pass{(*this << args)...};
48         }
49
50         void rawbytes(const void *p, size_t n) {
51             reserve(n);
52             copy((char *)p, (char *)p+n, &buf_[index_]);
53             index_ += n;
54         }
55
56         // with header
57         operator string () const { return buf_.substr(0,index_); }
58         // without header
59         string content() { return buf_.substr(RPC_HEADER_SZ,index_-RPC_HEADER_SZ); }
60
61         template <class T>
62         void pack_header(const T &h) {
63             VERIFY(sizeof(T)+sizeof(rpc_sz_t) <= RPC_HEADER_SZ);
64             size_t saved_sz = index_;
65             index_ = sizeof(rpc_sz_t); // first 4 bytes hold length field
66             *this << h;
67             index_ = saved_sz;
68         }
69 };
70
71 FORWARD_MARSHALLABLE(bool);
72 FORWARD_MARSHALLABLE(uint8_t);
73 FORWARD_MARSHALLABLE(int8_t);
74 FORWARD_MARSHALLABLE(uint16_t);
75 FORWARD_MARSHALLABLE(int16_t);
76 FORWARD_MARSHALLABLE(uint32_t);
77 FORWARD_MARSHALLABLE(int32_t);
78 FORWARD_MARSHALLABLE(size_t);
79 FORWARD_MARSHALLABLE(uint64_t);
80 FORWARD_MARSHALLABLE(int64_t);
81 FORWARD_MARSHALLABLE(string &);
82
83 template <class A> typename enable_if<is_iterable<A>::value, marshall>::type &
84 operator<<(marshall &m, const A &x) {
85     m << (unsigned int)x.size();
86     for (const auto &a : x)
87         m << a;
88     return m;
89 }
90
91 template <class A, class B> marshall &
92 operator<<(marshall &m, const pair<A,B> &d) {
93     return m << d.first << d.second;
94 }
95
96 template<typename E>
97 using enum_type_t = typename enable_if<is_enum<E>::value, typename underlying_type<E>::type>::type;
98 template<typename E> constexpr inline enum_type_t<E> from_enum(E e) noexcept { return (enum_type_t<E>)e; }
99 template<typename E> constexpr inline E to_enum(enum_type_t<E> value) noexcept { return (E)value; }
100
101 template <class E> typename enable_if<is_enum<E>::value, marshall>::type &
102 operator<<(marshall &m, E e) {
103     return m << from_enum(e);
104 }
105
106 template <class E> typename enable_if<is_enum<E>::value, unmarshall>::type &
107 operator>>(unmarshall &u, E &e);
108
109 class unmarshall {
110     private:
111         string buf_;
112         size_t index_ = 0;
113         bool ok_ = false;
114
115         inline bool ensure(size_t n) {
116             if (index_+n > buf_.size())
117                 ok_ = false;
118             return ok_;
119         }
120     public:
121         unmarshall() {}
122         unmarshall(const string &s, bool has_header)
123             : buf_(s),index_(RPC_HEADER_SZ) {
124             if (!has_header)
125                 buf_.insert(0, RPC_HEADER_SZ, 0);
126             ok_ = (buf_.size() >= RPC_HEADER_SZ);
127         }
128
129         bool ok() const { return ok_; }
130         bool okdone() const { return ok_ && index_ == buf_.size(); }
131
132         void rawbytes(void * t, size_t n) {
133             VERIFY(ensure(n));
134             copy(&buf_[index_], &buf_[index_+n], (char *)t);
135             index_ += n;
136         }
137
138         template <class T>
139         void unpack_header(T & h) {
140             // first 4 bytes hold length field
141             VERIFY(sizeof(T)+sizeof(rpc_sz_t) <= RPC_HEADER_SZ);
142             index_ = sizeof(rpc_sz_t);
143             *this >> h;
144             index_ = RPC_HEADER_SZ;
145         }
146
147         template <class T> inline T grab() { T t; *this >> t; return t; }
148 };
149
150 template <class A> typename enable_if<is_iterable<A>::value, unmarshall>::type &
151 operator>>(unmarshall &u, A &x) {
152     unsigned n = u.grab<unsigned>();
153     x.clear();
154     while (n--)
155         x.emplace_back(u.grab<typename A::value_type>());
156     return u;
157 }
158
159 template <class A, class B> unmarshall &
160 operator>>(unmarshall &u, map<A,B> &x) {
161     unsigned n = u.grab<unsigned>();
162     x.clear();
163     while (n--)
164         x.emplace(u.grab<pair<A,B>>());
165     return u;
166 }
167
168 template <class A, class B> unmarshall &
169 operator>>(unmarshall &u, pair<A,B> &d) {
170     return u >> d.first >> d.second;
171 }
172
173 template <class E> typename enable_if<is_enum<E>::value, unmarshall>::type &
174 operator>>(unmarshall &u, E &e) {
175     e = to_enum<E>(u.grab<enum_type_t<E>>());
176     return u;
177 }
178
179 typedef function<int(unmarshall &, marshall &)> handler;
180
181 //
182 // Automatic marshalling wrappers for RPC handlers
183 //
184
185 // PAI 2013/09/19
186 // C++11 does neither of these two things for us:
187 // 1) Declare variables using a parameter pack expansion, like so
188 //      Args... args;
189 // 2) Call a function with a tuple of the arguments it expects
190 //
191 // We implement an 'invoke' function for functions of the RPC handler
192 // signature, i.e. int(R & r, const Args...)
193 //
194 // One thing we need in order to accomplish this is a way to cause the compiler
195 // to specialize 'invoke' with a parameter pack containing a list of indices
196 // for the elements of the tuple.  This will allow us to call the underlying
197 // function with the exploded contents of the tuple.  The empty type
198 // tuple_indices<size_t...> accomplishes this.  It will be passed in to
199 // 'invoke' as a parameter which will be ignored, but its type will force the
200 // compiler to specialize 'invoke' appropriately.
201
202 // This class encapsulates the default response to runtime unmarshalling
203 // failures.  The templated wrappers below may optionally use a different
204 // class.
205
206 struct VerifyOnFailure {
207     static inline int unmarshall_args_failure() {
208         VERIFY(0);
209         return 0;
210     }
211 };
212
213 // Here's the implementation of 'invoke'.  It could be more general, but this
214 // meets our needs.
215
216 // One for function pointers...
217
218 template <class F, class R, class RV, class args_type, size_t... Indices>
219 typename enable_if<!is_member_function_pointer<F>::value, RV>::type
220 invoke(RV, F f, void *, R & r, args_type & t, tuple_indices<Indices...>) {
221     return f(r, move(get<Indices>(t))...);
222 }
223
224 // And one for pointers to member functions...
225
226 template <class F, class C, class RV, class R, class args_type, size_t... Indices>
227 typename enable_if<is_member_function_pointer<F>::value, RV>::type
228 invoke(RV, F f, C *c, R & r, args_type & t, tuple_indices<Indices...>) {
229     return (c->*f)(r, move(get<Indices>(t))...);
230 }
231
232 // The class marshalled_func_imp uses partial template specialization to
233 // implement the ::wrap static function.  ::wrap takes a function pointer or a
234 // pointer to a member function and returns a handler * object which
235 // unmarshalls arguments, verifies successful unmarshalling, calls the supplied
236 // function, and marshalls the response.
237
238 template <class Functor, class Instance, class Signature,
239           class ErrorHandler=VerifyOnFailure> struct marshalled_func_imp;
240
241 // Here we specialize on the Signature template parameter to obtain the list of
242 // argument types.  Note that we do not assume that the Functor parameter has
243 // the same pattern as Signature; this allows us to ignore the distinctions
244 // between various types of callable objects at this level of abstraction.
245
246 template <class F, class C, class ErrorHandler, class R, class RV, class... Args>
247 struct marshalled_func_imp<F, C, RV(R&, Args...), ErrorHandler> {
248     static inline handler *wrap(F f, C *c=nullptr) {
249         // This type definition corresponds to an empty struct with
250         // template parameters running from 0 up to (# args) - 1.
251         using Indices = typename make_tuple_indices<sizeof...(Args)>::type;
252         // This type definition represents storage for f's unmarshalled
253         // arguments.  decay is (most notably) stripping off const
254         // qualifiers.
255         using ArgsStorage = tuple<typename decay<Args>::type...>;
256         // Allocate a handler (i.e. function) to hold the lambda
257         // which will unmarshall RPCs and call f.
258         return new handler([=](unmarshall &u, marshall &m) -> RV {
259             // Unmarshall each argument with the correct type and store the
260             // result in a tuple.
261             ArgsStorage t = {u.grab<typename decay<Args>::type>()...};
262             // Verify successful unmarshalling of the entire input stream.
263             if (!u.okdone())
264                 return (RV)ErrorHandler::unmarshall_args_failure();
265             // Allocate space for the RPC response -- will be passed into the
266             // function as an lvalue reference.
267             R r;
268             // Perform the invocation.  Note that Indices() calls the default
269             // constructor of the empty struct with the special template
270             // parameters.
271             RV b = invoke(RV(), f, c, r, t, Indices());
272             // Marshall the response.
273             m << r;
274             // Make like a tree.
275             return b;
276         });
277     }
278 };
279
280 // More partial template specialization shenanigans to reduce the number of
281 // parameters which must be provided explicitly and to support a few common
282 // callable types.  C++11 doesn't allow partial function template
283 // specialization, so we use classes (structs).
284
285 template <class Functor, class ErrorHandler=VerifyOnFailure,
286     class Signature=Functor> struct marshalled_func;
287
288 template <class F, class ErrorHandler, class RV, class... Args>
289 struct marshalled_func<F, ErrorHandler, RV(*)(Args...)> :
290     public marshalled_func_imp<F, void, RV(Args...), ErrorHandler> {};
291
292 template <class F, class ErrorHandler, class RV, class C, class... Args>
293 struct marshalled_func<F, ErrorHandler, RV(C::*)(Args...)> :
294     public marshalled_func_imp<F, C, RV(Args...), ErrorHandler> {};
295
296 template <class F, class ErrorHandler, class Signature>
297 struct marshalled_func<F, ErrorHandler, function<Signature>> :
298     public marshalled_func_imp<F, void, Signature, ErrorHandler> {};
299
300 template <class... Args, size_t... Indices> unmarshall &
301 tuple_unmarshall_imp(unmarshall & u, tuple<Args &...> t, tuple_indices<Indices...>) {
302     (void)pass{(u >> get<Indices>(t))...};
303     return u;
304 }
305
306 template <class... Args> unmarshall &
307 operator>>(unmarshall & u, tuple<Args &...> && t) {
308     using Indices = typename make_tuple_indices<sizeof...(Args)>::type;
309     return tuple_unmarshall_imp(u, t, Indices());
310 }
311
312 template <class... Args, size_t... Indices> marshall &
313 tuple_marshall_imp(marshall & m, tuple<Args...> & t, tuple_indices<Indices...>) {
314     (void)pass{(m << get<Indices>(t))...};
315     return m;
316 }
317
318 template <class... Args> marshall &
319 operator<<(marshall & m, tuple<Args...> && t) {
320     using Indices = typename make_tuple_indices<sizeof...(Args)>::type;
321     return tuple_marshall_imp(m, t, Indices());
322 }
323
324 MARSHALLABLE(request_header)
325 MARSHALLABLE(reply_header)
326
327 #endif