So many changes. Broken.
[invirt/third/libt4.git] / include / rpc / marshall.h
1 #ifndef marshall_h
2 #define marshall_h
3
4 #include "include/types.h"
5 #include "include/rpc/rpc_protocol.h"
6
7 class marshall : public string {
8     public:
9         template <typename... Args>
10         marshall(const Args & ... args) {
11             UNPACK_STATEMENT(*this << args);
12         }
13
14         template <class T>
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);
20             return m + payload;
21         }
22 };
23
24 class unmarshall : string {
25     private:
26         string::const_iterator next = cbegin();
27
28     public:
29         template <typename... Args>
30         inline unmarshall(const string & s, Args && ...args) : string(s) {
31             UNPACK_STATEMENT(*this >> args);
32         }
33
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...);
39         }
40
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) {
46             auto from = next;
47             next += string::const_iterator::difference_type(n);
48             if (next <= end())
49                 std::copy(from, next, (char *)t);
50         }
51 };
52
53 //
54 // Marshalling for plain old data
55 //
56
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; }
61 #endif
62
63 #define MARSHALL_RAW_NETWORK_ORDER(_c_) MARSHALL_RAW_NETWORK_ORDER_AS(_c_, _c_)
64
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)
75
76 //
77 // Marshalling for tuples (used to implement marshalling for structs)
78 //
79
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.
85
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));
89     return m;
90 }
91
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...>{});
95 }
96
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));
100     return u;
101 }
102
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...>{});
106 }
107
108 //
109 // Marshalling for structs or classes containing a MEMBERS declaration
110 //
111
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); }
116
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); }
120
121 //
122 // Marshalling for STL containers
123 //
124
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)
131         m << a;
132     return m;
133 }
134
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>();
140     x.clear();
141     while (n--)
142         x.emplace_back(u.get<typename A::value_type>());
143     return u;
144 }
145
146 // std::map<A, B>
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>();
150     x.clear();
151     while (n--)
152         x.emplace(u.get<std::pair<A,B>>());
153     return u;
154 }
155
156 // std::string
157 inline marshall & operator<<(marshall & m, const string & s) {
158     m << (uint32_t)s.size();
159     m.append(s);
160     return m;
161 }
162
163 inline unmarshall & operator>>(unmarshall & u, string & s) {
164     uint32_t sz;
165     if (u >> sz) {
166         s.resize(sz);
167         u.read(&s[0], sz);
168     }
169     return u;
170 }
171
172 //
173 // Marshalling for strongly-typed enums
174 //
175
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);
179 }
180
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>());
184     return u;
185 }
186
187 #endif