Cosmetic improvements.
[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 //
8 // Marshall and unmarshall objects
9 //
10
11 class marshall {
12     private:
13         string buf_ = string(rpc_protocol::DEFAULT_RPC_SZ, 0); // Raw bytes buffer
14         size_t index_ = rpc_protocol::RPC_HEADER_SZ; // Read/write head position
15
16     public:
17         template <typename... Args>
18         marshall(const Args & ... args) {
19             (void)pass{(*this << args)...};
20         }
21
22         void rawbytes(const void *p, size_t n) {
23             if (index_+n > buf_.size())
24                 buf_.resize(index_+n);
25             copy((char *)p, (char *)p+n, &buf_[index_]);
26             index_ += n;
27         }
28
29         // with header
30         inline operator string() const { return buf_.substr(0,index_); }
31         // without header
32         inline string content() const { return buf_.substr(rpc_protocol::RPC_HEADER_SZ,index_-rpc_protocol::RPC_HEADER_SZ); }
33
34         // letting S be a defaulted template parameter forces the compiler to
35         // delay looking up operator<<(marshall &, rpc_sz_t) until we define it
36         // (i.e. we define an operator for marshalling uint32_t)
37         template <class T, class S=rpc_protocol::rpc_sz_t> inline void
38         pack_header(const T & h) {
39             VERIFY(sizeof(T)+sizeof(S) <= rpc_protocol::RPC_HEADER_SZ);
40             size_t saved_sz = index_;
41             index_ = 0;
42             *this << (S)(saved_sz - sizeof(S)) << (T)h;
43             index_ = saved_sz;
44         }
45 };
46
47 class unmarshall {
48     private:
49         string buf_;
50         size_t index_ = 0;
51         bool ok_ = false;
52
53     public:
54         template <typename... Args>
55         unmarshall(const string & s, bool has_header, Args && ... args)
56             : buf_(s),index_(rpc_protocol::RPC_HEADER_SZ) {
57             if (!has_header)
58                 buf_.insert(0, rpc_protocol::RPC_HEADER_SZ, 0);
59             ok_ = (buf_.size() >= rpc_protocol::RPC_HEADER_SZ);
60             (void)pass{(*this >> args)...};
61         }
62
63         bool ok() const { return ok_; }
64         bool okdone() const { return ok_ && index_ == buf_.size(); }
65
66         void rawbytes(void * t, size_t n) {
67             if (index_+n > buf_.size())
68                 ok_ = false;
69             VERIFY(ok_);
70             copy(&buf_[index_], &buf_[index_+n], (char *)t);
71             index_ += n;
72         }
73
74         template <class T> inline void
75         unpack_header(T & h) {
76             VERIFY(sizeof(T)+sizeof(rpc_protocol::rpc_sz_t) <= rpc_protocol::RPC_HEADER_SZ);
77             // first 4 bytes hold length field
78             index_ = sizeof(rpc_protocol::rpc_sz_t);
79             *this >> h;
80             index_ = rpc_protocol::RPC_HEADER_SZ;
81         }
82
83         template <class T> inline T _grab() { T t; *this >> t; return t; }
84 };
85
86 //
87 // Marshalling for plain old data
88 //
89
90 #define MARSHALL_RAW_NETWORK_ORDER_AS(_c_, _d_) \
91 inline marshall & operator<<(marshall & m, _c_ x) { _d_ y = hton((_d_)x); m.rawbytes(&y, sizeof(_d_)); return m; } \
92 inline unmarshall & operator>>(unmarshall & u, _c_ & x) { _d_ y; u.rawbytes(&y, sizeof(_d_)); x = (_c_)ntoh(y); return u; }
93
94 #define MARSHALL_RAW_NETWORK_ORDER(_c_) MARSHALL_RAW_NETWORK_ORDER_AS(_c_, _c_)
95
96 MARSHALL_RAW_NETWORK_ORDER_AS(bool, uint8_t)
97 MARSHALL_RAW_NETWORK_ORDER(uint8_t)
98 MARSHALL_RAW_NETWORK_ORDER(int8_t)
99 MARSHALL_RAW_NETWORK_ORDER(uint16_t)
100 MARSHALL_RAW_NETWORK_ORDER(int16_t)
101 MARSHALL_RAW_NETWORK_ORDER(uint32_t)
102 MARSHALL_RAW_NETWORK_ORDER(int32_t)
103 MARSHALL_RAW_NETWORK_ORDER_AS(size_t, uint32_t)
104 MARSHALL_RAW_NETWORK_ORDER(uint64_t)
105 MARSHALL_RAW_NETWORK_ORDER(int64_t)
106
107 //
108 // Marshalling for tuples (used to implement marshalling for structs)
109 //
110
111 // In order to iterate over the tuple elements, we first need a template
112 // parameter pack containing the tuple's indices.  The function templates named
113 // *_imp below accept an empty tag struct as their last argument, and use its
114 // template arguments to index the tuple.  The operator<< overloads instantiate
115 // the appropriate tag struct to make this possible.
116
117 template <class... Args, size_t... Indices> inline marshall &
118 tuple_marshall_imp(marshall & m, tuple<Args...> & t, tuple_indices<Indices...>) {
119     // Note that brace initialization is used for the empty structure "pack",
120     // forcing the comma-separated expressions expanded from the parameter pack
121     // to be evaluated in order.  Order matters because the elements must be
122     // serialized consistently!  The empty struct resulting from construction
123     // is discarded.
124     (void)pass{(m << get<Indices>(t))...};
125     return m;
126 }
127
128 template <class... Args> marshall &
129 operator<<(marshall & m, tuple<Args...> && t) {
130     using Indices = typename make_tuple_indices<sizeof...(Args)>::type;
131     return tuple_marshall_imp(m, t, Indices());
132 }
133
134 template <class... Args, size_t... Indices> inline unmarshall &
135 tuple_unmarshall_imp(unmarshall & u, tuple<Args & ...> t, tuple_indices<Indices...>) {
136     (void)pass{(u >> get<Indices>(t))...};
137     return u;
138 }
139
140 template <class... Args> unmarshall &
141 operator>>(unmarshall & u, tuple<Args & ...> && t) {
142     using Indices = typename make_tuple_indices<sizeof...(Args)>::type;
143     return tuple_unmarshall_imp(u, t, Indices());
144 }
145
146 //
147 // Marshalling for structs or classes containing a MEMBERS declaration
148 //
149
150 // Implements struct marshalling via tuple marshalling of members.
151 #define MARSHALLABLE_STRUCT(_c_) \
152 inline unmarshall & operator>>(unmarshall & u, _c_ & a) { return u >> a._tuple_(); } \
153 inline marshall & operator<<(marshall & m, const _c_ a) { return m << a._tuple_(); }
154
155 // our first two marshallable structs...
156 MARSHALLABLE_STRUCT(rpc_protocol::request_header)
157 MARSHALLABLE_STRUCT(rpc_protocol::reply_header)
158
159 //
160 // Marshalling for STL containers
161 //
162
163 // this overload is visible for type A only if A::cbegin and A::cend exist
164 template <class A> inline typename
165 enable_if<is_const_iterable<A>::value, marshall>::type &
166 operator<<(marshall & m, const A & x) {
167     m << (unsigned int)x.size();
168     for (const auto & a : x)
169         m << a;
170     return m;
171 }
172
173 // visible for type A if A::emplace_back(a) makes sense
174 template <class A> inline typename
175 enable_if<supports_emplace_back<A>::value, unmarshall>::type &
176 operator>>(unmarshall & u, A & x) {
177     unsigned n = u._grab<unsigned>();
178     x.clear();
179     while (n--)
180         x.emplace_back(u._grab<typename A::value_type>());
181     return u;
182 }
183
184 // std::pair<A, B>
185 template <class A, class B> inline marshall &
186 operator<<(marshall & m, const pair<A,B> & d) {
187     return m << d.first << d.second;
188 }
189
190 template <class A, class B> inline unmarshall &
191 operator>>(unmarshall & u, pair<A,B> & d) {
192     return u >> d.first >> d.second;
193 }
194
195 // std::map<A, B>
196 template <class A, class B> inline unmarshall &
197 operator>>(unmarshall & u, map<A,B> & x) {
198     unsigned n = u._grab<unsigned>();
199     x.clear();
200     while (n--)
201         x.emplace(u._grab<pair<A,B>>());
202     return u;
203 }
204
205 // std::string
206 inline marshall & operator<<(marshall & m, const string & s) {
207     m << (uint32_t)s.size();
208     m.rawbytes(s.data(), s.size());
209     return m;
210 }
211
212 inline unmarshall & operator>>(unmarshall & u, string & s) {
213     uint32_t sz = u._grab<uint32_t>();
214     if (u.ok()) {
215         s.resize(sz);
216         u.rawbytes(&s[0], sz);
217     }
218     return u;
219 }
220
221 //
222 // Marshalling for strongly-typed enums
223 //
224
225 template <class E> typename enable_if<is_enum<E>::value, marshall>::type &
226 operator<<(marshall & m, E e) {
227     return m << from_enum(e);
228 }
229
230 template <class E> typename enable_if<is_enum<E>::value, unmarshall>::type &
231 operator>>(unmarshall & u, E & e) {
232     e = to_enum<E>(u._grab<enum_type_t<E>>());
233     return u;
234 }
235
236 //
237 // Recursive marshalling
238 //
239
240 inline marshall & operator<<(marshall & m, marshall & n) {
241     return m << n.content();
242 }
243
244 inline unmarshall & operator>>(unmarshall & u, unmarshall & v) {
245     v = unmarshall(u._grab<string>(), false);
246     return u;
247 }
248
249 #endif