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