]> git.tdb.fi Git - libs/net.git/blob - source/protocol.h
Style update: spaces around assignments
[libs/net.git] / source / protocol.h
1 #ifndef MSP_NET_PROTOCOL_H_
2 #define MSP_NET_PROTOCOL_H_
3
4 #include <map>
5 #include <vector>
6 #include <msp/core/except.h>
7 #include "receiver.h"
8
9 namespace Msp {
10 namespace Net {
11
12 class Protocol
13 {
14 private:
15         class PacketDefBase
16         {
17         protected:
18                 unsigned id;
19
20                 PacketDefBase(unsigned i): id(i) { }
21         public:
22                 virtual ~PacketDefBase() { }
23                 virtual unsigned get_class_id() const = 0;
24                 unsigned get_id() const { return id; }
25                 virtual const char *disassemble(ReceiverBase &, const char *, const char *) const = 0;
26
27                 static unsigned next_class_id;
28         };
29
30         template<typename P>
31         class FieldBase
32         {
33         protected:
34                 FieldBase() { }
35         public:
36                 virtual ~FieldBase() { }
37                 virtual char *assemble(const P &, char *, char *) const = 0;
38                 virtual const char *disassemble(P &, const char *, const char *) const = 0;
39         };
40
41         template<typename P, typename T>
42         class Field: public FieldBase<P>
43         {
44         private:
45                 T P::*ptr;
46
47         public:
48                 Field(T P::*p): ptr(p) { }
49
50                 virtual char *assemble(const P &p, char *d, char *e) const
51                 { return assemble_field(p.*ptr, d, e); }
52
53                 virtual const char *disassemble(P &p, const char *d, const char *e) const
54                 { return disassemble_field(p.*ptr, d, e); }
55         };
56
57 protected:
58         template<typename P>
59         class PacketDef: public PacketDefBase
60         {
61         private:
62                 std::vector<FieldBase<P> *> fields;
63
64         public:
65                 PacketDef(unsigned i): PacketDefBase(i)
66                 { if(!class_id) class_id = next_class_id++; }
67
68                 ~PacketDef()
69                 {
70                         for(typename std::vector<FieldBase<P> *>::const_iterator i=fields.begin(); i!=fields.end(); ++i)
71                                 delete *i;
72                 }
73
74                 virtual unsigned get_class_id() const { return class_id; }
75
76                 template<typename T>
77                 PacketDef &operator()(T P::*p)
78                 { fields.push_back(new Field<P, T>(p)); return *this; }
79
80                 char *assemble(const P &p, char *d, char *e) const
81                 {
82                         for(typename std::vector<FieldBase<P> *>::const_iterator i=fields.begin(); i!=fields.end(); ++i)
83                                 d = (*i)->assemble(p, d, e);
84                         return d;
85                 }
86
87                 const char *disassemble(ReceiverBase &r, const char *d, const char *e) const
88                 {
89                         PacketReceiver<P> *prcv = dynamic_cast<PacketReceiver<P> *>(&r);
90                         if(!prcv)
91                                 throw Exception("Packet type not supported by receiver");
92                         P pkt;
93                         for(typename std::vector<FieldBase<P> *>::const_iterator i=fields.begin(); i!=fields.end(); ++i)
94                                 d = (*i)->disassemble(pkt, d, e);
95                         prcv->receive(pkt);
96                         return d;
97                 }
98
99                 static unsigned class_id;
100         };
101
102         typedef std::map<unsigned, PacketDefBase *> PacketMap;
103
104         unsigned next_packet_id;
105         PacketMap packet_class_defs;
106         PacketMap packet_id_defs;
107
108         Protocol(unsigned = 1);
109 public:
110         ~Protocol();
111
112 private:
113         void add_packet(PacketDefBase &);
114
115 protected:
116         template<typename P>
117         PacketDef<P> &add()
118         {
119                 PacketDef<P> *pdef = new PacketDef<P>(next_packet_id++);
120                 add_packet(*pdef);
121                 return *pdef;
122         }
123
124         const PacketDefBase &get_packet_by_class(unsigned) const;
125         const PacketDefBase &get_packet_by_id(unsigned) const;
126
127 public:
128         template<typename P>
129         unsigned assemble(const P &pkt, char *buf, unsigned size) const
130         {
131                 unsigned id = PacketDef<P>::class_id;
132                 const PacketDef<P> &pdef = static_cast<const PacketDef<P> &>(get_packet_by_class(id));
133                 char *ptr = pdef.assemble(pkt, buf+4, buf+size);
134                 assemble_header(buf, pdef.get_id(), (size = ptr-buf));
135                 return size;
136         }
137
138         unsigned disassemble(ReceiverBase &, const char *, unsigned) const;
139
140         unsigned get_packet_size(const char *, unsigned) const;
141
142         unsigned get_hash() const;
143
144 private:
145         static void assemble_header(char *, unsigned, unsigned);
146
147         template<typename T>
148         static char *assemble_field(const T &, char *, char *);
149
150         template<typename T>
151         static const char *disassemble_field(T &, const char *, const char *);
152 };
153
154 template<typename P>
155 unsigned Protocol::PacketDef<P>::class_id = 0;
156
157 } // namespace Net
158 } // namespace Msp
159
160 #endif