-#ifndef marshall_h
-#define marshall_h
-
-#include "types.h"
-#include "rpc_protocol.h"
-
-class marshall {
- private:
- string buf_ = string(rpc_protocol::DEFAULT_RPC_SZ, 0);
- size_t index_ = rpc_protocol::RPC_HEADER_SZ;
-
- public:
- template <typename... Args>
- marshall(const Args & ... args) {
- (void)pass{(*this << args)...};
- }
-
- void write(const void *p, size_t n) {
- if (index_+n > buf_.size())
- buf_.resize(index_+n);
- std::copy((char *)p, (char *)p+n, &buf_[index_]);
- index_ += n;
- }
-
- // with header
- inline operator string() const { return buf_.substr(0,index_); }
- // without header
- inline string content() const { return buf_.substr(rpc_protocol::RPC_HEADER_SZ,index_-rpc_protocol::RPC_HEADER_SZ); }
-
- // letting S be a defaulted template parameter forces the compiler to
- // delay looking up operator<<(marshall &, rpc_sz_t) until we define it
- // (i.e. we define an operator for marshalling uint32_t)
- template <class T, class S=rpc_protocol::rpc_sz_t> inline void
- write_header(const T & h) {
- VERIFY(sizeof(T)+sizeof(S) <= rpc_protocol::RPC_HEADER_SZ);
- size_t saved_sz = index_;
- index_ = 0;
- *this << (S)(saved_sz - sizeof(S)) << (T)h;
- index_ = saved_sz;
- }
-};
-
-class unmarshall {
- private:
- string buf_;
- size_t index_ = rpc_protocol::RPC_HEADER_SZ;
- bool ok_ = false;
-
- public:
- template <typename... Args>
- unmarshall(const string & s, bool has_header, Args && ... args)
- : buf_(s) {
- if (!has_header)
- buf_.insert(0, rpc_protocol::RPC_HEADER_SZ, 0);
- ok_ = (buf_.size() >= rpc_protocol::RPC_HEADER_SZ);
- (void)pass{(*this >> args)...};
- }
-
- inline bool ok() const { return ok_; }
- inline bool okdone() const { return ok_ && index_ == buf_.size(); }
-
- void read(void * t, size_t n) {
- if (index_+n > buf_.size())
- ok_ = false;
- if (ok_) {
- std::copy(&buf_[index_], &buf_[index_+n], (char *)t);
- index_ += n;
- }
- }
-
- template <class T> inline void
- read_header(T & h) {
- VERIFY(sizeof(T)+sizeof(rpc_protocol::rpc_sz_t) <= rpc_protocol::RPC_HEADER_SZ);
- // first 4 bytes hold length field
- index_ = sizeof(rpc_protocol::rpc_sz_t);
- *this >> h;
- index_ = rpc_protocol::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.write(&y, sizeof(_d_)); return m; } \
-inline unmarshall & operator>>(unmarshall & u, _c_ & x) { _d_ y; u.read(&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, std::index_sequence<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 << std::get<Indices>(t))...};
- return m;
-}
-
-template <class... Args> inline marshall &
-operator<<(marshall & m, tuple<Args...> && t) {
- return tuple_marshall_imp(m, t, std::index_sequence_for<Args...>{});
-}
-
-template <class... Args, size_t... Indices> inline unmarshall &
-tuple_unmarshall_imp(unmarshall & u, tuple<Args & ...> t, std::index_sequence<Indices...>) {
- (void)pass{(u >> std::get<Indices>(t))...};
- return u;
-}
-
-template <class... Args> inline unmarshall &
-operator>>(unmarshall & u, tuple<Args & ...> && t) {
- return tuple_unmarshall_imp(u, t, std::index_sequence_for<Args...>{});
-}
-
-//
-// Marshalling for structs or classes containing a MEMBERS declaration
-//
-
-// Implements struct marshalling via tuple marshalling of members.
-template <class T> inline typename
-enable_if<is_tuple_convertible<T>::value, unmarshall>::type &
-operator>>(unmarshall & u, T & a) { return u >> a._tuple_(); }
-
-template <class T> inline typename
-enable_if<is_tuple_convertible<T>::value, marshall>::type &
-operator<<(marshall & m, const T a) { return m << a._tuple_(); }
-
-//
-// Marshalling for STL containers
-//
-
-// this overload is visible for type A only if A::cbegin and A::cend exist
-template <class A> inline typename
-enable_if<is_const_iterable<A>::value, marshall>::type &
-operator<<(marshall & m, const A & x) {
- m << (uint32_t)x.size();
- for (const auto & a : x)
- m << a;
- return m;
-}
-
-// visible for type A if A::emplace_back(a) makes sense
-template <class A> inline typename
-enable_if<supports_emplace_back<A>::value, unmarshall>::type &
-operator>>(unmarshall & u, A & x) {
- uint32_t n = u._grab<uint32_t>();
- x.clear();
- while (n--)
- x.emplace_back(u._grab<typename A::value_type>());
- return u;
-}
-
-// std::pair<A, B>
-template <class A, class B> inline marshall &
-operator<<(marshall & m, const std::pair<A,B> & d) {
- return m << d.first << d.second;
-}
-
-template <class A, class B> inline unmarshall &
-operator>>(unmarshall & u, std::pair<A,B> & d) {
- return u >> d.first >> d.second;
-}
-
-// std::map<A, B>
-template <class A, class B> inline unmarshall &
-operator>>(unmarshall & u, std::map<A,B> & x) {
- uint32_t n = u._grab<uint32_t>();
- x.clear();
- while (n--)
- x.emplace(u._grab<std::pair<A,B>>());
- return u;
-}
-
-// std::string
-inline marshall & operator<<(marshall & m, const string & s) {
- m << (uint32_t)s.size();
- m.write(s.data(), s.size());
- return m;
-}
-
-inline unmarshall & operator>>(unmarshall & u, string & s) {
- uint32_t sz = u._grab<uint32_t>();
- if (u.ok()) {
- s.resize(sz);
- u.read(&s[0], sz);
- }
- return u;
-}
-
-//
-// Marshalling for strongly-typed enums
-//
-
-template <class E> typename enable_if<std::is_enum<E>::value, marshall>::type &
-operator<<(marshall & m, E e) {
- return m << from_enum(e);
-}
-
-template <class E> typename enable_if<std::is_enum<E>::value, unmarshall>::type &
-operator>>(unmarshall & u, E & e) {
- e = to_enum<E>(u._grab<enum_type_t<E>>());
- return u;
-}
-
-//
-// Recursive marshalling
-//
-
-inline marshall & operator<<(marshall & m, marshall & n) {
- return m << n.content();
-}
-
-inline unmarshall & operator>>(unmarshall & u, unmarshall & v) {
- v = unmarshall(u._grab<string>(), false);
- return u;
-}
-
-#endif