#include "types.h"
#include "rpc_protocol.h"
-class marshall;
-class unmarshall;
-
//
// Marshall and unmarshall objects
//
class marshall {
private:
- string buf_ = string(DEFAULT_RPC_SZ, 0); // Raw bytes buffer
- size_t index_ = RPC_HEADER_SZ; // Read/write head position
+ 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) {
+ marshall(const Args & ... args) {
(void)pass{(*this << args)...};
}
- void rawbytes(const void *p, size_t n) {
+ void write(const void *p, size_t n) {
if (index_+n > buf_.size())
buf_.resize(index_+n);
- copy((char *)p, (char *)p+n, &buf_[index_]);
+ 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() { return buf_.substr(RPC_HEADER_SZ,index_-RPC_HEADER_SZ); }
+ 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
+ // 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_sz_t> inline void
- pack_header(const T & h) {
- VERIFY(sizeof(T)+sizeof(S) <= RPC_HEADER_SZ);
+ 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;
class unmarshall {
private:
string buf_;
- size_t index_ = 0;
+ size_t index_ = rpc_protocol::RPC_HEADER_SZ;
bool ok_ = false;
public:
- unmarshall(const string &s, bool has_header)
- : buf_(s),index_(RPC_HEADER_SZ) {
+ template <typename... Args>
+ unmarshall(const string & s, bool has_header, Args && ... args)
+ : buf_(s) {
if (!has_header)
- buf_.insert(0, RPC_HEADER_SZ, 0);
- ok_ = (buf_.size() >= RPC_HEADER_SZ);
+ buf_.insert(0, rpc_protocol::RPC_HEADER_SZ, 0);
+ ok_ = (buf_.size() >= rpc_protocol::RPC_HEADER_SZ);
+ (void)pass{(*this >> args)...};
}
- bool ok() const { return ok_; }
- bool okdone() const { return ok_ && index_ == buf_.size(); }
+ inline bool ok() const { return ok_; }
+ inline bool okdone() const { return ok_ && index_ == buf_.size(); }
- void rawbytes(void * t, size_t n) {
+ void read(void * t, size_t n) {
if (index_+n > buf_.size())
ok_ = false;
- VERIFY(ok_);
- copy(&buf_[index_], &buf_[index_+n], (char *)t);
- index_ += n;
+ if (ok_) {
+ std::copy(&buf_[index_], &buf_[index_+n], (char *)t);
+ index_ += n;
+ }
}
- template <class T> void
- unpack_header(T & h) {
- VERIFY(sizeof(T)+sizeof(rpc_sz_t) <= RPC_HEADER_SZ);
+ 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_sz_t);
+ index_ = sizeof(rpc_protocol::rpc_sz_t);
*this >> h;
- index_ = RPC_HEADER_SZ;
+ index_ = rpc_protocol::RPC_HEADER_SZ;
}
- template <class T> inline T grab() { T t; *this >> t; return t; }
+ template <class T> inline T _grab() { T t; *this >> t; return t; }
};
//
//
#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; }
+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_)
// 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))...};
+ (void)pass{(m << std::get<Indices>(t))...};
return m;
}
-template <class... Args> marshall &
+template <class... Args> inline marshall &
operator<<(marshall & m, tuple<Args...> && t) {
- using Indices = typename make_tuple_indices<sizeof...(Args)>::type;
- return tuple_marshall_imp(m, t, Indices());
+ return tuple_marshall_imp(m, t, TUPLE_INDICES(Args));
}
template <class... Args, size_t... Indices> inline unmarshall &
-tuple_unmarshall_imp(unmarshall & u, tuple<Args &...> t, tuple_indices<Indices...>) {
- (void)pass{(u >> get<Indices>(t))...};
+tuple_unmarshall_imp(unmarshall & u, tuple<Args & ...> t, tuple_indices<Indices...>) {
+ (void)pass{(u >> std::get<Indices>(t))...};
return u;
}
-template <class... Args> unmarshall &
-operator>>(unmarshall & u, tuple<Args &...> && t) {
- using Indices = typename make_tuple_indices<sizeof...(Args)>::type;
- return tuple_unmarshall_imp(u, t, Indices());
+template <class... Args> inline unmarshall &
+operator>>(unmarshall & u, tuple<Args & ...> && t) {
+ return tuple_unmarshall_imp(u, t, TUPLE_INDICES(Args));
}
//
//
// Implements struct marshalling via tuple marshalling of members.
-#define MARSHALLABLE(_c_) \
-inline unmarshall & operator>>(unmarshall &u, _c_ &a) { return u >> a._tuple_(); } \
-inline marshall & operator<<(marshall &m, const _c_ a) { return m << a._tuple_(); }
+template <class T> inline typename
+enable_if<is_tuple_convertible<T>::value, unmarshall>::type &
+operator>>(unmarshall & u, T & a) { return u >> a._tuple_(); }
-// our first two marshallable structs...
-MARSHALLABLE(request_header)
-MARSHALLABLE(reply_header)
+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 << (unsigned int)x.size();
- for (const auto &a : x)
+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) {
- unsigned n = u.grab<unsigned>();
+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>());
+ 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 pair<A,B> &d) {
+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, pair<A,B> &d) {
+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, map<A,B> &x) {
- unsigned n = u.grab<unsigned>();
+operator>>(unmarshall & u, std::map<A,B> & x) {
+ uint32_t n = u._grab<uint32_t>();
x.clear();
while (n--)
- x.emplace(u.grab<pair<A,B>>());
+ x.emplace(u._grab<std::pair<A,B>>());
return u;
}
// std::string
-inline marshall & operator<<(marshall &m, const string &s) {
+inline marshall & operator<<(marshall & m, const string & s) {
m << (uint32_t)s.size();
- m.rawbytes(s.data(), s.size());
+ m.write(s.data(), s.size());
return m;
}
-inline unmarshall & operator>>(unmarshall &u, string &s) {
- uint32_t sz = u.grab<uint32_t>();
+inline unmarshall & operator>>(unmarshall & u, string & s) {
+ uint32_t sz = u._grab<uint32_t>();
if (u.ok()) {
s.resize(sz);
- u.rawbytes(&s[0], sz);
+ u.read(&s[0], sz);
}
return u;
}
// Marshalling for strongly-typed enums
//
-template <class E> typename enable_if<is_enum<E>::value, marshall>::type &
-operator<<(marshall &m, E e) {
+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<is_enum<E>::value, unmarshall>::type &
-operator>>(unmarshall &u, E &e) {
- e = to_enum<E>(u.grab<enum_type_t<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;
}