Renamed a method that isn't part of the public interface of unmarshall
[invirt/third/libt4.git] / rpc / marshall.h
1 #ifndef marshall_h
2 #define marshall_h
3
4 #include "types.h"
5 #include "rpc_protocol.h"
6
7 class marshall;
8 class unmarshall;
9
10 //
11 // Marshall and unmarshall objects
12 //
13
14 class marshall {
15     private:
16         string buf_ = string(DEFAULT_RPC_SZ, 0); // Raw bytes buffer
17         size_t index_ = RPC_HEADER_SZ; // Read/write head position
18
19     public:
20         template <typename... Args>
21         marshall(const Args&... args) {
22             (void)pass{(*this << args)...};
23         }
24
25         void rawbytes(const void *p, size_t n) {
26             if (index_+n > buf_.size())
27                 buf_.resize(index_+n);
28             copy((char *)p, (char *)p+n, &buf_[index_]);
29             index_ += n;
30         }
31
32         // with header
33         inline operator string() const { return buf_.substr(0,index_); }
34         // without header
35         inline string content() { return buf_.substr(RPC_HEADER_SZ,index_-RPC_HEADER_SZ); }
36
37         // letting S be a defaulted template parameter forces the compiler to
38         // delay looking up operator<<(marshall&, rpc_sz_t) until we define it
39         // (i.e. we define an operator for marshalling uint32_t)
40         template <class T, class S=rpc_sz_t> inline void
41         pack_header(const T & h) {
42             VERIFY(sizeof(T)+sizeof(S) <= RPC_HEADER_SZ);
43             size_t saved_sz = index_;
44             index_ = 0;
45             *this << (S)(saved_sz - sizeof(S)) << (T)h;
46             index_ = saved_sz;
47         }
48 };
49
50 class unmarshall {
51     private:
52         string buf_;
53         size_t index_ = 0;
54         bool ok_ = false;
55
56     public:
57         unmarshall(const string &s, bool has_header)
58             : buf_(s),index_(RPC_HEADER_SZ) {
59             if (!has_header)
60                 buf_.insert(0, RPC_HEADER_SZ, 0);
61             ok_ = (buf_.size() >= RPC_HEADER_SZ);
62         }
63
64         bool ok() const { return ok_; }
65         bool okdone() const { return ok_ && index_ == buf_.size(); }
66
67         void rawbytes(void * t, size_t n) {
68             if (index_+n > buf_.size())
69                 ok_ = false;
70             VERIFY(ok_);
71             copy(&buf_[index_], &buf_[index_+n], (char *)t);
72             index_ += n;
73         }
74
75         template <class T> inline void
76         unpack_header(T & h) {
77             VERIFY(sizeof(T)+sizeof(rpc_sz_t) <= RPC_HEADER_SZ);
78             // first 4 bytes hold length field
79             index_ = sizeof(rpc_sz_t);
80             *this >> h;
81             index_ = RPC_HEADER_SZ;
82         }
83
84         template <class T> inline T _grab() { T t; *this >> t; return t; }
85 };
86
87 //
88 // Marshalling for plain old data
89 //
90
91 #define MARSHALL_RAW_NETWORK_ORDER_AS(_c_, _d_) \
92 inline marshall & operator<<(marshall &m, _c_ x) { _d_ y = hton((_d_)x); m.rawbytes(&y, sizeof(_d_)); return m; } \
93 inline unmarshall & operator>>(unmarshall &u, _c_ &x) { _d_ y; u.rawbytes(&y, sizeof(_d_)); x = (_c_)ntoh(y); return u; }
94
95 #define MARSHALL_RAW_NETWORK_ORDER(_c_) MARSHALL_RAW_NETWORK_ORDER_AS(_c_, _c_)
96
97 MARSHALL_RAW_NETWORK_ORDER_AS(bool, uint8_t)
98 MARSHALL_RAW_NETWORK_ORDER(uint8_t)
99 MARSHALL_RAW_NETWORK_ORDER(int8_t)
100 MARSHALL_RAW_NETWORK_ORDER(uint16_t)
101 MARSHALL_RAW_NETWORK_ORDER(int16_t)
102 MARSHALL_RAW_NETWORK_ORDER(uint32_t)
103 MARSHALL_RAW_NETWORK_ORDER(int32_t)
104 MARSHALL_RAW_NETWORK_ORDER_AS(size_t, uint32_t)
105 MARSHALL_RAW_NETWORK_ORDER(uint64_t)
106 MARSHALL_RAW_NETWORK_ORDER(int64_t)
107
108 //
109 // Marshalling for tuples (used to implement marshalling for structs)
110 //
111
112 // In order to iterate over the tuple elements, we first need a template
113 // parameter pack containing the tuple's indices.  The function templates named
114 // *_imp below accept an empty tag struct as their last argument, and use its
115 // template arguments to index the tuple.  The operator<< overloads instantiate
116 // the appropriate tag struct to make this possible.
117
118 template <class... Args, size_t... Indices> inline marshall &
119 tuple_marshall_imp(marshall & m, tuple<Args...> & t, tuple_indices<Indices...>) {
120     // Note that brace initialization is used for the empty structure "pack",
121     // forcing the comma-separated expressions expanded from the parameter pack
122     // to be evaluated in order.  Order matters because the elements must be
123     // serialized consistently!  The empty struct resulting from construction
124     // is discarded.
125     (void)pass{(m << get<Indices>(t))...};
126     return m;
127 }
128
129 template <class... Args> marshall &
130 operator<<(marshall & m, tuple<Args...> && t) {
131     using Indices = typename make_tuple_indices<sizeof...(Args)>::type;
132     return tuple_marshall_imp(m, t, Indices());
133 }
134
135 template <class... Args, size_t... Indices> inline unmarshall &
136 tuple_unmarshall_imp(unmarshall & u, tuple<Args &...> t, tuple_indices<Indices...>) {
137     (void)pass{(u >> get<Indices>(t))...};
138     return u;
139 }
140
141 template <class... Args> unmarshall &
142 operator>>(unmarshall & u, tuple<Args &...> && t) {
143     using Indices = typename make_tuple_indices<sizeof...(Args)>::type;
144     return tuple_unmarshall_imp(u, t, Indices());
145 }
146
147 //
148 // Marshalling for structs or classes containing a MEMBERS declaration
149 //
150
151 // Implements struct marshalling via tuple marshalling of members.
152 #define MARSHALLABLE(_c_) \
153 inline unmarshall & operator>>(unmarshall &u, _c_ &a) { return u >> a._tuple_(); } \
154 inline marshall & operator<<(marshall &m, const _c_ a) { return m << a._tuple_(); }
155
156 // our first two marshallable structs...
157 MARSHALLABLE(request_header)
158 MARSHALLABLE(reply_header)
159
160 //
161 // Marshalling for STL containers
162 //
163
164 // this overload is visible for type A only if A::cbegin and A::cend exist
165 template <class A> inline typename
166 enable_if<is_const_iterable<A>::value, marshall>::type &
167 operator<<(marshall &m, const A &x) {
168     m << (unsigned int)x.size();
169     for (const auto &a : x)
170         m << a;
171     return m;
172 }
173
174 // visible for type A if A::emplace_back(a) makes sense
175 template <class A> inline typename
176 enable_if<supports_emplace_back<A>::value, unmarshall>::type &
177 operator>>(unmarshall &u, A &x) {
178     unsigned n = u._grab<unsigned>();
179     x.clear();
180     while (n--)
181         x.emplace_back(u._grab<typename A::value_type>());
182     return u;
183 }
184
185 // std::pair<A, B>
186 template <class A, class B> inline marshall &
187 operator<<(marshall &m, const pair<A,B> &d) {
188     return m << d.first << d.second;
189 }
190
191 template <class A, class B> inline unmarshall &
192 operator>>(unmarshall &u, pair<A,B> &d) {
193     return u >> d.first >> d.second;
194 }
195
196 // std::map<A, B>
197 template <class A, class B> inline unmarshall &
198 operator>>(unmarshall &u, map<A,B> &x) {
199     unsigned n = u._grab<unsigned>();
200     x.clear();
201     while (n--)
202         x.emplace(u._grab<pair<A,B>>());
203     return u;
204 }
205
206 // std::string
207 inline marshall & operator<<(marshall &m, const string &s) {
208     m << (uint32_t)s.size();
209     m.rawbytes(s.data(), s.size());
210     return m;
211 }
212
213 inline unmarshall & operator>>(unmarshall &u, string &s) {
214     uint32_t sz = u._grab<uint32_t>();
215     if (u.ok()) {
216         s.resize(sz);
217         u.rawbytes(&s[0], sz);
218     }
219     return u;
220 }
221
222 //
223 // Marshalling for strongly-typed enums
224 //
225
226 template <class E> typename enable_if<is_enum<E>::value, marshall>::type &
227 operator<<(marshall &m, E e) {
228     return m << from_enum(e);
229 }
230
231 template <class E> typename enable_if<is_enum<E>::value, unmarshall>::type &
232 operator>>(unmarshall &u, E &e) {
233     e = to_enum<E>(u._grab<enum_type_t<E>>());
234     return u;
235 }
236
237 #endif