5 #include "rpc_protocol.h"
11 // Marshall and unmarshall objects
16 string buf_ = string(DEFAULT_RPC_SZ, 0); // Raw bytes buffer
17 size_t index_ = RPC_HEADER_SZ; // Read/write head position
20 template <typename... Args>
21 marshall(const Args&... args) {
22 (void)pass{(*this << args)...};
25 void rawbytes(const void *p, size_t n) {
26 if (index_+n > buf_.size())
27 buf_.resize(index_+n);
28 copy((char *)p, (char *)p+n, &buf_[index_]);
33 inline operator string() const { return buf_.substr(0,index_); }
35 inline string content() { return buf_.substr(RPC_HEADER_SZ,index_-RPC_HEADER_SZ); }
37 // letting S be a defaulted template parameter forces the compiler to
38 // delay looking up operator<<(marshall&, rpc_sz_t) until we define it
39 // (i.e. we define an operator for marshalling uint32_t)
40 template <class T, class S=rpc_sz_t> inline void
41 pack_header(const T & h) {
42 VERIFY(sizeof(T)+sizeof(S) <= RPC_HEADER_SZ);
43 size_t saved_sz = index_;
45 *this << (S)(saved_sz - sizeof(S)) << (T)h;
58 unmarshall(const string &s, bool has_header)
59 : buf_(s),index_(RPC_HEADER_SZ) {
61 buf_.insert(0, RPC_HEADER_SZ, 0);
62 ok_ = (buf_.size() >= RPC_HEADER_SZ);
65 bool ok() const { return ok_; }
66 bool okdone() const { return ok_ && index_ == buf_.size(); }
68 void rawbytes(void * t, size_t n) {
69 if (index_+n > buf_.size())
72 copy(&buf_[index_], &buf_[index_+n], (char *)t);
76 template <class T> void
77 unpack_header(T & h) {
78 VERIFY(sizeof(T)+sizeof(rpc_sz_t) <= RPC_HEADER_SZ);
79 // first 4 bytes hold length field
80 index_ = sizeof(rpc_sz_t);
82 index_ = RPC_HEADER_SZ;
85 template <class T> inline T grab() { T t; *this >> t; return t; }
89 // Marshalling for plain old data
92 #define MARSHALL_RAW_NETWORK_ORDER_AS(_c_, _d_) \
93 inline marshall & operator<<(marshall &m, _c_ x) { _d_ y = hton((_d_)x); m.rawbytes(&y, sizeof(_d_)); return m; } \
94 inline unmarshall & operator>>(unmarshall &u, _c_ &x) { _d_ y; u.rawbytes(&y, sizeof(_d_)); x = (_c_)ntoh(y); return u; }
96 #define MARSHALL_RAW_NETWORK_ORDER(_c_) MARSHALL_RAW_NETWORK_ORDER_AS(_c_, _c_)
98 MARSHALL_RAW_NETWORK_ORDER_AS(bool, uint8_t)
99 MARSHALL_RAW_NETWORK_ORDER(uint8_t)
100 MARSHALL_RAW_NETWORK_ORDER(int8_t)
101 MARSHALL_RAW_NETWORK_ORDER(uint16_t)
102 MARSHALL_RAW_NETWORK_ORDER(int16_t)
103 MARSHALL_RAW_NETWORK_ORDER(uint32_t)
104 MARSHALL_RAW_NETWORK_ORDER(int32_t)
105 MARSHALL_RAW_NETWORK_ORDER_AS(size_t, uint32_t)
106 MARSHALL_RAW_NETWORK_ORDER(uint64_t)
107 MARSHALL_RAW_NETWORK_ORDER(int64_t)
110 // Marshalling for tuples (used to implement marshalling for structs)
113 // In order to iterate over the tuple elements, we first need a template
114 // parameter pack containing the tuple's indices. The function templates named
115 // *_imp below accept an empty tag struct as their last argument, and use its
116 // template arguments to index the tuple. The operator<< overloads instantiate
117 // the appropriate tag struct to make this possible.
119 template <class... Args, size_t... Indices> inline marshall &
120 tuple_marshall_imp(marshall & m, tuple<Args...> & t, tuple_indices<Indices...>) {
121 // Note that brace initialization is used for the empty structure "pack",
122 // forcing the comma-separated expressions expanded from the parameter pack
123 // to be evaluated in order. Order matters because the elements must be
124 // serialized consistently! The empty struct resulting from construction
126 (void)pass{(m << get<Indices>(t))...};
130 template <class... Args> marshall &
131 operator<<(marshall & m, tuple<Args...> && t) {
132 using Indices = typename make_tuple_indices<sizeof...(Args)>::type;
133 return tuple_marshall_imp(m, t, Indices());
136 template <class... Args, size_t... Indices> inline unmarshall &
137 tuple_unmarshall_imp(unmarshall & u, tuple<Args &...> t, tuple_indices<Indices...>) {
138 (void)pass{(u >> get<Indices>(t))...};
142 template <class... Args> unmarshall &
143 operator>>(unmarshall & u, tuple<Args &...> && t) {
144 using Indices = typename make_tuple_indices<sizeof...(Args)>::type;
145 return tuple_unmarshall_imp(u, t, Indices());
149 // Marshalling for structs or classes containing a MEMBERS declaration
152 // Implements struct marshalling via tuple marshalling of members.
153 #define MARSHALLABLE(_c_) \
154 inline unmarshall & operator>>(unmarshall &u, _c_ &a) { return u >> a._tuple_(); } \
155 inline marshall & operator<<(marshall &m, const _c_ a) { return m << a._tuple_(); }
157 // our first two marshallable structs...
158 MARSHALLABLE(request_header)
159 MARSHALLABLE(reply_header)
162 // Marshalling for STL containers
165 // this overload is visible for type A only if A::cbegin and A::cend exist
166 template <class A> inline typename
167 enable_if<is_const_iterable<A>::value, marshall>::type &
168 operator<<(marshall &m, const A &x) {
169 m << (unsigned int)x.size();
170 for (const auto &a : x)
175 // visible for type A if A::emplace_back(a) makes sense
176 template <class A> inline typename
177 enable_if<supports_emplace_back<A>::value, unmarshall>::type &
178 operator>>(unmarshall &u, A &x) {
179 unsigned n = u.grab<unsigned>();
182 x.emplace_back(u.grab<typename A::value_type>());
187 template <class A, class B> inline marshall &
188 operator<<(marshall &m, const pair<A,B> &d) {
189 return m << d.first << d.second;
192 template <class A, class B> inline unmarshall &
193 operator>>(unmarshall &u, pair<A,B> &d) {
194 return u >> d.first >> d.second;
198 template <class A, class B> inline unmarshall &
199 operator>>(unmarshall &u, map<A,B> &x) {
200 unsigned n = u.grab<unsigned>();
203 x.emplace(u.grab<pair<A,B>>());
208 inline marshall & operator<<(marshall &m, const string &s) {
209 m << (uint32_t)s.size();
210 m.rawbytes(s.data(), s.size());
214 inline unmarshall & operator>>(unmarshall &u, string &s) {
215 uint32_t sz = u.grab<uint32_t>();
218 u.rawbytes(&s[0], sz);
224 // Marshalling for strongly-typed enums
227 template <class E> typename enable_if<is_enum<E>::value, marshall>::type &
228 operator<<(marshall &m, E e) {
229 return m << from_enum(e);
232 template <class E> typename enable_if<is_enum<E>::value, unmarshall>::type &
233 operator>>(unmarshall &u, E &e) {
234 e = to_enum<E>(u.grab<enum_type_t<E>>());