Program Listing for File any_service_callback.hpp

Return to documentation for file (include/ros_babel_fish/detail/any_service_callback.hpp)

// Copyright (c) 2022 Stefan Fabian. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.

#ifndef ROS_BABEL_FISH_BABEL_FISH_ANY_SERVICE_CALLBACK_HPP
#define ROS_BABEL_FISH_BABEL_FISH_ANY_SERVICE_CALLBACK_HPP

#include <rclcpp/any_service_callback.hpp>

namespace ros_babel_fish
{
class BabelFishService;
class CompoundMessage;

class AnyServiceCallback
{
  template<typename CallbackT,
           typename std::enable_if<rclcpp::detail::can_be_nullptr<CallbackT>::value, int>::type = 0>
  bool isNullptr( CallbackT &&callback )
  {
    return !callback;
  }

  template<typename CallbackT,
           typename std::enable_if<!rclcpp::detail::can_be_nullptr<CallbackT>::value, int>::type = 0>
  constexpr bool isNullptr( CallbackT && )
  {
    return false;
  }

public:
  template<typename CallbackT>
  explicit AnyServiceCallback( CallbackT &&callback )
  {
    if ( isNullptr( callback ) ) {
      throw std::invalid_argument( "Service callback cannot be nullptr!" );
    }
    if constexpr ( rclcpp::function_traits::same_arguments<CallbackT, SharedPtrCallback>::value ) {
      callback_.template emplace<SharedPtrCallback>( callback );
    } else if constexpr ( rclcpp::function_traits::same_arguments<
                              CallbackT, SharedPtrWithRequestHeaderCallback>::value ) {
      callback_.template emplace<SharedPtrWithRequestHeaderCallback>( callback );
    } else if constexpr ( rclcpp::function_traits::same_arguments<
                              CallbackT, SharedPtrDeferResponseCallback>::value ) {
      callback_.template emplace<SharedPtrDeferResponseCallback>( callback );
    } else if constexpr ( rclcpp::function_traits::same_arguments<
                              CallbackT, SharedPtrDeferResponseCallbackWithServiceHandle>::value ) {
      callback_.template emplace<SharedPtrDeferResponseCallbackWithServiceHandle>( callback );
    } else {
      static_assert( "Invalid callback type passed to AnyServiceCallback!" );
    }
  }

  void dispatch( const std::shared_ptr<BabelFishService> &service_handle,
                 const std::shared_ptr<rmw_request_id_t> &request_header,
                 std::shared_ptr<CompoundMessage> request, std::shared_ptr<CompoundMessage> response )
  {
    TRACEPOINT( callback_start, static_cast<const void *>( this ), false );
    if ( std::holds_alternative<SharedPtrCallback>( callback_ ) ) {
      (void)request_header;
      const auto &cb = std::get<SharedPtrCallback>( callback_ );
      cb( std::move( request ), response );
    } else if ( std::holds_alternative<SharedPtrWithRequestHeaderCallback>( callback_ ) ) {
      const auto &cb = std::get<SharedPtrWithRequestHeaderCallback>( callback_ );
      cb( request_header, std::move( request ), response );
    } else if ( std::holds_alternative<SharedPtrDeferResponseCallback>( callback_ ) ) {
      const auto &cb = std::get<SharedPtrDeferResponseCallback>( callback_ );
      cb( request_header, std::move( request ) );
    } else if ( std::holds_alternative<SharedPtrDeferResponseCallbackWithServiceHandle>( callback_ ) ) {
      const auto &cb = std::get<SharedPtrDeferResponseCallbackWithServiceHandle>( callback_ );
      cb( service_handle, request_header, std::move( request ) );
    }
    TRACEPOINT( callback_end, static_cast<const void *>( this ) );
  }

  void register_callback_for_tracing()
  {
#ifndef TRACETOOLS_DISABLED
    std::visit(
        [this]( auto &&arg ) {
          TRACEPOINT( rclcpp_callback_register, static_cast<const void *>( this ),
                      tracetools::get_symbol( arg ) );
        },
        callback_ );
#endif // TRACETOOLS_DISABLED
  }

private:
  using SharedPtrCallback =
      std::function<void( std::shared_ptr<CompoundMessage>, std::shared_ptr<CompoundMessage> )>;
  using SharedPtrWithRequestHeaderCallback =
      std::function<void( std::shared_ptr<rmw_request_id_t>, std::shared_ptr<CompoundMessage>,
                          std::shared_ptr<CompoundMessage> )>;
  using SharedPtrDeferResponseCallback =
      std::function<void( std::shared_ptr<rmw_request_id_t>, std::shared_ptr<CompoundMessage> )>;
  using SharedPtrDeferResponseCallbackWithServiceHandle =
      std::function<void( std::shared_ptr<BabelFishService>, std::shared_ptr<rmw_request_id_t>,
                          std::shared_ptr<CompoundMessage> )>;

  std::variant<SharedPtrCallback, SharedPtrWithRequestHeaderCallback,
               SharedPtrDeferResponseCallback, SharedPtrDeferResponseCallbackWithServiceHandle>
      callback_;
};

} // namespace ros_babel_fish

#endif // ROS_BABEL_FISH_BABEL_FISH_ANY_SERVICE_CALLBACK_HPP