Program Listing for File generic_client.hpp

Return to documentation for file (include/rclcpp/generic_client.hpp)

// Copyright 2023 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_CLIENT_HPP_
#define RCLCPP__GENERIC_CLIENT_HPP_

#include <map>
#include <memory>
#include <future>
#include <string>
#include <tuple>
#include <vector>
#include <utility>

#include "rcl/client.h"

#include "rclcpp/client.hpp"
#include "rclcpp/visibility_control.hpp"
#include "rcpputils/shared_library.hpp"

#include "rosidl_typesupport_introspection_cpp/message_introspection.hpp"

namespace rclcpp
{
class GenericClient : public ClientBase
{
public:
  using Request = void *;   // Deserialized data pointer of request message
  using Response = void *;  // Deserialized data pointer of response message

  using SharedResponse = std::shared_ptr<void>;

  using Promise = std::promise<SharedResponse>;
  using SharedPromise = std::shared_ptr<Promise>;

  using Future = std::future<SharedResponse>;
  using SharedFuture = std::shared_future<SharedResponse>;

  using CallbackType = std::function<void (SharedFuture)>;

  RCLCPP_SMART_PTR_DEFINITIONS(GenericClient)


  struct FutureAndRequestId
    : detail::FutureAndRequestId<Future>
  {
    using detail::FutureAndRequestId<Future>::FutureAndRequestId;

    SharedFuture share() noexcept {return this->future.share();}

    FutureAndRequestId(FutureAndRequestId && other) noexcept = default;
    FutureAndRequestId(const FutureAndRequestId & other) = delete;
    FutureAndRequestId & operator=(FutureAndRequestId && other) noexcept = default;
    FutureAndRequestId & operator=(const FutureAndRequestId & other) = delete;
    ~FutureAndRequestId() = default;
  };


  struct SharedFutureAndRequestId
    : detail::FutureAndRequestId<std::shared_future<SharedResponse>>
  {
    using detail::FutureAndRequestId<std::shared_future<SharedResponse>>::FutureAndRequestId;
  };

  GenericClient(
    rclcpp::node_interfaces::NodeBaseInterface * node_base,
    rclcpp::node_interfaces::NodeGraphInterface::SharedPtr node_graph,
    const std::string & service_name,
    const std::string & service_type,
    rcl_client_options_t & client_options);

  RCLCPP_PUBLIC
  SharedResponse
  create_response() override;

  RCLCPP_PUBLIC
  std::shared_ptr<rmw_request_id_t>
  create_request_header() override;

  RCLCPP_PUBLIC
  void
  handle_response(
    std::shared_ptr<rmw_request_id_t> request_header,
    std::shared_ptr<void> response) override;


  RCLCPP_PUBLIC
  FutureAndRequestId
  async_send_request(const Request request);


  template<
    typename CallbackT,
    typename std::enable_if<
      rclcpp::function_traits::same_arguments<
        CallbackT,
        CallbackType
      >::value
    >::type * = nullptr
  >
  SharedFutureAndRequestId
  async_send_request(const Request request, CallbackT && cb)
  {
    Promise promise;
    auto shared_future = promise.get_future().share();
    auto req_id = async_send_request_impl(
      request,
      std::make_tuple(
        CallbackType{std::forward<CallbackT>(cb)},
        shared_future,
        std::move(promise)));
    return SharedFutureAndRequestId{std::move(shared_future), req_id};
  }


  template<typename AllocatorT = std::allocator<int64_t>>
  size_t
  prune_requests_older_than(
    std::chrono::time_point<std::chrono::system_clock> time_point,
    std::vector<int64_t, AllocatorT> * pruned_requests = nullptr)
  {
    return detail::prune_requests_older_than_impl(
      pending_requests_,
      pending_requests_mutex_,
      time_point,
      pruned_requests);
  }


  RCLCPP_PUBLIC
  size_t
  prune_pending_requests();


  RCLCPP_PUBLIC
  bool
  remove_pending_request(
    int64_t request_id);


  RCLCPP_PUBLIC
  bool
  remove_pending_request(
    const FutureAndRequestId & future);


  RCLCPP_PUBLIC
  bool
  remove_pending_request(
    const SharedFutureAndRequestId & future);


  RCLCPP_PUBLIC
  bool
  take_response(Response response_out, rmw_request_id_t & request_header_out)
  {
    return this->take_type_erased_response(response_out, request_header_out);
  }

protected:
  using CallbackTypeValueVariant = std::tuple<CallbackType, SharedFuture, Promise>;
  using CallbackInfoVariant = std::variant<
    std::promise<SharedResponse>,
    CallbackTypeValueVariant>;  // Use variant for extension

  RCLCPP_PUBLIC
  int64_t
  async_send_request_impl(
    const Request request,
    CallbackInfoVariant value);

  std::optional<CallbackInfoVariant>
  get_and_erase_pending_request(
    int64_t request_number);

  RCLCPP_DISABLE_COPY(GenericClient)

  std::map<int64_t, std::pair<
      std::chrono::time_point<std::chrono::system_clock>,
      CallbackInfoVariant>> pending_requests_;
  std::mutex pending_requests_mutex_;

private:
  std::shared_ptr<rcpputils::SharedLibrary> ts_lib_;
  const rosidl_typesupport_introspection_cpp::MessageMembers * response_members_;
};
}  // namespace rclcpp

#endif  // RCLCPP__GENERIC_CLIENT_HPP_