Callback wrappers

This page contains documentation for CoroCallback and related classes.

The CoroCallback is a wrapper used for passing coroutines as callbacks to other interfaces in mrs_lib. Since coroutines do not work well with mutually exclusive callback groups, it also provides policies for handling concurrent calls to the same callback.

mrs_lib::CoroCallback

template<typename CallbackRetType, typename ...CallbackArgs>
class CoroCallback<CallbackRetType(CallbackArgs...)>

Wrapper for safe binding of coroutines to use as callbacks.

This wrapper is used to bind arguments to coroutines and pass them to other interfaces that will use this as a callback.

Since coroutines do not work well with mutually exclusive callback group, this wrapper adds some functionality to configure behavior of reentrant callbacks. The behavior is chosen using policy argument passed in the constructor.

Template Parameters:
  • CallbackRetType – Return type of the callback coroutine.

  • CallbackArgs – Argument types of the callback coroutine.

Public Functions

template<typename F, typename ...BoundArgs>
inline explicit CoroCallback(CoroReentrantPolicyVariant<CallbackRetType> reentrant_policy, F callback_ptr, BoundArgs&&... args)

Constructor for binding coroutine callbacks.

Constructs the callback by binding args to the front parameters of callback.

The constructed callback will have reentrant behavior according to the specified policy.

Template Parameters:
  • F – Callback function type.

  • BoundArgs – Types of arguments to bind to the callback function.

Parameters:
  • reentrant_policy – Reentrancy policy for the callback.

  • callback_ptr – Callback function pointer (or member function pointer).

  • args – Arguments to bind to the callback function.

inline coro::Task<CallbackRetType> operator()(CallbackArgs... args) const

Executes the callback.

Parameters:

args – Arguments to pass to the callback.

Returns:

The result of the callback execution.

template<typename...>
class CoroCallback

Base template for CoroCallback.

Policies

template<typename CallbackRetType>
using mrs_lib::CoroReentrantPolicyVariant = std::variant<coro_callback_tags::Reentrant, coro_callback_tags::CancelNew<CallbackRetType>>

Variant of CoroCallback reentrancy policies.

Template Parameters:

CallbackRetType – Return type of the callback function.

namespace coro_callback_tags

Namespace for tag types used in CoroCallback.

Note

All of the policy tags are in the mrs_lib::coro_callback_tags namespace.

mrs_lib::coro_callback_tags::Reentrant

class Reentrant

Policy tag for reentrant CoroCallback.

This policy tells the callback to run every time it is called.

Public Functions

explicit Reentrant() = default

mrs_lib::coro_callback_tags::CancelNew

template<typename CallbackRetType = void>
class CancelNew

Policy tag for CoroCallback ignores new callbacks, when another is already running.

This policy tells the callback to run only if it is not already running. If this callback is already running, the new callback is cancelled. All copies of the callback share the same state and only one can be run at the same time. However, different callbacks created by the main constructor can run at the same time.

Since invoking every callback must return a value according to the return type fo the callback, if it not launched, the return value must be obtained somewhere else. For this purpose, this policy stores a factory function that creates the return value for cancelled callbacks.

Note

If you want to return a default constructed value, you can use the CancelNewDefault tag instead.

Warning

When a callback is canceled, you will lose the event that triggered it. This means that when using this as e.g. a subscription callback, you might miss some messages.

Template Parameters:

CallbackRetType – Return type of the callback.

Public Functions

inline explicit CancelNew(std::function<CallbackRetType()> default_factory)

Constructor accepting factory function.

Parameters:

default_factory – Factory function for return value of cancelled callbacks.

inline CallbackRetType create_value() const

Create a return value for a cancelled callback.

Returns:

Value created by the stored factory function.

template<>
class CancelNew<void>

Void specialization of CancelNew.

Public Functions

explicit CancelNew() = default

Default constructor.

inline void create_value() const

Returns void.

mrs_lib::coro_callback_tags::CancelNewDefault

class CancelNewDefault

Policy tag for CoroCallback ignores new callbacks, when another is already running.

Can be used instead of CancelNew for any default constructible type or void.

See also

CancelNew

Public Functions

explicit CancelNewDefault() = default

Default constructor.

inline operator CancelNew<void>()

Conversion operator to create CancelNew<void>.

template<typename T>
inline operator CancelNew<T>()

Conversion operator to create CancelNew<T> for any default constructible T.

The created CancelNew policy will contain factory creating default constructed values of type T.

Example

Example of the coro callback usage (p1).
 1mrs_lib::Task<int> add(int a, int b)
 2{
 3  co_return a + b;
 4}
 5
 6class MyNode : public rclcpp::Node
 7{
 8public:
 9  using rclcpp::Node::Node;
10
11  mrs_lib::CoroCallback<int(int)> create_callback()
12  {
13    using mrs_lib::coro_callback_tags::Reentrant;
14    // Binding to methods of nodes. A callback like this would be typically
15    // passed to mrs_lib ros wrappers (timer, subscriber, ...).
16    return mrs_lib::CoroCallback(Reentrant{}, &MyNode::calculate, this);
17  }
18
19  mrs_lib::Task<int> calculate(int x)
20  {
21    co_return x + val_;
22  }
23
24private:
25  int val_ = 10;
26};
Example of the coro callback usage (p2).
 1using mrs_lib::CoroCallback;
 2using mrs_lib::coro_callback_tags::CancelNew;
 3using mrs_lib::coro_callback_tags::CancelNewDefault;
 4using mrs_lib::coro_callback_tags::Reentrant;
 5
 6// Reentrant callbacks
 7// No argument bound
 8CoroCallback<int(int, int)> callback1 = CoroCallback(Reentrant{}, &add);
 9// First argument bound
10CoroCallback<int(int)> callback2 = CoroCallback(Reentrant{}, &add, 1);
11
12// Cancel new callback
13// This callback will return default constructed int (0) if cancelled by the policy
14CoroCallback<int(int)> callback3 = CoroCallback(CancelNewDefault{}, &add, 1);
15// This callback will return 42 if cancelled by the policy
16CoroCallback<int(int)> callback4 = CoroCallback(CancelNew([] { return 42; }), &add, 1);