]> git.tdb.fi Git - libs/net.git/blob - source/net/receiver.h
Add a dynamic receiver class for more flexible packet handling
[libs/net.git] / source / net / receiver.h
1 #ifndef MSP_NET_RECEIVER_H_
2 #define MSP_NET_RECEIVER_H_
3
4 #include <vector>
5 #include <msp/core/algorithm.h>
6 #include <msp/core/maputils.h>
7 #include <msp/core/variant.h>
8 #include "mspnet_api.h"
9
10 namespace Msp {
11 namespace Net {
12
13 class MSPNET_API ReceiverBase
14 {
15 protected:
16         ReceiverBase() = default;
17 public:
18         virtual ~ReceiverBase() = default;
19 };
20
21
22 template<typename P>
23 class PacketReceiver: public virtual ReceiverBase
24 {
25 protected:
26         PacketReceiver() = default;
27 public:
28         virtual void receive(const P &) = 0;
29 };
30
31
32 class MSPNET_API DynamicReceiver: public ReceiverBase
33 {
34 protected:
35         DynamicReceiver() = default;
36 public:
37         virtual void receive(unsigned, const Variant &) = 0;
38 };
39
40
41 class MSPNET_API DynamicDispatcher: public DynamicReceiver
42 {
43 private:
44         using DispatchFunc = void(ReceiverBase &, const Variant &);
45
46         struct Target
47         {
48                 unsigned packet_id;
49                 ReceiverBase *receiver;
50                 DispatchFunc *func;
51
52                 Target(unsigned i, ReceiverBase &r, DispatchFunc *f): packet_id(i), receiver(&r), func(f) { }
53         };
54
55         std::vector<Target> targets;
56
57 public:
58         template<typename P>
59         void add_receiver(unsigned, PacketReceiver<P> &);
60
61         void receive(unsigned, const Variant &) override;
62 };
63
64
65 template<typename P>
66 void DynamicDispatcher::add_receiver(unsigned packet_id, PacketReceiver<P> &r)
67 {
68         auto i = lower_bound_member(targets, packet_id, &Target::packet_id);
69         if(i!=targets.end() && i->packet_id==packet_id)
70                 throw key_error(packet_id);
71
72         auto dispatch = [](ReceiverBase &receiver, const Variant &packet){
73                 dynamic_cast<PacketReceiver<P> &>(receiver).receive(packet.value<P>());
74         };
75
76         targets.emplace(i, packet_id, r, +dispatch);
77 }
78
79 } // namespace Net
80 } // namespace Msp
81
82 #endif