]> git.tdb.fi Git - libs/net.git/blob - source/net/protocol.h
Simplify the inner workings of Protocol
[libs/net.git] / source / net / protocol.h
1 #ifndef MSP_NET_PROTOCOL_H_
2 #define MSP_NET_PROTOCOL_H_
3
4 #include <cstdint>
5 #include <map>
6 #include <stdexcept>
7 #include <vector>
8 #include <msp/core/hash.h>
9 #include "receiver.h"
10
11 namespace Msp {
12 namespace Net {
13
14 class bad_packet: public std::runtime_error
15 {
16 public:
17         bad_packet(const std::string &w): std::runtime_error(w) { }
18 };
19
20
21 class buffer_error: public std::runtime_error
22 {
23 public:
24         buffer_error(const std::string &w): std::runtime_error(w) { }
25 };
26
27
28 class Protocol
29 {
30 private:
31         template<typename T, std::uint8_t K>
32         struct BasicTraits;
33
34         template<typename T>
35         struct Traits;
36
37         template<typename C>
38         class Serializer;
39
40         template<typename T>
41         class BasicSerializer
42         {
43         public:
44                 typedef T ValueType;
45
46                 BasicSerializer(const Protocol &) { }
47
48                 std::uint64_t get_hash() const { return Traits<T>::signature; }
49                 char *serialize(const T &, char *, char *) const;
50                 const char *deserialize(T &, const char *, const char *) const;
51         };
52
53         class StringSerializer
54         {
55         public:
56                 typedef std::string ValueType;
57
58         private:
59                 BasicSerializer<std::uint16_t> length_serializer;
60
61         public:
62                 StringSerializer(const Protocol &);
63
64                 std::uint64_t get_hash() const;
65                 char *serialize(const std::string &, char *, char *) const;
66                 const char *deserialize(std::string &, const char *, const char *) const;
67         };
68
69         template<typename A>
70         class ArraySerializer
71         {
72         public:
73                 typedef A ValueType;
74
75         private:
76                 BasicSerializer<std::uint16_t> length_serializer;
77                 typename Traits<typename A::value_type>::Serializer element_serializer;
78
79         public:
80                 ArraySerializer(const Protocol &);
81
82                 std::uint64_t get_hash() const;
83                 char *serialize(const A &, char *, char *) const;
84                 const char *deserialize(A &, const char *, const char *) const;
85         };
86
87         template<typename C>
88         class CompoundSerializer
89         {
90         public:
91                 typedef C ValueType;
92
93         private:
94                 const Serializer<C> &serializer;
95
96         public:
97                 CompoundSerializer(const Protocol &);
98
99                 std::uint64_t get_hash() const;
100                 char *serialize(const C &, char *, char *) const;
101                 const char *deserialize(C &, const char *, const char *) const;
102         };
103
104         template<typename C, typename Head, typename S>
105         class FieldSerializer: public Head
106         {
107         public:
108                 template<typename N>
109                 struct Next
110                 {
111                         typedef FieldSerializer<C, FieldSerializer<C, Head, S>, typename Traits<N>::Serializer> Type;
112                 };
113
114         private:
115                 typedef typename S::ValueType C::*Pointer;
116
117                 Pointer ptr;
118                 S ser;
119
120         public:
121                 FieldSerializer(const Head &, Pointer, const Protocol &);
122
123                 std::uint64_t get_hash() const;
124                 char *serialize(const C &, char *, char *) const;
125                 const char *deserialize(C &, const char *, const char *) const;
126         };
127
128         template<typename C>
129         class Serializer
130         {
131         public:
132                 template<typename N>
133                 struct Next
134                 {
135                         typedef FieldSerializer<C, Serializer<C>, typename Traits<N>::Serializer> Type;
136                 };
137
138                 virtual ~Serializer() = default;
139
140                 virtual std::uint64_t get_hash() const { return 0; }
141                 virtual char *serialize(const C &, char *b, char *) const { return b; }
142                 virtual const char *deserialize(C &, const char *b, const char *) const { return b; }
143         };
144
145         class PacketDefBase
146         {
147         protected:
148                 unsigned id;
149
150                 PacketDefBase(unsigned);
151         public:
152                 virtual ~PacketDefBase() = default;
153
154                 virtual unsigned get_class_id() const = 0;
155                 unsigned get_id() const { return id; }
156                 virtual std::uint64_t get_hash() const = 0;
157                 virtual const char *dispatch(ReceiverBase &, const char *, const char *) const = 0;
158         };
159
160         template<typename P>
161         class PacketTypeDef: public PacketDefBase
162         {
163         private:
164                 Serializer<P> *serializer;
165
166         public:
167                 PacketTypeDef(unsigned);
168                 ~PacketTypeDef();
169
170                 unsigned get_class_id() const override { return get_packet_class_id<P>(); }
171
172                 template<typename S>
173                 void set_serializer(const S &);
174
175                 const Serializer<P> &get_serializer() const { return *serializer; }
176
177                 std::uint64_t get_hash() const override { return serializer->get_hash(); }
178                 char *serialize(const P &, char *, char *) const;
179                 const char *deserialize(P &, const char *, const char *) const;
180                 const char *dispatch(ReceiverBase &, const char *, const char *) const override;
181         };
182
183         template<typename P, typename S>
184         class PacketDefBuilder
185         {
186         private:
187                 const Protocol &protocol;
188                 PacketTypeDef<P> &pktdef;
189                 S serializer;
190
191         public:
192                 PacketDefBuilder(const Protocol &, PacketTypeDef<P> &, const S &);
193                 
194                 template<typename T>
195                 PacketDefBuilder<P, typename S::template Next<T>::Type> operator()(T P::*);
196         };
197
198         struct PacketHeader
199         {
200                 std::uint16_t type = 0;
201                 std::uint16_t length = 0;
202
203                 PacketHeader() = default;
204                 PacketHeader(std::uint16_t, std::uint16_t);
205         };
206
207         typedef std::map<unsigned, PacketDefBase *> PacketMap;
208
209         PacketTypeDef<PacketHeader> header_def;
210         unsigned next_packet_id;
211         PacketMap packet_class_defs;
212         PacketMap packet_id_defs;
213
214 protected:
215         Protocol(unsigned = 1);
216 public:
217         ~Protocol();
218
219 private:
220         static unsigned get_next_packet_class_id();
221
222         template<typename P>
223         static unsigned get_packet_class_id();
224
225         void add_packet(PacketDefBase *);
226
227 protected:
228         template<typename P>
229         PacketDefBuilder<P, Serializer<P>> add(unsigned);
230
231         template<typename P>
232         PacketDefBuilder<P, Serializer<P>> add();
233
234         const PacketDefBase &get_packet_by_class_id(unsigned) const;
235         const PacketDefBase &get_packet_by_id(unsigned) const;
236
237         template<typename P>
238         const PacketTypeDef<P> &get_packet_by_class() const;
239
240 public:
241         template<typename P>
242         std::size_t serialize(const P &, char *, std::size_t) const;
243
244         std::size_t get_packet_size(const char *, std::size_t) const;
245         std::size_t dispatch(ReceiverBase &, const char *, std::size_t) const;
246
247         std::uint64_t get_hash() const;
248 };
249
250
251 template<typename P>
252 unsigned Protocol::get_packet_class_id()
253 {
254         static unsigned id = get_next_packet_class_id();
255         return id;
256 }
257
258 template<typename P>
259 Protocol::PacketDefBuilder<P, Protocol::Serializer<P>> Protocol::add(unsigned id)
260 {
261         PacketTypeDef<P> *pdef = new PacketTypeDef<P>(id);
262         add_packet(pdef);
263         return PacketDefBuilder<P, Serializer<P>>(*this, *pdef, Serializer<P>());
264 }
265
266 template<typename P>
267 Protocol::PacketDefBuilder<P, Protocol::Serializer<P>> Protocol::add()
268 {
269         return add<P>(next_packet_id++);
270 }
271
272 template<typename P>
273 const Protocol::PacketTypeDef<P> &Protocol::get_packet_by_class() const
274 {
275         const PacketDefBase &pdef = get_packet_by_class_id(get_packet_class_id<P>());
276         return static_cast<const PacketTypeDef<P> &>(pdef);
277 }
278
279 template<typename P>
280 std::size_t Protocol::serialize(const P &pkt, char *buf, std::size_t size) const
281 {
282         const PacketTypeDef<P> &pdef = get_packet_by_class<P>();
283         if(!pdef.get_id())
284                 throw std::invalid_argument("no packet id");
285         char *ptr = pdef.serialize(pkt, buf+4, buf+size);
286         size = ptr-buf;
287         header_def.serialize(PacketHeader(pdef.get_id(), size), buf, buf+4);
288         return size;
289 }
290
291
292 template<typename T, std::uint8_t K>
293 struct Protocol::BasicTraits
294 {
295         static const std::uint16_t signature = K | (sizeof(T)<<8);
296         typedef BasicSerializer<T> Serializer;
297 };
298
299 template<typename T>
300 struct Protocol::Traits
301 {
302         static const std::uint16_t signature = 'C';
303         typedef CompoundSerializer<T> Serializer;
304 };
305
306 template<> struct Protocol::Traits<bool>: BasicTraits<bool, 'B'> { };
307 template<> struct Protocol::Traits<std::int8_t>: BasicTraits<std::int8_t, 'I'> { };
308 template<> struct Protocol::Traits<std::uint8_t>: BasicTraits<std::uint8_t, 'U'> { };
309 template<> struct Protocol::Traits<std::int16_t>: BasicTraits<std::int16_t, 'I'> { };
310 template<> struct Protocol::Traits<std::uint16_t>: BasicTraits<std::uint16_t, 'U'> { };
311 template<> struct Protocol::Traits<std::int32_t>: BasicTraits<std::int32_t, 'I'> { };
312 template<> struct Protocol::Traits<std::uint32_t>: BasicTraits<std::uint32_t, 'U'> { };
313 template<> struct Protocol::Traits<std::int64_t>: BasicTraits<std::int64_t, 'I'> { };
314 template<> struct Protocol::Traits<std::uint64_t>: BasicTraits<std::uint64_t, 'U'> { };
315 template<> struct Protocol::Traits<float>: BasicTraits<float, 'F'> { };
316 template<> struct Protocol::Traits<double>: BasicTraits<double, 'F'> { };
317
318 template<> struct Protocol::Traits<std::string>
319 {
320         static const std::uint16_t signature = 'S';
321         typedef StringSerializer Serializer;
322 };
323
324 template<typename T>
325 struct Protocol::Traits<std::vector<T>>
326 {
327         static const std::uint16_t signature = 'A';
328         typedef ArraySerializer<std::vector<T>> Serializer;
329 };
330
331
332 inline std::uint64_t Protocol::StringSerializer::get_hash() const
333 {
334         return Traits<std::string>::signature;
335 }
336
337
338 template<typename A>
339 Protocol::ArraySerializer<A>::ArraySerializer(const Protocol &proto):
340         length_serializer(proto),
341         element_serializer(proto)
342 { }
343
344 template<typename A>
345 std::uint64_t Protocol::ArraySerializer<A>::get_hash() const
346 {
347         return hash_round<64>(element_serializer.get_hash(), 'A');
348 }
349
350 template<typename A>
351 char *Protocol::ArraySerializer<A>::serialize(const A &array, char *buf, char *end) const
352 {
353         buf = length_serializer.serialize(array.size(), buf, end);
354         for(const auto &e: array)
355                 buf = element_serializer.serialize(e, buf, end);
356         return buf;
357 }
358
359 template<typename A>
360 const char *Protocol::ArraySerializer<A>::deserialize(A &array, const char *buf, const char *end) const
361 {
362         std::uint16_t length;
363         buf = length_serializer.deserialize(length, buf, end);
364         array.resize(length);
365         for(unsigned i=0; i<length; ++i)
366                 buf = element_serializer.deserialize(array[i], buf, end);
367         return buf;
368 }
369
370
371 template<typename C>
372 Protocol::CompoundSerializer<C>::CompoundSerializer(const Protocol &proto):
373         serializer(proto.get_packet_by_class<C>().get_serializer())
374 { }
375
376 template<typename C>
377 std::uint64_t Protocol::CompoundSerializer<C>::get_hash() const
378 {
379         return hash_round<64>(serializer.get_hash(), 'C');
380 }
381
382 template<typename C>
383 char *Protocol::CompoundSerializer<C>::serialize(const C &com, char *buf, char *end) const
384 {
385         return serializer.serialize(com, buf, end);
386 }
387
388 template<typename C>
389 const char *Protocol::CompoundSerializer<C>::deserialize(C &com, const char *buf, const char *end) const
390 {
391         return serializer.deserialize(com, buf, end);
392 }
393
394
395 template<typename P, typename Head, typename S>
396 Protocol::FieldSerializer<P, Head, S>::FieldSerializer(const Head &h, Pointer p, const Protocol &proto):
397         Head(h),
398         ptr(p),
399         ser(proto)
400 { }
401
402 template<typename P, typename Head, typename S>
403 std::uint64_t Protocol::FieldSerializer<P, Head, S>::get_hash() const
404 {
405         return hash_update<64>(Head::get_hash(), ser.get_hash());
406 }
407
408 template<typename P, typename Head, typename S>
409 char *Protocol::FieldSerializer<P, Head, S>::serialize(const P &pkt, char *buf, char *end) const
410 {
411         buf = Head::serialize(pkt, buf, end);
412         return ser.serialize(pkt.*ptr, buf, end);
413 }
414
415 template<typename P, typename Head, typename S>
416 const char *Protocol::FieldSerializer<P, Head, S>::deserialize(P &pkt, const char *buf, const char *end) const
417 {
418         buf = Head::deserialize(pkt, buf, end);
419         return ser.deserialize(pkt.*ptr, buf, end);
420 }
421
422
423 template<typename P>
424 Protocol::PacketTypeDef<P>::PacketTypeDef(unsigned i):
425         PacketDefBase(i),
426         serializer(new Serializer<P>)
427 { }
428
429 template<typename P>
430 Protocol::PacketTypeDef<P>::~PacketTypeDef()
431 {
432         delete serializer;
433 }
434
435 template<typename P>
436 template<typename S>
437 void Protocol::PacketTypeDef<P>::set_serializer(const S &ser)
438 {
439         delete serializer;
440         serializer = new S(ser);
441 }
442
443 template<typename P>
444 char *Protocol::PacketTypeDef<P>::serialize(const P &pkt, char *buf, char *end) const
445 {
446         return serializer->serialize(pkt, buf, end);
447 }
448
449 template<typename P>
450 const char *Protocol::PacketTypeDef<P>::deserialize(P &pkt, const char *buf, const char *end) const
451 {
452         return serializer->deserialize(pkt, buf, end);
453 }
454
455 template<typename P>
456 const char *Protocol::PacketTypeDef<P>::dispatch(ReceiverBase &rcv, const char *buf, const char *end) const
457 {
458         PacketReceiver<P> *prcv = dynamic_cast<PacketReceiver<P> *>(&rcv);
459         if(!prcv)
460                 throw bad_packet("unsupported");
461         P pkt;
462         buf = deserialize(pkt, buf, end);
463         prcv->receive(pkt);
464         return buf;
465 }
466
467
468 template<typename P, typename S>
469 Protocol::PacketDefBuilder<P, S>::PacketDefBuilder(const Protocol &p, PacketTypeDef<P> &k, const S &s):
470         protocol(p),
471         pktdef(k),
472         serializer(s)
473 { }
474
475 template<typename P, typename S>
476 template<typename T>
477 Protocol::PacketDefBuilder<P, typename S::template Next<T>::Type> Protocol::PacketDefBuilder<P, S>::operator()(T P::*ptr)
478 {
479         typename S::template Next<T>::Type next_ser(serializer, ptr, protocol);
480         pktdef.set_serializer(next_ser);
481         return PacketDefBuilder<P, typename S::template Next<T>::Type>(protocol, pktdef, next_ser);
482 }
483
484 } // namespace Net
485 } // namespace Msp
486
487 #endif