-marshall& operator<<(marshall &, bool);
-marshall& operator<<(marshall &, unsigned int);
-marshall& operator<<(marshall &, int);
-marshall& operator<<(marshall &, unsigned char);
-marshall& operator<<(marshall &, char);
-marshall& operator<<(marshall &, unsigned short);
-marshall& operator<<(marshall &, short);
-marshall& operator<<(marshall &, unsigned long long);
-marshall& operator<<(marshall &, const std::string &);
-
-template <class C> marshall &
-operator<<(marshall &m, std::vector<C> v)
-{
- m << (unsigned int) v.size();
- for(unsigned i = 0; i < v.size(); i++)
- m << v[i];
- return m;
+class unmarshall {
+ private:
+ string buf_;
+ size_t index_ = 0;
+ bool ok_ = false;
+
+ public:
+ unmarshall(const string &s, bool has_header)
+ : buf_(s),index_(RPC_HEADER_SZ) {
+ if (!has_header)
+ buf_.insert(0, RPC_HEADER_SZ, 0);
+ ok_ = (buf_.size() >= RPC_HEADER_SZ);
+ }
+
+ bool ok() const { return ok_; }
+ bool okdone() const { return ok_ && index_ == buf_.size(); }
+
+ void rawbytes(void * t, size_t n) {
+ if (index_+n > buf_.size())
+ ok_ = false;
+ VERIFY(ok_);
+ copy(&buf_[index_], &buf_[index_+n], (char *)t);
+ index_ += n;
+ }
+
+ template <class T> inline void
+ unpack_header(T & h) {
+ VERIFY(sizeof(T)+sizeof(rpc_sz_t) <= RPC_HEADER_SZ);
+ // first 4 bytes hold length field
+ index_ = sizeof(rpc_sz_t);
+ *this >> h;
+ index_ = RPC_HEADER_SZ;
+ }
+
+ template <class T> inline T _grab() { T t; *this >> t; return t; }
+};
+
+//
+// Marshalling for plain old data
+//
+
+#define MARSHALL_RAW_NETWORK_ORDER_AS(_c_, _d_) \
+inline marshall & operator<<(marshall &m, _c_ x) { _d_ y = hton((_d_)x); m.rawbytes(&y, sizeof(_d_)); return m; } \
+inline unmarshall & operator>>(unmarshall &u, _c_ &x) { _d_ y; u.rawbytes(&y, sizeof(_d_)); x = (_c_)ntoh(y); return u; }
+
+#define MARSHALL_RAW_NETWORK_ORDER(_c_) MARSHALL_RAW_NETWORK_ORDER_AS(_c_, _c_)
+
+MARSHALL_RAW_NETWORK_ORDER_AS(bool, uint8_t)
+MARSHALL_RAW_NETWORK_ORDER(uint8_t)
+MARSHALL_RAW_NETWORK_ORDER(int8_t)
+MARSHALL_RAW_NETWORK_ORDER(uint16_t)
+MARSHALL_RAW_NETWORK_ORDER(int16_t)
+MARSHALL_RAW_NETWORK_ORDER(uint32_t)
+MARSHALL_RAW_NETWORK_ORDER(int32_t)
+MARSHALL_RAW_NETWORK_ORDER_AS(size_t, uint32_t)
+MARSHALL_RAW_NETWORK_ORDER(uint64_t)
+MARSHALL_RAW_NETWORK_ORDER(int64_t)
+
+//
+// Marshalling for tuples (used to implement marshalling for structs)
+//
+
+// In order to iterate over the tuple elements, we first need a template
+// parameter pack containing the tuple's indices. The function templates named
+// *_imp below accept an empty tag struct as their last argument, and use its
+// template arguments to index the tuple. The operator<< overloads instantiate
+// the appropriate tag struct to make this possible.
+
+template <class... Args, size_t... Indices> inline marshall &
+tuple_marshall_imp(marshall & m, tuple<Args...> & t, tuple_indices<Indices...>) {
+ // Note that brace initialization is used for the empty structure "pack",
+ // forcing the comma-separated expressions expanded from the parameter pack
+ // to be evaluated in order. Order matters because the elements must be
+ // serialized consistently! The empty struct resulting from construction
+ // is discarded.
+ (void)pass{(m << get<Indices>(t))...};
+ return m;