ROS 2 rclcpp + rcl - rolling  rolling-20536064
ROS 2 C++ Client Library with ROS Client Library
client.hpp
1 // Copyright 2014 Open Source Robotics Foundation, Inc.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 #ifndef RCLCPP__CLIENT_HPP_
16 #define RCLCPP__CLIENT_HPP_
17 
18 #include <atomic>
19 #include <functional>
20 #include <future>
21 #include <memory>
22 #include <mutex>
23 #include <optional>
24 #include <sstream>
25 #include <string>
26 #include <tuple>
27 #include <unordered_map>
28 #include <utility>
29 #include <variant>
30 #include <vector>
31 
32 #include "rcl/client.h"
33 #include "rcl/error_handling.h"
34 #include "rcl/event_callback.h"
35 #include "rcl/service_introspection.h"
36 #include "rcl/wait.h"
37 
38 #include "rclcpp/clock.hpp"
39 #include "rclcpp/exceptions.hpp"
40 #include "rclcpp/expand_topic_or_service_name.hpp"
41 #include "rclcpp/function_traits.hpp"
42 #include "rclcpp/logging.hpp"
43 #include "rclcpp/macros.hpp"
44 #include "rclcpp/node_interfaces/node_graph_interface.hpp"
45 #include "rclcpp/qos.hpp"
46 #include "rclcpp/type_support_decl.hpp"
47 #include "rclcpp/visibility_control.hpp"
48 
49 #include "rmw/error_handling.h"
50 #include "rmw/rmw.h"
51 
52 namespace rclcpp
53 {
54 
55 namespace detail
56 {
57 template<typename FutureT>
59 {
60  FutureT future;
61  int64_t request_id;
62 
63  FutureAndRequestId(FutureT impl, int64_t req_id)
64  : future(std::move(impl)), request_id(req_id)
65  {}
66 
68  operator FutureT &() {return this->future;}
69 
70  // delegate future like methods in the std::future impl_
71 
73  auto get() {return this->future.get();}
75  bool valid() const noexcept {return this->future.valid();}
77  void wait() const {return this->future.wait();}
79  template<class Rep, class Period>
80  std::future_status wait_for(
81  const std::chrono::duration<Rep, Period> & timeout_duration) const
82  {
83  return this->future.wait_for(timeout_duration);
84  }
86  template<class Clock, class Duration>
87  std::future_status wait_until(
88  const std::chrono::time_point<Clock, Duration> & timeout_time) const
89  {
90  return this->future.wait_until(timeout_time);
91  }
92 
93  // Rule of five, we could use the rule of zero here, but better be explicit as some of the
94  // methods are deleted.
95 
97  FutureAndRequestId(FutureAndRequestId && other) noexcept = default;
99  FutureAndRequestId(const FutureAndRequestId & other) = delete;
101  FutureAndRequestId & operator=(FutureAndRequestId && other) noexcept = default;
105  ~FutureAndRequestId() = default;
106 };
107 
108 template<typename PendingRequestsT, typename AllocatorT = std::allocator<int64_t>>
109 size_t
110 prune_requests_older_than_impl(
111  PendingRequestsT & pending_requests,
112  std::mutex & pending_requests_mutex,
113  std::chrono::time_point<std::chrono::system_clock> time_point,
114  std::vector<int64_t, AllocatorT> * pruned_requests = nullptr)
115 {
116  std::lock_guard guard(pending_requests_mutex);
117  auto old_size = pending_requests.size();
118  for (auto it = pending_requests.begin(), last = pending_requests.end(); it != last; ) {
119  if (it->second.first < time_point) {
120  if (pruned_requests) {
121  pruned_requests->push_back(it->first);
122  }
123  it = pending_requests.erase(it);
124  } else {
125  ++it;
126  }
127  }
128  return old_size - pending_requests.size();
129 }
130 } // namespace detail
131 
132 namespace node_interfaces
133 {
134 class NodeBaseInterface;
135 } // namespace node_interfaces
136 
138 {
139 public:
140  RCLCPP_SMART_PTR_DEFINITIONS_NOT_COPYABLE(ClientBase)
141 
142  RCLCPP_PUBLIC
143  ClientBase(
145  const rclcpp::node_interfaces::NodeGraphInterface::SharedPtr & node_graph);
146 
147  RCLCPP_PUBLIC
148  virtual ~ClientBase() = default;
149 
151 
167  RCLCPP_PUBLIC
168  bool
169  take_type_erased_response(void * response_out, rmw_request_id_t & request_header_out);
170 
172 
173  RCLCPP_PUBLIC
174  const char *
175  get_service_name() const;
176 
178 
182  RCLCPP_PUBLIC
183  std::shared_ptr<rcl_client_t>
185 
187 
191  RCLCPP_PUBLIC
192  std::shared_ptr<const rcl_client_t>
193  get_client_handle() const;
194 
196 
199  RCLCPP_PUBLIC
200  bool
201  service_is_ready() const;
202 
204 
208  template<typename RepT = int64_t, typename RatioT = std::milli>
209  bool
211  std::chrono::duration<RepT, RatioT> timeout = std::chrono::duration<RepT, RatioT>(-1))
212  {
213  return wait_for_service_nanoseconds(
214  std::chrono::duration_cast<std::chrono::nanoseconds>(timeout)
215  );
216  }
217 
218  virtual std::shared_ptr<void> create_response() = 0;
219  virtual std::shared_ptr<rmw_request_id_t> create_request_header() = 0;
220  virtual void handle_response(
221  const std::shared_ptr<rmw_request_id_t> & request_header,
222  const std::shared_ptr<void> & response) = 0;
223 
225 
234  RCLCPP_PUBLIC
235  bool
236  exchange_in_use_by_wait_set_state(bool in_use_state);
237 
239 
250  RCLCPP_PUBLIC
253 
255 
266  RCLCPP_PUBLIC
269 
271 
296  RCLCPP_PUBLIC
297  void
298  set_on_new_response_callback(const std::function<void(size_t)> & callback);
299 
301  RCLCPP_PUBLIC
302  void
304 
305 protected:
306  RCLCPP_DISABLE_COPY(ClientBase)
307 
308  RCLCPP_PUBLIC
309  bool
310  wait_for_service_nanoseconds(std::chrono::nanoseconds timeout);
311 
312  RCLCPP_PUBLIC
313  rcl_node_t *
314  get_rcl_node_handle();
315 
316  RCLCPP_PUBLIC
317  const rcl_node_t *
318  get_rcl_node_handle() const;
319 
320  RCLCPP_PUBLIC
321  void
322  set_on_new_response_callback(rcl_event_callback_t callback, const void * user_data);
323 
324  rclcpp::node_interfaces::NodeGraphInterface::WeakPtr node_graph_;
325  std::shared_ptr<rcl_node_t> node_handle_;
326  std::shared_ptr<rclcpp::Context> context_;
327  rclcpp::Logger node_logger_;
328 
329  std::recursive_mutex callback_mutex_;
330  // It is important to declare on_new_response_callback_ before
331  // client_handle_, so on destruction the client is
332  // destroyed first. Otherwise, the rmw client callback
333  // would point briefly to a destroyed function.
334  std::function<void(size_t)> on_new_response_callback_{nullptr};
335  // Declare client_handle_ after callback
336  std::shared_ptr<rcl_client_t> client_handle_;
337 
338  std::atomic<bool> in_use_by_wait_set_{false};
339 };
340 
341 template<typename ServiceT>
342 class Client : public ClientBase
343 {
344 public:
345  using Request = typename ServiceT::Request;
346  using Response = typename ServiceT::Response;
347 
348  using SharedRequest = typename ServiceT::Request::SharedPtr;
349  using SharedResponse = typename ServiceT::Response::SharedPtr;
350 
351  using Promise = std::promise<SharedResponse>;
352  using PromiseWithRequest = std::promise<std::pair<SharedRequest, SharedResponse>>;
353 
354  using SharedPromise = std::shared_ptr<Promise>;
355  using SharedPromiseWithRequest = std::shared_ptr<PromiseWithRequest>;
356 
357  using Future = std::future<SharedResponse>;
358  using SharedFuture = std::shared_future<SharedResponse>;
359  using SharedFutureWithRequest = std::shared_future<std::pair<SharedRequest, SharedResponse>>;
360 
361  using CallbackType = std::function<void (SharedFuture)>;
362  using CallbackWithRequestType = std::function<void (SharedFutureWithRequest)>;
363 
364  RCLCPP_SMART_PTR_DEFINITIONS(Client)
365 
366 
375  : detail::FutureAndRequestId<std::future<SharedResponse>>
376  {
378 
379  // delegate future like methods in the std::future impl_
380 
382  SharedFuture share() noexcept {return this->future.share();}
383  };
384 
386 
394  : detail::FutureAndRequestId<std::shared_future<SharedResponse>>
395  {
397  };
398 
400 
408  : detail::FutureAndRequestId<std::shared_future<std::pair<SharedRequest, SharedResponse>>>
409  {
411  std::shared_future<std::pair<SharedRequest, SharedResponse>>
413  };
414 
416 
428  const rclcpp::node_interfaces::NodeGraphInterface::SharedPtr & node_graph,
429  const std::string & service_name,
430  rcl_client_options_t & client_options)
431  : ClientBase(node_base, node_graph),
432  srv_type_support_handle_(rosidl_typesupport_cpp::get_service_type_support_handle<ServiceT>())
433  {
435  this->get_client_handle().get(),
436  this->get_rcl_node_handle(),
437  srv_type_support_handle_,
438  service_name.c_str(),
439  &client_options);
440  if (ret != RCL_RET_OK) {
441  if (ret == RCL_RET_SERVICE_NAME_INVALID) {
442  auto rcl_node_handle = this->get_rcl_node_handle();
443  // this will throw on any validation problem
444  rcl_reset_error();
446  service_name,
447  rcl_node_get_name(rcl_node_handle),
448  rcl_node_get_namespace(rcl_node_handle),
449  true);
450  }
451  rclcpp::exceptions::throw_from_rcl_error(ret, "could not create client");
452  }
453  }
454 
455  virtual ~Client()
456  {
457  }
458 
460 
472  bool
473  take_response(typename ServiceT::Response & response_out, rmw_request_id_t & request_header_out)
474  {
475  return this->take_type_erased_response(&response_out, request_header_out);
476  }
477 
479 
482  std::shared_ptr<void>
483  create_response() override
484  {
485  return std::shared_ptr<void>(new typename ServiceT::Response());
486  }
487 
489 
492  std::shared_ptr<rmw_request_id_t>
494  {
495  // TODO(wjwwood): This should probably use rmw_request_id's allocator.
496  // (since it is a C type)
497  return std::shared_ptr<rmw_request_id_t>(new rmw_request_id_t);
498  }
499 
501 
505  void
507  const std::shared_ptr<rmw_request_id_t> & request_header,
508  const std::shared_ptr<void> & response) override
509  {
510  std::optional<CallbackInfoVariant>
511  optional_pending_request = this->get_and_erase_pending_request(request_header->sequence_number);
512  if (!optional_pending_request) {
513  return;
514  }
515  auto & value = *optional_pending_request;
516  auto typed_response = std::static_pointer_cast<typename ServiceT::Response>(
517  response);
518  if (std::holds_alternative<Promise>(value)) {
519  auto & promise = std::get<Promise>(value);
520  promise.set_value(std::move(typed_response));
521  } else if (std::holds_alternative<CallbackTypeValueVariant>(value)) {
522  auto & inner = std::get<CallbackTypeValueVariant>(value);
523  const auto & callback = std::get<CallbackType>(inner);
524  auto & promise = std::get<Promise>(inner);
525  auto & future = std::get<SharedFuture>(inner);
526  promise.set_value(std::move(typed_response));
527  callback(std::move(future));
528  } else if (std::holds_alternative<CallbackWithRequestTypeValueVariant>(value)) {
529  auto & inner = std::get<CallbackWithRequestTypeValueVariant>(value);
530  const auto & callback = std::get<CallbackWithRequestType>(inner);
531  auto & promise = std::get<PromiseWithRequest>(inner);
532  auto & future = std::get<SharedFutureWithRequest>(inner);
533  auto & request = std::get<SharedRequest>(inner);
534  promise.set_value(std::make_pair(std::move(request), std::move(typed_response)));
535  callback(std::move(future));
536  }
537  }
538 
540 
567  FutureAndRequestId
568  async_send_request(const SharedRequest & request)
569  {
570  Promise promise;
571  auto future = promise.get_future();
572  auto req_id = async_send_request_impl(
573  *request,
574  std::move(promise));
575  return FutureAndRequestId(std::move(future), req_id);
576  }
577 
579 
593  template<
594  typename CallbackT,
595  typename std::enable_if<
597  CallbackT,
598  CallbackType
599  >::value
600  >::type * = nullptr
601  >
602  SharedFutureAndRequestId
603  async_send_request(const SharedRequest & request, CallbackT && cb)
604  {
605  Promise promise;
606  auto shared_future = promise.get_future().share();
607  auto req_id = async_send_request_impl(
608  *request,
609  std::make_tuple(
610  CallbackType{std::forward<CallbackT>(cb)},
611  shared_future,
612  std::move(promise)));
613  return SharedFutureAndRequestId{std::move(shared_future), req_id};
614  }
615 
617 
624  template<
625  typename CallbackT,
626  typename std::enable_if<
628  CallbackT,
629  CallbackWithRequestType
630  >::value
631  >::type * = nullptr
632  >
633  SharedFutureWithRequestAndRequestId
634  async_send_request(const SharedRequest & request, CallbackT && cb)
635  {
636  PromiseWithRequest promise;
637  auto shared_future = promise.get_future().share();
638  auto req_id = async_send_request_impl(
639  *request,
640  std::make_tuple(
641  CallbackWithRequestType{std::forward<CallbackT>(cb)},
642  request,
643  shared_future,
644  std::move(promise)));
645  return SharedFutureWithRequestAndRequestId{std::move(shared_future), req_id};
646  }
647 
649 
659  bool
660  remove_pending_request(int64_t request_id)
661  {
662  std::lock_guard guard(pending_requests_mutex_);
663  return pending_requests_.erase(request_id) != 0u;
664  }
665 
667 
672  bool
674  {
675  return this->remove_pending_request(future.request_id);
676  }
677 
679 
684  bool
686  {
687  return this->remove_pending_request(future.request_id);
688  }
689 
691 
696  bool
698  {
699  return this->remove_pending_request(future.request_id);
700  }
701 
703 
706  size_t
708  {
709  std::lock_guard guard(pending_requests_mutex_);
710  auto ret = pending_requests_.size();
711  pending_requests_.clear();
712  return ret;
713  }
714 
716 
722  template<typename AllocatorT = std::allocator<int64_t>>
723  size_t
725  std::chrono::time_point<std::chrono::system_clock> time_point,
726  std::vector<int64_t, AllocatorT> * pruned_requests = nullptr)
727  {
728  return detail::prune_requests_older_than_impl(
729  pending_requests_,
730  pending_requests_mutex_,
731  time_point,
732  pruned_requests);
733  }
734 
736 
744  void
746  const Clock::SharedPtr & clock, const QoS & qos_service_event_pub,
747  rcl_service_introspection_state_t introspection_state)
748  {
750  pub_opts.qos = qos_service_event_pub.get_rmw_qos_profile();
751 
753  client_handle_.get(),
754  node_handle_.get(),
755  clock->get_clock_handle(),
756  srv_type_support_handle_,
757  pub_opts,
758  introspection_state);
759 
760  if (RCL_RET_OK != ret) {
761  rclcpp::exceptions::throw_from_rcl_error(ret, "failed to configure client introspection");
762  }
763  }
764 
765 protected:
766  using CallbackTypeValueVariant = std::tuple<CallbackType, SharedFuture, Promise>;
767  using CallbackWithRequestTypeValueVariant = std::tuple<
768  CallbackWithRequestType, SharedRequest, SharedFutureWithRequest, PromiseWithRequest>;
769 
770  using CallbackInfoVariant = std::variant<
771  std::promise<SharedResponse>,
772  CallbackTypeValueVariant,
773  CallbackWithRequestTypeValueVariant>;
774 
775  int64_t
776  async_send_request_impl(const Request & request, CallbackInfoVariant value)
777  {
778  int64_t sequence_number;
779  std::lock_guard<std::mutex> lock(pending_requests_mutex_);
780  rcl_ret_t ret = rcl_send_request(get_client_handle().get(), &request, &sequence_number);
781  if (RCL_RET_OK != ret) {
782  rclcpp::exceptions::throw_from_rcl_error(ret, "failed to send request");
783  }
784  pending_requests_.try_emplace(
785  sequence_number,
786  std::make_pair(std::chrono::system_clock::now(), std::move(value)));
787  return sequence_number;
788  }
789 
790  std::optional<CallbackInfoVariant>
791  get_and_erase_pending_request(int64_t request_number)
792  {
793  std::unique_lock<std::mutex> lock(pending_requests_mutex_);
794  auto it = this->pending_requests_.find(request_number);
795  if (it == this->pending_requests_.end()) {
796  RCUTILS_LOG_DEBUG_NAMED(
797  "rclcpp",
798  "Received invalid sequence number. Ignoring...");
799  return std::nullopt;
800  }
801  std::optional<CallbackInfoVariant> value = std::move(it->second.second);
802  this->pending_requests_.erase(request_number);
803  return value;
804  }
805 
806  RCLCPP_DISABLE_COPY(Client)
807 
808  std::unordered_map<
809  int64_t,
810  std::pair<
811  std::chrono::time_point<std::chrono::system_clock>,
812  CallbackInfoVariant>>
813  pending_requests_;
814  std::mutex pending_requests_mutex_;
815 
816 private:
817  const rosidl_service_type_support_t * srv_type_support_handle_;
818 };
819 
820 } // namespace rclcpp
821 
822 #endif // RCLCPP__CLIENT_HPP_
RCLCPP_PUBLIC bool exchange_in_use_by_wait_set_state(bool in_use_state)
Exchange the "in use by wait set" state for this client.
Definition: client.cpp:200
RCLCPP_PUBLIC rclcpp::QoS get_request_publisher_actual_qos() const
Get the actual request publsher QoS settings, after the defaults have been determined.
Definition: client.cpp:206
RCLCPP_PUBLIC std::shared_ptr< rcl_client_t > get_client_handle()
Return the rcl_client_t client handle in a std::shared_ptr.
Definition: client.cpp:98
RCLCPP_PUBLIC void set_on_new_response_callback(const std::function< void(size_t)> &callback)
Set a callback to be called when each new response is received.
Definition: client.cpp:257
RCLCPP_PUBLIC bool take_type_erased_response(void *response_out, rmw_request_id_t &request_header_out)
Take the next response for this client as a type erased pointer.
Definition: client.cpp:77
bool wait_for_service(std::chrono::duration< RepT, RatioT > timeout=std::chrono::duration< RepT, RatioT >(-1))
Wait for a service to be ready.
Definition: client.hpp:210
RCLCPP_PUBLIC void clear_on_new_response_callback()
Unset the callback registered for new responses, if any.
Definition: client.cpp:305
RCLCPP_PUBLIC const char * get_service_name() const
Return the name of the service.
Definition: client.cpp:92
RCLCPP_PUBLIC rclcpp::QoS get_response_subscription_actual_qos() const
Get the actual response subscription QoS settings, after the defaults have been determined.
Definition: client.cpp:225
RCLCPP_PUBLIC bool service_is_ready() const
Return if the service is ready.
Definition: client.cpp:110
bool take_response(typename ServiceT::Response &response_out, rmw_request_id_t &request_header_out)
Take the next response for this client.
Definition: client.hpp:473
std::shared_ptr< rmw_request_id_t > create_request_header() override
Create a shared pointer with a rmw_request_id_t.
Definition: client.hpp:493
bool remove_pending_request(int64_t request_id)
Cleanup a pending request.
Definition: client.hpp:660
std::shared_ptr< void > create_response() override
Create a shared pointer with the response type.
Definition: client.hpp:483
size_t prune_requests_older_than(std::chrono::time_point< std::chrono::system_clock > time_point, std::vector< int64_t, AllocatorT > *pruned_requests=nullptr)
Clean all pending requests older than a time_point.
Definition: client.hpp:724
void configure_introspection(const Clock::SharedPtr &clock, const QoS &qos_service_event_pub, rcl_service_introspection_state_t introspection_state)
Configure client introspection.
Definition: client.hpp:745
FutureAndRequestId async_send_request(const SharedRequest &request)
Send a request to the service server.
Definition: client.hpp:568
Client(rclcpp::node_interfaces::NodeBaseInterface *node_base, const rclcpp::node_interfaces::NodeGraphInterface::SharedPtr &node_graph, const std::string &service_name, rcl_client_options_t &client_options)
Default constructor.
Definition: client.hpp:426
size_t prune_pending_requests()
Clean all pending requests.
Definition: client.hpp:707
bool remove_pending_request(const SharedFutureAndRequestId &future)
Cleanup a pending request.
Definition: client.hpp:685
SharedFutureWithRequestAndRequestId async_send_request(const SharedRequest &request, CallbackT &&cb)
Send a request to the service server and schedule a callback in the executor.
Definition: client.hpp:634
bool remove_pending_request(const SharedFutureWithRequestAndRequestId &future)
Cleanup a pending request.
Definition: client.hpp:697
void handle_response(const std::shared_ptr< rmw_request_id_t > &request_header, const std::shared_ptr< void > &response) override
Handle a server response.
Definition: client.hpp:506
SharedFutureAndRequestId async_send_request(const SharedRequest &request, CallbackT &&cb)
Send a request to the service server and schedule a callback in the executor.
Definition: client.hpp:603
bool remove_pending_request(const FutureAndRequestId &future)
Cleanup a pending request.
Definition: client.hpp:673
Encapsulation of Quality of Service settings.
Definition: qos.hpp:114
rmw_qos_profile_t & get_rmw_qos_profile()
Return the rmw qos profile.
Definition: qos.cpp:109
Pure virtual interface class for the NodeBase part of the Node API.
RCL_PUBLIC RCL_WARN_UNUSED rcl_ret_t rcl_client_configure_service_introspection(rcl_client_t *client, rcl_node_t *node, rcl_clock_t *clock, const rosidl_service_type_support_t *type_support, const rcl_publisher_options_t publisher_options, rcl_service_introspection_state_t introspection_state)
Configures service introspection features for the client.
Definition: client.c:456
RCL_PUBLIC RCL_WARN_UNUSED rcl_ret_t rcl_client_init(rcl_client_t *client, const rcl_node_t *node, const rosidl_service_type_support_t *type_support, const char *service_name, const rcl_client_options_t *options)
Initialize a rcl client.
Definition: client.c:76
RCL_PUBLIC RCL_WARN_UNUSED rcl_ret_t rcl_send_request(const rcl_client_t *client, const void *ros_request, int64_t *sequence_number)
Send a ROS request using a client.
Definition: client.c:308
Versions of rosidl_typesupport_cpp::get_message_type_support_handle that handle adapted types.
RCLCPP_PUBLIC std::string expand_topic_or_service_name(const std::string &name, const std::string &node_name, const std::string &namespace_, bool is_service=false)
Expand a topic or service name and throw if it is not valid.
RCL_PUBLIC RCL_WARN_UNUSED const char * rcl_node_get_name(const rcl_node_t *node)
Return the name of the node.
Definition: node.c:416
RCL_PUBLIC RCL_WARN_UNUSED const char * rcl_node_get_namespace(const rcl_node_t *node)
Return the namespace of the node.
Definition: node.c:425
RCL_PUBLIC RCL_WARN_UNUSED rcl_publisher_options_t rcl_publisher_get_default_options(void)
Return the default publisher options in a rcl_publisher_options_t.
Definition: publisher.c:217
Options available for a rcl_client_t.
Definition: client.h:50
Structure which encapsulates a ROS Node.
Definition: node.h:45
Options available for a rcl publisher.
Definition: publisher.h:44
rmw_qos_profile_t qos
Middleware quality of service settings for the publisher.
Definition: publisher.h:46
A convenient Client::Future and request id pair.
Definition: client.hpp:376
SharedFuture share() noexcept
See std::future::share().
Definition: client.hpp:382
A convenient Client::SharedFuture and request id pair.
Definition: client.hpp:395
A convenient Client::SharedFutureWithRequest and request id pair.
Definition: client.hpp:409
std::future_status wait_for(const std::chrono::duration< Rep, Period > &timeout_duration) const
See std::future::wait_for().
Definition: client.hpp:80
std::future_status wait_until(const std::chrono::time_point< Clock, Duration > &timeout_time) const
See std::future::wait_until().
Definition: client.hpp:87
FutureAndRequestId & operator=(FutureAndRequestId &&other) noexcept=default
Move assignment.
FutureAndRequestId & operator=(const FutureAndRequestId &other)=delete
Deleted copy assignment, each instance is a unique owner of the future.
FutureAndRequestId(const FutureAndRequestId &other)=delete
Deleted copy constructor, each instance is a unique owner of the future.
void wait() const
See std::future::wait().
Definition: client.hpp:77
FutureAndRequestId(FutureAndRequestId &&other) noexcept=default
Move constructor.
~FutureAndRequestId()=default
Destructor.
auto get()
See std::future::get().
Definition: client.hpp:73
bool valid() const noexcept
See std::future::valid().
Definition: client.hpp:75
#define RCL_RET_SERVICE_NAME_INVALID
Service name (same as topic name) does not pass validation.
Definition: types.h:49
#define RCL_RET_OK
Success return code.
Definition: types.h:27
rmw_ret_t rcl_ret_t
The type that holds an rcl return code.
Definition: types.h:24