CppWAMP
C++11 client library for the WAMP protocol
unpacker.hpp
Go to the documentation of this file.
1 /*------------------------------------------------------------------------------
2  Copyright Butterfly Energy Systems 2014-2016, 2022.
3  Distributed under the Boost Software License, Version 1.0.
4  http://www.boost.org/LICENSE_1_0.txt
5 ------------------------------------------------------------------------------*/
6 
7 #ifndef CPPWAMP_UNPACKER_HPP
8 #define CPPWAMP_UNPACKER_HPP
9 
10 //------------------------------------------------------------------------------
14 //------------------------------------------------------------------------------
15 
16 #include <functional>
17 #include <tuple>
18 #include "api.hpp"
19 #include "config.hpp"
20 #include "peerdata.hpp"
21 #include "traits.hpp"
22 #include "variant.hpp"
23 #include "./internal/integersequence.hpp"
24 
25 namespace wamp
26 {
27 
28 //------------------------------------------------------------------------------
30 //------------------------------------------------------------------------------
31 template <typename TSlot>
32 using DecayedSlot = typename std::decay<TSlot>::type;
33 
34 
35 //------------------------------------------------------------------------------
45 //------------------------------------------------------------------------------
46 template <typename TSlot, typename... TArgs>
47 class CPPWAMP_API EventUnpacker
48 {
49 public:
51  using Slot = TSlot;
52 
54  explicit EventUnpacker(Slot slot);
55 
59  void operator()(Event event) const;
60 
61 private:
62  template <int ...S>
63  void invoke(Event&& event, internal::IntegerSequence<S...>) const;
64 
65  Slot slot_;
66 };
67 
68 //------------------------------------------------------------------------------
77 //------------------------------------------------------------------------------
78 template <typename... TArgs, typename TSlot>
79 CPPWAMP_API EventUnpacker<DecayedSlot<TSlot>, TArgs...>
80 unpackedEvent(TSlot&& slot);
81 
82 
83 //------------------------------------------------------------------------------
95 //------------------------------------------------------------------------------
96 template <typename TSlot, typename... TArgs>
97 class CPPWAMP_API SimpleEventUnpacker
98 {
99 public:
101  using Slot = TSlot;
102 
104  explicit SimpleEventUnpacker(Slot slot);
105 
109  void operator()(Event event) const;
110 
111 private:
112  template <int ...S>
113  CPPWAMP_HIDDEN void invoke(Event&& event,
114  internal::IntegerSequence<S...>) const;
115 
116  Slot slot_;
117 };
118 
119 //------------------------------------------------------------------------------
122 //------------------------------------------------------------------------------
123 template <typename TSlot, typename... TArgs>
124 using BasicEventUnpacker CPPWAMP_DEPRECATED
125  = SimpleEventUnpacker<TSlot, TArgs...>;
126 
127 //------------------------------------------------------------------------------
137 //------------------------------------------------------------------------------
138 template <typename... TArgs, typename TSlot>
139 CPPWAMP_API SimpleEventUnpacker<DecayedSlot<TSlot>, TArgs...>
140 simpleEvent(TSlot&& slot);
141 
142 //------------------------------------------------------------------------------
144 //------------------------------------------------------------------------------
145 template <typename... TArgs, typename TSlot>
146 CPPWAMP_API SimpleEventUnpacker<DecayedSlot<TSlot>, TArgs...>
147 basicEvent(TSlot&& slot);
148 
149 
150 //------------------------------------------------------------------------------
160 //------------------------------------------------------------------------------
161 template <typename TSlot, typename... TArgs>
162 class CPPWAMP_API InvocationUnpacker
163 {
164 public:
166  using Slot = TSlot;
167 
169  explicit InvocationUnpacker(Slot slot);
170 
174  Outcome operator()(Invocation inv) const;
175 
176 private:
177  template <int ...S>
178  CPPWAMP_HIDDEN Outcome invoke(Invocation&& inv,
179  internal::IntegerSequence<S...>) const;
180 
181  Slot slot_;
182 };
183 
184 //------------------------------------------------------------------------------
193 //------------------------------------------------------------------------------
194 template <typename... TArgs, typename TSlot>
195 CPPWAMP_API InvocationUnpacker<DecayedSlot<TSlot>, TArgs...>
196 unpackedRpc(TSlot&& slot);
197 
198 
199 //------------------------------------------------------------------------------
213 //------------------------------------------------------------------------------
214 template <typename TSlot, typename TResult, typename... TArgs>
215 class CPPWAMP_API SimpleInvocationUnpacker
216 {
217 public:
219  using Slot = TSlot;
220 
222  using ResultType = TResult;
223 
225  explicit SimpleInvocationUnpacker(Slot slot);
226 
230  Outcome operator()(Invocation inv) const;
231 
232 private:
233  template <int ...S>
234  Outcome invoke(TrueType, Invocation&& inv,
235  internal::IntegerSequence<S...>) const;
236 
237  template <int ...S>
238  Outcome invoke(FalseType, Invocation&& inv,
239  internal::IntegerSequence<S...>) const;
240 
241  Slot slot_;
242 };
243 
244 
245 //------------------------------------------------------------------------------
248 //------------------------------------------------------------------------------
249 template <typename TSlot, typename TResult, typename... TArgs>
250 using BasicInvocationUnpacker CPPWAMP_DEPRECATED =
251  SimpleInvocationUnpacker<TSlot, TResult, TArgs...>;
252 
253 //------------------------------------------------------------------------------
264 //------------------------------------------------------------------------------
265 template <typename TResult, typename... TArgs, typename TSlot>
266 CPPWAMP_API SimpleInvocationUnpacker<DecayedSlot<TSlot>, TResult, TArgs...>
267 simpleRpc(TSlot&& slot);
268 
269 //------------------------------------------------------------------------------
271 //------------------------------------------------------------------------------
272 template <typename TResult, typename... TArgs, typename TSlot>
273 CPPWAMP_API SimpleInvocationUnpacker<DecayedSlot<TSlot>, TResult, TArgs...>
274 basicRpc(TSlot&& slot);
275 
276 
277 
278 //******************************************************************************
279 // Internal helper types
280 //******************************************************************************
281 
282 namespace internal
283 {
284 
285 //------------------------------------------------------------------------------
286 // This is caught internally by Client while dispatching RPCs and is never
287 // propagated through the API.
288 //------------------------------------------------------------------------------
289 struct UnpackError : public Error
290 {
291  UnpackError() : Error("wamp.error.invalid_argument") {}
292 };
293 
294 } // namespace internal
295 
296 
297 //******************************************************************************
298 // EventUnpacker implementation
299 //******************************************************************************
300 
301 //------------------------------------------------------------------------------
302 template <typename S, typename... A>
304  : slot_(std::move(slot))
305 {}
306 
307 //------------------------------------------------------------------------------
308 template <typename S, typename... A>
310 {
311  if (event.args().size() < sizeof...(A))
312  {
313  std::ostringstream oss;
314  oss << "Expected " << sizeof...(A)
315  << " args, but only got " << event.args().size();
316  throw internal::UnpackError().withArgs(oss.str());
317  }
318 
319  // Use the integer parameter pack technique shown in
320  // http://stackoverflow.com/a/7858971/245265
321  using Seq = typename internal::GenIntegerSequence<sizeof...(A)>::type;
322  invoke(std::move(event), Seq());
323 }
324 
325 //------------------------------------------------------------------------------
326 template <typename S, typename... A>
327 template <int ...Seq>
329  internal::IntegerSequence<Seq...>) const
330 {
331  std::tuple<ValueTypeOf<A>...> args;
332 
333  try
334  {
335  event.convertToTuple(args);
336  }
337  catch (const error::Conversion& e)
338  {
339  throw internal::UnpackError().withArgs(e.what());
340  }
341 
342  slot_(std::move(event), std::get<Seq>(std::move(args))...);
343 }
344 
345 //------------------------------------------------------------------------------
346 template <typename... TArgs, typename TSlot>
347 EventUnpacker<DecayedSlot<TSlot>, TArgs...> unpackedEvent(TSlot&& slot)
348 {
349  return EventUnpacker<DecayedSlot<TSlot>, TArgs...>(
350  std::forward<TSlot>(slot));
351 }
352 
353 
354 //******************************************************************************
355 // SimpleEventUnpacker implementation
356 //******************************************************************************
357 
358 //------------------------------------------------------------------------------
359 template <typename S, typename... A>
361  : slot_(std::move(slot))
362 {}
363 
364 //------------------------------------------------------------------------------
365 template <typename S, typename... A>
367 {
368  if (event.args().size() < sizeof...(A))
369  {
370  std::ostringstream oss;
371  oss << "Expected " << sizeof...(A)
372  << " args, but only got " << event.args().size();
373  throw internal::UnpackError().withArgs(oss.str());
374  }
375 
376  // Use the integer parameter pack technique shown in
377  // http://stackoverflow.com/a/7858971/245265
378  using Seq = typename internal::GenIntegerSequence<sizeof...(A)>::type;
379  invoke(std::move(event), Seq());
380 }
381 
382 //------------------------------------------------------------------------------
383 template <typename S, typename... A>
384 template <int ...Seq>
386  internal::IntegerSequence<Seq...>) const
387 {
388  std::tuple<ValueTypeOf<A>...> args;
389 
390  try
391  {
392  event.convertToTuple(args);
393  }
394  catch (const error::Conversion& e)
395  {
396  throw internal::UnpackError().withArgs(e.what());
397  }
398 
399  slot_(std::get<Seq>(std::move(args))...);
400 }
401 
402 //------------------------------------------------------------------------------
403 template <typename... TArgs, typename TSlot>
404 SimpleEventUnpacker<DecayedSlot<TSlot>, TArgs...> simpleEvent(TSlot&& slot)
405 {
406  return SimpleEventUnpacker<DecayedSlot<TSlot>, TArgs...>(
407  std::forward<TSlot>(slot));
408 }
409 
410 //------------------------------------------------------------------------------
411 template <typename... TArgs, typename TSlot>
413 {
414  return SimpleEventUnpacker<DecayedSlot<TSlot>, TArgs...>(
415  std::forward<TSlot>(slot));
416 }
417 
418 
419 //******************************************************************************
420 // InvocationUnpacker implementation
421 //******************************************************************************
422 
423 //------------------------------------------------------------------------------
424 template <typename S, typename... A>
426  : slot_(std::move(slot))
427 {}
428 
429 //------------------------------------------------------------------------------
430 template <typename S, typename... A>
432 {
433  if (inv.args().size() < sizeof...(A))
434  {
435  std::ostringstream oss;
436  oss << "Expected " << sizeof...(A)
437  << " args, but only got " << inv.args().size();
438  throw internal::UnpackError().withArgs(oss.str());
439  }
440 
441  // Use the integer parameter pack technique shown in
442  // http://stackoverflow.com/a/7858971/245265
443  using Seq = typename internal::GenIntegerSequence<sizeof...(A)>::type;
444  return invoke(std::move(inv), Seq());
445 }
446 
447 //------------------------------------------------------------------------------
448 template <typename S, typename... A>
449 template <int ...Seq>
450 Outcome
452  internal::IntegerSequence<Seq...>) const
453 {
454  std::tuple<ValueTypeOf<A>...> args;
455 
456  try
457  {
458  inv.convertToTuple(args);
459  }
460  catch (const error::Conversion& e)
461  {
462  throw internal::UnpackError().withArgs(e.what());
463  }
464 
465  return slot_(std::move(inv), std::get<Seq>(std::move(args))...);
466 }
467 
468 //------------------------------------------------------------------------------
469 template <typename... TArgs, typename TSlot>
470 InvocationUnpacker<DecayedSlot<TSlot>, TArgs...> unpackedRpc(TSlot&& slot)
471 {
472  return InvocationUnpacker<DecayedSlot<TSlot>, TArgs...>(
473  std::forward<TSlot>(slot) );
474 }
475 
476 
477 //******************************************************************************
478 // SimpleInvocationUnpacker implementation
479 //******************************************************************************
480 
481 //------------------------------------------------------------------------------
482 template <typename S, typename R, typename... A>
484  : slot_(std::move(slot))
485 {}
486 
487 //------------------------------------------------------------------------------
488 template <typename S, typename R, typename... A>
490 {
491  if (inv.args().size() < sizeof...(A))
492  {
493  std::ostringstream oss;
494  oss << "Expected " << sizeof...(A)
495  << " args, but only got " << inv.args().size();
496  throw internal::UnpackError().withArgs(oss.str());
497  }
498 
499  // Use the integer parameter pack technique shown in
500  // http://stackoverflow.com/a/7858971/245265
501  using Seq = typename internal::GenIntegerSequence<sizeof...(A)>::type;
503  return invoke(IsVoidResult{}, std::move(inv), Seq());
504 }
505 
506 //------------------------------------------------------------------------------
507 template <typename S, typename R, typename... A>
508 template <int ...Seq>
510  TrueType, Invocation&& inv, internal::IntegerSequence<Seq...>) const
511 {
512  std::tuple<ValueTypeOf<A>...> args;
513 
514  try
515  {
516  inv.convertToTuple(args);
517  }
518  catch (const error::Conversion& e)
519  {
520  throw internal::UnpackError().withArgs(e.what());
521  }
522 
523  slot_(std::get<Seq>(std::move(args))...);
524  return {};
525 }
526 
527 //------------------------------------------------------------------------------
528 template <typename S, typename R, typename... A>
529 template <int ...Seq>
530 Outcome SimpleInvocationUnpacker<S,R,A...>::invoke(
531  FalseType, Invocation&& inv, internal::IntegerSequence<Seq...>) const
532 {
533  std::tuple<ValueTypeOf<A>...> args;
534 
535  try
536  {
537  inv.convertToTuple(args);
538  }
539  catch (const error::Conversion& e)
540  {
541  throw internal::UnpackError().withArgs(e.what());
542  }
543 
544  ResultType result = slot_(std::get<Seq>(std::move(args))...);
545  return Result().withArgs(std::move(result));
546 }
547 
548 //------------------------------------------------------------------------------
549 template <typename TResult, typename... TArgs, typename TSlot>
550 SimpleInvocationUnpacker<DecayedSlot<TSlot>, TResult, TArgs...>
551 simpleRpc(TSlot&& slot)
552 {
553  return SimpleInvocationUnpacker<DecayedSlot<TSlot>, TResult, TArgs...>(
554  std::forward<TSlot>(slot) );
555 }
556 
557 //------------------------------------------------------------------------------
558 template <typename TResult, typename... TArgs, typename TSlot>
560 basicRpc(TSlot&& slot)
561 {
562  return SimpleInvocationUnpacker<DecayedSlot<TSlot>, TResult, TArgs...>(
563  std::forward<TSlot>(slot) );
564 }
565 
566 } // namespace wamp
567 
568 #endif // CPPWAMP_UNPACKER_HPP
wamp::SimpleInvocationUnpacker::operator()
Outcome operator()(Invocation inv) const
Dispatches the stored call slot.
Definition: unpacker.hpp:489
wamp::EventUnpacker
Wrapper around an event slot which automatically unpacks positional payload arguments.
Definition: unpacker.hpp:47
wamp::SimpleInvocationUnpacker::Slot
TSlot Slot
The function type to be wrapped.
Definition: unpacker.hpp:219
wamp::FalseType
BoolConstant< false > FalseType
Equivalent to std::false_type provided in C++17.
Definition: traits.hpp:122
wamp::EventUnpacker::Slot
TSlot Slot
The function type to be wrapped.
Definition: unpacker.hpp:51
wamp::basicRpc
SimpleInvocationUnpacker< DecayedSlot< TSlot >, TResult, TArgs... > basicRpc(TSlot &&slot)
Definition: unpacker.hpp:560
wamp::InvocationUnpacker::InvocationUnpacker
InvocationUnpacker(Slot slot)
Constructor taking a callable target.
Definition: unpacker.hpp:425
wamp::InvocationUnpacker::Slot
TSlot Slot
The function type to be wrapped.
Definition: unpacker.hpp:166
wamp::TrueType
BoolConstant< true > TrueType
Equivalent to std::true_type provided in C++17.
Definition: traits.hpp:117
wamp::basicEvent
SimpleEventUnpacker< DecayedSlot< TSlot >, TArgs... > basicEvent(TSlot &&slot)
Definition: unpacker.hpp:412
api.hpp
Defines macros related to exporting/importing APIs.
wamp::EventUnpacker::operator()
void operator()(Event event) const
Dispatches the stored event slot.
Definition: unpacker.hpp:309
wamp::Error
Provides the reason URI, options, and payload arguments contained within WAMP ERROR messages.
Definition: peerdata.hpp:292
wamp::SimpleInvocationUnpacker
Wrapper around a call slot which automatically unpacks positional payload arguments.
Definition: unpacker.hpp:215
wamp::SimpleEventUnpacker::Slot
TSlot Slot
The function type to be wrapped.
Definition: unpacker.hpp:101
peerdata.hpp
Contains declarations for data structures exchanged between WAMP peers.
wamp
Definition: anyhandler.hpp:36
wamp::SimpleInvocationUnpacker::SimpleInvocationUnpacker
SimpleInvocationUnpacker(Slot slot)
Constructor taking a callable target.
Definition: unpacker.hpp:483
wamp::SimpleInvocationUnpacker::ResultType
TResult ResultType
The static result type returned by the slot.
Definition: unpacker.hpp:222
wamp::InvocationUnpacker
Wrapper around a call slot which automatically unpacks positional payload arguments.
Definition: unpacker.hpp:162
wamp::SimpleEventUnpacker::SimpleEventUnpacker
SimpleEventUnpacker(Slot slot)
Constructor taking a callable target.
Definition: unpacker.hpp:360
wamp::Outcome
Contains the outcome of an RPC invocation.
Definition: peerdata.hpp:709
wamp::DecayedSlot
typename std::decay< TSlot >::type DecayedSlot
Metafunction that removes const/reference decorations off a slot type.
Definition: unpacker.hpp:32
wamp::InvocationUnpacker::operator()
Outcome operator()(Invocation inv) const
Dispatches the stored call slot.
Definition: unpacker.hpp:431
wamp::EventUnpacker::EventUnpacker
EventUnpacker(Slot slot)
Constructor taking a callable target.
Definition: unpacker.hpp:303
variant.hpp
Contains the declaration of Variant and other closely related types/functions.
traits.hpp
Contains general-purpose type traits.
wamp::SimpleEventUnpacker::operator()
void operator()(Event event) const
Dispatches the stored event slot.
Definition: unpacker.hpp:366
wamp::Invocation
Contains payload arguments and other options within WAMP INVOCATION messages.
Definition: peerdata.hpp:799
wamp::Event
Provides the subscription/publication ids, options, and payload contained within WAMP EVENT messages.
Definition: peerdata.hpp:427
wamp::SimpleEventUnpacker
Wrapper around an event slot which automatically unpacks positional payload arguments.
Definition: unpacker.hpp:97
wamp::BoolConstant
std::integral_constant< bool, B > BoolConstant
Equivalent to std::bool_constant provided in C++17.
Definition: traits.hpp:112