emlabcpp
modern opinionated embedded C++ library
rpc.h
Go to the documentation of this file.
1 
24 #pragma once
25 
26 #include "../match.h"
27 #include "../protocol/handler.h"
28 #include "../protocol/streams.h"
29 #include "../static_function.h"
30 
31 namespace emlabcpp::rpc
32 {
33 
35 {
36 };
37 
39 {
41 };
42 
44 {
45  std::size_t expected_index;
46  std::size_t index;
47 };
48 
49 struct error
50 {
51  std::variant< reactor_error, protocol::error_record, reply_error > er;
52 };
53 
54 template < typename T >
55 struct traits;
56 
57 template < typename... Calls >
58 struct traits< std::tuple< Calls... > >
59 {
60  template < typename Call >
61  struct request_wrapper : protocol::converter_def_type_base
62  {
63  static constexpr auto id = Call::id;
64 
65  using def_type = typename Call::request;
66  };
67 
68  template < typename Call >
69  struct reply_wrapper : protocol::converter_def_type_base
70  {
71  static constexpr auto id = Call::id;
72 
73  static_assert( !std::is_void_v< typename Call::reply > );
74 
75  using def_type = typename Call::reply;
76  };
77 
78  using call_defs = std::tuple< Calls... >;
79 
82 
85 
86  using outter_reply_group = std::variant< reply_group, reactor_error >;
88 
91 
94 };
95 
96 template < typename Wrapper >
98 
99 template < typename CallDefs >
100 class reactor
101 {
102 public:
104  using reply_variant = typename traits_type::reply_variant;
105  using request_type = typename traits_type::request_type;
106  using request_group = typename traits_type::request_group;
107  using reply_type = typename traits_type::reply_type;
108  using outter_reply_group = typename traits_type::outter_reply_group;
109  using request_message_type = typename traits_type::request_message_type;
110  using reply_message_type = typename traits_type::reply_message_type;
111 
114 
115  template < typename Handler >
116  static reply_message_type on_message( request_message_type const& msg, Handler&& h )
117  {
118  return match(
120  [&]( request_type const& req_var ) {
122  [&]< std::size_t i >() {
123  auto val = h( tag< i >{}, *std::get_if< i >( &req_var ) );
124  return reply_variant( std::in_place_index< i >, val );
125  },
126  req_var );
127  return reply_handler::serialize( rep );
128  },
129  [&]( protocol::error_record const& rec ) {
130  return reply_handler::serialize( reactor_error{ rec } );
131  } );
132  }
133 };
134 
135 template < typename CallDefs >
136 static constexpr std::size_t get_call_index( auto id )
137 {
138  return find_if_index< std::tuple_size_v< CallDefs > >( [id]< std::size_t i >() {
139  return std::tuple_element_t< i, CallDefs >::id == id;
140  } );
141 }
142 
143 template < typename Wrapper >
145 {
146 
147 public:
149  using call_defs = typename traits_type::call_defs;
150  using reply_variant = typename traits_type::reply_variant;
151  using request_type = typename traits_type::request_type;
152  using reply_type = typename traits_type::reply_type;
153  using request_group = typename traits_type::request_group;
154  using outter_reply_group = typename traits_type::outter_reply_group;
155  using request_message_type = typename traits_type::request_message_type;
156  using reply_message_type = typename traits_type::reply_message_type;
157 
160 
161  template < auto ID >
162  static constexpr std::size_t call_index = get_call_index< call_defs >( ID );
163 
164  template < auto ID >
165  using call_type = std::tuple_element_t< call_index< ID >, call_defs >;
166 
167  template < auto ID, typename... Args, typename MsgCallback >
168  static std::variant< typename call_type< ID >::reply, error >
169  call( MsgCallback&& cb, Args const&... args )
170  {
171  auto req_msg = make_call_msg< ID >( args... );
172  auto reply_msg = cb( req_msg );
173 
174  return on_reply_msg< ID >( reply_msg );
175  }
176 
177  template < auto ID, typename... Args >
178  static auto make_call_msg( Args const&... args )
179  {
180 
181  typename call_type< ID >::request req{ args... };
182  auto req_msg = request_handler::serialize(
183  request_type{ std::in_place_index< call_index< ID > >, req } );
184  return req_msg;
185  }
186 
187  template < auto ID >
188  static std::variant< typename call_type< ID >::reply, error >
189  on_reply_msg( auto const& reply_msg )
190  {
191  auto tmp = reply_handler::extract( reply_msg );
192  if ( auto* err = std::get_if< protocol::error_record >( &tmp ) )
193  return error{ *err };
194 
195  auto const& var = *std::get_if< 0 >( &tmp );
196  auto* err_ptr = std::get_if< reactor_error >( &var );
197  if ( err_ptr != nullptr )
198  return error{ *err_ptr };
199 
200  auto& reply_var = std::get< 0 >( var );
201  auto* ptr = std::get_if< call_index< ID > >( &reply_var );
202  if ( ptr == nullptr ) {
203  return error{ reply_error{
204  .expected_index = call_index< ID >, .index = reply_var.index() } };
205  }
206  return *ptr;
207  }
208 };
209 
210 template < auto ID, auto Method >
211 struct derive
212 {
213  static constexpr auto id = ID;
214 
215  using sig = signature_of< decltype( Method ) >;
216 
217  static constexpr bool void_returning = std::is_void_v< typename sig::return_type >;
218 
219  using request = typename sig::args_type;
220  using reply =
221  std::conditional_t< void_returning, void_return_type, typename sig::return_type >;
222 
223  static constexpr reply handle( auto& obj, auto const&... args )
224  {
225  if constexpr ( void_returning ) {
226  ( obj.*Method )( args... );
227  return void_return_type{};
228  } else {
229  return ( obj.*Method )( args... );
230  }
231  }
232 };
233 
234 template < typename Class, typename... Bindings >
236 {
237 public:
238  using bindings_tuple = std::tuple< Bindings... >;
243 
244  class_wrapper( Class& obj )
245  : obj_( obj ){};
246 
248  {
249  return reactor_type::on_message( msg, *this );
250  }
251 
252  template < std::size_t I, typename Request >
253  auto operator()( tag< I >, Request const& req )
254  {
255  using call_type = std::tuple_element_t< I, bindings_tuple >;
256 
257  return std::apply(
258  [&]( auto const&... args ) -> typename call_type::reply {
259  return call_type::handle( obj_, args... );
260  },
261  req );
262  }
263 
264 private:
265  Class& obj_;
266 };
267 
268 template < auto ID, typename Signature, std::size_t CallableSize = 32 >
269 struct bind
270 {
271  static constexpr auto id = ID;
274 
275  static constexpr bool void_returning = std::is_void_v< typename sig::return_type >;
276 
277  using request = typename sig::args_type;
278  using reply =
279  std::conditional_t< void_returning, void_return_type, typename sig::return_type >;
280 };
281 
282 template < typename... Bindings >
284 {
285  using def_type = std::tuple< Bindings... >;
286  using callbacks = std::tuple< typename Bindings::sfunction... >;
288  using request_message_type = typename reactor_type::request_message_type;
289  using reply_message_type = typename reactor_type::reply_message_type;
290 
291  template < auto ID >
292  static constexpr std::size_t call_index = get_call_index< def_type >( ID );
293 
294 public:
295  reply_message_type on_message( request_message_type const& msg )
296  {
297  return reactor_type::on_message( msg, *this );
298  }
299 
300  template < auto ID, typename Callable >
301  void bind( Callable cb )
302  {
303  static constexpr std::size_t i = call_index< ID >;
304 
305  std::get< i >( cbs_ ) = cb;
306  }
307 
308  template < std::size_t I, typename Request >
309  auto operator()( tag< I >, Request const& req )
310  {
311  using call_type = std::tuple_element_t< I, def_type >;
312 
313  return std::apply(
314  [&]( auto const&... args ) -> typename call_type::reply {
315  if constexpr ( call_type::void_returning ) {
316  std::get< I >( cbs_ )( args... );
317  return void_return_type{};
318  } else {
319  return std::get< I >( cbs_ )( args... );
320  }
321  },
322  req );
323  }
324 
325 private:
326  callbacks cbs_;
327 };
328 
329 } // namespace emlabcpp::rpc
Protocol library has custom type that represents message, however this is just simple overaly over st...
Definition: message.h:40
Definition: rpc.h:284
reply_message_type on_message(request_message_type const &msg)
Definition: rpc.h:295
void bind(Callable cb)
Definition: rpc.h:301
auto operator()(tag< I >, Request const &req)
Definition: rpc.h:309
Definition: rpc.h:236
reply_message_type on_message(request_message_type const &msg)
Definition: rpc.h:247
bindings_tuple call_defs
Definition: rpc.h:239
std::tuple< Bindings... > bindings_tuple
Definition: rpc.h:238
typename reactor_type::request_message_type request_message_type
Definition: rpc.h:241
class_wrapper(Class &obj)
Definition: rpc.h:244
auto operator()(tag< I >, Request const &req)
Definition: rpc.h:253
typename reactor_type::reply_message_type reply_message_type
Definition: rpc.h:242
Definition: rpc.h:145
typename traits_type::reply_message_type reply_message_type
Definition: rpc.h:156
static std::variant< typename call_type< ID >::reply, error > call(MsgCallback &&cb, Args const &... args)
Definition: rpc.h:169
static std::variant< typename call_type< ID >::reply, error > on_reply_msg(auto const &reply_msg)
Definition: rpc.h:189
typename traits_type::call_defs call_defs
Definition: rpc.h:149
std::tuple_element_t< call_index< ID >, call_defs > call_type
Definition: rpc.h:165
typename traits_type::reply_type reply_type
Definition: rpc.h:152
typename traits_type::request_type request_type
Definition: rpc.h:151
typename traits_type::request_group request_group
Definition: rpc.h:153
static constexpr std::size_t call_index
Definition: rpc.h:162
typename traits_type::reply_variant reply_variant
Definition: rpc.h:150
typename traits_type::outter_reply_group outter_reply_group
Definition: rpc.h:154
static auto make_call_msg(Args const &... args)
Definition: rpc.h:178
typename traits_type::request_message_type request_message_type
Definition: rpc.h:155
Definition: rpc.h:101
typename traits_type::request_group request_group
Definition: rpc.h:106
typename traits_type::outter_reply_group outter_reply_group
Definition: rpc.h:108
static reply_message_type on_message(request_message_type const &msg, Handler &&h)
Definition: rpc.h:116
typename traits_type::reply_variant reply_variant
Definition: rpc.h:104
typename traits_type::request_type request_type
Definition: rpc.h:105
typename traits_type::reply_message_type reply_message_type
Definition: rpc.h:110
typename traits_type::reply_type reply_type
Definition: rpc.h:107
typename traits_type::request_message_type request_message_type
Definition: rpc.h:109
decltype(traits_for_impl< D >()) traits_for
Definition: traits.h:59
Definition: error.h:39
Definition: base.h:95
MIT License.
Definition: rpc.h:32
static constexpr std::size_t get_call_index(auto id)
Definition: rpc.h:136
std::variant< reply_group, reactor_error > outter_reply_group
Definition: rpc.h:86
protocol::traits_for< request_type > request_traits
Definition: rpc.h:89
std::size_t index
Definition: rpc.h:46
protocol::traits_for< outter_reply_group > reply_traits
Definition: rpc.h:90
typename protocol::traits_for< request_group >::value_type request_type
Definition: rpc.h:83
std::variant< reactor_error, protocol::error_record, reply_error > er
Definition: rpc.h:51
std::size_t expected_index
Definition: rpc.h:45
typename protocol::traits_for< reply_group >::value_type reply_variant
Definition: rpc.h:84
typename protocol::traits_for< outter_reply_group >::value_type reply_type
Definition: rpc.h:87
protocol::error_record record
Definition: rpc.h:40
std::tuple< Calls... > call_defs
Definition: rpc.h:78
Definition: rpc.h:50
Definition: rpc.h:39
Definition: rpc.h:44
Definition: rpc.h:55
decltype(auto) visit_index(Visitor &&vis, Variant const &var)
Definition: visit.h:35
decltype(auto) match(Variant &&var, Callables &&... cals)
Definition: match.h:55
Args const & args
Definition: min_max.h:83
Definition: static_function.h:109
Definition: base.h:218
More complex constructs have custom mechanics that internally produces def_type alias used by the lib...
Definition: base.h:122
handler< T > should be used to execute actual serialization and deserealization of protocol definitio...
Definition: handler.h:39
static std::variant< value_type, error_record > extract(view< std::byte const * > const &msg)
Definition: handler.h:57
static message_type serialize(value_type const &val)
Definition: handler.h:45
Definition: rpc.h:270
typename sig::args_type request
Definition: rpc.h:277
static constexpr bool void_returning
Definition: rpc.h:275
std::conditional_t< void_returning, void_return_type, typename sig::return_type > reply
Definition: rpc.h:279
Definition: rpc.h:212
std::conditional_t< void_returning, void_return_type, typename sig::return_type > reply
Definition: rpc.h:221
static constexpr reply handle(auto &obj, auto const &... args)
Definition: rpc.h:223
static constexpr bool void_returning
Definition: rpc.h:217
typename sig::args_type request
Definition: rpc.h:219
typename Call::reply def_type
Definition: rpc.h:75
typename Call::request def_type
Definition: rpc.h:65
Definition: types.h:73