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