.. _program_listing_file_include_rclcpp_generic_service.hpp: Program Listing for File generic_service.hpp ============================================ |exhale_lsh| :ref:`Return to documentation for file ` (``include/rclcpp/generic_service.hpp``) .. |exhale_lsh| unicode:: U+021B0 .. UPWARDS ARROW WITH TIP LEFTWARDS .. code-block:: cpp // Copyright 2024 Sony Group Corporation. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. #ifndef RCLCPP__GENERIC_SERVICE_HPP_ #define RCLCPP__GENERIC_SERVICE_HPP_ #include #include #include #include #include #include #include #include "rclcpp/typesupport_helpers.hpp" #include "rosidl_runtime_c/service_type_support_struct.h" #include "rosidl_typesupport_introspection_cpp/identifier.hpp" #include "rosidl_typesupport_introspection_cpp/service_introspection.hpp" #include "service.hpp" namespace rclcpp { class GenericService; class GenericServiceCallback { public: using SharedRequest = std::shared_ptr; using SharedResponse = std::shared_ptr; GenericServiceCallback() : callback_(std::monostate{}) {} template< typename CallbackT, typename std::enable_if_t::value, int> = 0> void set(CallbackT && callback) { // Workaround Windows issue with std::bind if constexpr ( rclcpp::function_traits::same_arguments< CallbackT, SharedPtrCallback >::value) { callback_.template emplace(callback); } else if constexpr ( // NOLINT, can't satisfy both cpplint and uncrustify rclcpp::function_traits::same_arguments< CallbackT, SharedPtrWithRequestHeaderCallback >::value) { callback_.template emplace(callback); } else if constexpr ( // NOLINT rclcpp::function_traits::same_arguments< CallbackT, SharedPtrDeferResponseCallback >::value) { callback_.template emplace(callback); } else if constexpr ( // NOLINT rclcpp::function_traits::same_arguments< CallbackT, SharedPtrDeferResponseCallbackWithServiceHandle >::value) { callback_.template emplace(callback); } else { // the else clause is not needed, but anyways we should only be doing this instead // of all the above workaround ... callback_ = std::forward(callback); } } template< typename CallbackT, typename std::enable_if_t::value, int> = 0> void set(CallbackT && callback) { if (!callback) { throw std::invalid_argument("AnyServiceCallback::set(): callback cannot be nullptr"); } // Workaround Windows issue with std::bind if constexpr ( rclcpp::function_traits::same_arguments< CallbackT, SharedPtrCallback >::value) { callback_.template emplace(callback); } else if constexpr ( // NOLINT rclcpp::function_traits::same_arguments< CallbackT, SharedPtrWithRequestHeaderCallback >::value) { callback_.template emplace(callback); } else if constexpr ( // NOLINT rclcpp::function_traits::same_arguments< CallbackT, SharedPtrDeferResponseCallback >::value) { callback_.template emplace(callback); } else if constexpr ( // NOLINT rclcpp::function_traits::same_arguments< CallbackT, SharedPtrDeferResponseCallbackWithServiceHandle >::value) { callback_.template emplace(callback); } else { // the else clause is not needed, but anyways we should only be doing this instead // of all the above workaround ... callback_ = std::forward(callback); } } SharedResponse dispatch( const std::shared_ptr & service_handle, const std::shared_ptr & request_header, SharedRequest request, SharedRequest response) { TRACETOOLS_TRACEPOINT(callback_start, static_cast(this), false); if (std::holds_alternative(callback_)) { // TODO(ivanpauno): Remove the set method, and force the users of this class // to pass a callback at construnciton. throw std::runtime_error{"unexpected request without any callback set"}; } if (std::holds_alternative(callback_)) { const auto & cb = std::get(callback_); cb(request_header, std::move(request)); return nullptr; } if (std::holds_alternative(callback_)) { const auto & cb = std::get(callback_); cb(service_handle, request_header, std::move(request)); return nullptr; } if (std::holds_alternative(callback_)) { (void)request_header; const auto & cb = std::get(callback_); cb(std::move(request), std::move(response)); } else if (std::holds_alternative(callback_)) { const auto & cb = std::get(callback_); cb(request_header, std::move(request), std::move(response)); } TRACETOOLS_TRACEPOINT(callback_end, static_cast(this)); return response; } void register_callback_for_tracing() { #ifndef TRACETOOLS_DISABLED std::visit( [this](auto && arg) { if (TRACETOOLS_TRACEPOINT_ENABLED(rclcpp_callback_register)) { char * symbol = tracetools::get_symbol(arg); TRACETOOLS_DO_TRACEPOINT( rclcpp_callback_register, static_cast(this), symbol); std::free(symbol); } }, callback_); #endif // TRACETOOLS_DISABLED } private: using SharedPtrCallback = std::function; using SharedPtrWithRequestHeaderCallback = std::function< void ( std::shared_ptr, SharedRequest, SharedResponse )>; using SharedPtrDeferResponseCallback = std::function< void ( std::shared_ptr, SharedRequest )>; using SharedPtrDeferResponseCallbackWithServiceHandle = std::function< void ( std::shared_ptr, std::shared_ptr, SharedRequest )>; std::variant< std::monostate, SharedPtrCallback, SharedPtrWithRequestHeaderCallback, SharedPtrDeferResponseCallback, SharedPtrDeferResponseCallbackWithServiceHandle> callback_; }; class GenericService : public ServiceBase, public std::enable_shared_from_this { public: using Request = void *; // Serialized/Deserialized data pointer of request message using Response = void *; // Serialized/Deserialized data pointer of response message using SharedRequest = std::shared_ptr; using SharedResponse = std::shared_ptr; using CallbackType = std::function; using CallbackWithHeaderType = std::function, const SharedRequest, SharedResponse)>; RCLCPP_SMART_PTR_DEFINITIONS(GenericService) RCLCPP_PUBLIC GenericService( std::shared_ptr node_handle, const std::string & service_name, const std::string & service_type, GenericServiceCallback any_callback, rcl_service_options_t & service_options); GenericService() = delete; RCLCPP_PUBLIC virtual ~GenericService() {} RCLCPP_PUBLIC bool take_request(SharedRequest request_out, rmw_request_id_t & request_id_out); RCLCPP_PUBLIC std::shared_ptr create_request() override; RCLCPP_PUBLIC std::shared_ptr create_response(); RCLCPP_PUBLIC std::shared_ptr create_request_header() override; RCLCPP_PUBLIC void handle_request( std::shared_ptr request_header, std::shared_ptr request) override; RCLCPP_PUBLIC void send_response(rmw_request_id_t & req_id, SharedResponse & response); private: RCLCPP_DISABLE_COPY(GenericService) GenericServiceCallback any_callback_; std::shared_ptr ts_lib_; const rosidl_typesupport_introspection_cpp::MessageMembers * request_members_; const rosidl_typesupport_introspection_cpp::MessageMembers * response_members_; }; } // namespace rclcpp #endif // RCLCPP__GENERIC_SERVICE_HPP_