4 #include "include/types.h"
5 #include "include/rpc/rpc_protocol.h"
7 class marshall : public string {
9 template <typename... Args>
10 marshall(const Args & ... args) {
11 UNPACK_STATEMENT(*this << args);
15 static inline string datagram(const T & h, const marshall & payload="") {
16 using namespace rpc_protocol;
17 marshall m{rpc_sz_t(payload.size() + RPC_HEADER_SZ - sizeof(rpc_sz_t)), (T)h};
18 VERIFY(m.size() <= RPC_HEADER_SZ); // Datagram header too large
19 m.resize(RPC_HEADER_SZ);
24 class unmarshall : string {
26 string::const_iterator next = cbegin();
29 template <typename... Args>
30 inline unmarshall(const string & s, Args && ...args) : string(s) {
31 UNPACK_STATEMENT(*this >> args);
34 template <class H, typename... Args>
35 static inline unmarshall datagram(const string & datagram, H & h, Args && ... args) {
36 rpc_protocol::rpc_sz_t s;
37 VERIFY(unmarshall(datagram, s, h)); // Datagram header too large
38 return unmarshall(datagram.substr(rpc_protocol::RPC_HEADER_SZ), args...);
41 template <class S> inline S get() { S s; *this >> s; return s; }
42 inline bool ok() const { return next <= end(); }
43 inline bool okdone() const { return next == end(); }
44 inline operator bool() const { return ok(); }
45 inline void read(void * t, size_t n) {
47 next += string::const_iterator::difference_type(n);
49 std::copy(from, next, (char *)t);
54 // Marshalling for plain old data
57 #ifndef MARSHALL_RAW_NETWORK_ORDER_AS
58 #define MARSHALL_RAW_NETWORK_ORDER_AS(_c_, _d_) \
59 inline marshall & operator<<(marshall & m, _c_ x) { _d_ y = hton((_d_)x); m.append((const char *)&y, sizeof(_d_)); return m; } \
60 inline unmarshall & operator>>(unmarshall & u, _c_ & x) { _d_ y; u.read(&y, sizeof(_d_)); x = (_c_)ntoh(y); return u; }
63 #define MARSHALL_RAW_NETWORK_ORDER(_c_) MARSHALL_RAW_NETWORK_ORDER_AS(_c_, _c_)
65 MARSHALL_RAW_NETWORK_ORDER_AS(bool, uint8_t)
66 MARSHALL_RAW_NETWORK_ORDER(uint8_t)
67 MARSHALL_RAW_NETWORK_ORDER(int8_t)
68 MARSHALL_RAW_NETWORK_ORDER(uint16_t)
69 MARSHALL_RAW_NETWORK_ORDER(int16_t)
70 MARSHALL_RAW_NETWORK_ORDER(uint32_t)
71 MARSHALL_RAW_NETWORK_ORDER(int32_t)
72 MARSHALL_RAW_NETWORK_ORDER_AS(size_t, uint64_t)
73 MARSHALL_RAW_NETWORK_ORDER(uint64_t)
74 MARSHALL_RAW_NETWORK_ORDER(int64_t)
77 // Marshalling for tuples (used to implement marshalling for structs)
80 // In order to iterate over the tuple elements, we first need a template
81 // parameter pack containing the tuple's indices. The function templates named
82 // *_imp below accept an empty tag struct as their last argument, and use its
83 // template arguments to index the tuple. The operator<< overloads instantiate
84 // the appropriate tag struct to make this possible.
86 template <class... Args, size_t... Indices> inline marshall &
87 tuple_marshall_imp(marshall & m, tuple<Args...> & t, std::index_sequence<Indices...>) {
88 UNPACK_STATEMENT(m << std::get<Indices>(t));
92 template <class... Args> inline marshall &
93 operator<<(marshall & m, tuple<Args...> && t) {
94 return tuple_marshall_imp(m, t, std::index_sequence_for<Args...>{});
97 template <class... Args, size_t... Indices> inline unmarshall &
98 tuple_unmarshall_imp(unmarshall & u, tuple<Args & ...> t, std::index_sequence<Indices...>) {
99 UNPACK_STATEMENT(u >> std::get<Indices>(t));
103 template <class... Args> inline unmarshall &
104 operator>>(unmarshall & u, tuple<Args & ...> && t) {
105 return tuple_unmarshall_imp(u, t, std::index_sequence_for<Args...>{});
109 // Marshalling for structs or classes containing a MEMBERS declaration
112 // Implements struct marshalling via tuple marshalling of members.
113 template <class A> inline typename
114 enable_if<is_tuple_convertible<A>::value, unmarshall>::type &
115 operator>>(unmarshall & u, A & a) { return u >> _tuple_(a); }
117 template <class T> inline typename
118 enable_if<is_tuple_convertible<T>::value, marshall>::type &
119 operator<<(marshall & m, const T a) { return m << _tuple_(a); }
122 // Marshalling for STL containers
125 // this overload is visible for type A only if A::cbegin and A::cend exist
126 template <class A> inline typename
127 enable_if<is_const_iterable<A>::value, marshall>::type &
128 operator<<(marshall & m, const A & x) {
129 m << (uint32_t)x.size();
130 for (const auto & a : x)
135 // visible for type A if A::emplace_back(a) makes sense
136 template <class A> inline typename
137 enable_if<supports_emplace_back<A>::value, unmarshall>::type &
138 operator>>(unmarshall & u, A & x) {
139 uint32_t n = u.get<uint32_t>();
142 x.emplace_back(u.get<typename A::value_type>());
147 template <class A, class B> inline unmarshall &
148 operator>>(unmarshall & u, std::map<A,B> & x) {
149 uint32_t n = u.get<uint32_t>();
152 x.emplace(u.get<std::pair<A,B>>());
157 inline marshall & operator<<(marshall & m, const string & s) {
158 m << (uint32_t)s.size();
163 inline unmarshall & operator>>(unmarshall & u, string & s) {
173 // Marshalling for strongly-typed enums
176 template <class E> typename enable_if<std::is_enum<E>::value, marshall>::type &
177 operator<<(marshall & m, E e) {
178 return m << typename std::underlying_type<E>::type(e);
181 template <class E> typename enable_if<std::is_enum<E>::value, unmarshall>::type &
182 operator>>(unmarshall & u, E & e) {
183 e = E(u.get<typename std::underlying_type<E>::type>());