5 #include "rpc_protocol.h"
8 // Marshall and unmarshall objects
13 string buf_ = string(rpc_protocol::DEFAULT_RPC_SZ, 0);
14 size_t index_ = rpc_protocol::RPC_HEADER_SZ;
17 template <typename... Args>
18 marshall(const Args & ... args) {
19 (void)pass{(*this << args)...};
22 void write(const void *p, size_t n) {
23 if (index_+n > buf_.size())
24 buf_.resize(index_+n);
25 std::copy((char *)p, (char *)p+n, &buf_[index_]);
30 inline operator string() const { return buf_.substr(0,index_); }
32 inline string content() const { return buf_.substr(rpc_protocol::RPC_HEADER_SZ,index_-rpc_protocol::RPC_HEADER_SZ); }
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 write_header(const T & h) {
39 VERIFY(sizeof(T)+sizeof(S) <= rpc_protocol::RPC_HEADER_SZ);
40 size_t saved_sz = index_;
42 *this << (S)(saved_sz - sizeof(S)) << (T)h;
50 size_t index_ = rpc_protocol::RPC_HEADER_SZ;
54 template <typename... Args>
55 unmarshall(const string & s, bool has_header, Args && ... args)
58 buf_.insert(0, rpc_protocol::RPC_HEADER_SZ, 0);
59 ok_ = (buf_.size() >= rpc_protocol::RPC_HEADER_SZ);
60 (void)pass{(*this >> args)...};
63 inline bool ok() const { return ok_; }
64 inline bool okdone() const { return ok_ && index_ == buf_.size(); }
66 void read(void * t, size_t n) {
67 if (index_+n > buf_.size())
70 std::copy(&buf_[index_], &buf_[index_+n], (char *)t);
75 template <class T> inline void
77 VERIFY(sizeof(T)+sizeof(rpc_protocol::rpc_sz_t) <= rpc_protocol::RPC_HEADER_SZ);
78 // first 4 bytes hold length field
79 index_ = sizeof(rpc_protocol::rpc_sz_t);
81 index_ = rpc_protocol::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.write(&y, sizeof(_d_)); return m; } \
93 inline unmarshall & operator>>(unmarshall & u, _c_ & x) { _d_ y; u.read(&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> inline marshall &
130 operator<<(marshall & m, tuple<Args...> && t) {
131 return tuple_marshall_imp(m, t, TUPLE_INDICES(Args));
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))...};
140 template <class... Args> inline unmarshall &
141 operator>>(unmarshall & u, tuple<Args & ...> && t) {
142 return tuple_unmarshall_imp(u, t, TUPLE_INDICES(Args));
146 // Marshalling for structs or classes containing a MEMBERS declaration
149 // Implements struct marshalling via tuple marshalling of members.
150 template <class T> inline typename
151 enable_if<is_tuple_convertible<T>::value, unmarshall>::type &
152 operator>>(unmarshall & u, T & a) { return u >> a._tuple_(); }
154 template <class T> inline typename
155 enable_if<is_tuple_convertible<T>::value, marshall>::type &
156 operator<<(marshall & m, const T a) { return m << a._tuple_(); }
159 // Marshalling for STL containers
162 // this overload is visible for type A only if A::cbegin and A::cend exist
163 template <class A> inline typename
164 enable_if<is_const_iterable<A>::value, marshall>::type &
165 operator<<(marshall & m, const A & x) {
166 m << (uint32_t)x.size();
167 for (const auto & a : x)
172 // visible for type A if A::emplace_back(a) makes sense
173 template <class A> inline typename
174 enable_if<supports_emplace_back<A>::value, unmarshall>::type &
175 operator>>(unmarshall & u, A & x) {
176 uint32_t n = u._grab<uint32_t>();
179 x.emplace_back(u._grab<typename A::value_type>());
184 template <class A, class B> inline marshall &
185 operator<<(marshall & m, const pair<A,B> & d) {
186 return m << d.first << d.second;
189 template <class A, class B> inline unmarshall &
190 operator>>(unmarshall & u, pair<A,B> & d) {
191 return u >> d.first >> d.second;
195 template <class A, class B> inline unmarshall &
196 operator>>(unmarshall & u, map<A,B> & x) {
197 uint32_t n = u._grab<uint32_t>();
200 x.emplace(u._grab<pair<A,B>>());
205 inline marshall & operator<<(marshall & m, const string & s) {
206 m << (uint32_t)s.size();
207 m.write(s.data(), s.size());
211 inline unmarshall & operator>>(unmarshall & u, string & s) {
212 uint32_t sz = u._grab<uint32_t>();
221 // Marshalling for strongly-typed enums
224 template <class E> typename enable_if<is_enum<E>::value, marshall>::type &
225 operator<<(marshall & m, E e) {
226 return m << from_enum(e);
229 template <class E> typename enable_if<is_enum<E>::value, unmarshall>::type &
230 operator>>(unmarshall & u, E & e) {
231 e = to_enum<E>(u._grab<enum_type_t<E>>());
236 // Recursive marshalling
239 inline marshall & operator<<(marshall & m, marshall & n) {
240 return m << n.content();
243 inline unmarshall & operator>>(unmarshall & u, unmarshall & v) {
244 v = unmarshall(u._grab<string>(), false);