emlabcpp
modern opinionated embedded C++ library
multiplexer.h
Go to the documentation of this file.
1 
24 #pragma once
25 
26 #include "../outcome.h"
27 #include "../protocol/endpoint.h"
28 #include "../protocol/handler.h"
29 #include "../protocol/tuple.h"
30 #include "../static_vector.h"
31 
33 {
34 
35 using channel_type = uint16_t;
36 
38 
39 template < std::size_t N >
41 
42 template < std::size_t N >
44 
45 template < std::size_t N >
47 
48 template < std::size_t N >
50 
51 enum multiplexer_enum : uint8_t
52 {
55 };
56 
57 static constexpr channel_type multiplexer_service_id = 0;
58 
59 using multiplexer_service_protocol = std::tuple< multiplexer_enum >;
61 
62 inline std::tuple< bool, std::span< std::byte > > serialize_multiplexed(
63  channel_type channel,
64  std::span< std::byte const > data,
65  std::span< std::byte > target )
66 {
68  if ( target.size() < chan_ser::max_size + data.size() )
69  return { false, {} };
70 
71  chan_ser::serialize_at( target.subspan< 0, chan_ser::max_size >(), channel );
72  std::memcpy( target.data() + chan_ser::max_size, data.data(), data.size() );
73 
74  return { false, target.subspan( 0, chan_ser::max_size + data.size() ) };
75 }
76 
77 template < std::size_t N >
79 {
81  std::make_tuple( channel, sizeless_message< N >( m ) ) );
82 }
83 
84 template < typename BinaryCallable >
85 outcome extract_multiplexed( std::span< std::byte const > const& msg, BinaryCallable handle_cb )
86 {
88  if ( msg.size() < chan_ser::max_size )
89  return outcome::ERROR;
90  channel_type id = chan_ser::deserialize( msg.subspan< 0, chan_ser::max_size >() );
91 
92  // TODO: there might be a better way than callback?
93  return handle_cb( id, msg.subspan( chan_ser::max_size ) );
94 }
95 
96 template < typename T >
97 concept slot = requires( T s, std::span< std::byte const > data ) {
98  { s.get_channel() } -> std::convertible_to< channel_type >;
99  { s.on_msg( data ) } -> std::convertible_to< outcome >;
100 };
101 
102 template < slot... Slotted >
103 outcome multiplexed_dispatch( channel_type chann, auto const& data, Slotted&... slotted )
104 {
105  outcome res = outcome::SUCCESS;
106 
107  // TODO: assert that channels are unique
108  auto f = [&]< typename T >( T& item ) {
109  if ( chann != item.get_channel() )
110  return false;
111  res = item.on_msg( data );
112  return true;
113  };
114  if ( !( f( slotted ) || ... || false ) )
115  res = outcome::ERROR;
116  return res;
117 }
118 
119 template < typename Packet >
121 {
122 public:
123  using message_type = typename Packet::message_type;
124  using payload_message = typename Packet::payload_type::template nth_def< 1 >;
125 
126  // TODO: !!! use "has_static_size" concept!
127  // TODO: maybe message_like concept?
128  template < std::size_t N >
130  {
131  return ep.serialize( std::make_tuple( chann, payload_message{ msg } ) );
132  }
133 
134  template < std::size_t N >
136  {
137  return ep.serialize( std::make_tuple( chann, payload_message{ msg } ) );
138  }
139 
140  template < typename Container >
141  void insert( Container&& data )
142  {
143  ep.insert( std::forward< Container >( data ) );
144  }
145 
146  std::variant< std::size_t, std::tuple< channel_type, payload_message >, error_record >
148  {
149  return ep.get_value();
150  }
151 
152  template < typename NextCallable, typename ValueCallable, typename ErrorCallable >
153  auto match_value( NextCallable&& nc, ValueCallable&& vc, ErrorCallable&& ec )
154  {
155  return match(
156  ep.get_value(),
157  std::forward< NextCallable >( nc ),
158  [&vc]( std::tuple< channel_type, payload_message > const& payload ) {
159  return std::apply( std::forward< ValueCallable >( vc ), payload );
160  },
161  std::forward< ErrorCallable >( ec ) );
162  }
163 
164  template < typename... Slotted >
165  outcome dispatch_value( Slotted&... slotted )
166  {
167  return match(
168  ep.get_value(),
169  []( std::size_t const ) -> outcome {
170  return outcome::SUCCESS;
171  },
172  [&slotted...]( std::tuple< channel_type, payload_message > const& payload ) {
173  auto const& [id, data] = payload;
174  return multiplexed_dispatch( id, data, slotted... );
175  },
176  []( error_record const& ) -> outcome {
177  return outcome::ERROR;
178  } );
179  }
180 
181 private:
183 };
184 
185 } // namespace emlabcpp::protocol
output_message serialize(output_value const &val)
Definition: endpoint.h:48
void insert(Container &&data)
Definition: endpoint.h:55
std::variant< std::size_t, input_value, error_record > get_value()
Definition: endpoint.h:60
Protocol library has custom type that represents message, however this is just simple overaly over st...
Definition: message.h:40
Definition: multiplexer.h:121
void insert(Container &&data)
Definition: multiplexer.h:141
outcome dispatch_value(Slotted &... slotted)
Definition: multiplexer.h:165
typename Packet::payload_type::template nth_def< 1 > payload_message
Definition: multiplexer.h:124
std::variant< std::size_t, std::tuple< channel_type, payload_message >, error_record > get_value()
Definition: multiplexer.h:147
message_type serialize(channel_type chann, message< N > const &msg)
Definition: multiplexer.h:129
auto match_value(NextCallable &&nc, ValueCallable &&vc, ErrorCallable &&ec)
Definition: multiplexer.h:153
typename Packet::message_type message_type
Definition: multiplexer.h:123
message_type serialize(channel_type chann, sizeless_message< N > const &msg)
Definition: multiplexer.h:135
Sizeless message is class that behaves in a same way as normal message, however it is serialized diff...
Definition: message.h:183
MIT License.
Definition: multiplexer.h:33
uint16_t channel_type
Definition: multiplexer.h:35
outcome extract_multiplexed(std::span< std::byte const > const &msg, BinaryCallable handle_cb)
Definition: multiplexer.h:85
typename multiplexer_payload< N >::value_type multiplexer_value
Definition: multiplexer.h:43
outcome multiplexed_dispatch(channel_type chann, auto const &data, Slotted &... slotted)
Definition: multiplexer.h:103
requires(std::is_enum_v< T >) struct serializer< T
static constexpr T deserialize(std::span< std::byte const, max_size > const &buffer)
Definition: serializer.h:81
static constexpr void serialize_at(std::span< std::byte, max_size > buffer, T item)
Definition: serializer.h:76
std::tuple< multiplexer_enum > multiplexer_service_protocol
Definition: multiplexer.h:59
multiplexer_enum
Definition: multiplexer.h:52
@ PROTOCOL_ERROR
Definition: multiplexer.h:54
@ PORT_MATCH_ERROR
Definition: multiplexer.h:53
static constexpr std::size_t max_size
Definition: serializer.h:73
static constexpr channel_type multiplexer_service_id
Definition: multiplexer.h:57
concept slot
Definition: multiplexer.h:97
typename handler< multiplexer_service_protocol >::message_type multiplexer_service_msg
Definition: multiplexer.h:60
typename multiplexer_payload< N >::message_type multiplexer_message
Definition: multiplexer.h:46
std::tuple< bool, std::span< std::byte > > serialize_multiplexed(channel_type channel, std::span< std::byte const > data, std::span< std::byte > target)
Definition: multiplexer.h:62
Definition: error.h:39
constexpr pointer data() noexcept
Returns pointer to first item of the storage.
Definition: static_storage.h:108
decltype(auto) match(Variant &&var, Callables &&... cals)
Definition: match.h:55
T res
Definition: algorithm.h:505
UnaryCallable && f
Definition: algorithm.h:161
outcome represents tristate resut of some operation, which can succeed, fail or produce an error.
Definition: outcome.h:49
handler< T > should be used to execute actual serialization and deserealization of protocol definitio...
Definition: handler.h:39
static message_type serialize(value_type const &val)
Definition: handler.h:45
Definition: serializer.h:38
tuple is high levle alternative to use just 'std::tuple' that is more friendly for standalone protoco...
Definition: tuple.h:43
typename traits::value_type value_type
Definition: tuple.h:57