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;
57 unmarshall(const string &s, bool has_header)
58 : buf_(s),index_(RPC_HEADER_SZ) {
60 buf_.insert(0, RPC_HEADER_SZ, 0);
61 ok_ = (buf_.size() >= RPC_HEADER_SZ);
64 bool ok() const { return ok_; }
65 bool okdone() const { return ok_ && index_ == buf_.size(); }
67 void rawbytes(void * t, size_t n) {
68 if (index_+n > buf_.size())
71 copy(&buf_[index_], &buf_[index_+n], (char *)t);
75 template <class T> inline void
76 unpack_header(T & h) {
77 VERIFY(sizeof(T)+sizeof(rpc_sz_t) <= RPC_HEADER_SZ);
78 // first 4 bytes hold length field
79 index_ = sizeof(rpc_sz_t);
81 index_ = RPC_HEADER_SZ;
84 template <class T> inline T _grab() { T t; *this >> t; return t; }
88 // Marshalling for plain old data
91 #define MARSHALL_RAW_NETWORK_ORDER_AS(_c_, _d_) \
92 inline marshall & operator<<(marshall &m, _c_ x) { _d_ y = hton((_d_)x); m.rawbytes(&y, sizeof(_d_)); return m; } \
93 inline unmarshall & operator>>(unmarshall &u, _c_ &x) { _d_ y; u.rawbytes(&y, sizeof(_d_)); x = (_c_)ntoh(y); return u; }
95 #define MARSHALL_RAW_NETWORK_ORDER(_c_) MARSHALL_RAW_NETWORK_ORDER_AS(_c_, _c_)
97 MARSHALL_RAW_NETWORK_ORDER_AS(bool, uint8_t)
98 MARSHALL_RAW_NETWORK_ORDER(uint8_t)
99 MARSHALL_RAW_NETWORK_ORDER(int8_t)
100 MARSHALL_RAW_NETWORK_ORDER(uint16_t)
101 MARSHALL_RAW_NETWORK_ORDER(int16_t)
102 MARSHALL_RAW_NETWORK_ORDER(uint32_t)
103 MARSHALL_RAW_NETWORK_ORDER(int32_t)
104 MARSHALL_RAW_NETWORK_ORDER_AS(size_t, uint32_t)
105 MARSHALL_RAW_NETWORK_ORDER(uint64_t)
106 MARSHALL_RAW_NETWORK_ORDER(int64_t)
109 // Marshalling for tuples (used to implement marshalling for structs)
112 // In order to iterate over the tuple elements, we first need a template
113 // parameter pack containing the tuple's indices. The function templates named
114 // *_imp below accept an empty tag struct as their last argument, and use its
115 // template arguments to index the tuple. The operator<< overloads instantiate
116 // the appropriate tag struct to make this possible.
118 template <class... Args, size_t... Indices> inline marshall &
119 tuple_marshall_imp(marshall & m, tuple<Args...> & t, tuple_indices<Indices...>) {
120 // Note that brace initialization is used for the empty structure "pack",
121 // forcing the comma-separated expressions expanded from the parameter pack
122 // to be evaluated in order. Order matters because the elements must be
123 // serialized consistently! The empty struct resulting from construction
125 (void)pass{(m << get<Indices>(t))...};
129 template <class... Args> marshall &
130 operator<<(marshall & m, tuple<Args...> && t) {
131 using Indices = typename make_tuple_indices<sizeof...(Args)>::type;
132 return tuple_marshall_imp(m, t, Indices());
135 template <class... Args, size_t... Indices> inline unmarshall &
136 tuple_unmarshall_imp(unmarshall & u, tuple<Args &...> t, tuple_indices<Indices...>) {
137 (void)pass{(u >> get<Indices>(t))...};
141 template <class... Args> unmarshall &
142 operator>>(unmarshall & u, tuple<Args &...> && t) {
143 using Indices = typename make_tuple_indices<sizeof...(Args)>::type;
144 return tuple_unmarshall_imp(u, t, Indices());
148 // Marshalling for structs or classes containing a MEMBERS declaration
151 // Implements struct marshalling via tuple marshalling of members.
152 #define MARSHALLABLE(_c_) \
153 inline unmarshall & operator>>(unmarshall &u, _c_ &a) { return u >> a._tuple_(); } \
154 inline marshall & operator<<(marshall &m, const _c_ a) { return m << a._tuple_(); }
156 // our first two marshallable structs...
157 MARSHALLABLE(request_header)
158 MARSHALLABLE(reply_header)
161 // Marshalling for STL containers
164 // this overload is visible for type A only if A::cbegin and A::cend exist
165 template <class A> inline typename
166 enable_if<is_const_iterable<A>::value, marshall>::type &
167 operator<<(marshall &m, const A &x) {
168 m << (unsigned int)x.size();
169 for (const auto &a : x)
174 // visible for type A if A::emplace_back(a) makes sense
175 template <class A> inline typename
176 enable_if<supports_emplace_back<A>::value, unmarshall>::type &
177 operator>>(unmarshall &u, A &x) {
178 unsigned n = u._grab<unsigned>();
181 x.emplace_back(u._grab<typename A::value_type>());
186 template <class A, class B> inline marshall &
187 operator<<(marshall &m, const pair<A,B> &d) {
188 return m << d.first << d.second;
191 template <class A, class B> inline unmarshall &
192 operator>>(unmarshall &u, pair<A,B> &d) {
193 return u >> d.first >> d.second;
197 template <class A, class B> inline unmarshall &
198 operator>>(unmarshall &u, map<A,B> &x) {
199 unsigned n = u._grab<unsigned>();
202 x.emplace(u._grab<pair<A,B>>());
207 inline marshall & operator<<(marshall &m, const string &s) {
208 m << (uint32_t)s.size();
209 m.rawbytes(s.data(), s.size());
213 inline unmarshall & operator>>(unmarshall &u, string &s) {
214 uint32_t sz = u._grab<uint32_t>();
217 u.rawbytes(&s[0], sz);
223 // Marshalling for strongly-typed enums
226 template <class E> typename enable_if<is_enum<E>::value, marshall>::type &
227 operator<<(marshall &m, E e) {
228 return m << from_enum(e);
231 template <class E> typename enable_if<is_enum<E>::value, unmarshall>::type &
232 operator>>(unmarshall &u, E &e) {
233 e = to_enum<E>(u._grab<enum_type_t<E>>());